MediaCodec refactoring part 1-c: buffer ownership

- Buffers are (roughly) owned by themselves.
- As a corollary, remove output format change related events
and replace by inspecting formats associated with each buffers.

Bug: 32133435
Test: gts-tradefed run gts -m GtsExoPlayerTestCases
Test: (manual) Run Play Movies app to play a secure content.
Change-Id: I6b57da61c2d71acd0d5be4281de823ba1c95b72f
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 1a4bf08..8fe1dd4 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -230,7 +230,6 @@
                     mCodec->signalResume();
 
                     (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == CodecBase::kWhatOutputFormatChanged) {
                 } else if (what == CodecBase::kWhatShutdownCompleted) {
                     mDecodeLooper->unregisterHandler(mCodec->id());
 
diff --git a/include/media/MediaCodecBuffer.h b/include/media/MediaCodecBuffer.h
index 2df81dd..05aaa14 100644
--- a/include/media/MediaCodecBuffer.h
+++ b/include/media/MediaCodecBuffer.h
@@ -58,6 +58,8 @@
     sp<AMessage> meta();
     sp<AMessage> format();
 
+    virtual sp<MediaCodecBuffer> clone(const sp<AMessage> &format);
+
 private:
     MediaCodecBuffer() = delete;
 
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index cdfe2c9..64a542d 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -81,7 +81,7 @@
         friend struct ACodec;
 
         Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer>> mBuffers;
+        Vector<sp<MediaCodecBuffer> > mBuffers;
 
         PortDescription();
         void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
@@ -188,7 +188,6 @@
         sp<RefBase> mCodecRef;            // and a reference to the IMemory
 
         sp<GraphicBuffer> mGraphicBuffer;
-        sp<NativeHandle> mNativeHandle;
         int mFenceFd;
         FrameRenderTracker::Info *mRenderInfo;
 
@@ -200,8 +199,6 @@
         // 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 1295b59..d8c43a4 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -45,7 +45,6 @@
         kWhatEOS                 = 'eos ',
         kWhatShutdownCompleted   = 'scom',
         kWhatFlushCompleted      = 'fcom',
-        kWhatOutputFormatChanged = 'outC',
         kWhatError               = 'erro',
         kWhatComponentAllocated  = 'cAll',
         kWhatComponentConfigured = 'cCon',
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 19d7047..2c31a0d 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -246,7 +246,7 @@
         kFlagIsSecure                   = 64,
         kFlagSawMediaServerDie          = 128,
         kFlagIsEncoder                  = 256,
-        kFlagGatherCodecSpecificData    = 512,
+        // 512 skipped
         kFlagIsAsync                    = 1024,
         kFlagIsComponentAllocated       = 2048,
         kFlagPushBlankBuffersOnShutdown = 4096,
@@ -258,7 +258,6 @@
         sp<MediaCodecBuffer> mSecureData;
         sp<IMemory> mSharedEncryptedBuffer;
         sp<AMessage> mNotify;
-        sp<AMessage> mFormat;
         bool mOwnedByClient;
     };
 
@@ -329,6 +328,7 @@
 
     List<size_t> mAvailPortBuffers[2];
     Vector<BufferInfo> mPortBuffers[2];
+    Vector<sp<MediaCodecBuffer>> mPortBufferArrays[2];
 
     int32_t mDequeueInputTimeoutGeneration;
     sp<AReplyToken> mDequeueInputReplyID;
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index 6aa87e8..0e39431 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -144,7 +144,6 @@
     void postFillThisBuffer(BufferInfo *info);
     void postDrainThisBuffer(BufferInfo *info);
     void postEOS();
-    void sendFormatChange();
     void requestFillEmptyInput();
     void processBuffers();
 
diff --git a/media/libmedia/MediaCodecBuffer.cpp b/media/libmedia/MediaCodecBuffer.cpp
index 2d255be..2af31d0 100644
--- a/media/libmedia/MediaCodecBuffer.cpp
+++ b/media/libmedia/MediaCodecBuffer.cpp
@@ -80,4 +80,8 @@
     return mFormat;
 }
 
