IOMX: consolidate buffer passing on IOMX

- Use OMXBuffer to parcel different buffer types.

- Only leave one useBuffer, emptyBuffer and fillBuffer.

- Remove the update metadata calls.

bug: 31399200
Change-Id: I307e59415c3c5be61772210431bd8225ce6b75a3
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index b902cf5..839945c 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -19,7 +19,7 @@
 #define ANDROID_IOMX_H_
 
 #include <binder/IInterface.h>
-#include <ui/GraphicBuffer.h>
+#include <gui/IGraphicBufferProducer.h>
 #include <utils/List.h>
 #include <utils/String8.h>
 
@@ -39,6 +39,7 @@
 class IOMXNode;
 class IOMXObserver;
 class NativeHandle;
+class OMXBuffer;
 struct omx_message;
 
 class IOMX : public IInterface {
@@ -108,23 +109,6 @@
     virtual status_t getGraphicBufferUsage(
             OMX_U32 port_index, OMX_U32* usage) = 0;
 
-    // Use |params| as an OMX buffer, but limit the size of the OMX buffer to |allottedSize|.
-    virtual status_t useBuffer(
-            OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer, OMX_U32 allottedSize) = 0;
-
-    virtual status_t useGraphicBuffer(
-            OMX_U32 port_index,
-            const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) = 0;
-
-    virtual status_t updateGraphicBufferInMeta(
-            OMX_U32 port_index,
-            const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) = 0;
-
-    virtual status_t updateNativeHandleInMeta(
-            OMX_U32 port_index,
-            const sp<NativeHandle> &nativeHandle, buffer_id buffer) = 0;
-
     virtual status_t setInputSurface(
             const sp<IOMXBufferSource> &bufferSource) = 0;
 
@@ -137,34 +121,37 @@
             OMX_U32 port_index, size_t size, buffer_id *buffer,
             void **buffer_data, sp<NativeHandle> *native_handle) = 0;
 
+    // Instructs the component to use the buffer passed in via |omxBuf| on the
+    // specified port. Returns in |*buffer| the buffer id that the component
+    // assigns to this buffer. |omxBuf| must be one of:
+    // 1) OMXBuffer::sPreset for meta-mode,
+    // 2) type kBufferTypeANWBuffer for non-meta-graphic buffer mode,
+    // 3) type kBufferTypeSharedMem for bytebuffer mode.
+    virtual status_t useBuffer(
+            OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) = 0;
+
+    // Frees the buffer on the specified port with buffer id |buffer|.
     virtual status_t freeBuffer(
             OMX_U32 port_index, buffer_id buffer) = 0;
 
-    // Calls OMX_FillBuffer on buffer, and passes |fenceFd| to component if it supports
-    // fences. Otherwise, it waits on |fenceFd| before calling OMX_FillBuffer.
-    // Takes ownership of |fenceFd| even if this call fails.
-    virtual status_t fillBuffer(buffer_id buffer, int fenceFd = -1) = 0;
+    // Calls OMX_FillBuffer on buffer. Passes |fenceFd| to component if it
+    // supports fences. Otherwise, it waits on |fenceFd| before calling
+    // OMX_FillBuffer. Takes ownership of |fenceFd| even if this call fails.
+    // If the port is in metadata mode, the buffer will be updated to point
+    // to the new buffer passed in via |omxBuf| before OMX_FillBuffer is called.
+    // Otherwise info in the |omxBuf| is not used.
+    virtual status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd = -1) = 0;
 
-    // Calls OMX_EmptyBuffer on buffer (after updating buffer header with |range_offset|,
-    // |range_length|, |flags| and |timestamp|). Passes |fenceFd| to component if it
-    // supports fences. Otherwise, it waits on |fenceFd| before calling OMX_EmptyBuffer.
-    // Takes ownership of |fenceFd| even if this call fails.
+    // Calls OMX_EmptyBuffer on buffer. Passes |fenceFd| to component if it
+    // supports fences. Otherwise, it waits on |fenceFd| before calling
+    // OMX_EmptyBuffer. Takes ownership of |fenceFd| even if this call fails.
+    // If the port is in metadata mode, the buffer will be updated to point
+    // to the new buffer passed in via |omxBuf| before OMX_EmptyBuffer is called.
     virtual status_t emptyBuffer(
-            buffer_id buffer,
-            OMX_U32 range_offset, OMX_U32 range_length,
+            buffer_id buffer, const OMXBuffer &omxBuf,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1) = 0;
 
-    // Calls OMX_EmptyBuffer on buffer (after updating buffer header with metadata of
-    // |graphicBuffer|, |flags| and |timestamp|). Passes |fenceFd| to component if it
-    // supports fences. Otherwise, it waits on |fenceFd| before calling OMX_EmptyBuffer.
-    // Takes ownership of |fenceFd| even if this call fails. If |origTimestamp| >= 0,
-    // timestamp on the filled buffer corresponding to this frame will be modified to
-    // |origTimestamp| after it's filled.
-    virtual status_t emptyGraphicBuffer(
-            buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, int fenceFd) = 0;
-
     virtual status_t getExtensionIndex(
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
diff --git a/include/media/OMXBuffer.h b/include/media/OMXBuffer.h
new file mode 100644
index 0000000..0322b73
--- /dev/null
+++ b/include/media/OMXBuffer.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OMXBUFFER_H_
+#define _OMXBUFFER_H_
+
+#include <cutils/native_handle.h>
+#include <media/IOMX.h>
+#include <system/window.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IMemory;
+class MediaCodecBuffer;
+class NativeHandle;
+class OMXNodeInstance;
+
+class OMXBuffer {
+public:
+    // sPreset is used in places where we are referring to a pre-registered
+    // buffer on a port. It has type kBufferTypePreset and mRangeLength of 0.
+    static OMXBuffer sPreset;
+
+    // Default constructor, constructs a buffer of type kBufferTypeInvalid.
+    OMXBuffer();
+
+    // Constructs a buffer of type kBufferTypePreset with mRangeLength set to
+    // |codecBuffer|'s size (or 0 if |codecBuffer| is NULL).
+    OMXBuffer(const sp<MediaCodecBuffer> &codecBuffer);
+
+    // Constructs a buffer of type kBufferTypeSharedMem.
+    OMXBuffer(const sp<IMemory> &mem, size_t allottedSize = 0);
+
+    // Constructs a buffer of type kBufferTypeANWBuffer.
+    OMXBuffer(const sp<GraphicBuffer> &gbuf);
+
+    // Constructs a buffer of type kBufferTypeNativeHandle.
+    OMXBuffer(const sp<NativeHandle> &handle);
+
+    // Parcelling/Un-parcelling.
+    status_t writeToParcel(Parcel *parcel) const;
+    status_t readFromParcel(const Parcel *parcel);
+
+    ~OMXBuffer();
+
+private:
+    friend class OMXNodeInstance;
+
+    enum BufferType {
+        kBufferTypeInvalid = 0,
+        kBufferTypePreset,
+        kBufferTypeSharedMem,
+        kBufferTypeANWBuffer,
+        kBufferTypeNativeHandle,
+    };
+
+    BufferType mBufferType;
+
+    // kBufferTypePreset
+    // If the port is operating in byte buffer mode, mRangeLength is the valid
+    // range length. Otherwise the range info should also be ignored.
+    OMX_U32 mRangeLength;
+
+    // kBufferTypeSharedMem
+    sp<IMemory> mMem;
+    OMX_U32 mAllottedSize;
+
+    // kBufferTypeANWBuffer
+    sp<GraphicBuffer> mGraphicBuffer;
+
+    // kBufferTypeNativeHandle
+    sp<NativeHandle> mNativeHandle;
+
+    OMXBuffer(const OMXBuffer &);
+    OMXBuffer &operator=(const OMXBuffer &);
+};
+
+}  // namespace android
+
+#endif  // _OMXBUFFER_H_
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 64a542d..13ceeb6 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -330,6 +330,8 @@
             uint32_t portIndex, IOMX::buffer_id bufferID,
             ssize_t *index = NULL);
 
