Bug 1128939: Part3. Allocate media buffer internal memory dynamically. r=k17e a=abillings
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 12 Feb 2015 18:52:12 +1100
changeset 249737 089b5e6cd72e07ff8d220a9ef02bf5a03a3438e7
parent 249736 39c0f3dac6040520290e15d7cebcc81d62e49506
child 249738 895903e491e00d4ef3dc0f2bb56a0eb853f827f9
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersk17e, abillings
bugs1128939
milestone37.0a2
Bug 1128939: Part3. Allocate media buffer internal memory dynamically. r=k17e a=abillings
media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
--- a/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
+++ b/media/libstagefright/frameworks/av/include/media/stagefright/MediaBuffer.h
@@ -17,16 +17,17 @@
 #ifndef MEDIA_BUFFER_H_
 
 #define MEDIA_BUFFER_H_
 
 #include <pthread.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include "nsTArray.h"
 
 namespace stagefright {
 
 struct ABuffer;
 class GraphicBuffer;
 class MediaBuffer;
 class MediaBufferObserver;
 class MetaData;
@@ -80,16 +81,18 @@ public:
 
     // Returns a clone of this MediaBuffer increasing its reference count.
     // The clone references the same data but has its own range and
     // MetaData.
     MediaBuffer *clone();
 
     int refcount() const;
 
+    bool ensuresize(size_t length);
+
 protected:
     virtual ~MediaBuffer();
 
 private:
     friend class MediaBufferGroup;
     friend class OMXDecoder;
 
     // For use by OMXDecoder, reference count must be 1, drop reference
@@ -111,13 +114,15 @@ private:
 
     MediaBuffer *mOriginal;
 
     void setNextBuffer(MediaBuffer *buffer);
     MediaBuffer *nextBuffer();
 
     MediaBuffer(const MediaBuffer &);
     MediaBuffer &operator=(const MediaBuffer &);
+
+    FallibleTArray<uint8_t> mBufferBackend;
 };
 
 }  // namespace stagefright
 
 #endif  // MEDIA_BUFFER_H_
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -18,16 +18,17 @@
 #undef LOG_TAG
 #define LOG_TAG "MPEG4Extractor"
 #include <utils/Log.h>
 
 #include "include/MPEG4Extractor.h"
 #include "include/SampleTable.h"
 #include "include/ESDS.h"
 
+#include <algorithm>
 #include <ctype.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -3277,24 +3278,24 @@ bool MPEG4Source::ensureSrcBufferAllocat
               aSize, mSrcBackend.Length());
         return false;
     }
     mSrcBuffer = mSrcBackend.Elements();
     return true;
 }
 
 bool MPEG4Source::ensureMediaBufferAllocated(int32_t aSize) {
-  if (mBuffer->size() < aSize) {
-      ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
-            aSize, mBuffer->size());
-      mBuffer->release();
-      mBuffer = NULL;
-      return false;
+  if (mBuffer->ensuresize(aSize)) {
+      return true;
   }
-  return true;
+  ALOGE("Error insufficient memory, requested %u bytes (had:%u)",
+        aSize, mBuffer->size());
+  mBuffer->release();
+  mBuffer = NULL;
+  return false;
 }
 
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
@@ -3411,22 +3412,17 @@ status_t MPEG4Source::read(
                     &isSyncSample, &dts);
 
         if (err != OK) {
             return err;
         }
 
         int32_t max_size;
         CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