+sp<MediaCodecBuffer> MediaCodecBuffer::clone(const sp<AMessage> &format) {
+    return new MediaCodecBuffer(format, mBuffer);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index ed29859..52c0feb 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -866,7 +866,8 @@
             size_t totalSize = def.nBufferCountActual * (alignedSize + alignedConvSize);
             mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
 
-            const sp<AMessage> &format = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
+            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) {
@@ -1478,20 +1479,20 @@
 
     if (mOutputMetadataType == kMetadataBufferTypeGrallocSource) {
         VideoGrallocMetadata *grallocMeta =
-            reinterpret_cast<VideoGrallocMetadata *>(oldest->mData->data());
+            reinterpret_cast<VideoGrallocMetadata *>(oldest->mCodecData->base());
         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->data());
+                oldest->mGraphicBuffer->handle, oldest->mCodecData->base());
     } else if (mOutputMetadataType == kMetadataBufferTypeANWBuffer) {
         VideoNativeMetadata *nativeMeta =
-            reinterpret_cast<VideoNativeMetadata *>(oldest->mData->data());
+            reinterpret_cast<VideoNativeMetadata *>(oldest->mCodecData->base());
         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->data());
+                oldest->mGraphicBuffer->getNativeBuffer(), oldest->mCodecData->base());
     }
 
     updateRenderInfoForDequeuedBuffer(buf, fenceFd, oldest);
@@ -1541,9 +1542,9 @@
     // there should not be any fences in the metadata
     MetadataBufferType type =
         portIndex == kPortIndexOutput ? mOutputMetadataType : mInputMetadataType;
-    if (type == kMetadataBufferTypeANWBuffer && info->mData != NULL
-            && info->mData->size() >= sizeof(VideoNativeMetadata)) {
-        int fenceFd = ((VideoNativeMetadata *)info->mData->data())->nFenceFd;
+    if (type == kMetadataBufferTypeANWBuffer && info->mCodecData != NULL
+            && info->mCodecData->size() >= sizeof(VideoNativeMetadata)) {
+        int fenceFd = ((VideoNativeMetadata *)info->mCodecData->base())->nFenceFd;
         if (fenceFd >= 0) {
             ALOGW("unreleased fence (%d) in %s metadata buffer %zu",
                     fenceFd, portIndex == kPortIndexInput ? "input" : "output", i);
@@ -2190,7 +2191,6 @@
 
     // NOTE: both mBaseOutputFormat and mOutputFormat are outputFormat to signal first frame.
     mBaseOutputFormat = outputFormat;
-    // trigger a kWhatOutputFormatChanged msg on first buffer
     mLastOutputFormat.clear();
 
     err = getPortFormat(kPortIndexInput, inputFormat);
@@ -5188,11 +5188,6 @@
         mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay, mEncoderPadding, channelCount);
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatOutputFormatChanged);
-    notify->setMessage("format", mOutputFormat);
-    notify->post();
-
     // mLastOutputFormat is not used when tunneled; doing this just to stay consistent
     mLastOutputFormat = mOutputFormat;
 }
@@ -5572,8 +5567,8 @@
     notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
     notify->setInt32("buffer-id", info->mBufferID);
 
-    info->mData->meta()->clear();
-    notify->setObject("buffer", info->mData);
+    notify->setObject("buffer", info->mData->clone(mCodec->mInputFormat));
+    info->mData.clear();
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
     reply->setInt32("buffer-id", info->mBufferID);
@@ -5606,8 +5601,6 @@
                  mCodec->mComponentName.c_str(), err);
             eos = true;
         }
-
-        buffer.clear();
     } else {
         buffer = static_cast<MediaCodecBuffer *>(obj.get());
     }
@@ -5628,6 +5621,7 @@
     }
 
     info->mStatus = BufferInfo::OWNED_BY_US;
+    info->mData = buffer;
 
     switch (mode) {
         case KEEP_BUFFERS:
@@ -5672,11 +5666,12 @@
                     flags |= OMX_BUFFERFLAG_EOS;
                 }
 
-                if (buffer != info->mCodecData) {
+                size_t size = buffer->size();
+                if (buffer->base() != info->mCodecData->base()) {
                     ALOGV("[%s] Needs to copy input data for buffer %u. (%p != %p)",
                          mCodec->mComponentName.c_str(),
                          bufferID,
-                         buffer.get(), info->mCodecData.get());
+                         buffer->base(), info->mCodecData->base());
 
                     sp<DataConverter> converter = mCodec->mConverter[kPortIndexInput];
                     if (converter == NULL || isCSD) {
@@ -5687,6 +5682,7 @@
                         mCodec->signalError(OMX_ErrorUndefined, err);
                         return;
                     }
+                    size = info->mCodecData->size();
                 }
 
                 if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