+    status_t fillBuffer(BufferInfo *info);
+
     status_t setComponentRole(bool isEncoder, const char *mime);
 
     status_t configureCodec(const char *mime, const sp<AMessage> &msg);
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index ca96098..56b2979 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -65,6 +65,7 @@
     MediaProfiles.cpp \
     MediaResource.cpp \
     MediaResourcePolicy.cpp \
+    OMXBuffer.cpp \
     IEffect.cpp \
     IEffectClient.cpp \
     AudioEffect.cpp \
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 4bd1ab8..1a6d6b8 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -26,8 +26,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/openmax/OMX_IndexExt.h>
 #include <utils/NativeHandle.h>
+#include <media/OMXBuffer.h>
 
-#include <gui/IGraphicBufferProducer.h>
 #include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 
@@ -45,7 +45,6 @@
     SET_CONFIG,
     ENABLE_NATIVE_BUFFERS,
     USE_BUFFER,
-    USE_GRAPHIC_BUFFER,
     CREATE_INPUT_SURFACE,
     SET_INPUT_SURFACE,
     STORE_META_DATA_IN_BUFFERS,
@@ -54,13 +53,10 @@
     FREE_BUFFER,
     FILL_BUFFER,
     EMPTY_BUFFER,
-    EMPTY_GRAPHIC_BUFFER,
     GET_EXTENSION_INDEX,
     OBSERVER_ON_MSG,
     GET_GRAPHIC_BUFFER_USAGE,
-    UPDATE_GRAPHIC_BUFFER_IN_META,
     CONFIGURE_VIDEO_TUNNEL_MODE,
-    UPDATE_NATIVE_HANDLE_IN_META,
     DISPATCH_MESSAGE,
     SET_QUIRKS,
 };
