MediaBuffer: ABuffer will release MediaBuffer when it's destructed.

Bug: 17454455
Change-Id: Ia423bcc2e1fa39137f114eac44912ed15357bb99
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 3d79596..c8a50e8 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_BUFFER_H_
 
+#include <media/stagefright/foundation/MediaBufferBase.h>
+
 #include <pthread.h>
 
 #include <utils/Errors.h>
@@ -43,7 +45,7 @@
     MediaBufferObserver &operator=(const MediaBufferObserver &);
 };
 
-class MediaBuffer {
+class MediaBuffer : public MediaBufferBase {
 public:
     // The underlying data remains the responsibility of the caller!
     MediaBuffer(void *data, size_t size);
@@ -56,10 +58,10 @@
 
     // Decrements the reference count and returns the buffer to its
     // associated MediaBufferGroup if the reference count drops to 0.
-    void release();
+    virtual void release();
 
     // Increments the reference count.
-    void add_ref();
+    virtual void add_ref();
 
     void *data() const;
     size_t size() const;
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
index 602f7ab..6294ee7 100644
--- a/include/media/stagefright/foundation/ABuffer.h
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -27,6 +27,7 @@
 namespace android {
 
 struct AMessage;
+class MediaBufferBase;
 
 struct ABuffer : public RefBase {
     ABuffer(size_t capacity);
@@ -50,6 +51,9 @@
 
     sp<AMessage> meta();
 
+    MediaBufferBase *getMediaBufferBase();
+    void setMediaBufferBase(MediaBufferBase *mediaBuffer);
+
 protected:
     virtual ~ABuffer();
 
@@ -57,6 +61,8 @@
     sp<AMessage> mFarewell;
     sp<AMessage> mMeta;
 
+    MediaBufferBase *mMediaBufferBase;
+
     void *mData;
     size_t mCapacity;
     size_t mRangeOffset;
diff --git a/include/media/stagefright/foundation/MediaBufferBase.h b/include/media/stagefright/foundation/MediaBufferBase.h
new file mode 100644
index 0000000..99418fb
--- /dev/null
+++ b/include/media/stagefright/foundation/MediaBufferBase.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014 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_BUFFER_BASE_H_
+
+#define MEDIA_BUFFER_BASE_H_
+
+namespace android {
+
+class MediaBufferBase {
+public:
+    MediaBufferBase() {}
+
+    virtual void release() = 0;
+    virtual void add_ref() = 0;
+
+protected:
+    virtual ~MediaBufferBase() {}
+
+private:
+    MediaBufferBase(const MediaBufferBase &);
+    MediaBufferBase &operator=(const MediaBufferBase &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_BUFFER_BASE_H_
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 511871d..a0870fd 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1097,8 +1097,8 @@
     if (mIsWidevine && !audio) {
         // data is already provided in the buffer
         ab = new ABuffer(NULL, mb->range_length());
-        ab->meta()->setPointer("mediaBuffer", mb);
         mb->add_ref();
+        ab->setMediaBufferBase(mb);
     } else {
         ab = new ABuffer(outLength);
         memcpy(ab->data(),
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 87f85e7..601cd40 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -283,14 +283,9 @@
 
     // handle widevine classic source - that fills an arbitrary input buffer
     MediaBuffer *mediaBuffer = NULL;
-    if (hasBuffer && buffer->meta()->findPointer(
-            "mediaBuffer", (void **)&mediaBuffer)) {
-        if (mediaBuffer == NULL) {
-            // received no actual buffer
-            ALOGW("[%s] received null MediaBuffer %s",
-                    mComponentName.c_str(), msg->debugString().c_str());
-            buffer = NULL;
-        } else {
+    if (hasBuffer) {
+        mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
+        if (mediaBuffer != NULL) {
             // likely filled another buffer than we requested: adjust buffer index
             size_t ix;
             for (ix = 0; ix < mInputBuffers.size(); ix++) {
@@ -598,16 +593,6 @@
         {
             if (!isStaleReply(msg)) {
                 onInputBufferFilled(msg);
-            } else {
-                /* release any MediaBuffer passed in the stale buffer */
-                sp<ABuffer> buffer;
-                MediaBuffer *mediaBuffer = NULL;
-                if (msg->findBuffer("buffer", &buffer) &&
-                    buffer->meta()->findPointer(
-                            "mediaBuffer", (void **)&mediaBuffer) &&
-                    mediaBuffer != NULL) {
-                    mediaBuffer->release();
-                }
             }
 
             break;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9b03b71..3c04859 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -3782,23 +3782,12 @@
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT);
     info->mStatus = BufferInfo::OWNED_BY_US;
 
-    const sp<AMessage> &bufferMeta = info->mData->meta();
-    void *mediaBuffer;
-    if (bufferMeta->findPointer("mediaBuffer", &mediaBuffer)
-            && mediaBuffer != NULL) {
-        // We're in "store-metadata-in-buffers" mode, the underlying
-        // OMX component had access to data that's implicitly refcounted
-        // by this "mediaBuffer" object. Now that the OMX component has
-        // told us that it's done with the input buffer, we can decrement
-        // the mediaBuffer's reference count.
-
-        ALOGV("releasing mbuf %p", mediaBuffer);
-
-        ((MediaBuffer *)mediaBuffer)->release();
-        mediaBuffer = NULL;
-
-        bufferMeta->setPointer("mediaBuffer", NULL);
-    }
+    // We're in "store-metadata-in-buffers" mode, the underlying
+    // OMX component had access to data that's implicitly refcounted
+    // by this "MediaBuffer" object. Now that the OMX component has
+    // told us that it's done with the input buffer, we can decrement
+    // the mediaBuffer's reference count.
+    info->mData->setMediaBufferBase(NULL);
 
     PortMode mode = getPortMode(kPortIndexInput);
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 1a80dcc..27cd231 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -37,19 +37,6 @@
 
 namespace android {
 
-static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) {
-    void *mbuf;
-    if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
-            && mbuf != NULL) {
-        ALOGV("releasing mbuf %p", mbuf);
-
-        accessUnit->meta()->setPointer("mediaBuffer", NULL);
-
-        static_cast<MediaBuffer *>(mbuf)->release();
-        mbuf = NULL;
-    }
-}
-
 struct MediaCodecSource::Puller : public AHandler {
     Puller(const sp<MediaSource> &source);
 
@@ -477,7 +464,7 @@
 
     for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) {
         sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i);
-        ReleaseMediaBufferReference(accessUnit);
+        accessUnit->setMediaBufferBase(NULL);
     }
 
     mEncoderInputBuffers.clear();
@@ -608,8 +595,8 @@
             if (mIsVideo) {
                 // video encoder will release MediaBuffer when done
                 // with underlying data.
-                mEncoderInputBuffers.itemAt(bufferIndex)->meta()
-                        ->setPointer("mediaBuffer", mbuf);
+                mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase(
+                        mbuf);
             } else {
                 mbuf->release();
             }
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index c93c7e8..b214870 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -19,11 +19,13 @@
 #include "ADebug.h"
 #include "ALooper.h"
 #include "AMessage.h"
+#include "MediaBufferBase.h"
 
 namespace android {
 
 ABuffer::ABuffer(size_t capacity)
-    : mData(malloc(capacity)),
+    : mMediaBufferBase(NULL),
+      mData(malloc(capacity)),
       mCapacity(capacity),
       mRangeOffset(0),
       mRangeLength(capacity),
@@ -32,7 +34,8 @@
 }
 
 ABuffer::ABuffer(void *data, size_t capacity)
-    : mData(data),
+    : mMediaBufferBase(NULL),
+      mData(data),
       mCapacity(capacity),
       mRangeOffset(0),
       mRangeLength(capacity),
@@ -59,6 +62,8 @@
     if (mFarewell != NULL) {
         mFarewell->post();
     }
+
+    setMediaBufferBase(NULL);
 }
 
 void ABuffer::setRange(size_t offset, size_t size) {
@@ -80,5 +85,19 @@
     return mMeta;
 }
 
+MediaBufferBase *ABuffer::getMediaBufferBase() {
+    if (mMediaBufferBase != NULL) {
+        mMediaBufferBase->add_ref();
+    }
+    return mMediaBufferBase;
+}
+
+void ABuffer::setMediaBufferBase(MediaBufferBase *mediaBuffer) {
+    if (mMediaBufferBase != NULL) {
+        mMediaBufferBase->release();
+    }
+    mMediaBufferBase = mediaBuffer;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index c74c3e7..a03f6f9 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -254,11 +254,6 @@
             int32_t oldDiscontinuityType;
             if (!oldBuffer->meta()->findInt32(
                         "discontinuity", &oldDiscontinuityType)) {
-                MediaBuffer *mbuf = NULL;
-                oldBuffer->meta()->findPointer("mediaBuffer", (void**)&mbuf);
-                if (mbuf != NULL) {
-                    mbuf->release();
-                }
                 it = mBuffers.erase(it);
                 continue;
             }
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 753b3ec..2834a66 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -74,19 +74,6 @@
     }
 }
 
-static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) {
-    void *mbuf;
-    if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
-            && mbuf != NULL) {
-        ALOGV("releasing mbuf %p", mbuf);
-
-        accessUnit->meta()->setPointer("mediaBuffer", NULL);
-
-        static_cast<MediaBuffer *>(mbuf)->release();
-        mbuf = NULL;
-    }
-}
-
 void Converter::releaseEncoder() {
     if (mEncoder == NULL) {
         return;
@@ -95,18 +82,7 @@
     mEncoder->release();
     mEncoder.clear();
 
-    while (!mInputBufferQueue.empty()) {
-        sp<ABuffer> accessUnit = *mInputBufferQueue.begin();
-        mInputBufferQueue.erase(mInputBufferQueue.begin());
-
-        ReleaseMediaBufferReference(accessUnit);
-    }
-
-    for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) {
-        sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i);
-        ReleaseMediaBufferReference(accessUnit);
-    }
-
+    mInputBufferQueue.clear();
     mEncoderInputBuffers.clear();
     mEncoderOutputBuffers.clear();
 }
@@ -328,7 +304,7 @@
                     sp<ABuffer> accessUnit;
                     CHECK(msg->findBuffer("accessUnit", &accessUnit));
 
-                    ReleaseMediaBufferReference(accessUnit);
+                    accessUnit->setMediaBufferBase(NULL);
                 }
                 break;
             }
@@ -351,15 +327,16 @@
                         ALOGI("dropping frame.");
                     }
 
-                    ReleaseMediaBufferReference(accessUnit);
+                    accessUnit->setMediaBufferBase(NULL);
                     break;
                 }
 
 #if 0
-                void *mbuf;
-                if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
-                        && mbuf != NULL) {
+                MediaBuffer *mbuf =
+                    (MediaBuffer *)(accessUnit->getMediaBufferBase());
+                if (mbuf != NULL) {
                     ALOGI("queueing mbuf %p", mbuf);
+                    mbuf->release();
                 }
 #endif
 
@@ -647,13 +624,13 @@
                    buffer->data(),
                    buffer->size());
 
-            void *mediaBuffer;
-            if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer)
-                    && mediaBuffer != NULL) {
-                mEncoderInputBuffers.itemAt(bufferIndex)->meta()
-                    ->setPointer("mediaBuffer", mediaBuffer);
+            MediaBuffer *mediaBuffer =
+                (MediaBuffer *)(buffer->getMediaBufferBase());
+            if (mediaBuffer != NULL) {
+                mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase(
+                        mediaBuffer);
 
-                buffer->meta()->setPointer("mediaBuffer", NULL);
+                buffer->setMediaBufferBase(NULL);
             }
         } else {
             flags = MediaCodec::BUFFER_FLAG_EOS;
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
index 7e8891d..86b918f 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp
@@ -179,7 +179,7 @@
                 } else {
                     // video encoder will release MediaBuffer when done
                     // with underlying data.
-                    accessUnit->meta()->setPointer("mediaBuffer", mbuf);
+                    accessUnit->setMediaBufferBase(mbuf);
                 }
 
                 sp<AMessage> notify = mNotify->dup();