@@ -5763,7 +5759,7 @@
                     err2 = mCodec->mOMXNode->emptyBuffer(
                         bufferID,
                         0,
-                        info->mCodecData->size(),
+                        size,
                         flags,
                         timeUs,
                         info->mFenceFd);
@@ -5774,6 +5770,8 @@
                     return;
                 }
                 info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
+                // Hold the reference while component is using the buffer.
+                info->mData = buffer;
 
                 if (!eos && err == OK) {
                     getMoreInputDataIfPossible();
@@ -5940,7 +5938,7 @@
 
             sp<AMessage> reply =
                 new AMessage(kWhatOutputBufferDrained, mCodec);
-            sp<MediaCodecBuffer> buffer = info->mData;
+            sp<MediaCodecBuffer> buffer = info->mData->clone(mCodec->mOutputFormat);
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
                 // pretend that output format has changed on the first frame (we used to do this)
@@ -5971,7 +5969,7 @@
                 buffer->meta()->setPointer("handle", handle);
                 buffer->meta()->setInt32("rangeOffset", rangeOffset);
                 buffer->meta()->setInt32("rangeLength", rangeLength);
-            } else if (buffer == info->mCodecData) {
+            } else if (buffer->base() == info->mCodecData->base()) {
                 buffer->setRange(rangeOffset, rangeLength);
             } else {
                 info->mCodecData->setRange(rangeOffset, rangeLength);
@@ -6000,6 +5998,7 @@
             notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
             notify->setInt32("buffer-id", info->mBufferID);
             notify->setObject("buffer", buffer);
+            info->mData.clear();
             notify->setInt32("flags", flags);
 
             reply->setInt32("buffer-id", info->mBufferID);
@@ -6056,6 +6055,7 @@
         mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
         return;
     }
+    info->mData = buffer;
 
     android_native_rect_t crop;
     if (msg->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 4ed7911..81fe0fe 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -34,7 +34,11 @@
       mMemory(mem) {
 }
 
-SecureBuffer::SecureBuffer(const sp<AMessage> &format, void *ptr, size_t size)
+sp<MediaCodecBuffer> SharedMemoryBuffer::clone(const sp<AMessage> &format) {
+    return new SharedMemoryBuffer(format, mMemory);
+}
+
+SecureBuffer::SecureBuffer(const sp<AMessage> &format, const void *ptr, size_t size)
     : MediaCodecBuffer(format, new ABuffer(nullptr, size)),
       mPointer(ptr) {
 }
@@ -46,6 +50,12 @@
       mHandle(handle) {
 }
 
+sp<MediaCodecBuffer> SecureBuffer::clone(const sp<AMessage> &format) {
+    return (mHandle == nullptr)
+            ? new SecureBuffer(format, mPointer, capacity())
+            : new SecureBuffer(format, mHandle, capacity());
+}
+
 void *SecureBuffer::getDestinationPointer() {
     return (void *)(mHandle == nullptr ? mPointer : mHandle->handle());
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 5ab5f3e..12eca10 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -929,9 +929,8 @@
         return INVALID_OPERATION;
     }
 
-    // by the time buffers array is initialized, crypto is set
     *buffer = info.mData;
-    *format = info.mFormat;
+    *format = info.mData->format();
 
     return OK;
 }
@@ -1323,6 +1322,7 @@
                             || portIndex == kPortIndexOutput);
 
                     mPortBuffers[portIndex].clear();
+                    mPortBufferArrays[portIndex].clear();
 
                     Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
 
@@ -1333,32 +1333,12 @@
                         static_cast<CodecBase::PortDescription *>(obj.get());
 
                     size_t numBuffers = portDesc->countBuffers();
-
-                    size_t totalSize = 0;
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            totalSize += portDesc->bufferAt(i)->capacity();
-                        }
-                    }
-
-                    if (totalSize) {
-                        mDealer = new MemoryDealer(totalSize, "MediaCodec");
-                    }
-
                     for (size_t i = 0; i < numBuffers; ++i) {
                         BufferInfo info;
                         info.mBufferID = portDesc->bufferIDAt(i);
                         info.mOwnedByClient = false;
-                        info.mData = portDesc->bufferAt(i);
-
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
-                            info.mSecureData = info.mData;
-                            info.mData = new SharedMemoryBuffer(mInputFormat, mem);
-                            info.mSharedEncryptedBuffer = mem;
-                        }
-
                         buffers->push_back(info);