@@ -255,16 +251,19 @@
     }
 
     virtual status_t useBuffer(
-            OMX_U32 port_index, const sp<IMemory> &params,
-            buffer_id *buffer, OMX_U32 allottedSize) {
+            OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
         data.writeInt32(port_index);
-        data.writeStrongBinder(IInterface::asBinder(params));
-        data.writeInt32(allottedSize);
+
+        status_t err = omxBuf.writeToParcel(&data);
+        if (err != OK) {
+            return err;
+        }
+
         remote()->transact(USE_BUFFER, data, &reply);
 
-        status_t err = reply.readInt32();
+        err = reply.readInt32();
         if (err != OK) {
             *buffer = 0;
 
@@ -276,59 +275,6 @@
         return err;
     }
 
-
-    virtual status_t useGraphicBuffer(
-            OMX_U32 port_index,
-            const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
-        data.writeInt32(port_index);
-        data.write(*graphicBuffer);
-        remote()->transact(USE_GRAPHIC_BUFFER, data, &reply);
-
-        status_t err = reply.readInt32();
-        if (err != OK) {
-            *buffer = 0;
-
-            return err;
-        }
-
-        *buffer = (buffer_id)reply.readInt32();
-
-        return err;
-    }
-
-    virtual status_t updateGraphicBufferInMeta(
-            OMX_U32 port_index,
-            const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
-        data.writeInt32(port_index);
-        data.write(*graphicBuffer);
-        data.writeInt32((int32_t)buffer);
-        remote()->transact(UPDATE_GRAPHIC_BUFFER_IN_META, data, &reply);
-
-        status_t err = reply.readInt32();
-        return err;
-    }
-
-    virtual status_t updateNativeHandleInMeta(
-            OMX_U32 port_index,
-            const sp<NativeHandle> &nativeHandle, buffer_id buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
-        data.writeInt32(port_index);
-        data.writeInt32(nativeHandle != NULL);
-        if (nativeHandle != NULL) {
-            data.writeNativeHandle(nativeHandle->handle());
-        }
-        data.writeInt32((int32_t)buffer);
-        remote()->transact(UPDATE_NATIVE_HANDLE_IN_META, data, &reply);
-
-        status_t err = reply.readInt32();
-        return err;
-    }
-
     virtual status_t setInputSurface(
             const sp<IOMXBufferSource> &bufferSource) {
         Parcel data, reply;
@@ -439,10 +385,15 @@
         return reply.readInt32();
     }
 
-    virtual status_t fillBuffer(buffer_id buffer, int fenceFd) {
+    virtual status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
         data.writeInt32((int32_t)buffer);
+        status_t err = omxBuf.writeToParcel(&data);
+        if (err != OK) {
+            return err;
+        }
         data.writeInt32(fenceFd >= 0);
         if (fenceFd >= 0) {
             data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
@@ -453,14 +404,15 @@
     }
 
     virtual status_t emptyBuffer(
-            buffer_id buffer,
-            OMX_U32 range_offset, OMX_U32 range_length,
+            buffer_id buffer, const OMXBuffer &omxBuf,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
         data.writeInt32((int32_t)buffer);
-        data.writeInt32(range_offset);
-        data.writeInt32(range_length);
+        status_t err = omxBuf.writeToParcel(&data);
+        if (err != OK) {
+            return err;
+        }
         data.writeInt32(flags);
         data.writeInt64(timestamp);
         data.writeInt32(fenceFd >= 0);
@@ -472,25 +424,6 @@
         return reply.readInt32();
     }
 
-    virtual status_t emptyGraphicBuffer(
-            buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, int fenceFd) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
-        data.writeInt32((int32_t)buffer);
-        data.write(*graphicBuffer);
-        data.writeInt32(flags);
-        data.writeInt64(timestamp);
-        data.writeInt32(fenceFd >= 0);
-        if (fenceFd >= 0) {
-            data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
-        }
-        remote()->transact(EMPTY_GRAPHIC_BUFFER, data, &reply);
-
-        return reply.readInt32();
-    }
-
     virtual status_t getExtensionIndex(
             const char *parameter_name,
             OMX_INDEXTYPE *index) {
@@ -770,18 +703,15 @@
             CHECK_OMX_INTERFACE(IOMXNode, data, reply);
 
             OMX_U32 port_index = data.readInt32();
-            sp<IMemory> params =
-                interface_cast<IMemory>(data.readStrongBinder());
-            OMX_U32 allottedSize = data.readInt32();
 
-            if (params == NULL) {
-                ALOGE("b/26392700");
-                reply->writeInt32(INVALID_OPERATION);
-                return NO_ERROR;
+            OMXBuffer omxBuf;
+            status_t err = omxBuf.readFromParcel(&data);
+            if (err != OK) {
+                return err;
             }
 
             buffer_id buffer;
-            status_t err = useBuffer(port_index, params, &buffer, allottedSize);
+            err = useBuffer(port_index, omxBuf, &buffer);
             reply->writeInt32(err);
 
             if (err == OK) {
@@ -791,60 +721,6 @@
             return NO_ERROR;
         }
 
-        case USE_GRAPHIC_BUFFER:
-        {
-            CHECK_OMX_INTERFACE(IOMXNode, data, reply);
-
-            OMX_U32 port_index = data.readInt32();
-            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
-            data.read(*graphicBuffer);
-
-            buffer_id buffer;
-            status_t err = useGraphicBuffer(
-                    port_index, graphicBuffer, &buffer);
-            reply->writeInt32(err);
-
-            if (err == OK) {
-                reply->writeInt32((int32_t)buffer);
-            }
-
-            return NO_ERROR;
-        }
-
-        case UPDATE_GRAPHIC_BUFFER_IN_META:
-        {
-            CHECK_OMX_INTERFACE(IOMXNode, data, reply);
-
-            OMX_U32 port_index = data.readInt32();
-            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
-            data.read(*graphicBuffer);
-            buffer_id buffer = (buffer_id)data.readInt32();
-
-            status_t err = updateGraphicBufferInMeta(
-                    port_index, graphicBuffer, buffer);
-            reply->writeInt32(err);
-
-            return NO_ERROR;
-        }
-
-        case UPDATE_NATIVE_HANDLE_IN_META:
-        {
-            CHECK_OMX_INTERFACE(IOMXNode, data, reply);
-
-            OMX_U32 port_index = data.readInt32();
-            native_handle *handle = NULL;
-            if (data.readInt32()) {
-                handle = data.readNativeHandle();
-            }
-            buffer_id buffer = (buffer_id)data.readInt32();
-
-            status_t err = updateNativeHandleInMeta(
-                    port_index, NativeHandle::create(handle, true /* ownshandle */), buffer);
-            reply->writeInt32(err);
-
-            return NO_ERROR;
-        }
-
         case SET_INPUT_SURFACE:
         {
             CHECK_OMX_INTERFACE(IOMXNode, data, reply);
@@ -956,9 +832,17 @@
             CHECK_OMX_INTERFACE(IOMXNode, data, reply);
 
             buffer_id buffer = (buffer_id)data.readInt32();
+
+            OMXBuffer omxBuf;
+            status_t err = omxBuf.readFromParcel(&data);
+            if (err != OK) {
+                return err;
+            }
+
             bool haveFence = data.readInt32();
             int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
-            reply->writeInt32(fillBuffer(buffer, fenceFd));
+
+            reply->writeInt32(fillBuffer(buffer, omxBuf, fenceFd));
 
             return NO_ERROR;
         }
@@ -968,31 +852,17 @@
             CHECK_OMX_INTERFACE(IOMXNode, data, reply);
 
             buffer_id buffer = (buffer_id)data.readInt32();
-            OMX_U32 range_offset = data.readInt32();
-            OMX_U32 range_length = data.readInt32();
+            OMXBuffer omxBuf;
+            status_t err = omxBuf.readFromParcel(&data);
+            if (err != OK) {
+                return err;
+            }
             OMX_U32 flags = data.readInt32();
             OMX_TICKS timestamp = data.readInt64();
             bool haveFence = data.readInt32();
             int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
             reply->writeInt32(emptyBuffer(
-                    buffer, range_offset, range_length, flags, timestamp, fenceFd));
-
-            return NO_ERROR;
-        }
-
-        case EMPTY_GRAPHIC_BUFFER:
-        {
-            CHECK_OMX_INTERFACE(IOMXNode, data, reply);
-
-            buffer_id buffer = (buffer_id)data.readInt32();
-            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
-            data.read(*graphicBuffer);
-            OMX_U32 flags = data.readInt32();
-            OMX_TICKS timestamp = data.readInt64();
-            bool haveFence = data.readInt32();
-            int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
-            reply->writeInt32(emptyGraphicBuffer(
-                    buffer, graphicBuffer, flags, timestamp, fenceFd));
+                    buffer, omxBuf, flags, timestamp, fenceFd));
 
             return NO_ERROR;
         }
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
new file mode 100644
index 0000000..0931872
--- /dev/null
+++ b/media/libmedia/OMXBuffer.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OMXBuffer"
+
+#include <media/MediaCodecBuffer.h>
+#include <media/OMXBuffer.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/NativeHandle.h>
+
+namespace android {
+
+//static
+OMXBuffer OMXBuffer::sPreset(static_cast<sp<MediaCodecBuffer> >(NULL));
+
+OMXBuffer::OMXBuffer()
+    : mBufferType(kBufferTypeInvalid) {
+}
+
+OMXBuffer::OMXBuffer(const sp<MediaCodecBuffer>& codecBuffer)
+    : mBufferType(kBufferTypePreset),
+      mRangeLength(codecBuffer != NULL ? codecBuffer->size() : 0) {
+}
+
+OMXBuffer::OMXBuffer(const sp<IMemory> &mem, size_t allottedSize)
+    : mBufferType(kBufferTypeSharedMem),
+      mMem(mem),
+      mAllottedSize(allottedSize ? : mem->size()) {
+}
+
+OMXBuffer::OMXBuffer(const sp<GraphicBuffer> &gbuf)
+    : mBufferType(kBufferTypeANWBuffer),
+      mGraphicBuffer(gbuf) {
+}
+
+OMXBuffer::OMXBuffer(const sp<NativeHandle> &handle)
+    : mBufferType(kBufferTypeNativeHandle),
+      mNativeHandle(handle) {
+}
+
+OMXBuffer::~OMXBuffer() {
+}
+
+status_t OMXBuffer::writeToParcel(Parcel *parcel) const {
+    parcel->writeInt32(mBufferType);
+
+    switch(mBufferType) {
+        case kBufferTypePreset:
+        {
+            return parcel->writeUint32(mRangeLength);
+        }
+
+        case kBufferTypeSharedMem:
+        {
+            status_t err = parcel->writeStrongBinder(IInterface::asBinder(mMem));
+            if (err != NO_ERROR) {
+                return err;
+            }
+            return parcel->writeUint32(mAllottedSize);
+        }
+
+        case kBufferTypeANWBuffer:
+        {
+            return parcel->write(*mGraphicBuffer);
+        }
+
+        case kBufferTypeNativeHandle:
+        {
+            return parcel->writeNativeHandle(mNativeHandle->handle());
+        }
+
+        default:
+            return BAD_VALUE;
+    }
+    return BAD_VALUE;
+}
+
+status_t OMXBuffer::readFromParcel(const Parcel *parcel) {
+    BufferType bufferType = (BufferType) parcel->readInt32();
+
+    switch(bufferType) {
+        case kBufferTypePreset:
+        {
+            mRangeLength = parcel->readUint32();
+            break;
+        }
+
+        case kBufferTypeSharedMem:
+        {
+            sp<IMemory> params = interface_cast<IMemory>(parcel->readStrongBinder());
+
+            mMem = params;
+            mAllottedSize = parcel->readUint32();
+            break;
+        }
+
+        case kBufferTypeANWBuffer:
+        {
+            sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+            status_t err = parcel->read(*buffer);
+
+            if (err != OK) {
+                return err;
+            }
+
+            mGraphicBuffer = buffer;
+            break;
+        }
+
+        case kBufferTypeNativeHandle:
+        {
+            sp<NativeHandle> handle = NativeHandle::create(
+                    parcel->readNativeHandle(), true /* ownsHandle */);
+
+            mNativeHandle = handle;
+            break;
+        }
+
+        default:
+            return BAD_VALUE;
+    }
+
+    mBufferType = bufferType;
+    return OK;
+}
+
+} // namespace android
+
+
+
+
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 52c0feb..094f5cc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -44,6 +44,7 @@
 #include <media/stagefright/PersistentSurface.h>
 #include <media/stagefright/SurfaceUtils.h>
 #include <media/hardware/HardwareAPI.h>