-        if (!ValidInputSize(max_size)) {
-          ALOGE("Invalid max input size %d", max_size);
-          return ERROR_MALFORMED;
-        }
-        mBuffer = new MediaBuffer(max_size);
-        assert(mBuffer);
+        mBuffer = new MediaBuffer(std::min(max_size, 1024 * 1024));
     }
 
     if (!mIsAVC || mWantsNALFragments) {
         if (newBuffer) {
             if (!ensureMediaBufferAllocated(size)) {
                 return ERROR_MALFORMED;
             }
             ssize_t num_bytes_read =
@@ -3562,17 +3558,16 @@ status_t MPEG4Source::read(
             return ERROR_IO;
         }
 
         if (usesDRM) {
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
 
         } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
             size_t srcOffset = 0;
             size_t dstOffset = 0;
 
             while (srcOffset < size) {
                 bool isMalFormed = (srcOffset + mNALLengthSize > size);
                 size_t nalLength = 0;
                 if (!isMalFormed) {
                     nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
@@ -3589,16 +3584,17 @@ status_t MPEG4Source::read(
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
                     return ERROR_MALFORMED;
                 }
+                uint8_t *dstData = (uint8_t *)mBuffer->data();
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
@@ -3788,22 +3784,17 @@ status_t MPEG4Source::fragmentedRead(
         dts = mCurrentTime;
         cts = mCurrentTime + smpl->ctsOffset;
         duration = smpl->duration;
         mCurrentTime += smpl->duration;
         isSyncSample = smpl->isSync();
 
         int32_t max_size;
         CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
-        if (!ValidInputSize(max_size)) {
-          ALOGE("Invalid max input size %d", max_size);
-          return ERROR_MALFORMED;
-        }
-        mBuffer = new MediaBuffer(max_size);
-        assert(mBuffer);
+        mBuffer = new MediaBuffer(std::min(max_size, 1024 * 1024));
     }
 
     const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
     const sp<MetaData> bufmeta = mBuffer->meta_data();
     bufmeta->clear();
     if (smpl->encryptedsizes.size()) {
         // store clear/encrypted lengths in metadata
         bufmeta->setData(kKeyPlainSizes, 0,
@@ -3933,17 +3924,16 @@ status_t MPEG4Source::fragmentedRead(
             return ERROR_IO;
         }
 
         if (usesDRM) {
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
 
         } else {
-            uint8_t *dstData = (uint8_t *)mBuffer->data();
             size_t srcOffset = 0;
             size_t dstOffset = 0;
 
             while (srcOffset < size) {
                 bool isMalFormed = (srcOffset + mNALLengthSize > size);
                 size_t nalLength = 0;
                 if (!isMalFormed) {
                     nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
@@ -3960,16 +3950,17 @@ status_t MPEG4Source::fragmentedRead(
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 if (!ensureMediaBufferAllocated(dstOffset + 4 + nalLength)) {
                     return ERROR_MALFORMED;
                 }
+                uint8_t *dstData = (uint8_t *)mBuffer->data();
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 24);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 16);
                 dstData[dstOffset++] = (uint8_t) (nalLength >> 8);
                 dstData[dstOffset++] = (uint8_t) nalLength;
                 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                 srcOffset += nalLength;
                 dstOffset += nalLength;
             }
--- a/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MediaBuffer.cpp
@@ -43,23 +43,24 @@ MediaBuffer::MediaBuffer(void *data, siz
       mMetaData(new MetaData),
       mOriginal(NULL) {
 }
 
 MediaBuffer::MediaBuffer(size_t size)
     : mObserver(NULL),
       mNextBuffer(NULL),
       mRefCount(0),
-      mData(malloc(size)),
+      mData(NULL),
       mSize(size),
       mRangeOffset(0),
       mRangeLength(size),
       mOwnsData(true),
       mMetaData(new MetaData),
       mOriginal(NULL) {
+    ensuresize(size);
 }
 
 MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
     : mObserver(NULL),
       mNextBuffer(NULL),
       mRefCount(0),
       mData(NULL),
       mSize(1),
@@ -154,21 +155,16 @@ sp<MetaData> MediaBuffer::meta_data() {
 void MediaBuffer::reset() {
     mMetaData->clear();
     set_range(0, mSize);
 }
 
 MediaBuffer::~MediaBuffer() {
     CHECK(mObserver == NULL);
 
-    if (mOwnsData && mData != NULL) {
-        free(mData);
-        mData = NULL;
-    }
-
     if (mOriginal != NULL) {
         mOriginal->release();
         mOriginal = NULL;
     }
 }
 
 void MediaBuffer::setObserver(MediaBufferObserver *observer) {
     CHECK(observer == NULL || mObserver == NULL);
@@ -195,9 +191,25 @@ MediaBuffer *MediaBuffer::clone() {
     buffer->mMetaData = new MetaData(*mMetaData.get());
 
     add_ref();
     buffer->mOriginal = this;
 
     return buffer;
 }
 
+bool MediaBuffer::ensuresize(size_t length) {
+    if (mBufferBackend.Length() >= length) {
+        return true;
+    }
+    // Can't reallocate data we don't owned or shared with another.
+    if (!mOwnsData || refcount()) {
+        return false;
+    }
+    if (!mBufferBackend.SetLength(length)) {
+        return false;
+    }
+    mData = mBufferBackend.Elements();
+    mSize = length;
+    return true;
+}
+
 }  // namespace stagefright