+                        mPortBufferArrays[portIndex].push_back(portDesc->bufferAt(i));
                     }
 
                     if (portIndex == kPortIndexOutput) {
@@ -1382,62 +1362,6 @@
                     break;
                 }
 
-                case CodecBase::kWhatOutputFormatChanged:
-                {
-                    CHECK(msg->findMessage("format", &mOutputFormat));
-
-                    ALOGV("[%s] output format changed to: %s",
-                            mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
-
-                    if (mSoftRenderer == NULL &&
-                            mSurface != NULL &&
-                            (mFlags & kFlagUsesSoftwareRenderer)) {
-                        AString mime;
-                        CHECK(mOutputFormat->findString("mime", &mime));
-
-                        // TODO: propagate color aspects to software renderer to allow better
-                        // color conversion to RGB. For now, just mark dataspace for YUV
-                        // rendering.
-                        int32_t dataSpace;
-                        if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
-                            ALOGD("[%s] setting dataspace on output surface to #%x",
-                                    mComponentName.c_str(), dataSpace);
-                            int err = native_window_set_buffers_data_space(
-                                    mSurface.get(), (android_dataspace)dataSpace);
-                            ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err);
-                        }
-
-                        if (mime.startsWithIgnoreCase("video/")) {
-                            mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
-                        }
-                    }
-
-                    if (mFlags & kFlagIsEncoder) {
-                        // Before we announce the format change we should
-                        // collect codec specific data and amend the output
-                        // format as necessary.
-                        mFlags |= kFlagGatherCodecSpecificData;
-                    } else if (mFlags & kFlagIsAsync) {
-                        onOutputFormatChanged();
-                    } else {
-                        mFlags |= kFlagOutputFormatChanged;
-                        postActivityNotificationIfPossible();
-                    }
-
-                    // Notify mCrypto of video resolution changes
-                    if (mCrypto != NULL) {
-                        int32_t left, top, right, bottom, width, height;
-                        if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
-                            mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
-                        } else if (mOutputFormat->findInt32("width", &width)
-                                && mOutputFormat->findInt32("height", &height)) {
-                            mCrypto->notifyResolution(width, height);
-                        }
-                    }
-
-                    break;
-                }
-
                 case CodecBase::kWhatOutputFramesRendered:
                 {
                     // ignore these in all states except running, and check that we have a
@@ -1528,27 +1452,65 @@
                     CHECK(msg->findInt32("flags", &omxFlags));
 
                     buffer->meta()->setInt32("omxFlags", omxFlags);
+                    if (mOutputFormat != buffer->format()) {
+                        mOutputFormat = buffer->format();
+                        ALOGV("[%s] output format changed to: %s",
+                                mComponentName.c_str(), mOutputFormat->debugString(4).c_str());
 
-                    if (mFlags & kFlagGatherCodecSpecificData) {
-                        // This is the very first output buffer after a
-                        // format change was signalled, it'll either contain
-                        // the one piece of codec specific data we can expect
-                        // or there won't be codec specific data.
-                        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-                            status_t err =
-                                amendOutputFormatWithCodecSpecificData(buffer);
+                        if (mSoftRenderer == NULL &&
+                                mSurface != NULL &&
+                                (mFlags & kFlagUsesSoftwareRenderer)) {
+                            AString mime;
+                            CHECK(mOutputFormat->findString("mime", &mime));
 
-                            if (err != OK) {
-                                ALOGE("Codec spit out malformed codec "
-                                      "specific data!");
+                            // TODO: propagate color aspects to software renderer to allow better
+                            // color conversion to RGB. For now, just mark dataspace for YUV
+                            // rendering.
+                            int32_t dataSpace;
+                            if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
+                                ALOGD("[%s] setting dataspace on output surface to #%x",
+                                        mComponentName.c_str(), dataSpace);
+                                int err = native_window_set_buffers_data_space(
+                                        mSurface.get(), (android_dataspace)dataSpace);
+                                ALOGW_IF(err != 0, "failed to set dataspace on surface (%d)", err);
+                            }
+
+                            if (mime.startsWithIgnoreCase("video/")) {
+                                mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
                             }
                         }
 
-                        mFlags &= ~kFlagGatherCodecSpecificData;
+                        if (mFlags & kFlagIsEncoder) {
+                            // Before we announce the format change we should
+                            // collect codec specific data and amend the output
+                            // format as necessary.
+                            if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                                status_t err =
+                                    amendOutputFormatWithCodecSpecificData(buffer);
+
+                                if (err != OK) {
+                                    ALOGE("Codec spit out malformed codec "
+                                          "specific data!");
+                                }
+                            }
+                        }
+
                         if (mFlags & kFlagIsAsync) {
                             onOutputFormatChanged();
                         } else {
                             mFlags |= kFlagOutputFormatChanged;
+                            postActivityNotificationIfPossible();
+                        }
+
+                        // Notify mCrypto of video resolution changes
+                        if (mCrypto != NULL) {
+                            int32_t left, top, right, bottom, width, height;
+                            if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
+                                mCrypto->notifyResolution(right - left + 1, bottom - top + 1);
+                            } else if (mOutputFormat->findInt32("width", &width)
+                                    && mOutputFormat->findInt32("height", &height)) {
+                                mCrypto->notifyResolution(width, height);
+                            }
                         }
                     }
 