+#include <media/OMXBuffer.h>
 
 #include <OMX_AudioExt.h>
 #include <OMX_VideoExt.h>
@@ -796,7 +797,7 @@
 
     status_t err;
     if (mNativeWindow != NULL && portIndex == kPortIndexOutput) {
-        if (storingMetadataInDecodedBuffers()) {
+        if (storingMetadataInDecodedBuffers() && !mLegacyAdaptiveExperiment) {
             err = allocateOutputMetadataBuffers();
         } else {
             err = allocateOutputBuffersFromNativeWindow();
@@ -893,8 +894,8 @@
                             : new SecureBuffer(format, native_handle, bufSize);
                     info.mCodecData = info.mData;
                 } else {
-                    err = mOMXNode->useBuffer(
-                            portIndex, mem, &info.mBufferID, allottedSize);
+                    err = mOMXNode->useBuffer(portIndex,
+                            OMXBuffer(mem, allottedSize), &info.mBufferID);
                 }
 
                 if (mem != NULL) {
@@ -1085,6 +1086,11 @@
 }
 
 status_t ACodec::allocateOutputBuffersFromNativeWindow() {
+    // This method only handles the non-metadata mode, or legacy metadata mode
+    // (where the headers for each buffer id will be fixed). Non-legacy metadata
+    // mode shouldn't go through this path.
+    CHECK(!storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment);
+
     OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
     status_t err = configureOutputBuffersFromNativeWindow(
             &bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);
@@ -1092,10 +1098,8 @@
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
 
-    if (!storingMetadataInDecodedBuffers()) {
-        static_cast<Surface*>(mNativeWindow.get())
-                ->getIGraphicBufferProducer()->allowAllocation(true);
-    }
+    static_cast<Surface*>(mNativeWindow.get())
+            ->getIGraphicBufferProducer()->allowAllocation(true);
 
     ALOGV("[%s] Allocating %u buffers from a native window of size %u on "
          "output port",
@@ -1118,11 +1122,19 @@
         info.mIsReadFence = false;
         info.mRenderInfo = NULL;
         info.mGraphicBuffer = graphicBuffer;
+
+        // TODO: We shouln't need to create MediaCodecBuffer. In metadata mode
+        //       OMX doesn't use the shared memory buffer, but some code still
+        //       access info.mData. Create an ABuffer as a placeholder.
+        if (storingMetadataInDecodedBuffers()) {
+            info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
+            info.mCodecData = info.mData;
+        }
+
         mBuffers[kPortIndexOutput].push(info);
 
         IOMX::buffer_id bufferId;
-        err = mOMXNode->useGraphicBuffer(
-                kPortIndexOutput, graphicBuffer, &bufferId);
+        err = mOMXNode->useBuffer(kPortIndexOutput, graphicBuffer, &bufferId);
         if (err != 0) {
             ALOGE("registering GraphicBuffer %u with OMX IL component failed: "
                  "%d", i, err);
@@ -1139,9 +1151,9 @@
     OMX_U32 cancelStart;
     OMX_U32 cancelEnd;
 
-    if (err != 0) {
+    if (err != 0 || storingMetadataInDecodedBuffers()) {
         // If an error occurred while dequeuing we need to cancel any buffers
-        // that were dequeued.
+        // that were dequeued. Also cancel all if we're in legacy metadata mode.
         cancelStart = 0;
         cancelEnd = mBuffers[kPortIndexOutput].size();
     } else {
@@ -1160,19 +1172,23 @@
         }
     }
 
-    if (!storingMetadataInDecodedBuffers()) {
-        static_cast<Surface*>(mNativeWindow.get())
-                ->getIGraphicBufferProducer()->allowAllocation(false);
+    static_cast<Surface*>(mNativeWindow.get())
+            ->getIGraphicBufferProducer()->allowAllocation(false);
+
+    if (storingMetadataInDecodedBuffers()) {
+        mMetadataBuffersToSubmit = bufferCount - minUndequeuedBuffers;
     }
 
     return err;
 }
 
 status_t ACodec::allocateOutputMetadataBuffers() {
+    CHECK(storingMetadataInDecodedBuffers() && !mLegacyAdaptiveExperiment);
+
     OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
     status_t err = configureOutputBuffersFromNativeWindow(
             &bufferCount, &bufferSize, &minUndequeuedBuffers,
-            mLegacyAdaptiveExperiment /* preregister */);
+            false /* preregister */);
     if (err != 0)
         return err;
     mNumUndequeuedBuffers = minUndequeuedBuffers;
@@ -1185,7 +1201,6 @@
     size_t totalSize = bufferCount * align(bufSize, MemoryDealer::getAllocationAlignment());
     mDealer[kPortIndexOutput] = new MemoryDealer(totalSize, "ACodec");
 
-    // Dequeue buffers and send them to OMX
     for (OMX_U32 i = 0; i < bufferCount; i++) {
         BufferInfo info;
         info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
@@ -1206,57 +1221,13 @@
         info.mCodecData = info.mData;
         info.mCodecRef = mem;
 
-        err = mOMXNode->useBuffer(
-                kPortIndexOutput, mem, &info.mBufferID, mem->size());
+        err = mOMXNode->useBuffer(kPortIndexOutput, mem, &info.mBufferID);
         mBuffers[kPortIndexOutput].push(info);
 
         ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
              mComponentName.c_str(), info.mBufferID, mem->pointer());
     }
 
-    if (mLegacyAdaptiveExperiment) {
-        // preallocate and preregister buffers
-        static_cast<Surface *>(mNativeWindow.get())
-                ->getIGraphicBufferProducer()->allowAllocation(true);
-
-        ALOGV("[%s] Allocating %u buffers from a native window of size %u on "
-             "output port",
-             mComponentName.c_str(), bufferCount, bufferSize);
-
-        // Dequeue buffers then cancel them all
-        for (OMX_U32 i = 0; i < bufferCount; i++) {
-            BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
-
-            ANativeWindowBuffer *buf;
-            int fenceFd;
-            err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
-            if (err != 0) {
-                ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
-                break;
-            }
-
-            sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));
-            mOMXNode->updateGraphicBufferInMeta(
-                    kPortIndexOutput, graphicBuffer, info->mBufferID);
-            info->mStatus = BufferInfo::OWNED_BY_US;
-            info->setWriteFence(fenceFd, "allocateOutputMetadataBuffers for legacy");
-            info->mGraphicBuffer = graphicBuffer;
-        }
-
-        for (OMX_U32 i = 0; i < mBuffers[kPortIndexOutput].size(); i++) {
-            BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
-            if (info->mStatus == BufferInfo::OWNED_BY_US) {
-                status_t error = cancelBufferToNativeWindow(info);
-                if (err == OK) {
-                    err = error;
-                }
-            }
-        }
-
-        static_cast<Surface*>(mNativeWindow.get())
-                ->getIGraphicBufferProducer()->allowAllocation(false);
-    }
-
     mMetadataBuffersToSubmit = bufferCount - minUndequeuedBuffers;
     return err;
 }
@@ -1276,13 +1247,7 @@
 
     --mMetadataBuffersToSubmit;
     info->checkWriteFence("submitOutputMetadataBuffer");
-    status_t err = mOMXNode->fillBuffer(info->mBufferID, info->mFenceFd);
-    info->mFenceFd = -1;
-    if (err == OK) {
-        info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
-    }
-
-    return err;
+    return fillBuffer(info);
 }
 
 status_t ACodec::waitForFence(int fd, const char *dbg ) {
@@ -1467,6 +1432,12 @@
     // while loop above does not complete
     CHECK(storingMetadataInDecodedBuffers());
 
+    if (storingMetadataInDecodedBuffers() && mLegacyAdaptiveExperiment) {
+        // If we're here while running legacy experiment, we dequeued some
+        // unrecognized buffers, and the experiment can't continue.
+        ALOGE("Legacy experiment failed, drop back to metadata mode");
+        mLegacyAdaptiveExperiment = false;
+    }
     // discard buffer in LRU info and replace with new buffer
     oldest->mGraphicBuffer = new GraphicBuffer(buf, false);
     oldest->mStatus = BufferInfo::OWNED_BY_US;
@@ -1474,9 +1445,6 @@
     mRenderTracker.untrackFrame(oldest->mRenderInfo);
     oldest->mRenderInfo = NULL;
 
-    mOMXNode->updateGraphicBufferInMeta(
-            kPortIndexOutput, oldest->mGraphicBuffer, oldest->mBufferID);
-
     if (mOutputMetadataType == kMetadataBufferTypeGrallocSource) {
         VideoGrallocMetadata *grallocMeta =
             reinterpret_cast<VideoGrallocMetadata *>(oldest->mCodecData->base());
@@ -1599,6 +1567,23 @@
     return NULL;
 }
 
+status_t ACodec::fillBuffer(BufferInfo *info) {
+    status_t err;
+    if (!storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment) {
+        err = mOMXNode->fillBuffer(
+            info->mBufferID, OMXBuffer::sPreset, info->mFenceFd);
+    } else {
+        err = mOMXNode->fillBuffer(
+            info->mBufferID, info->mGraphicBuffer, info->mFenceFd);
+    }
+
+    info->mFenceFd = -1;
+    if (err == OK) {
+        info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
+    }
+    return err;
+}
+
 status_t ACodec::setComponentRole(
         bool isEncoder, const char *mime) {
     const char *role = GetComponentRole(isEncoder, mime);
@@ -5683,6 +5668,8 @@
                         return;
                     }
                     size = info->mCodecData->size();
+                } else {
+                    info->mCodecData->setRange(0, size);
                 }
 
                 if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
