Bug 1128410 - Lazily allocate the MP4 parser buffer. r=kentuckyfriedtakahe, a=sledru
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 02 Feb 2015 21:36:48 +1100
changeset 243651 cd4ce87ac395
parent 243650 361d53acbf3a
child 243652 08a02585bc60
push id4421
push userryanvm@gmail.com
push date2015-02-02 19:52 +0000
treeherdermozilla-beta@08a02585bc60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe, sledru
bugs1128410
milestone36.0
Bug 1128410 - Lazily allocate the MP4 parser buffer. r=kentuckyfriedtakahe, a=sledru This buffer is unsused for fragmented MP4. So we don't need to unecessarily allocate it and block a chunk of 3MB data. Also, this removes the restriction of playing YouTube video > 1080p
media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -98,16 +98,17 @@ private:
 
     bool mStarted;
 
     MediaBuffer *mBuffer;
 
     bool mWantsNALFragments;
 
     uint8_t *mSrcBuffer;
+    int32_t mSrcBufferSize;
 
     size_t parseNALSize(const uint8_t *data) const;
     status_t parseChunk(off64_t *offset);
     status_t parseTrackFragmentData(off64_t offset, off64_t size);
     status_t parseTrackFragmentHeader(off64_t offset, off64_t size);
     status_t parseTrackFragmentRun(off64_t offset, off64_t size);
     status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size);
     status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
@@ -158,16 +159,18 @@ private:
         off64_t mStart;
         off64_t mSize;
     };
     Vector<AuxRange> mDeferredSaiz;
     Vector<AuxRange> mDeferredSaio;
 
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
+
+    bool ensureSrcBufferAllocated();
 };
 
 // This custom data source wraps an existing one and satisfies requests
 // falling entirely within a cached range from the cache while forwarding
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
 // possibly wrapping multiple times to cover all tracks, i.e.
 // Each MPEG4DataSource caches the sampletable metadata for a single track.
@@ -718,16 +721,23 @@ static void convertTimeToDate(int64_t ti
     }
 
     char tmp[32];
     strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S.000Z", gmtime(&time_1970));
 
     s->setTo(tmp);
 }
 
+static bool ValidInputSize(int32_t size) {
+  // Reject compressed samples larger than an uncompressed UHD
+  // frame. This is a reasonable cut-off for a lossy codec,
+  // combined with the current Firefox limit to 5k video.
+  return (size > 0 && size <= 4 * (1920 * 1080) * 3 / 2);
+}
+
 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
     ALOGV("entering parseChunk %lld/%d", *offset, depth);
     uint32_t hdr[2];
     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
         return ERROR_IO;
     }
     uint64_t chunk_size = ntohl(hdr[0]);
     uint32_t chunk_type = ntohl(hdr[1]);
@@ -2497,16 +2507,17 @@ MPEG4Source::MPEG4Source(
       mCurrentSampleInfoOffsetsAllocSize(0),
       mCurrentSampleInfoOffsets(NULL),
       mIsAVC(false),
       mNALLengthSize(0),
       mStarted(false),
       mBuffer(NULL),
       mWantsNALFragments(false),
       mSrcBuffer(NULL),
+      mSrcBufferSize(0),
       mTrackExtends(trackExtends) {
 
     mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
     mDefaultIVSize = 0;
     mFormat->findInt32(kKeyCryptoDefaultIVSize, &mDefaultIVSize);
     uint32_t keytype;
     const void *key;
     size_t keysize;
@@ -2543,44 +2554,30 @@ MPEG4Source::MPEG4Source(
 MPEG4Source::~MPEG4Source() {
     if (mStarted) {
         stop();
     }
     free(mCurrentSampleInfoSizes);
     free(mCurrentSampleInfoOffsets);
 }
 
-static bool ValidInputSize(int32_t size) {
-  // Reject compressed samples larger than an uncompressed UHD
-  // frame. This is a reasonable cut-off for a lossy codec,
-  // combined with the current Firefox limit to 5k video.
-  return (size > 0 && size <= 4 * (1920 * 1080) * 3 / 2);
-}
-
 status_t MPEG4Source::start(MetaData *params) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(!mStarted);
 
     int32_t val;
     if (params && params->findInt32(kKeyWantsNALFragments, &val)
         && val != 0) {
         mWantsNALFragments = true;
     } else {
         mWantsNALFragments = false;
     }
 
-    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;
-    }
-
-    mSrcBuffer = new uint8_t[max_size];
+    CHECK(mFormat->findInt32(kKeyMaxInputSize, &mSrcBufferSize));
 
     mStarted = true;
 
     return OK;
 }
 
 status_t MPEG4Source::stop() {
     Mutex::Autolock autoLock(mLock);
@@ -3264,16 +3261,27 @@ status_t MPEG4Source::lookForMoof() {
         }
         if (chunk_type == FOURCC('m', 'd', 'a', 't')) {
             return OK;
         }
         offset += chunk_size;
     }
 }
 
+bool MPEG4Source::ensureSrcBufferAllocated() {
+    if (mSrcBuffer) {
+        return true;
+    }
+    if (!ValidInputSize(mSrcBufferSize)) {
+      ALOGE("Invalid max input size %d", mSrcBufferSize);
+      return false;
+    }
+    mSrcBuffer = new uint8_t[mSrcBufferSize];
+    return true;
+}
 
 status_t MPEG4Source::read(
         MediaBuffer **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
 
     if (!mLookedForMoof) {
@@ -3509,16 +3517,19 @@ status_t MPEG4Source::read(
         // the NAL length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated()) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             return ERROR_IO;
@@ -3861,16 +3872,19 @@ status_t MPEG4Source::fragmentedRead(
         // the NAL unit's length, stored in four bytes.
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
         if (usesDRM) {
             num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
         } else {
+            if (!ensureSrcBufferAllocated()) {
+                return ERROR_MALFORMED;
+            }
             num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
         }
 
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
             ALOGV("i/o error");