MediaCodec refactoring part 1-a: buffers become separate class

MediaCodecBuffer is meant to replace ABuffer and MediaBuffer in
communication between framework components. As the first step, replace
use of ABuffer in MediaCodec with MediaCodecBuffer, and adjust related
classes accordingly.

MediaCodec.getBuffer() and related APIs now returns MediaCodecBuffers;
thus change MediaCodec clients to use MediaCodecBuffer accordingly.

Test: manually tested for key use cases (Camera, YouTube and Play Movies)
Change-Id: Iba7ce131645e75ce5ddbf497fb793ab38b7f245b
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index a7eace1..6097f01 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -51,6 +51,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaMuxer.h>
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 
 #include "screenrecord.h"
 #include "Overlay.h"
@@ -328,7 +329,7 @@
 
     assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
 
-    Vector<sp<ABuffer> > buffers;
+    Vector<sp<MediaCodecBuffer> > buffers;
     err = encoder->getOutputBuffers(&buffers);
     if (err != NO_ERROR) {
         fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
@@ -411,7 +412,10 @@
                     // want to queue these up and do them on a different thread.
                     ATRACE_NAME("write sample");
                     assert(trackIdx != -1);
-                    err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
+                    // TODO
+                    sp<ABuffer> buffer = new ABuffer(
+                            buffers[bufIndex]->data(), buffers[bufIndex]->size());
+                    err = muxer->writeSampleData(buffer, trackIdx,
                             ptsUsec, flags);
                     if (err != NO_ERROR) {
                         fprintf(stderr,
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 50913cd..afb7db3 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -25,6 +25,7 @@
 #include <media/AudioTrack.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -355,7 +356,7 @@
             err = state->mCodec->dequeueInputBuffer(&index, -1ll);
             CHECK_EQ(err, (status_t)OK);
 
-            const sp<ABuffer> &dstBuffer = state->mBuffers[0].itemAt(index);
+            const sp<MediaCodecBuffer> &dstBuffer = state->mBuffers[0].itemAt(index);
 
             CHECK_LE(srcBuffer->size(), dstBuffer->capacity());
             dstBuffer->setRange(0, srcBuffer->size());
@@ -482,11 +483,13 @@
             state->mAvailInputBufferIndices.erase(
                     state->mAvailInputBufferIndices.begin());
 
-            const sp<ABuffer> &dstBuffer =
+            const sp<MediaCodecBuffer> &dstBuffer =
                 state->mBuffers[0].itemAt(index);
+            sp<ABuffer> abuffer = new ABuffer(dstBuffer->base(), dstBuffer->capacity());
 
-            err = mExtractor->readSampleData(dstBuffer);
+            err = mExtractor->readSampleData(abuffer);
             CHECK_EQ(err, (status_t)OK);
+            dstBuffer->setRange(abuffer->offset(), abuffer->size());
 
             int64_t timeUs;
             CHECK_EQ(mExtractor->getSampleTime(&timeUs), (status_t)OK);
@@ -530,7 +533,7 @@
                     state->mCodec->releaseOutputBuffer(info->mIndex);
                 } else {
                     if (state->mAudioTrack != NULL) {
-                        const sp<ABuffer> &srcBuffer =
+                        const sp<MediaCodecBuffer> &srcBuffer =
                             state->mBuffers[1].itemAt(info->mIndex);
 
                         renderAudio(state, info, srcBuffer);
@@ -597,7 +600,7 @@
 }
 
 void SimplePlayer::renderAudio(
-        CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer) {
+        CodecState *state, BufferInfo *info, const sp<MediaCodecBuffer> &buffer) {
     CHECK(state->mAudioTrack != NULL);
 
     if (state->mAudioTrack->stopped()) {
diff --git a/cmds/stagefright/SimplePlayer.h b/cmds/stagefright/SimplePlayer.h
index ae9dfd2..918fd24 100644
--- a/cmds/stagefright/SimplePlayer.h
+++ b/cmds/stagefright/SimplePlayer.h
@@ -25,6 +25,7 @@
 struct AudioTrack;
 class IGraphicBufferProducer;
 struct MediaCodec;
+class MediaCodecBuffer;
 struct NuMediaExtractor;
 class Surface;
 
@@ -73,7 +74,7 @@
     {
         sp<MediaCodec> mCodec;
         Vector<sp<ABuffer> > mCSD;
-        Vector<sp<ABuffer> > mBuffers[2];
+        Vector<sp<MediaCodecBuffer> > mBuffers[2];
 
         List<size_t> mAvailInputBufferIndices;
         List<BufferInfo> mAvailOutputBufferInfos;
@@ -101,7 +102,7 @@
     status_t onOutputFormatChanged(size_t trackIndex, CodecState *state);
 
     void renderAudio(
-            CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer);
+            CodecState *state, BufferInfo *info, const sp<MediaCodecBuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(SimplePlayer);
 };
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index dae9bbe..26135d7 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -26,6 +26,7 @@
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -56,8 +57,8 @@
 
 struct CodecState {
     sp<MediaCodec> mCodec;
-    Vector<sp<ABuffer> > mInBuffers;
-    Vector<sp<ABuffer> > mOutBuffers;
+    Vector<sp<MediaCodecBuffer> > mInBuffers;
+    Vector<sp<MediaCodecBuffer> > mOutBuffers;
     bool mSignalledInputEOS;
     bool mSawOutputEOS;
     int64_t mNumBuffersDecoded;
@@ -174,10 +175,12 @@
                 if (err == OK) {
                     ALOGV("filling input buffer %zu", index);
 
-                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
+                    const sp<MediaCodecBuffer> &buffer = state->mInBuffers.itemAt(index);
+                    sp<ABuffer> abuffer = new ABuffer(buffer->base(), buffer->capacity());
 
-                    err = extractor->readSampleData(buffer);
+                    err = extractor->readSampleData(abuffer);
                     CHECK_EQ(err, (status_t)OK);
+                    buffer->setRange(abuffer->offset(), abuffer->size());
 
                     int64_t timeUs;
                     err = extractor->getSampleTime(&timeUs);
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index d829df0..410dd69 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -26,6 +26,7 @@
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -131,8 +132,8 @@
 
 struct CodecState {
     sp<MediaCodec> mCodec;
-    Vector<sp<ABuffer> > mInBuffers;
-    Vector<sp<ABuffer> > mOutBuffers;
+    Vector<sp<MediaCodecBuffer> > mInBuffers;
+    Vector<sp<MediaCodecBuffer> > mOutBuffers;
     bool mSignalledInputEOS;
     bool mSawOutputEOS;
     int64_t mNumBuffersDecoded;
@@ -183,9 +184,9 @@
     }
     size_t outIndex = frame.index;
 
-    const sp<ABuffer> &srcBuffer =
+    const sp<MediaCodecBuffer> &srcBuffer =
         vidState->mOutBuffers.itemAt(outIndex);
-    const sp<ABuffer> &destBuffer =
+    const sp<MediaCodecBuffer> &destBuffer =
         filterState->mInBuffers.itemAt(filterIndex);
 
     sp<AMessage> srcFormat, destFormat;
@@ -532,10 +533,12 @@
                 if (err == OK) {
                     ALOGV("filling input buffer %zu", index);
 
-                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
+                    const sp<MediaCodecBuffer> &buffer = state->mInBuffers.itemAt(index);
+                    sp<ABuffer> abuffer = new ABuffer(buffer->base(), buffer->capacity());
 
-                    err = extractor->readSampleData(buffer);
+                    err = extractor->readSampleData(abuffer);
                     CHECK(err == OK);
+                    buffer->setRange(abuffer->offset(), abuffer->size());
 
                     int64_t timeUs;
                     err = extractor->getSampleTime(&timeUs);
diff --git a/include/media/MediaCodecBuffer.h b/include/media/MediaCodecBuffer.h
new file mode 100644
index 0000000..2df81dd
--- /dev/null
+++ b/include/media/MediaCodecBuffer.h
@@ -0,0 +1,72 @@
+/*
+ * 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 MEDIA_CODEC_BUFFER_H_
+
+#define MEDIA_CODEC_BUFFER_H_
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct ABuffer;
+struct AMessage;
+class MediaBufferBase;
+
+/**
+ * Buffers used by MediaCodec.
+ */
+class MediaCodecBuffer : public RefBase {
+public:
+    MediaCodecBuffer(const sp<AMessage> &format, const sp<ABuffer> &buffer);
+
+    /**
+     * MediaCodec will release all references to the buffer when it's done using
+     * it, so the destructor should return the buffer to the owner, such as OMX
+     * components, buffer allocators, surfaces, etc.
+     */
+    virtual ~MediaCodecBuffer() = default;
+
+    // ABuffer-like interface
+    uint8_t *base();
+    uint8_t *data();
+    size_t capacity() const;
+    size_t size() const;
+    size_t offset() const;
+    // Default implementation calls ABuffer::setRange() and returns OK.
+    virtual status_t setRange(size_t offset, size_t size);
+    // TODO: These can be removed if we finish replacing all MediaBuffer's.
+    MediaBufferBase *getMediaBufferBase();
+    void setMediaBufferBase(MediaBufferBase *mediaBuffer);
+
+    // TODO: Specify each field for meta/format.
+    sp<AMessage> meta();
+    sp<AMessage> format();
+
+private:
+    MediaCodecBuffer() = delete;
+
+    const sp<AMessage> mMeta;
+    const sp<AMessage> mFormat;
+    const sp<ABuffer> mBuffer;
+    MediaBufferBase *mMediaBufferBase;
+};
+
+}  // namespace android
+
+#endif  // MEDIA_CODEC_BUFFER_H_
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index faf62ad..6f6f2f9 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -35,6 +35,7 @@
 namespace android {
 
 struct ABuffer;
+class MediaCodecBuffer;
 struct MemoryDealer;
 struct DescribeColorFormat2Params;
 struct DataConverter;
@@ -74,7 +75,7 @@
     struct PortDescription : public CodecBase::PortDescription {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
-        sp<ABuffer> bufferAt(size_t index) const;
+        sp<MediaCodecBuffer> bufferAt(size_t index) const;
         sp<NativeHandle> handleAt(size_t index) const;
         sp<RefBase> memRefAt(size_t index) const;
 
@@ -82,13 +83,13 @@
         friend struct ACodec;
 
         Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<ABuffer> > mBuffers;
+        Vector<sp<MediaCodecBuffer>> mBuffers;
         Vector<sp<NativeHandle> > mHandles;
         Vector<sp<RefBase> > mMemRefs;
 
         PortDescription();
         void addBuffer(
-                IOMX::buffer_id id, const sp<ABuffer> &buffer,
+                IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer,
                 const sp<NativeHandle> &handle, const sp<RefBase> &memRef);
 
         DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
@@ -186,11 +187,12 @@
         Status mStatus;
         unsigned mDequeuedAt;
 
-        sp<ABuffer> mData;      // the client's buffer; if not using data conversion, this is the
-                                // codec buffer; otherwise, it is allocated separately
-        sp<RefBase> mMemRef;    // and a reference to the IMemory, so it does not go away
-        sp<ABuffer> mCodecData; // the codec's buffer
-        sp<RefBase> mCodecRef;  // and a reference to the IMemory
+        sp<MediaCodecBuffer> mData;  // the client's buffer; if not using data conversion, this is
+                                     // the codec buffer; otherwise, it is allocated separately
+        sp<RefBase> mMemRef;         // and a reference to the IMemory, so it does not go away
+        sp<MediaCodecBuffer> mCodecData;  // the codec's buffer
+        sp<RefBase> mCodecRef;            // and a reference to the IMemory
+
         sp<GraphicBuffer> mGraphicBuffer;
         sp<NativeHandle> mNativeHandle;
         int mFenceFd;
@@ -204,6 +206,8 @@
         // Log error, if the current fence is not a read/write fence.
         void checkReadFence(const char *dbg);
         void checkWriteFence(const char *dbg);
+
+        sp<MediaCodecBuffer> alloc(const sp<AMessage> &format);
     };
 
     static const char *_asString(BufferInfo::Status s);
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index be2835d..92a5593 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -34,7 +34,7 @@
 
 namespace android {
 
-struct ABuffer;
+class MediaCodecBuffer;
 struct PersistentSurface;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
@@ -88,7 +88,7 @@
     struct PortDescription : public RefBase {
         virtual size_t countBuffers() = 0;
         virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
-        virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const = 0;
         virtual sp<NativeHandle> handleAt(size_t index) const { return NULL; };
         virtual sp<RefBase> memRefAt(size_t index) const { return NULL; }
 
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 8291cec..98780ce 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -35,6 +35,7 @@
 struct CodecBase;
 struct IBatteryStats;
 struct ICrypto;
+class MediaCodecBuffer;
 class IMemory;
 struct MemoryDealer;
 class IResourceManagerClient;
@@ -149,14 +150,14 @@
     status_t getOutputFormat(sp<AMessage> *format) const;
     status_t getInputFormat(sp<AMessage> *format) const;
 
-    status_t getWidevineLegacyBuffers(Vector<sp<ABuffer> > *buffers) const;
+    status_t getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
 
-    status_t getInputBuffers(Vector<sp<ABuffer> > *buffers) const;
-    status_t getOutputBuffers(Vector<sp<ABuffer> > *buffers) const;
+    status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
+    status_t getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
 
-    status_t getOutputBuffer(size_t index, sp<ABuffer> *buffer);
+    status_t getOutputBuffer(size_t index, sp<MediaCodecBuffer> *buffer);
     status_t getOutputFormat(size_t index, sp<AMessage> *format);
-    status_t getInputBuffer(size_t index, sp<ABuffer> *buffer);
+    status_t getInputBuffer(size_t index, sp<MediaCodecBuffer> *buffer);
 
     status_t setSurface(const sp<Surface> &nativeWindow);
 
@@ -253,10 +254,10 @@
 
     struct BufferInfo {
         uint32_t mBufferID;
-        sp<ABuffer> mData;
+        sp<MediaCodecBuffer> mData;
         sp<NativeHandle> mNativeHandle;
         sp<RefBase> mMemRef;
-        sp<ABuffer> mEncryptedData;
+        sp<MediaCodecBuffer> mEncryptedData;
         sp<IMemory> mSharedEncryptedBuffer;
         sp<AMessage> mNotify;
         sp<AMessage> mFormat;
@@ -367,7 +368,7 @@
 
     status_t getBufferAndFormat(
             size_t portIndex, size_t index,
-            sp<ABuffer> *buffer, sp<AMessage> *format);
+            sp<MediaCodecBuffer> *buffer, sp<AMessage> *format);
 
     bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
     bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
@@ -389,7 +390,7 @@
 
     status_t onSetParameters(const sp<AMessage> &params);
 
-    status_t amendOutputFormatWithCodecSpecificData(const sp<ABuffer> &buffer);
+    status_t amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> &buffer);
     void updateBatteryStat();
     bool isExecuting() const;
 
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index d0a572c..6aa87e8 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -21,7 +21,6 @@
 
 namespace android {
 
-struct ABuffer;
 struct GraphicBufferListener;
 struct MemoryDealer;
 struct SimpleFilter;
@@ -51,7 +50,7 @@
     struct PortDescription : public CodecBase::PortDescription {
         virtual size_t countBuffers();
         virtual IOMX::buffer_id bufferIDAt(size_t index) const;
-        virtual sp<ABuffer> bufferAt(size_t index) const;
+        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const;
 
     protected:
         PortDescription();
@@ -60,9 +59,9 @@
         friend struct MediaFilter;
 
         Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<ABuffer> > mBuffers;
+        Vector<sp<MediaCodecBuffer> > mBuffers;
 
-        void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer);
+        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
 
         DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
     };
@@ -82,7 +81,7 @@
         int32_t mOutputFlags;
         Status mStatus;
 
-        sp<ABuffer> mData;
+        sp<MediaCodecBuffer> mData;
     };
 
     enum State {
diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h
index 61f9949..0fb5690 100644
--- a/include/media/stagefright/SkipCutBuffer.h
+++ b/include/media/stagefright/SkipCutBuffer.h
@@ -18,6 +18,7 @@
 
 #define SKIP_CUT_BUFFER_H_
 
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 
@@ -39,6 +40,7 @@
     // After this, the caller should continue processing the buffer as usual.
     void submit(MediaBuffer *buffer);
     void submit(const sp<ABuffer>& buffer);    // same as above, but with an ABuffer
+    void submit(const sp<MediaCodecBuffer>& buffer);    // same as above, but with an ABuffer
     void clear();
     size_t size(); // how many bytes are currently stored in the buffer
 
@@ -48,6 +50,8 @@
  private:
     void write(const char *src, size_t num);
     size_t read(char *dst, size_t num);
+    template <typename T>
+    void submitInternal(const sp<T>& buffer);
     int32_t mSkip;
     int32_t mFrontPadding;
     int32_t mBackPadding;
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 59cb28c..81232bb 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -43,6 +43,7 @@
     IResourceManagerClient.cpp \
     IResourceManagerService.cpp \
     IStreamSource.cpp \
+    MediaCodecBuffer.cpp \
     MediaCodecInfo.cpp \
     MediaDefs.cpp \
     MediaUtils.cpp \
diff --git a/media/libmedia/MediaCodecBuffer.cpp b/media/libmedia/MediaCodecBuffer.cpp
new file mode 100644
index 0000000..2d255be
--- /dev/null
+++ b/media/libmedia/MediaCodecBuffer.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "MediaCodecBuffer"
+#include <utils/Log.h>
+
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/MediaBufferBase.h>
+
+namespace android {
+
+MediaCodecBuffer::MediaCodecBuffer(const sp<AMessage> &format, const sp<ABuffer> &buffer)
+    : mMeta(new AMessage),
+      mFormat(format),
+      mBuffer(buffer),
+      mMediaBufferBase(nullptr) {
+}
+
+// ABuffer-like interface
+uint8_t *MediaCodecBuffer::base() {
+    return mBuffer->base();
+}
+
+uint8_t *MediaCodecBuffer::data() {
+    return mBuffer->data();
+}
+
+size_t MediaCodecBuffer::capacity() const {
+    return mBuffer->capacity();
+}
+
+size_t MediaCodecBuffer::size() const {
+    return mBuffer->size();
+}
+
+size_t MediaCodecBuffer::offset() const {
+    return mBuffer->offset();
+}
+
+status_t MediaCodecBuffer::setRange(size_t offset, size_t size) {
+    mBuffer->setRange(offset, size);
+    return OK;
+}
+
+MediaBufferBase *MediaCodecBuffer::getMediaBufferBase() {
+    if (mMediaBufferBase != NULL) {
+        mMediaBufferBase->add_ref();
+    }
+    return mMediaBufferBase;
+}
+
+void MediaCodecBuffer::setMediaBufferBase(MediaBufferBase *mediaBuffer) {
+    if (mMediaBufferBase != NULL) {
+        mMediaBufferBase->release();
+    }
+    mMediaBufferBase = mediaBuffer;
+}
+
+sp<AMessage> MediaCodecBuffer::meta() {
+    return mMeta;
+}
+
+sp<AMessage> MediaCodecBuffer::format() {
+    return mFormat;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index e370c2b..ac49993 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -39,6 +39,7 @@
 
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
+#include <media/MediaCodecBuffer.h>
 
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -1657,12 +1658,12 @@
 
     // allocate buffers to decrypt widevine source buffers
     if (!audio && (mSourceFlags & Source::FLAG_SECURE)) {
-        Vector<sp<ABuffer> > inputBufs;
+        Vector<sp<MediaCodecBuffer> > inputBufs;
         CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
 
         Vector<MediaBuffer *> mediaBufs;
         for (size_t i = 0; i < inputBufs.size(); i++) {
-            const sp<ABuffer> &buffer = inputBufs[i];
+            const sp<MediaCodecBuffer> &buffer = inputBufs[i];
             MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size());
             mediaBufs.push(mbuf);
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cf38efc..822f154 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -28,6 +28,7 @@
 
 #include <cutils/properties.h>
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -417,7 +418,7 @@
 }
 
 void NuPlayer::Decoder::onGetInputBuffers(
-        Vector<sp<ABuffer> > *dstBuffers) {
+        Vector<sp<MediaCodecBuffer> > *dstBuffers) {
     CHECK_EQ((status_t)OK, mCodec->getWidevineLegacyBuffers(dstBuffers));
 }
 
@@ -561,7 +562,7 @@
         return false;
     }
 
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
     mCodec->getInputBuffer(index, &buffer);
 
     if (buffer == NULL) {
@@ -628,7 +629,7 @@
         int64_t timeUs,
         int32_t flags) {
 //    CHECK_LT(bufferIx, mOutputBuffers.size());
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
     mCodec->getOutputBuffer(index, &buffer);
 
     if (index >= mOutputBuffers.size()) {
@@ -865,10 +866,11 @@
     size_t bufferIx;
     CHECK(msg->findSize("buffer-ix", &bufferIx));
     CHECK_LT(bufferIx, mInputBuffers.size());
-    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
+    sp<MediaCodecBuffer> codecBuffer = mInputBuffers[bufferIx];
 
     sp<ABuffer> buffer;
     bool hasBuffer = msg->findBuffer("buffer", &buffer);
+    bool needsCopy = true;
 
     // handle widevine classic source - that fills an arbitrary input buffer
     MediaBuffer *mediaBuffer = NULL;
@@ -878,7 +880,7 @@
             // likely filled another buffer than we requested: adjust buffer index
             size_t ix;
             for (ix = 0; ix < mInputBuffers.size(); ix++) {
-                const sp<ABuffer> &buf = mInputBuffers[ix];
+                const sp<MediaCodecBuffer> &buf = mInputBuffers[ix];
                 if (buf->data() == mediaBuffer->data()) {
                     // all input buffers are dequeued on start, hence the check
                     if (!mInputBufferIsDequeued[ix]) {
@@ -891,11 +893,12 @@
                     // TRICKY: need buffer for the metadata, so instead, set
                     // codecBuffer to the same (though incorrect) buffer to
                     // avoid a memcpy into the codecBuffer
-                    codecBuffer = buffer;
+                    codecBuffer = new MediaCodecBuffer(codecBuffer->format(), buffer);
                     codecBuffer->setRange(
                             mediaBuffer->range_offset(),
                             mediaBuffer->range_length());
                     bufferIx = ix;
+                    needsCopy = false;
                     break;
                 }
             }
@@ -955,7 +958,7 @@
         }
 
         // copy into codec buffer
-        if (buffer != codecBuffer) {
+        if (needsCopy) {
             if (buffer->size() > codecBuffer->capacity()) {
                 handleError(ERROR_BUFFER_TOO_SMALL);
                 mDequeuedInputBuffers.push_back(bufferIx);
@@ -998,7 +1001,7 @@
 
     if (!mIsAudio) {
         int64_t timeUs;
-        sp<ABuffer> buffer = mOutputBuffers[bufferIx];
+        sp<MediaCodecBuffer> buffer = mOutputBuffers[bufferIx];
         buffer->meta()->findInt64("timeUs", &timeUs);
 
         if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 0c619ed..8186862 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -23,6 +23,8 @@
 
 namespace android {
 
+class MediaCodecBuffer;
+
 struct NuPlayer::Decoder : public DecoderBase {
     Decoder(const sp<AMessage> &notify,
             const sp<Source> &source,
@@ -44,7 +46,7 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
+    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
@@ -74,8 +76,8 @@
 
     List<sp<AMessage> > mPendingInputMessages;
 
-    Vector<sp<ABuffer> > mInputBuffers;
-    Vector<sp<ABuffer> > mOutputBuffers;
+    Vector<sp<MediaCodecBuffer> > mInputBuffers;
+    Vector<sp<MediaCodecBuffer> > mOutputBuffers;
     Vector<sp<ABuffer> > mCSDsForCurrentFormat;
     Vector<sp<ABuffer> > mCSDsToSubmit;
     Vector<bool> mInputBufferIsDequeued;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 04bb61c..9c007ae 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -23,6 +23,7 @@
 
 #include "NuPlayerRenderer.h"
 
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -91,7 +92,7 @@
     PostAndAwaitResponse(msg, &response);
 }
 
-status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
+status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
     msg->setPointer("buffers", buffers);
 
@@ -170,7 +171,7 @@
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            Vector<sp<ABuffer> > *dstBuffers;
+            Vector<sp<MediaCodecBuffer> > *dstBuffers;
             CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
 
             onGetInputBuffers(dstBuffers);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 9966144..6f4ead6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -27,6 +27,7 @@
 struct ABuffer;
 struct MediaCodec;
 class MediaBuffer;
+class MediaCodecBuffer;
 class Surface;
 
 struct NuPlayer::DecoderBase : public AHandler {
@@ -42,7 +43,7 @@
     void setRenderer(const sp<Renderer> &renderer);
     virtual status_t setVideoSurface(const sp<Surface> &) { return INVALID_OPERATION; }
 
-    status_t getInputBuffers(Vector<sp<ABuffer> > *dstBuffers) const;
+    status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) const;
     void signalFlush();
     void signalResume(bool notifyComplete);
     void initiateShutdown();
@@ -70,7 +71,7 @@
     virtual void onConfigure(const sp<AMessage> &format) = 0;
     virtual void onSetParameters(const sp<AMessage> &params) = 0;
     virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
-    virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers) = 0;
+    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) = 0;
     virtual void onResume(bool notifyComplete) = 0;
     virtual void onFlush() = 0;
     virtual void onShutdown(bool notifyComplete) = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index f224635..ffeea86 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -25,6 +25,7 @@
 #include "NuPlayerSource.h"
 
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -93,7 +94,7 @@
 }
 
 void NuPlayer::DecoderPassThrough::onGetInputBuffers(
-        Vector<sp<ABuffer> > * /* dstBuffers */) {
+        Vector<sp<MediaCodecBuffer> > * /* dstBuffers */) {
     ALOGE("onGetInputBuffers() called unexpectedly");
 }
 
@@ -289,8 +290,12 @@
         return;
     }
 
-    sp<ABuffer> buffer;
-    bool hasBuffer = msg->findBuffer("buffer", &buffer);
+    sp<RefBase> obj;
+    bool hasBuffer = msg->findObject("buffer", &obj);
+    sp<MediaCodecBuffer> buffer;
+    if (hasBuffer) {
+        buffer = static_cast<MediaCodecBuffer *>(obj.get());
+    }
     if (buffer == NULL) {
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 5850efa..9af25ff 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -38,7 +38,7 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<ABuffer> > *dstBuffers);
+    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index b742762..b78bdfb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -21,7 +21,6 @@
 #include "NuPlayerRenderer.h"
 #include <algorithm>
 #include <cutils/properties.h>
-#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -31,6 +30,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/VideoFrameScheduler.h>
+#include <media/MediaCodecBuffer.h>
 
 #include <inttypes.h>
 
@@ -156,12 +156,12 @@
 
 void NuPlayer::Renderer::queueBuffer(
         bool audio,
-        const sp<ABuffer> &buffer,
+        const sp<MediaCodecBuffer> &buffer,
         const sp<AMessage> &notifyConsumed) {
     sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
     msg->setInt32("queueGeneration", getQueueGeneration(audio));
     msg->setInt32("audio", static_cast<int32_t>(audio));
-    msg->setBuffer("buffer", buffer);
+    msg->setObject("buffer", buffer);
     msg->setMessage("notifyConsumed", notifyConsumed);
     msg->post();
 }
@@ -1368,8 +1368,9 @@
         }
     }
 
-    sp<ABuffer> buffer;
-    CHECK(msg->findBuffer("buffer", &buffer));
+    sp<RefBase> obj;
+    CHECK(msg->findObject("buffer", &obj));
+    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
     sp<AMessage> notifyConsumed;
     CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
@@ -1395,8 +1396,8 @@
         return;
     }
 
-    sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
-    sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
+    sp<MediaCodecBuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
+    sp<MediaCodecBuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
 
     if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
         // EOS signalled on either queue.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index fe7f8fa..0bd3aa1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -25,9 +25,9 @@
 
 namespace android {
 
-struct ABuffer;
 class  AWakeLock;
 struct MediaClock;
+class MediaCodecBuffer;
 struct VideoFrameScheduler;
 
 struct NuPlayer::Renderer : public AHandler {
@@ -46,7 +46,7 @@
 
     void queueBuffer(
             bool audio,
-            const sp<ABuffer> &buffer,
+            const sp<MediaCodecBuffer> &buffer,
             const sp<AMessage> &notifyConsumed);
 
     void queueEOS(bool audio, status_t finalResult);
@@ -125,7 +125,7 @@
     };
 
     struct QueueEntry {
-        sp<ABuffer> mBuffer;
+        sp<MediaCodecBuffer> mBuffer;
         sp<AMessage> mNotifyConsumed;
         size_t mOffset;
         status_t mFinalResult;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 62ebb3f..d36fca7 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -53,6 +53,7 @@
 
 #include "include/avc_utils.h"
 #include "include/DataConverter.h"
+#include "include/SharedMemoryBuffer.h"
 #include "omx/OMXUtils.h"
 
 #include <android/IGraphicBufferSource.h>
@@ -872,6 +873,7 @@
             size_t totalSize = def.nBufferCountActual * (alignedSize + alignedConvSize);
             mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
 
+            const sp<AMessage> &format = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
             for (OMX_U32 i = 0; i < def.nBufferCountActual && err == OK; ++i) {
                 sp<IMemory> mem = mDealer[portIndex]->allocate(bufSize);
                 if (mem == NULL || mem->pointer() == NULL) {
@@ -908,8 +910,8 @@
                     // because Widevine source only receives these base addresses.
                     const native_handle_t *native_handle_ptr =
                         native_handle == NULL ? NULL : native_handle->handle();
-                    info.mData = new ABuffer(
-                            ptr != NULL ? ptr : (void *)native_handle_ptr, bufSize);
+                    info.mData = new MediaCodecBuffer(format,
+                            new ABuffer(ptr != NULL ? ptr : (void *)native_handle_ptr, bufSize));
                     info.mNativeHandle = native_handle;
                     info.mCodecData = info.mData;
                 } else if (mQuirks & requiresAllocateBufferBit) {
@@ -920,7 +922,7 @@
                 }
 
                 if (mem != NULL) {
-                    info.mCodecData = new ABuffer(mem->pointer(), bufSize);
+                    info.mCodecData = new SharedMemoryBuffer(format, mem);
                     info.mCodecRef = mem;
 
                     if (type == kMetadataBufferTypeANWBuffer) {
@@ -935,7 +937,7 @@
                         if (mem == NULL|| mem->pointer() == NULL) {
                             return NO_MEMORY;
                         }
-                        info.mData = new ABuffer(mem->pointer(), conversionBufferSize);
+                        info.mData = new SharedMemoryBuffer(format, mem);
                         info.mMemRef = mem;
                     } else {
                         info.mData = info.mCodecData;
@@ -1139,8 +1141,6 @@
         info.mFenceFd = fenceFd;
         info.mIsReadFence = false;
         info.mRenderInfo = NULL;
-        info.mData = new ABuffer(NULL /* data */, bufferSize /* capacity */);
-        info.mCodecData = info.mData;
         info.mGraphicBuffer = graphicBuffer;
         mBuffers[kPortIndexOutput].push(info);
 
@@ -1225,7 +1225,7 @@
         if (mOutputMetadataType == kMetadataBufferTypeANWBuffer) {
             ((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
         }
-        info.mData = new ABuffer(mem->pointer(), mem->size());
+        info.mData = new SharedMemoryBuffer(mOutputFormat, mem);
         info.mMemRef = mem;
         info.mCodecData = info.mData;
         info.mCodecRef = mem;
@@ -1505,20 +1505,20 @@
 
     if (mOutputMetadataType == kMetadataBufferTypeGrallocSource) {
         VideoGrallocMetadata *grallocMeta =
-            reinterpret_cast<VideoGrallocMetadata *>(oldest->mData->base());
+            reinterpret_cast<VideoGrallocMetadata *>(oldest->mData->data());
         ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)",
                 (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]),
                 mDequeueCounter - oldest->mDequeuedAt,
                 (void *)(uintptr_t)grallocMeta->pHandle,
-                oldest->mGraphicBuffer->handle, oldest->mData->base());
+                oldest->mGraphicBuffer->handle, oldest->mData->data());
     } else if (mOutputMetadataType == kMetadataBufferTypeANWBuffer) {
         VideoNativeMetadata *nativeMeta =
-            reinterpret_cast<VideoNativeMetadata *>(oldest->mData->base());
+            reinterpret_cast<VideoNativeMetadata *>(oldest->mData->data());
         ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)",
                 (unsigned)(oldest - &mBuffers[kPortIndexOutput][0]),
                 mDequeueCounter - oldest->mDequeuedAt,
                 (void *)(uintptr_t)nativeMeta->pBuffer,
-                oldest->mGraphicBuffer->getNativeBuffer(), oldest->mData->base());
+                oldest->mGraphicBuffer->getNativeBuffer(), oldest->mData->data());
     }
 
     updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest);
@@ -5267,11 +5267,6 @@
     notify->post();
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-ACodec::PortDescription::PortDescription() {
-}
-
 status_t ACodec::requestIDRFrame() {
     if (!mIsEncoder) {
         return ERROR_UNSUPPORTED;
@@ -5290,8 +5285,13 @@
             sizeof(params));
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+ACodec::PortDescription::PortDescription() {
+}
+
 void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<ABuffer> &buffer,
+        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer,
         const sp<NativeHandle> &handle, const sp<RefBase> &memRef) {
     mBufferIDs.push_back(id);
     mBuffers.push_back(buffer);
@@ -5307,7 +5307,7 @@
     return mBufferIDs.itemAt(index);
 }
 
-sp<ABuffer> ACodec::PortDescription::bufferAt(size_t index) const {
+sp<MediaCodecBuffer> ACodec::PortDescription::bufferAt(size_t index) const {
     return mBuffers.itemAt(index);
 }
 
@@ -5633,7 +5633,7 @@
     notify->setInt32("buffer-id", info->mBufferID);
 
     info->mData->meta()->clear();
-    notify->setBuffer("buffer", info->mData);
+    notify->setObject("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
     reply->setInt32("buffer-id", info->mBufferID);
@@ -5648,12 +5648,13 @@
 void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
     IOMX::buffer_id bufferID;
     CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
     int32_t err = OK;
     bool eos = false;
     PortMode mode = getPortMode(kPortIndexInput);
 
-    if (!msg->findBuffer("buffer", &buffer)) {
+    sp<RefBase> obj;
+    if (!msg->findObject("buffer", &obj)) {
         /* these are unfilled buffers returned by client */
         CHECK(msg->findInt32("err", &err));
 
@@ -5667,6 +5668,8 @@
         }
 
         buffer.clear();
+    } else {
+        buffer = static_cast<MediaCodecBuffer *>(obj.get());
     }
 
     int32_t tmp;
@@ -5999,6 +6002,7 @@
 
             sp<AMessage> reply =
                 new AMessage(kWhatOutputBufferDrained, mCodec);
+            sp<MediaCodecBuffer> buffer = info->mData;
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
                 // pretend that output format has changed on the first frame (we used to do this)
@@ -6016,8 +6020,8 @@
             if (mCodec->usingMetadataOnEncoderOutput()) {
                 native_handle_t *handle = NULL;
                 VideoNativeHandleMetadata &nativeMeta =
-                    *(VideoNativeHandleMetadata *)info->mData->data();
-                if (info->mData->size() >= sizeof(nativeMeta)
+                    *(VideoNativeHandleMetadata *)buffer->data();
+                if (buffer->size() >= sizeof(nativeMeta)
                         && nativeMeta.eType == kMetadataBufferTypeNativeHandleSource) {
 #ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
                     // handle is only valid on 32-bit/mediaserver process
@@ -6026,16 +6030,16 @@
                     handle = (native_handle_t *)nativeMeta.pHandle;
 #endif
                 }
-                info->mData->meta()->setPointer("handle", handle);
-                info->mData->meta()->setInt32("rangeOffset", rangeOffset);
-                info->mData->meta()->setInt32("rangeLength", rangeLength);
-            } else if (info->mData == info->mCodecData) {
-                info->mData->setRange(rangeOffset, rangeLength);
+                buffer->meta()->setPointer("handle", handle);
+                buffer->meta()->setInt32("rangeOffset", rangeOffset);
+                buffer->meta()->setInt32("rangeLength", rangeLength);
+            } else if (buffer == info->mCodecData) {
+                buffer->setRange(rangeOffset, rangeLength);
             } else {
                 info->mCodecData->setRange(rangeOffset, rangeLength);
                 // in this case we know that mConverter is not null
                 status_t err = mCodec->mConverter[kPortIndexOutput]->convert(
-                        info->mCodecData, info->mData);
+                        info->mCodecData, buffer);
                 if (err != OK) {
                     mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
                     return true;
@@ -6050,14 +6054,14 @@
 #endif
 
             if (mCodec->mSkipCutBuffer != NULL) {
-                mCodec->mSkipCutBuffer->submit(info->mData);
+                mCodec->mSkipCutBuffer->submit(buffer);
             }
-            info->mData->meta()->setInt64("timeUs", timeUs);
+            buffer->meta()->setInt64("timeUs", timeUs);
 
             sp<AMessage> notify = mCodec->mNotify->dup();
             notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
             notify->setInt32("buffer-id", info->mBufferID);
-            notify->setBuffer("buffer", info->mData);
+            notify->setObject("buffer", buffer);
             notify->setInt32("flags", flags);
 
             reply->setInt32("buffer-id", info->mBufferID);
@@ -6100,6 +6104,11 @@
 void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
     IOMX::buffer_id bufferID;
     CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+    sp<RefBase> obj;
+    sp<MediaCodecBuffer> buffer = nullptr;
+    if (msg->findObject("buffer", &obj)) {
+        buffer = static_cast<MediaCodecBuffer *>(obj.get());
+    }
     ssize_t index;
     BufferInfo *info = mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
     BufferInfo::Status status = BufferInfo::getSafeStatus(info);
@@ -6130,13 +6139,13 @@
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
-            && info->mData != NULL && info->mData->size() != 0) {
+            && buffer != NULL && buffer->size() != 0) {
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
         // save buffers sent to the surface so we can get render time when they return
         int64_t mediaTimeUs = -1;
-        info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
+        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
         if (mediaTimeUs >= 0) {
             mCodec->mRenderTracker.onFrameQueued(
                     mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd)));
@@ -6145,7 +6154,7 @@
         int64_t timestampNs = 0;
         if (!msg->findInt64("timestampNs", &timestampNs)) {
             // use media timestamp if client did not request a specific render timestamp
-            if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
+            if (buffer->meta()->findInt64("timeUs", &timestampNs)) {
                 ALOGV("using buffer PTS of %lld", (long long)timestampNs);
                 timestampNs *= 1000;
             }
@@ -6170,7 +6179,7 @@
         }
     } else {
         if (mCodec->mNativeWindow != NULL &&
-            (info->mData == NULL || info->mData->size() != 0)) {
+            (buffer == NULL || buffer->size() != 0)) {
             // move read fence into write fence to avoid clobbering
             info->mIsReadFence = false;
             ATRACE_NAME("frame-drop");
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index b07d914..54f3c08 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -10,6 +10,7 @@
         AMRWriter.cpp                     \
         AudioPlayer.cpp                   \
         AudioSource.cpp                   \
+        BufferImpl.cpp                    \
         CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
new file mode 100644
index 0000000..7d195d3
--- /dev/null
+++ b/media/libstagefright/BufferImpl.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "BufferImpl"
+#include <utils/Log.h>
+
+#include <binder/IMemory.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include "include/SharedMemoryBuffer.h"
+
+namespace android {
+
+SharedMemoryBuffer::SharedMemoryBuffer(const sp<AMessage> &format, const sp<IMemory> &mem)
+    : MediaCodecBuffer(format, new ABuffer(mem->pointer(), mem->size())),
+      mMemory(mem) {
+}
+
+}  // namespace android
diff --git a/media/libstagefright/DataConverter.cpp b/media/libstagefright/DataConverter.cpp
index aea47f3..52be054 100644
--- a/media/libstagefright/DataConverter.cpp
+++ b/media/libstagefright/DataConverter.cpp
@@ -21,13 +21,13 @@
 
 #include <audio_utils/primitives.h>
 
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
 
 namespace android {
 
-status_t DataConverter::convert(const sp<ABuffer> &source, sp<ABuffer> &target) {
+status_t DataConverter::convert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target) {
     CHECK(source->base() != target->base());
     size_t size = targetSize(source->size());
     status_t err = OK;
@@ -43,7 +43,8 @@
     return err;
 }
 
-status_t DataConverter::safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target) {
+status_t DataConverter::safeConvert(
+        const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target) {
     memcpy(target->base(), source->data(), source->size());
     return OK;
 }
@@ -101,7 +102,7 @@
     return NULL;
 }
 
-status_t AudioConverter::safeConvert(const sp<ABuffer> &src, sp<ABuffer> &tgt) {
+status_t AudioConverter::safeConvert(const sp<MediaCodecBuffer> &src, sp<MediaCodecBuffer> &tgt) {
     if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcm16bit) {
         memcpy_to_u8_from_i16((uint8_t*)tgt->base(), (const int16_t*)src->data(), src->size() / 2);
     } else if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcmFloat) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f6763a0..fc9f644 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 
 #include "include/avc_utils.h"
+#include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
 
 #include <binder/IMemory.h>
@@ -30,6 +31,7 @@
 #include <media/ICrypto.h>
 #include <media/IOMX.h>
 #include <media/IResourceManagerService.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -860,7 +862,7 @@
     return OK;
 }
 
-status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<ABuffer> > *buffers) const {
+status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
     msg->setPointer("buffers", buffers);
@@ -870,7 +872,7 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
-status_t MediaCodec::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
+status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
     msg->setPointer("buffers", buffers);
@@ -879,7 +881,7 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
-status_t MediaCodec::getOutputBuffers(Vector<sp<ABuffer> > *buffers) const {
+status_t MediaCodec::getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexOutput);
     msg->setPointer("buffers", buffers);
@@ -888,17 +890,17 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
-status_t MediaCodec::getOutputBuffer(size_t index, sp<ABuffer> *buffer) {
+status_t MediaCodec::getOutputBuffer(size_t index, sp<MediaCodecBuffer> *buffer) {
     sp<AMessage> format;
     return getBufferAndFormat(kPortIndexOutput, index, buffer, &format);
 }
 
 status_t MediaCodec::getOutputFormat(size_t index, sp<AMessage> *format) {
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
     return getBufferAndFormat(kPortIndexOutput, index, &buffer, format);
 }
 
-status_t MediaCodec::getInputBuffer(size_t index, sp<ABuffer> *buffer) {
+status_t MediaCodec::getInputBuffer(size_t index, sp<MediaCodecBuffer> *buffer) {
     sp<AMessage> format;
     return getBufferAndFormat(kPortIndexInput, index, buffer, &format);
 }
@@ -909,7 +911,7 @@
 
 status_t MediaCodec::getBufferAndFormat(
         size_t portIndex, size_t index,
-        sp<ABuffer> *buffer, sp<AMessage> *format) {
+        sp<MediaCodecBuffer> *buffer, sp<AMessage> *format) {
     // use mutex instead of a context switch
     if (mReleasedByResourceManager) {
         ALOGE("getBufferAndFormat - resource already released");
@@ -917,7 +919,7 @@
     }
 
     if (buffer == NULL) {
-        ALOGE("getBufferAndFormat - null ABuffer");
+        ALOGE("getBufferAndFormat - null MediaCodecBuffer");
         return INVALID_OPERATION;
     }
 
@@ -956,7 +958,6 @@
     *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
                   info.mEncryptedData :
                   info.mData;
-
     *format = info.mFormat;
 
     return OK;
@@ -1046,7 +1047,7 @@
             return false;
         }
 
-        const sp<ABuffer> &buffer =
+        const sp<MediaCodecBuffer> &buffer =
             mPortBuffers[kPortIndexOutput].itemAt(index).mData;
 
         response->setSize("index", index);
@@ -1377,7 +1378,7 @@
                         if (portIndex == kPortIndexInput && mCrypto != NULL) {
                             sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
                             info.mEncryptedData =
-                                new ABuffer(mem->pointer(), info.mData->capacity());
+                                new SharedMemoryBuffer(mInputFormat, mem);
                             info.mSharedEncryptedBuffer = mem;
                         }
 
@@ -1484,6 +1485,9 @@
                         break;
                     }
 
+                    // TODO: hold reference of buffer from downstream when
+                    // mPortBuffers is removed.
+
                     if (!mCSD.empty()) {
                         ssize_t index = dequeuePortBuffer(kPortIndexInput);
                         CHECK_GE(index, 0);
@@ -1539,8 +1543,10 @@
                         break;
                     }
 
-                    sp<ABuffer> buffer;
-                    CHECK(msg->findBuffer("buffer", &buffer));
+                    sp<RefBase> obj;
+                    CHECK(msg->findObject("buffer", &obj));
+                    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+                    // TODO: hold buffer's reference when we remove mPortBuffers
 
                     int32_t omxFlags;
                     CHECK(msg->findInt32("flags", &omxFlags));
@@ -2156,7 +2162,7 @@
             int32_t portIndex;
             CHECK(msg->findInt32("portIndex", &portIndex));
 
-            Vector<sp<ABuffer> > *dstBuffers;
+            Vector<sp<MediaCodecBuffer> > *dstBuffers;
             CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
 
             dstBuffers->clear();
@@ -2306,7 +2312,7 @@
     sp<ABuffer> csd = *mCSD.begin();
     mCSD.erase(mCSD.begin());
 
-    const sp<ABuffer> &codecInputData =
+    const sp<MediaCodecBuffer> &codecInputData =
         (mCrypto != NULL) ? info->mEncryptedData : info->mData;
 
     if (csd->size() > codecInputData->capacity()) {
@@ -2553,13 +2559,14 @@
 
         info->mData->setRange(0, result);
     }
+    // TODO: release buffer reference.
 
     // synchronization boundary for getBufferAndFormat
     {
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
     }
-    reply->setBuffer("buffer", info->mData);
+    reply->setObject("buffer", info->mData);
     reply->post();
 
     info->mNotify = NULL;
@@ -2644,8 +2651,10 @@
         }
     }
 
+    info->mNotify->setObject("buffer", info->mData);
+    // TODO: release buffer reference.
     info->mNotify->post();
-    info->mNotify = NULL;
+    info->mNotify.clear();
 
     return OK;
 }
@@ -2765,7 +2774,7 @@
 void MediaCodec::onOutputBufferAvailable() {
     int32_t index;
     while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
-        const sp<ABuffer> &buffer =
+        const sp<MediaCodecBuffer> &buffer =
             mPortBuffers[kPortIndexOutput].itemAt(index).mData;
         sp<AMessage> msg = mCallback->dup();
         msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
@@ -2866,7 +2875,7 @@
 }
 
 status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
-        const sp<ABuffer> &buffer) {
+        const sp<MediaCodecBuffer> &buffer) {
     AString mime;
     CHECK(mOutputFormat->findString("mime", &mime));
 
@@ -2900,7 +2909,10 @@
     } else {
         // For everything else we just stash the codec specific data into
         // the output format as a single piece of csd under "csd-0".
-        mOutputFormat->setBuffer("csd-0", buffer);
+        sp<ABuffer> csd = new ABuffer(buffer->size());
+        memcpy(csd->data(), buffer->data(), buffer->size());
+        csd->setRange(0, buffer->size());
+        mOutputFormat->setBuffer("csd-0", csd);
     }
 
     return OK;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 30b078f..030c505 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -24,6 +24,7 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -689,7 +690,7 @@
 #endif // DEBUG_DRIFT_TIME
             }
 
-            sp<ABuffer> inbuf;
+            sp<MediaCodecBuffer> inbuf;
             status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
             if (err != OK || inbuf == NULL) {
                 mbuf->release();
@@ -851,7 +852,7 @@
                 break;
             }
 
-            sp<ABuffer> outbuf;
+            sp<MediaCodecBuffer> outbuf;
             status_t err = mEncoder->getOutputBuffer(index, &outbuf);
             if (err != OK || outbuf == NULL) {
                 signalEOS();
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index de21c5e..4c4d93e 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -17,7 +17,7 @@
 #include <gui/Surface.h>
 
 #include <media/ICrypto.h>
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -225,7 +225,7 @@
                 break;
             }
 
-            sp<ABuffer> in_buffer;
+            sp<MediaCodecBuffer> in_buffer;
             if (res == OK) {
                 res = mCodec->getInputBuffer(in_ix, &in_buffer);
             }
@@ -330,7 +330,7 @@
             return res;
         }
 
-        sp<ABuffer> out_buffer;
+        sp<MediaCodecBuffer> out_buffer;
         res = mCodec->getOutputBuffer(out_ix, &out_buffer);
         if (res != OK) {
             ALOGW("[%s] could not get output buffer #%zu",
diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
index d30be88..ee9016d 100644
--- a/media/libstagefright/SkipCutBuffer.cpp
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -88,7 +88,8 @@
     buffer->set_range(0, copied);
 }
 
-void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
+template <typename T>
+void SkipCutBuffer::submitInternal(const sp<T>& buffer) {
     if (mCutBuffer == NULL) {
         // passthrough mode
         return;
@@ -120,6 +121,14 @@
     buffer->setRange(0, copied);
 }
 
+void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
+    submitInternal(buffer);
+}
+
+void SkipCutBuffer::submit(const sp<MediaCodecBuffer>& buffer) {
+    submitInternal(buffer);
+}
+
 void SkipCutBuffer::clear() {
     mWriteHead = mReadHead = 0;
     mFrontPadding = mSkip;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index be5067d..773f3ed 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -27,8 +27,8 @@
 
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/MediaCodecBuffer.h>
 
-#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ColorConverter.h>
@@ -223,7 +223,7 @@
         return NULL;
     }
 
-    Vector<sp<ABuffer> > inputBuffers;
+    Vector<sp<MediaCodecBuffer> > inputBuffers;
     err = decoder->getInputBuffers(&inputBuffers);
     if (err != OK) {
         ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
@@ -232,7 +232,7 @@
         return NULL;
     }
 
-    Vector<sp<ABuffer> > outputBuffers;
+    Vector<sp<MediaCodecBuffer> > outputBuffers;
     err = decoder->getOutputBuffers(&outputBuffers);
     if (err != OK) {
         ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
@@ -264,7 +264,7 @@
         size_t inputIndex = -1;
         int64_t ptsUs = 0ll;
         uint32_t flags = 0;
-        sp<ABuffer> codecBuffer = NULL;
+        sp<MediaCodecBuffer> codecBuffer = NULL;
 
         while (haveMoreInputs) {
             err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
@@ -376,7 +376,7 @@
     }
 
     ALOGV("successfully decoded video frame.");
-    sp<ABuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+    sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
 
     if (thumbNailTime >= 0) {
         if (timeUs != thumbNailTime) {
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 0396dc6..9f15cf7 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -447,7 +447,8 @@
     return meta;
 }
 
-bool IsIDR(const sp<ABuffer> &buffer) {
+template <typename T>
+bool IsIDRInternal(const sp<T> &buffer) {
     const uint8_t *data = buffer->data();
     size_t size = buffer->size();
 
@@ -469,6 +470,14 @@
     return foundIDR;
 }
 
+bool IsIDR(const sp<ABuffer> &buffer) {
+    return IsIDRInternal(buffer);
+}
+
+bool IsIDR(const sp<MediaCodecBuffer> &buffer) {
+    return IsIDRInternal(buffer);
+}
+
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.cpp b/media/libstagefright/filters/IntrinsicBlurFilter.cpp
index cbcf699..e00afd9 100644
--- a/media/libstagefright/filters/IntrinsicBlurFilter.cpp
+++ b/media/libstagefright/filters/IntrinsicBlurFilter.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Log.h>
 
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -88,7 +88,7 @@
 }
 
 status_t IntrinsicBlurFilter::processBuffers(
-        const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+        const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
     mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
     mBlur->forEach(mAllocOut);
     mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.h b/media/libstagefright/filters/IntrinsicBlurFilter.h
index 4707ab7..a2aabfa 100644
--- a/media/libstagefright/filters/IntrinsicBlurFilter.h
+++ b/media/libstagefright/filters/IntrinsicBlurFilter.h
@@ -31,7 +31,7 @@
     virtual void reset();
     virtual status_t setParameters(const sp<AMessage> &msg);
     virtual status_t processBuffers(
-            const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+            const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
 
 protected:
     virtual ~IntrinsicBlurFilter() {};
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index cd69418..f26c840 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -31,6 +31,8 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaFilter.h>
 
+#include <media/MediaCodecBuffer.h>
+
 #include <gui/BufferItem.h>
 
 #include "ColorConvert.h"
@@ -40,6 +42,8 @@
 #include "SaturationFilter.h"
 #include "ZeroFilter.h"
 
+#include "../include/SharedMemoryBuffer.h"
+
 namespace android {
 
 // parameter: number of input and output buffers
@@ -195,7 +199,7 @@
 }
 
 void MediaFilter::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<ABuffer> &buffer) {
+        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
     mBufferIDs.push_back(id);
     mBuffers.push_back(buffer);
 }
@@ -208,7 +212,7 @@
     return mBufferIDs.itemAt(index);
 }
 
-sp<ABuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
+sp<MediaCodecBuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
     return mBuffers.itemAt(index);
 }
 
@@ -250,7 +254,8 @@
         info.mBufferID = i;
         info.mGeneration = mGeneration;
         info.mOutputFlags = 0;
-        info.mData = new ABuffer(mem->pointer(), bufferSize);
+        info.mData = new SharedMemoryBuffer(
+                isInput ? mInputFormat : mOutputFormat, mem);
         info.mData->meta()->setInt64("timeUs", 0);
 
         mBuffers[portIndex].push_back(info);
@@ -314,7 +319,7 @@
     notify->setInt32("buffer-id", info->mBufferID);
 
     info->mData->meta()->clear();
-    notify->setBuffer("buffer", info->mData);
+    notify->setObject("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
     reply->setInt32("buffer-id", info->mBufferID);
@@ -334,7 +339,7 @@
     notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
     notify->setInt32("buffer-id", info->mBufferID);
     notify->setInt32("flags", info->mOutputFlags);
-    notify->setBuffer("buffer", info->mData);
+    notify->setObject("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
     reply->setInt32("buffer-id", info->mBufferID);
@@ -597,11 +602,12 @@
     CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
     info->mStatus = BufferInfo::OWNED_BY_US;
 
-    sp<ABuffer> buffer;
+    sp<MediaCodecBuffer> buffer;
     int32_t err = OK;
     bool eos = false;
 
-    if (!msg->findBuffer("buffer", &buffer)) {
+    sp<RefBase> obj;
+    if (!msg->findObject("buffer", &obj)) {
         // these are unfilled buffers returned by client
         CHECK(msg->findInt32("err", &err));
 
@@ -616,6 +622,8 @@
         }
 
         buffer.clear();
+    } else {
+        buffer = static_cast<MediaCodecBuffer *>(obj.get());
     }
 
     int32_t isCSD;
@@ -768,7 +776,8 @@
     // TODO: check input format and convert only if necessary
     // copy RGBA graphic buffer into temporary ARGB input buffer
     BufferInfo *inputInfo = new BufferInfo;
-    inputInfo->mData = new ABuffer(buf->getWidth() * buf->getHeight() * 4);
+    inputInfo->mData = new MediaCodecBuffer(
+            mInputFormat, new ABuffer(buf->getWidth() * buf->getHeight() * 4));
     ALOGV("Copying surface data into temp buffer.");
     convertRGBAToARGB(
             (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
diff --git a/media/libstagefright/filters/RSFilter.cpp b/media/libstagefright/filters/RSFilter.cpp
index b569945..225a375 100644
--- a/media/libstagefright/filters/RSFilter.cpp
+++ b/media/libstagefright/filters/RSFilter.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Log.h>
 
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -85,7 +85,7 @@
 }
 
 status_t RSFilter::processBuffers(
-        const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+        const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
     mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
     mCallback->processBuffers(mAllocIn.get(), mAllocOut.get());
     mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
diff --git a/media/libstagefright/filters/RSFilter.h b/media/libstagefright/filters/RSFilter.h
index c5b5074..3326284 100644
--- a/media/libstagefright/filters/RSFilter.h
+++ b/media/libstagefright/filters/RSFilter.h
@@ -35,7 +35,7 @@
     virtual void reset();
     virtual status_t setParameters(const sp<AMessage> &msg);
     virtual status_t processBuffers(
-            const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+            const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
 
 protected:
     virtual ~RSFilter();
diff --git a/media/libstagefright/filters/SaturationFilter.cpp b/media/libstagefright/filters/SaturationFilter.cpp
index ba5f75a..0a1df05 100644
--- a/media/libstagefright/filters/SaturationFilter.cpp
+++ b/media/libstagefright/filters/SaturationFilter.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Log.h>
 
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -88,7 +88,7 @@
 }
 
 status_t SaturationFilter::processBuffers(
-        const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+        const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
     mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
     mScript->forEach_root(mAllocIn, mAllocOut);
     mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
diff --git a/media/libstagefright/filters/SaturationFilter.h b/media/libstagefright/filters/SaturationFilter.h
index 0545021..317e469 100644
--- a/media/libstagefright/filters/SaturationFilter.h
+++ b/media/libstagefright/filters/SaturationFilter.h
@@ -33,7 +33,7 @@
     virtual void reset();
     virtual status_t setParameters(const sp<AMessage> &msg);
     virtual status_t processBuffers(
-            const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+            const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
 
 protected:
     virtual ~SaturationFilter() {};
diff --git a/media/libstagefright/filters/SimpleFilter.h b/media/libstagefright/filters/SimpleFilter.h
index 4cd37ef..a3c2d76 100644
--- a/media/libstagefright/filters/SimpleFilter.h
+++ b/media/libstagefright/filters/SimpleFilter.h
@@ -21,11 +21,11 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
-struct ABuffer;
-struct AMessage;
-
 namespace android {
 
+struct AMessage;
+class MediaCodecBuffer;
+
 struct SimpleFilter : public RefBase {
 public:
     SimpleFilter() : mWidth(0), mHeight(0), mStride(0), mSliceHeight(0),
@@ -37,7 +37,7 @@
     virtual void reset() = 0;
     virtual status_t setParameters(const sp<AMessage> &msg) = 0;
     virtual status_t processBuffers(
-            const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) = 0;
+            const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) = 0;
 
 protected:
     int32_t mWidth, mHeight;
diff --git a/media/libstagefright/filters/ZeroFilter.cpp b/media/libstagefright/filters/ZeroFilter.cpp
index 3f1243c..74b94b7 100644
--- a/media/libstagefright/filters/ZeroFilter.cpp
+++ b/media/libstagefright/filters/ZeroFilter.cpp
@@ -17,7 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ZeroFilter"
 
-#include <media/stagefright/foundation/ABuffer.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -38,7 +38,7 @@
 }
 
 status_t ZeroFilter::processBuffers(
-        const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer) {
+        const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
     // assuming identical input & output buffers, since we're a copy filter
     if (mInvertData) {
         uint32_t* src = (uint32_t*)srcBuffer->data();
diff --git a/media/libstagefright/filters/ZeroFilter.h b/media/libstagefright/filters/ZeroFilter.h
index bd34dfb..f941cc8 100644
--- a/media/libstagefright/filters/ZeroFilter.h
+++ b/media/libstagefright/filters/ZeroFilter.h
@@ -29,7 +29,7 @@
     virtual void reset() {};
     virtual status_t setParameters(const sp<AMessage> &msg);
     virtual status_t processBuffers(
-            const sp<ABuffer> &srcBuffer, const sp<ABuffer> &outBuffer);
+            const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
 
 protected:
     virtual ~ZeroFilter() {};
diff --git a/media/libstagefright/include/DataConverter.h b/media/libstagefright/include/DataConverter.h
index 8d67921..60ebad1 100644
--- a/media/libstagefright/include/DataConverter.h
+++ b/media/libstagefright/include/DataConverter.h
@@ -24,18 +24,18 @@
 
 namespace android {
 
-struct ABuffer;
+class MediaCodecBuffer;
 
 // DataConverter base class, defaults to memcpy
 struct DataConverter : public RefBase {
     virtual size_t sourceSize(size_t targetSize); // will clamp to SIZE_MAX
     virtual size_t targetSize(size_t sourceSize); // will clamp to SIZE_MAX
 
-    status_t convert(const sp<ABuffer> &source, sp<ABuffer> &target);
+    status_t convert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target);
     virtual ~DataConverter();
 
 protected:
-    virtual status_t safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target);
+    virtual status_t safeConvert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target);
 };
 
 // SampleConverterBase uses a ratio to calculate the source and target sizes
@@ -45,7 +45,7 @@
     virtual size_t targetSize(size_t sourceSize);
 
 protected:
-    virtual status_t safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target) = 0;
+    virtual status_t safeConvert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target) = 0;
 
     // sourceSize = sourceSampleSize / targetSampleSize * targetSize
     SampleConverterBase(uint32_t sourceSampleSize, uint32_t targetSampleSize)
@@ -61,7 +61,7 @@
     static AudioConverter *Create(AudioEncoding source, AudioEncoding target);
 
 protected:
-    virtual status_t safeConvert(const sp<ABuffer> &src, sp<ABuffer> &tgt);
+    virtual status_t safeConvert(const sp<MediaCodecBuffer> &source, sp<MediaCodecBuffer> &target);
 
 private:
     AudioConverter(
diff --git a/media/libstagefright/include/SharedMemoryBuffer.h b/media/libstagefright/include/SharedMemoryBuffer.h
new file mode 100644
index 0000000..1d7f7a6
--- /dev/null
+++ b/media/libstagefright/include/SharedMemoryBuffer.h
@@ -0,0 +1,45 @@
+/*
+ * 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 SHARED_MEMORY_BUFFER_H_
+
+#define SHARED_MEMORY_BUFFER_H_
+
+#include <media/MediaCodecBuffer.h>
+
+namespace android {
+
+struct AMessage;
+class IMemory;
+
+/**
+ * MediaCodecBuffer implementation based on IMemory.
+ */
+class SharedMemoryBuffer : public MediaCodecBuffer {
+public:
+    SharedMemoryBuffer(const sp<AMessage> &format, const sp<IMemory> &mem);
+
+    virtual ~SharedMemoryBuffer() = default;
+
+private:
+    SharedMemoryBuffer() = delete;
+
+    const sp<IMemory> mMemory;
+};
+
+}  // namespace android
+
+#endif  // SHARED_MEMORY_BUFFER_H_
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index b2ef360..d05906a 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -18,6 +18,7 @@
 
 #define AVC_UTILS_H_
 
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <utils/Errors.h>
 
@@ -84,6 +85,7 @@
 sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
 
 bool IsIDR(const sp<ABuffer> &accessUnit);
+bool IsIDR(const sp<MediaCodecBuffer> &accessUnit);
 bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
 uint32_t FindAVCLayerId(const uint8_t *data, size_t size);
 
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 471152e..273af18 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -26,6 +26,7 @@
 #include <cutils/properties.h>
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -720,7 +721,7 @@
 #endif
 
             sp<ABuffer> buffer;
-            sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex);
+            sp<MediaCodecBuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex);
 
             if (outbuf->meta()->findPointer("handle", (void**)&handle) &&
                     handle != NULL) {
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index b182990..ad95ab5 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -25,6 +25,7 @@
 struct ABuffer;
 class IGraphicBufferProducer;
 struct MediaCodec;
+class MediaCodecBuffer;
 
 #define ENABLE_SILENCE_DETECTION        0
 
@@ -106,8 +107,8 @@
 
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
 
-    Vector<sp<ABuffer> > mEncoderInputBuffers;
-    Vector<sp<ABuffer> > mEncoderOutputBuffers;
+    Vector<sp<MediaCodecBuffer> > mEncoderInputBuffers;
+    Vector<sp<MediaCodecBuffer> > mEncoderOutputBuffers;
 
     List<size_t> mAvailEncoderInputIndices;
 
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 3d1eca1..22c90e2 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -30,10 +30,10 @@
 
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ABuffer.h>
 
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/MediaCodecBuffer.h>
 
 using namespace android;
 
@@ -268,13 +268,17 @@
 
 EXPORT
 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
-    android::Vector<android::sp<android::ABuffer> > abufs;
+    android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
     if (mData->mCodec->getInputBuffers(&abufs) == 0) {
         size_t n = abufs.size();
         if (idx >= n) {
             ALOGE("buffer index %zu out of range", idx);
             return NULL;
         }
+        if (abufs[idx] == NULL) {
+            ALOGE("buffer index %zu is NULL", idx);
+            return NULL;
+        }
         if (out_size != NULL) {
             *out_size = abufs[idx]->capacity();
         }
@@ -286,7 +290,7 @@
 
 EXPORT
 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
-    android::Vector<android::sp<android::ABuffer> > abufs;
+    android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
     if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
         size_t n = abufs.size();
         if (idx >= n) {