@@ -5725,25 +5712,29 @@
                 status_t err2 = OK;
                 switch (metaType) {
                 case kMetadataBufferTypeInvalid:
+                    {
+                        err2 = mCodec->mOMXNode->emptyBuffer(
+                            bufferID, info->mCodecData, flags, timeUs, info->mFenceFd);
+                    }
                     break;
 #ifndef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
                 case kMetadataBufferTypeNativeHandleSource:
                     if (info->mCodecData->size() >= sizeof(VideoNativeHandleMetadata)) {
                         VideoNativeHandleMetadata *vnhmd =
                             (VideoNativeHandleMetadata*)info->mCodecData->base();
-                        err2 = mCodec->mOMXNode->updateNativeHandleInMeta(
-                                mCodec->kPortIndexInput,
-                                NativeHandle::create(vnhmd->pHandle, false /* ownsHandle */),
-                                bufferID);
+                        sp<NativeHandle> handle = NativeHandle::create(
+                                vnhmd->pHandle, false /* ownsHandle */);
+                        err2 = mCodec->mOMXNode->emptyBuffer(
+                            bufferID, handle, flags, timeUs, info->mFenceFd);
                     }
                     break;
                 case kMetadataBufferTypeANWBuffer:
                     if (info->mCodecData->size() >= sizeof(VideoNativeMetadata)) {
                         VideoNativeMetadata *vnmd = (VideoNativeMetadata*)info->mCodecData->base();
-                        err2 = mCodec->mOMXNode->updateGraphicBufferInMeta(
-                                mCodec->kPortIndexInput,
-                                new GraphicBuffer(vnmd->pBuffer, false /* keepOwnership */),
-                                bufferID);
+                        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                                vnmd->pBuffer, false /* keepOwnership */);
+                        err2 = mCodec->mOMXNode->emptyBuffer(
+                            bufferID, graphicBuffer, flags, timeUs, info->mFenceFd);
                     }
                     break;
 #endif