@@ -2170,12 +2132,10 @@
             // createInputSurface(), or persistent set by setInputSurface()),
             // give the client an empty input buffers array.
             if (portIndex != kPortIndexInput || !mHaveInputSurface) {
-                const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
+                const Vector<sp<MediaCodecBuffer>> &srcBuffers = mPortBufferArrays[portIndex];
 
                 for (size_t i = 0; i < srcBuffers.size(); ++i) {
-                    const BufferInfo &info = srcBuffers.itemAt(i);
-
-                    dstBuffers->push_back(info.mData);
+                    dstBuffers->push_back(srcBuffers[i]);
                 }
             }
 
@@ -2345,7 +2305,6 @@
         mFlags &= ~kFlagOutputBuffersChanged;
         mFlags &= ~kFlagStickyError;
         mFlags &= ~kFlagIsEncoder;
-        mFlags &= ~kFlagGatherCodecSpecificData;
         mFlags &= ~kFlagIsAsync;
         mStickyError = OK;
 
@@ -2387,12 +2346,15 @@
         if (info->mNotify != NULL) {
             sp<AMessage> msg = info->mNotify;
             info->mNotify = NULL;
+            msg->setObject("buffer", (portIndex == kPortIndexInput && mCrypto != NULL)
+                    ? info->mSecureData : info->mData);
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
             } else {
-                // TODO: clear memory reference.
                 info->mOwnedByClient = false;
+                info->mData.clear();
+                info->mSecureData.clear();
             }
 
             if (portIndex == kPortIndexInput) {
@@ -2404,6 +2366,7 @@
     }
 
     mAvailPortBuffers[portIndex].clear();
+    mPortBufferArrays[portIndex].clear();
 }
 
 size_t MediaCodec::updateBuffers(
@@ -2412,8 +2375,22 @@
 
     uint32_t bufferID;
     CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+    sp<RefBase> obj;
+    CHECK(msg->findObject("buffer", &obj));
+    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
     Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+    if (portIndex == kPortIndexInput && mCrypto != NULL && mDealer == NULL) {
+        // Lazy initialization for encrypted buffers.
+        size_t capacity = buffer->capacity();
+        size_t totalSize = capacity * buffers->size();
+
+        mDealer = new MemoryDealer(totalSize, "MediaCodec");
+        for (size_t i = 0; i < buffers->size(); ++i) {
+            BufferInfo *info = &buffers->editItemAt(i);
+            info->mSharedEncryptedBuffer = mDealer->allocate(capacity);
+        }
+    }
 
     for (size_t i = 0; i < buffers->size(); ++i) {
         BufferInfo *info = &buffers->editItemAt(i);
@@ -2422,8 +2399,13 @@
             CHECK(info->mNotify == NULL);
             CHECK(msg->findMessage("reply", &info->mNotify));
 
-            info->mFormat =
-                (portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat;
+            if (portIndex == kPortIndexInput && mCrypto != NULL) {
+                info->mSecureData = buffer;
+                info->mData = new SharedMemoryBuffer(
+                        buffer->format(), info->mSharedEncryptedBuffer);
+            } else {
+                info->mData = buffer;
+            }
             mAvailPortBuffers[portIndex].push_back(i);
 
             return i;
@@ -2556,13 +2538,14 @@
     if (flags & BUFFER_FLAG_CODECCONFIG) {
         buffer->meta()->setInt32("csd", true);
     }
-    // TODO: release buffer reference.
 
     // synchronization boundary for getBufferAndFormat
     {
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
     }
+    info->mData.clear();
+    info->mSecureData.clear();
     reply->setObject("buffer", buffer);
     reply->post();
 
@@ -2634,7 +2617,7 @@
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
                     info->mData->data(), info->mData->size(),
-                    mediaTimeUs, renderTimeNs, NULL, info->mFormat);
+                    mediaTimeUs, renderTimeNs, NULL, info->mData->format());
 
             // if we are running, notify rendered frames
             if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
@@ -2649,7 +2632,7 @@
     }
 
     info->mNotify->setObject("buffer", info->mData);