@@ -5755,15 +5746,6 @@
                     break;
                 }
 
-                if (err2 == OK) {
-                    err2 = mCodec->mOMXNode->emptyBuffer(
-                        bufferID,
-                        0,
-                        size,
-                        flags,
-                        timeUs,
-                        info->mFenceFd);
-                }
                 info->mFenceFd = -1;
                 if (err2 != OK) {
                     mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err2));
@@ -5796,12 +5778,7 @@
 
                 info->checkReadFence("onInputBufferFilled");
                 status_t err2 = mCodec->mOMXNode->emptyBuffer(
-                        bufferID,
-                        0,
-                        0,
-                        OMX_BUFFERFLAG_EOS,
-                        0,
-                        info->mFenceFd);
+                        bufferID, OMXBuffer::sPreset, OMX_BUFFERFLAG_EOS, 0, info->mFenceFd);
                 info->mFenceFd = -1;
                 if (err2 != OK) {
                     mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err2));
@@ -5925,14 +5902,11 @@
                 ALOGV("[%s] calling fillBuffer %u",
                      mCodec->mComponentName.c_str(), info->mBufferID);
 
-                err = mCodec->mOMXNode->fillBuffer(info->mBufferID, info->mFenceFd);
-                info->mFenceFd = -1;
+                err = mCodec->fillBuffer(info);
                 if (err != OK) {
                     mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
                     return true;
                 }
-
-                info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
                 break;
             }
 
@@ -6155,12 +6129,8 @@
                     ALOGV("[%s] calling fillBuffer %u",
                          mCodec->mComponentName.c_str(), info->mBufferID);
                     info->checkWriteFence("onOutputBufferDrained::RESUBMIT_BUFFERS");
-                    status_t err = mCodec->mOMXNode->fillBuffer(
-                            info->mBufferID, info->mFenceFd);
-                    info->mFenceFd = -1;
-                    if (err == OK) {
-                        info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
-                    } else {
+                    status_t err = mCodec->fillBuffer(info);
+                    if (err != OK) {
                         mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
                     }
                 }
@@ -6960,14 +6930,11 @@
         ALOGV("[%s] calling fillBuffer %u", mCodec->mComponentName.c_str(), info->mBufferID);
 
         info->checkWriteFence("submitRegularOutputBuffers");
-        status_t err = mCodec->mOMXNode->fillBuffer(info->mBufferID, info->mFenceFd);
-        info->mFenceFd = -1;
+        status_t err = mCodec->fillBuffer(info);
         if (err != OK) {
             failed = true;
             break;
         }
-
-        info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
     }
 
     if (failed) {
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index bda29fa..85ee4ee 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -28,6 +28,7 @@
 class IOMXBufferSource;
 class IOMXObserver;
 struct OMXMaster;
+class OMXBuffer;
 
 struct OMXNodeInstance : public BnOMXNode {
     OMXNodeInstance(
@@ -64,22 +65,6 @@
             OMX_U32 portIndex, OMX_BOOL tunneled,
             OMX_U32 audioHwSync, native_handle_t **sidebandHandle);
 
-    status_t useBuffer(
-            OMX_U32 portIndex, const sp<IMemory> &params,
-            OMX::buffer_id *buffer, OMX_U32 allottedSize);
-
-    status_t useGraphicBuffer(
-            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id *buffer);
-
-    status_t updateGraphicBufferInMeta(
-            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
-            OMX::buffer_id buffer);
-
-    status_t updateNativeHandleInMeta(
-            OMX_U32 portIndex, const sp<NativeHandle> &nativeHandle,
-            OMX::buffer_id buffer);
-
     status_t setInputSurface(
             const sp<IOMXBufferSource> &bufferSource);
 
@@ -87,19 +72,18 @@
             OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
             void **buffer_data, sp<NativeHandle> *native_handle);
 
-    status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
+    status_t useBuffer(
+            OMX_U32 portIndex, const OMXBuffer &omxBuf, buffer_id *buffer);
 
-    status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);
+    status_t freeBuffer(
+            OMX_U32 portIndex, buffer_id buffer);
+
+    status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd = -1);
 
     status_t emptyBuffer(
-            OMX::buffer_id buffer,
-            OMX_U32 rangeOffset, OMX_U32 rangeLength,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
-
-    status_t emptyGraphicBuffer(
-            OMX::buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, int fenceFd);
+            buffer_id buffer, const OMXBuffer &omxBuf,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1);
 
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
@@ -196,9 +180,43 @@
 
     bool isProhibitedIndex_l(OMX_INDEXTYPE index);
 
+    status_t useBuffer(
+            OMX_U32 portIndex, const sp<IMemory> &params,
+            OMX::buffer_id *buffer, OMX_U32 allottedSize);
+
+    status_t useBuffer_l(
+            OMX_U32 portIndex, const sp<IMemory> &params,
+            OMX::buffer_id *buffer, OMX_U32 allottedSize);
+
+    status_t useGraphicBuffer(
+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
+            OMX::buffer_id *buffer);
+
+    status_t useGraphicBufferWithMetadata_l(
+            OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
+            OMX::buffer_id *buffer);
+
     status_t useGraphicBuffer2_l(
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
             OMX::buffer_id *buffer);
+
+    status_t emptyBuffer(
+            OMX::buffer_id buffer,
+            OMX_U32 rangeOffset, OMX_U32 rangeLength,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+
+    status_t emptyGraphicBuffer(
+            OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+
+    status_t emptyNativeHandleBuffer(
+            OMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+
+    status_t emptyBuffer_l(
+            OMX_BUFFERHEADERTYPE *header,
+            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr, int fenceFd);
+
     static OMX_ERRORTYPE OnEvent(
             OMX_IN OMX_HANDLETYPE hComponent,
             OMX_IN OMX_PTR pAppData,
@@ -229,10 +247,6 @@
     int retrieveFenceFromMeta_l(
             OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex);
 
-    status_t emptyBuffer_l(
-            OMX_BUFFERHEADERTYPE *header,
-            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr, int fenceFd);
-
     // Updates the graphic buffer handle in the metadata buffer for |buffer| and |header| to
     // |graphicBuffer|'s handle. If |updateCodecBuffer| is true, the update will happen in
     // the actual codec buffer (use this if not using emptyBuffer (with no _l) later to
@@ -242,6 +256,10 @@
             OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
             OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
 
+    status_t updateNativeHandleInMeta_l(
+            OMX_U32 portIndex, const sp<NativeHandle> &nativeHandle,
+            OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header);
+
     sp<IOMXBufferSource> getBufferSource();
     void setBufferSource(const sp<IOMXBufferSource> &bufferSource);
     // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 4575d28..7ffd3f6 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -34,6 +34,7 @@
 #include "omx/OMXUtils.h"
 #include <OMX_Component.h>
 #include <OMX_IndexExt.h>
+#include "OMXBuffer.h"
 
 #include <inttypes.h>
 #include "FrameDropper.h"
@@ -578,7 +579,7 @@
     const sp<GraphicBuffer> &buffer = codecBuffer.mGraphicBuffer;
     int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
 
-    status_t err = mOMXNode->emptyGraphicBuffer(
+    status_t err = mOMXNode->emptyBuffer(
             bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
 
     if (err != OK) {
@@ -611,8 +612,8 @@
     CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
     IOMX::buffer_id bufferID = codecBuffer.mBufferID;
 
-    status_t err = mOMXNode->emptyGraphicBuffer(
-            bufferID, NULL /* buffer */,
+    status_t err = mOMXNode->emptyBuffer(
+            bufferID, (sp<GraphicBuffer>)NULL,
             OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
             0 /* timestamp */, -1 /* fenceFd */);
     if (err != OK) {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 41f3e4a..fdc9d7f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -40,6 +40,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <utils/misc.h>
 #include <utils/NativeHandle.h>
+#include <media/OMXBuffer.h>
 
 static const OMX_U32 kPortIndexInput = 0;
 static const OMX_U32 kPortIndexOutput = 1;
@@ -901,6 +902,21 @@
 }
 
 status_t OMXNodeInstance::useBuffer(
+        OMX_U32 portIndex,
+        const OMXBuffer &omxBuffer, OMX::buffer_id *buffer) {
+    // TODO: the allotted size is probably no longer needed.
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeSharedMem) {
+        return useBuffer(portIndex, omxBuffer.mMem, buffer, omxBuffer.mAllottedSize);
+    }
+
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
+        return useGraphicBuffer(portIndex, omxBuffer.mGraphicBuffer, buffer);
+    }
+
+    return BAD_VALUE;
+}
+
+status_t OMXNodeInstance::useBuffer(
         OMX_U32 portIndex, const sp<IMemory> &params,
         OMX::buffer_id *buffer, OMX_U32 allottedSize) {
     if (params == NULL || buffer == NULL) {
@@ -913,6 +929,12 @@
         return BAD_VALUE;
     }
 
+    return useBuffer_l(portIndex, params, buffer, allottedSize);
+}
+
+status_t OMXNodeInstance::useBuffer_l(
+        OMX_U32 portIndex, const sp<IMemory> &params,
+        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
     BufferMeta *buffer_meta;
     OMX_BUFFERHEADERTYPE *header;
     OMX_ERRORTYPE err = OMX_ErrorNone;
@@ -937,16 +959,18 @@
 
         if (err != OMX_ErrorNone) {
             CLOG_ERROR(allocateBuffer, err,
-                    SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
+                    SIMPLE_BUFFER(portIndex, (size_t)allottedSize,
+                            params != NULL ? params->pointer() : NULL));
         }
     } else {
-        OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
+        OMX_U8 *data = NULL;
 
         // metadata buffers are not connected cross process
         // use a backup buffer instead of the actual buffer
         if (isMetadata) {
+            // TODO: this logic is very fishy, should it be removed?
             // if we are not connecting the buffers, the sizes must match
-            if (allottedSize != params->size()) {
+            if (params != NULL && allottedSize != params->size()) {
                 CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
                 return BAD_VALUE;
             }
@@ -960,6 +984,10 @@
             buffer_meta = new BufferMeta(
                     params, portIndex, false /* copy */, data);
         } else {
+            // NULL params is allowed only in metadata mode.
+            CHECK(params != NULL);
+            data = static_cast<OMX_U8 *>(params->pointer());
+
             buffer_meta = new BufferMeta(
                     params, portIndex, false /* copy */, NULL);
         }
@@ -1064,6 +1092,13 @@
     }
     Mutex::Autolock autoLock(mLock);
 
+    // First, see if we're in metadata mode. We could be running an experiment to simulate
+    // legacy behavior (preallocated buffers) on devices that supports meta.
+    if (mMetadataType[portIndex] != kMetadataBufferTypeInvalid) {
+        return useGraphicBufferWithMetadata_l(
+                portIndex, graphicBuffer, buffer);
+    }
+
     // See if the newer version of the extension is present.
     OMX_INDEXTYPE index;
     if (OMX_GetExtensionIndex(
@@ -1119,6 +1154,33 @@
     return OK;
 }
 
+status_t OMXNodeInstance::useGraphicBufferWithMetadata_l(
+        OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
+        OMX::buffer_id *buffer) {
+    if (portIndex != kPortIndexOutput) {
+        return BAD_VALUE;
+    }
+
+    OMX_U32 allottedSize = 0;
+    if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {
+        allottedSize = sizeof(VideoGrallocMetadata);
+    } else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {
+        allottedSize = sizeof(VideoNativeMetadata);
+    } else {
+        return BAD_VALUE;
+    }
+
+    status_t err = useBuffer_l(portIndex, NULL, buffer, allottedSize);
+    if (err != OK) {
+        return err;
+    }
+
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(*buffer, portIndex);
+
+    return updateGraphicBufferInMeta_l(portIndex, graphicBuffer, *buffer, header);
+
+}
+
 status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
@@ -1159,20 +1221,9 @@
     return OK;
 }
 
-status_t OMXNodeInstance::updateGraphicBufferInMeta(
-        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
-        OMX::buffer_id buffer) {
-    Mutex::Autolock autoLock(mLock);
-    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
-
-    return updateGraphicBufferInMeta_l(
-            portIndex, graphicBuffer, buffer, header);
-}
-
-status_t OMXNodeInstance::updateNativeHandleInMeta(
-        OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle, OMX::buffer_id buffer) {
-    Mutex::Autolock autoLock(mLock);
-    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, portIndex);
+status_t OMXNodeInstance::updateNativeHandleInMeta_l(
+        OMX_U32 portIndex, const sp<NativeHandle>& nativeHandle,
+        OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
     // No need to check |nativeHandle| since NULL is valid for it as below.
     if (header == NULL) {
         ALOGE("b/25884056");
@@ -1340,7 +1391,8 @@
     return StatusFromOMXError(err);
 }
 
-status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer, int fenceFd) {
+status_t OMXNodeInstance::fillBuffer(
+        OMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
@@ -1348,6 +1400,20 @@
         ALOGE("b/25884056");
         return BAD_VALUE;
     }
+
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
+        status_t err = updateGraphicBufferInMeta_l(
+                kPortIndexOutput, omxBuffer.mGraphicBuffer, buffer, header);
+
+        if (err != OK) {
+            CLOG_ERROR(fillBuffer, err, FULL_BUFFER(
+                    (intptr_t)header->pBuffer, header, fenceFd));
+            return err;
+        }
+    } else if (omxBuffer.mBufferType != OMXBuffer::kBufferTypePreset) {
+        return BAD_VALUE;
+    }
+
     header->nFilledLen = 0;
     header->nOffset = 0;
     header->nFlags = 0;
@@ -1375,6 +1441,27 @@
 }
 
 status_t OMXNodeInstance::emptyBuffer(
+        buffer_id buffer, const OMXBuffer &omxBuffer,
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypePreset) {
+        return emptyBuffer(
+                buffer, 0, omxBuffer.mRangeLength, flags, timestamp, fenceFd);
+    }
+
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
+        return emptyGraphicBuffer(
+                buffer, omxBuffer.mGraphicBuffer, flags, timestamp, fenceFd);
+    }
+
+    if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeNativeHandle) {
+        return emptyNativeHandleBuffer(
+                buffer, omxBuffer.mNativeHandle, flags, timestamp, fenceFd);
+    }
+
+    return BAD_VALUE;
+}
+
+status_t OMXNodeInstance::emptyBuffer(
         OMX::buffer_id buffer,
         OMX_U32 rangeOffset, OMX_U32 rangeLength,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
@@ -1601,6 +1688,31 @@
     return timestamp;
 }
 
+status_t OMXNodeInstance::emptyNativeHandleBuffer(
+        OMX::buffer_id buffer, const sp<NativeHandle> &nativeHandle,
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+    Mutex::Autolock autoLock(mLock);
+
+    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
+    status_t err = updateNativeHandleInMeta_l(
+            kPortIndexInput, nativeHandle, buffer, header);
+    if (err != OK) {
+        CLOG_ERROR(emptyNativeHandleBuffer, err, FULL_BUFFER(
+                (intptr_t)header->pBuffer, header, fenceFd));
+        return err;
+    }
+
+    header->nOffset = 0;
+    header->nFilledLen = (nativeHandle == NULL) ? 0 : sizeof(VideoNativeMetadata);
+
+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
+}
+
 void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
     Mutex::Autolock autoLock(mBufferIDLock);
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index ea99e53..935d7bf 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -38,6 +38,7 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
+#include <media/OMXBuffer.h>
 
 #define DEFAULT_TIMEOUT         500000
 
@@ -210,8 +211,7 @@
         buffer.mFlags = 0;
         CHECK(buffer.mMemory != NULL);
 
-        err = mOMXNode->useBuffer(
-                portIndex, buffer.mMemory, &buffer.mID, buffer.mMemory->size());
+        err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
         EXPECT_SUCCESS(err, "useBuffer");
 
         buffers->push(buffer);
@@ -338,7 +338,7 @@
            "executing state.");
 
     for (size_t i = 0; i < outputBuffers.size(); ++i) {
-        err = mOMXNode->fillBuffer(outputBuffers[i].mID);
+        err = mOMXNode->fillBuffer(outputBuffers[i].mID, OMXBuffer::sPreset);
         EXPECT_SUCCESS(err, "fillBuffer");
 
         outputBuffers.editItemAt(i).mFlags |= kBufferBusy;
@@ -363,7 +363,7 @@
     }
 
     for (size_t i = 0; i < outputBuffers.size(); ++i) {
-        err = mOMXNode->fillBuffer(outputBuffers[i].mID);
+        err = mOMXNode->fillBuffer(outputBuffers[i].mID, OMXBuffer::sPreset);
         EXPECT_SUCCESS(err, "fillBuffer");
 
         outputBuffers.editItemAt(i).mFlags |= kBufferBusy;