-    // TODO: release buffer reference.
+    info->mData.clear();
     info->mNotify->post();
     info->mNotify.clear();
 
@@ -2675,13 +2658,13 @@
         info->mOwnedByClient = true;
 
         // set image-data
-        if (info->mFormat != NULL) {
+        if (info->mData->format() != NULL) {
             sp<ABuffer> imageData;
-            if (info->mFormat->findBuffer("image-data", &imageData)) {
+            if (info->mData->format()->findBuffer("image-data", &imageData)) {
                 info->mData->meta()->setBuffer("image-data", imageData);
             }
             int32_t left, top, right, bottom;
-            if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) {
+            if (info->mData->format()->findRect("crop", &left, &top, &right, &bottom)) {
                 info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
             }
         }
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index f26c840..30e3643 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -360,25 +360,6 @@
     ALOGV("Sent kWhatEOS.");
 }
 
-void MediaFilter::sendFormatChange() {
-    sp<AMessage> notify = mNotify->dup();
-
-    notify->setInt32("what", kWhatOutputFormatChanged);
-
-    AString mime;
-    CHECK(mOutputFormat->findString("mime", &mime));
-    notify->setString("mime", mime.c_str());
-
-    notify->setInt32("stride", mStride);
-    notify->setInt32("slice-height", mSliceHeight);
-    notify->setInt32("color-format", mColorFormatOut);
-    notify->setRect("crop", 0, 0, mStride - 1, mSliceHeight - 1);
-    notify->setInt32("width", mWidth);
-    notify->setInt32("height", mHeight);
-
-    notify->post();
-}
-
 void MediaFilter::requestFillEmptyInput() {
     if (mPortEOS[kPortIndexInput]) {
         return;
@@ -553,8 +534,6 @@
     notify->post();
     mState = CONFIGURED;
     ALOGV("Handled kWhatConfigureComponent.");
-
-    sendFormatChange();
 }
 
 void MediaFilter::onStart() {
diff --git a/media/libstagefright/include/SecureBuffer.h b/media/libstagefright/include/SecureBuffer.h
index 4bb1418..ac7399a 100644
--- a/media/libstagefright/include/SecureBuffer.h
+++ b/media/libstagefright/include/SecureBuffer.h
@@ -34,7 +34,7 @@
  */
 class SecureBuffer : public MediaCodecBuffer {
 public:
-    SecureBuffer(const sp<AMessage> &format, void *ptr, size_t size);
+    SecureBuffer(const sp<AMessage> &format, const void *ptr, size_t size);
     SecureBuffer(const sp<AMessage> &format, const sp<NativeHandle> &handle, size_t size);
 
     virtual ~SecureBuffer() = default;
@@ -42,6 +42,8 @@
     void *getDestinationPointer();
     ICrypto::DestinationType getDestinationType();
 
+    virtual sp<MediaCodecBuffer> clone(const sp<AMessage> &format) override;
+
 private:
     SecureBuffer() = delete;
 
diff --git a/media/libstagefright/include/SharedMemoryBuffer.h b/media/libstagefright/include/SharedMemoryBuffer.h
index 1d7f7a6..c52e5c5 100644
--- a/media/libstagefright/include/SharedMemoryBuffer.h
+++ b/media/libstagefright/include/SharedMemoryBuffer.h
@@ -34,6 +34,8 @@
 
     virtual ~SharedMemoryBuffer() = default;
 
+    virtual sp<MediaCodecBuffer> clone(const sp<AMessage> &format) override;
+
 private:
     SharedMemoryBuffer() = delete;