Bug 1110534 - Simplify MP4 extradata handling. r=kentuckyfriedtakahe, a=sledru
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Dec 2014 14:36:09 +1100
changeset 242652 f08048b1b1692440fd56c46e94aaa669f56d928b
parent 242651 61c518a326a459d06b0ffe71513cff345304ca42
child 242653 c59838b615a4b6ce21a9e2691b18e664b1e12469
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe, sledru
bugs1110534
milestone36.0a2
Bug 1110534 - Simplify MP4 extradata handling. r=kentuckyfriedtakahe, a=sledru
dom/media/fmp4/android/AndroidDecoderModule.cpp
dom/media/fmp4/apple/AppleATDecoder.cpp
dom/media/fmp4/apple/AppleATDecoder.h
dom/media/fmp4/apple/AppleVDADecoder.cpp
dom/media/fmp4/apple/AppleVTDecoder.cpp
dom/media/fmp4/eme/EMEAudioDecoder.cpp
dom/media/fmp4/eme/EMEH264Decoder.cpp
dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
dom/media/fmp4/ffmpeg/FFmpegDataDecoder.h
dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
media/libstagefright/binding/AnnexB.cpp
media/libstagefright/binding/DecoderData.cpp
media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
media/libstagefright/binding/mp4_demuxer.cpp
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -257,18 +257,18 @@ AndroidDecoderModule::CreateAudioDecoder
   if(format == nullptr)
     return nullptr;
 
   JNIEnv* env = GetJNIForThread();
 
   if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
     uint8_t* csd0 = new uint8_t[2];
 
-    csd0[0] = aConfig.audio_specific_config[0];
-    csd0[1] = aConfig.audio_specific_config[1];
+    csd0[0] = (*aConfig.audio_specific_config)[0];
+    csd0[1] = (*aConfig.audio_specific_config)[1];
 
     jobject buffer = env->NewDirectByteBuffer(csd0, 2);
     format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
 
     env->DeleteLocalRef(buffer);
   }
 
   nsRefPtr<MediaDataDecoder> decoder =
--- a/dom/media/fmp4/apple/AppleATDecoder.cpp
+++ b/dom/media/fmp4/apple/AppleATDecoder.cpp
@@ -288,27 +288,27 @@ AppleATDecoder::DecodeSample(mp4_demuxer
                                             channels,
                                             rate);
   mCallback->Output(audio);
   return NS_OK;
 }
 
 nsresult
 AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
-                                         const mozilla::Vector<uint8_t>& aExtraData)
+                                         const nsTArray<uint8_t>& aExtraData)
 {
   // Request the properties from CoreAudio using the codec magic cookie
   AudioFormatInfo formatInfo;
   PodZero(&formatInfo.mASBD);
   formatInfo.mASBD.mFormatID = mFormatID;
   if (mFormatID == kAudioFormatMPEG4AAC) {
     formatInfo.mASBD.mFormatFlags = mConfig.extended_profile;
   }
-  formatInfo.mMagicCookieSize = aExtraData.length();
-  formatInfo.mMagicCookie = aExtraData.begin();
+  formatInfo.mMagicCookieSize = aExtraData.Length();
+  formatInfo.mMagicCookie = aExtraData.Elements();
 
   UInt32 formatListSize;
   // Attempt to retrieve the default format using
   // kAudioFormatProperty_FormatInfo method.
   // This method only retrieves the FramesPerPacket information required
   // by the decoder, which depends on the codec type and profile.
   aDesc.mFormatID = mFormatID;
   aDesc.mChannelsPerFrame = mConfig.channel_count;
@@ -369,31 +369,31 @@ nsresult
 AppleATDecoder::SetupDecoder(mp4_demuxer::MP4Sample* aSample)
 {
   if (mFormatID == kAudioFormatMPEG4AAC &&
       mConfig.extended_profile == 2) {
     // Check for implicit SBR signalling if stream is AAC-LC
     // This will provide us with an updated magic cookie for use with
     // GetInputAudioDescription.
     if (NS_SUCCEEDED(GetImplicitAACMagicCookie(aSample)) &&
-        !mMagicCookie.length()) {
+        !mMagicCookie.Length()) {
       // nothing found yet, will try again later
       return NS_ERROR_NOT_INITIALIZED;
     }
     // An error occurred, fallback to using default stream description
   }
 
   LOG("Initializing Apple AudioToolbox decoder");
 
   AudioStreamBasicDescription inputFormat;
   PodZero(&inputFormat);
   nsresult rv =
     GetInputAudioDescription(inputFormat,
-                             mMagicCookie.length() ?
-                                 mMagicCookie : mConfig.extra_data);
+                             mMagicCookie.Length() ?
+                                 mMagicCookie : *mConfig.extra_data);
   if (NS_FAILED(rv)) {
     return rv;
   }
   // Fill in the output format manually.
   PodZero(&mOutputFormat);
   mOutputFormat.mFormatID = kAudioFormatLinearPCM;
   mOutputFormat.mSampleRate = inputFormat.mSampleRate;
   mOutputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
@@ -444,17 +444,17 @@ static void
     rv = AudioFileStreamGetProperty(aStream, aProperty,
                                     &size, data);
     if (rv) {
       LOG("Couldn't get property '%s' (%s)",
           FourCC2Str(aProperty), FourCC2Str(rv));
       decoder->mFileStreamError = true;
       return;
     }
-    decoder->mMagicCookie.append(data.get(), size);
+    decoder->mMagicCookie.AppendElements(data.get(), size);
   }
 }
 
 static void
 _SampleCallback(void* aSBR,
                 UInt32 aNumBytes,
                 UInt32 aNumPackets,
                 const void* aData,
@@ -490,17 +490,17 @@ AppleATDecoder::GetImplicitAACMagicCooki
   OSStatus status = AudioFileStreamParseBytes(mStream,
                                               adtssample.size,
                                               adtssample.data,
                                               0 /* discontinuity */);
   if (status) {
     NS_WARNING("Couldn't parse sample");
   }
 
-  if (status || mFileStreamError || mMagicCookie.length()) {
+  if (status || mFileStreamError || mMagicCookie.Length()) {
     // We have decoded a magic cookie or an error occurred as such
     // we won't need the stream any longer.
     AudioFileStreamClose(mStream);
     mStream = nullptr;
   }
 
   return (mFileStreamError || status) ? NS_ERROR_FAILURE : NS_OK;
 }
--- a/dom/media/fmp4/apple/AppleATDecoder.h
+++ b/dom/media/fmp4/apple/AppleATDecoder.h
@@ -31,34 +31,34 @@ public:
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   // Callbacks also need access to the config.
   const mp4_demuxer::AudioDecoderConfig& mConfig;
 
   // Use to extract magic cookie for HE-AAC detection.
-  mozilla::Vector<uint8_t> mMagicCookie;
+  nsTArray<uint8_t> mMagicCookie;
   // Will be set to true should an error occurred while attempting to retrieve
   // the magic cookie property.
   bool mFileStreamError;
 
 private:
   RefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
   AudioConverterRef mConverter;
   AudioStreamBasicDescription mOutputFormat;
   UInt32 mFormatID;
   AudioFileStreamID mStream;
   nsTArray<nsAutoPtr<mp4_demuxer::MP4Sample>> mQueuedSamples;
 
   void SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample);
   nsresult DecodeSample(mp4_demuxer::MP4Sample* aSample);
   nsresult GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
-                                    const mozilla::Vector<uint8_t>& aExtraData);
+                                    const nsTArray<uint8_t>& aExtraData);
   // Setup AudioConverter once all information required has been gathered.
   // Will return NS_ERROR_NOT_INITIALIZED if more data is required.
   nsresult SetupDecoder(mp4_demuxer::MP4Sample* aSample);
   nsresult GetImplicitAACMagicCookie(const mp4_demuxer::MP4Sample* aSample);
 };
 
 } // namespace mozilla
 
--- a/dom/media/fmp4/apple/AppleVDADecoder.cpp
+++ b/dom/media/fmp4/apple/AppleVDADecoder.cpp
@@ -399,18 +399,18 @@ AppleVDADecoder::InitializeSession()
   }
 
   return NS_OK;
 }
 
 CFDictionaryRef
 AppleVDADecoder::CreateDecoderSpecification()
 {
-  const uint8_t* extradata = mConfig.extra_data.begin();
-  int extrasize = mConfig.extra_data.length();
+  const uint8_t* extradata = mConfig.extra_data->Elements();
+  int extrasize = mConfig.extra_data->Length();
 
   OSType format = 'avc1';
   AutoCFRelease<CFNumberRef> avc_width  =
     CFNumberCreate(kCFAllocatorDefault,
                    kCFNumberSInt32Type,
                    &mConfig.image_width);
   AutoCFRelease<CFNumberRef> avc_height =
     CFNumberCreate(kCFAllocatorDefault,
--- a/dom/media/fmp4/apple/AppleVTDecoder.cpp
+++ b/dom/media/fmp4/apple/AppleVTDecoder.cpp
@@ -255,25 +255,25 @@ AppleVTDecoder::SubmitFrame(mp4_demuxer:
 
 nsresult
 AppleVTDecoder::InitializeSession()
 {
   OSStatus rv;
 
 #ifdef LOG_MEDIA_SHA1
   SHA1Sum avc_hash;
-  avc_hash.update(mConfig.extra_data.begin(), mConfig.extra_data.length());
+  avc_hash.update(mConfig.extra_data->Elements(), mConfig.extra_data->Length());
   uint8_t digest_buf[SHA1Sum::kHashSize];
   avc_hash.finish(digest_buf);
   nsAutoCString avc_digest;
   for (size_t i = 0; i < sizeof(digest_buf); i++) {
     avc_digest.AppendPrintf("%02x", digest_buf[i]);
   }
   LOG("AVCDecoderConfig %ld bytes sha1 %s",
-      mConfig.extra_data.length(), avc_digest.get());
+      mConfig.extra_data->Length(), avc_digest.get());
 #endif // LOG_MEDIA_SHA1
 
   AutoCFRelease<CFDictionaryRef> extensions = CreateDecoderExtensions();
 
   rv = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
                                       kCMVideoCodecType_H264,
                                       mConfig.image_width,
                                       mConfig.image_height,
@@ -307,18 +307,18 @@ AppleVTDecoder::InitializeSession()
   return NS_OK;
 }
 
 CFDictionaryRef
 AppleVTDecoder::CreateDecoderExtensions()
 {
   AutoCFRelease<CFDataRef> avc_data =
     CFDataCreate(kCFAllocatorDefault,
-                 mConfig.extra_data.begin(),
-                 mConfig.extra_data.length());
+                 mConfig.extra_data->Elements(),
+                 mConfig.extra_data->Length());
 
   const void* atomsKey[] = { CFSTR("avcC") };
   const void* atomsValue[] = { avc_data };
   static_assert(ArrayLength(atomsKey) == ArrayLength(atomsValue),
                 "Non matching keys/values array size");
 
   AutoCFRelease<CFDictionaryRef> atoms =
     CFDictionaryCreate(kCFAllocatorDefault,
--- a/dom/media/fmp4/eme/EMEAudioDecoder.cpp
+++ b/dom/media/fmp4/eme/EMEAudioDecoder.cpp
@@ -247,19 +247,18 @@ EMEAudioDecoder::GmpInit()
   NS_ENSURE_SUCCESS(rv, rv);
   MOZ_ASSERT(mGMP);
 
   mAudioRate = mConfig.samples_per_second;
   mAudioBytesPerSample = mConfig.bits_per_sample / 8;
   mAudioChannels = mConfig.channel_count;
 
   nsTArray<uint8_t> extraData;
-  extraData.AppendElements(&mConfig.audio_specific_config[0],
-                           mConfig.audio_specific_config.length());
-
+  extraData.AppendElements(mConfig.audio_specific_config->Elements(),
+                           mConfig.audio_specific_config->Length());
   mGMP->InitDecode(kGMPAudioCodecAAC,
                    mAudioChannels,
                    mConfig.bits_per_sample,
                    mAudioRate,
                    extraData,
                    this);
 
   return NS_OK;
--- a/dom/media/fmp4/eme/EMEH264Decoder.cpp
+++ b/dom/media/fmp4/eme/EMEH264Decoder.cpp
@@ -246,18 +246,18 @@ EMEH264Decoder::GmpInit()
   codec.mGMPApiVersion = kGMPVersion33;
 
   codec.mCodecType = kGMPVideoCodecH264;
   codec.mWidth = mConfig.display_width;
   codec.mHeight = mConfig.display_height;
 
   nsTArray<uint8_t> codecSpecific;
   codecSpecific.AppendElement(0); // mPacketizationMode.
-  codecSpecific.AppendElements(mConfig.extra_data.begin(),
-                               mConfig.extra_data.length());
+  codecSpecific.AppendElements(mConfig.extra_data->Elements(),
+                               mConfig.extra_data->Length());
 
   rv = mGMP->InitDecode(codec,
                         codecSpecific,
                         this,
                         PR_GetNumberOfProcessors());
   NS_ENSURE_SUCCESS(rv, rv);
 
   mVideoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
--- a/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -19,18 +19,17 @@ namespace mozilla
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
-  mExtraData.append(aConfig.audio_specific_config.begin(),
-                    aConfig.audio_specific_config.length());
+  mExtraData = aConfig.audio_specific_config;
 }
 
 nsresult
 FFmpegAudioDecoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <string.h>
 #include <unistd.h>
 
 #include "MediaTaskQueue.h"
-#include "mp4_demuxer/mp4_demuxer.h"
 #include "FFmpegLibs.h"
 #include "FFmpegLog.h"
 #include "FFmpegDataDecoder.h"
 #include "prsystem.h"
 
 namespace mozilla
 {
 
@@ -89,21 +88,21 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
 
   // FFmpeg will call back to this to negotiate a video pixel format.
   mCodecContext->get_format = ChoosePixelFormat;
 
   mCodecContext->thread_count = PR_GetNumberOfProcessors();
   mCodecContext->thread_type = FF_THREAD_SLICE | FF_THREAD_FRAME;
   mCodecContext->thread_safe_callbacks = false;
 
-  mCodecContext->extradata_size = mExtraData.length();
+  mCodecContext->extradata_size = mExtraData->Length();
   for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
-    mExtraData.append(0);
+    mExtraData->AppendElement(0);
   }
-  mCodecContext->extradata = mExtraData.begin();
+  mCodecContext->extradata = mExtraData->Elements();
 
   if (codec->capabilities & CODEC_CAP_DR1) {
     mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
   }
 
   if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
     NS_WARNING("Couldn't initialise ffmpeg decoder");
     return NS_ERROR_FAILURE;
--- a/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegDataDecoder.h
@@ -4,18 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __FFmpegDataDecoder_h__
 #define __FFmpegDataDecoder_h__
 
 #include "PlatformDecoderModule.h"
 #include "FFmpegLibs.h"
-#include "mozilla/Vector.h"
 #include "mozilla/StaticMutex.h"
+#include "mp4_demuxer/mp4_demuxer.h"
 
 namespace mozilla
 {
 
 template <int V>
 class FFmpegDataDecoder : public MediaDataDecoder
 {
 };
@@ -36,17 +36,17 @@ public:
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
 protected:
   AVFrame*        PrepareFrame();
 
   MediaTaskQueue* mTaskQueue;
   AVCodecContext* mCodecContext;
   AVFrame*        mFrame;
-  Vector<uint8_t> mExtraData;
+  nsRefPtr<mp4_demuxer::ByteBuffer> mExtraData;
 
 private:
   static bool sFFmpegInitDone;
   static StaticMutex sMonitor;
 
   AVCodecID mCodecID;
 };
 
--- a/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -27,17 +27,17 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::VideoDecoderConfig& aConfig,
   ImageContainer* aImageContainer)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
   , mImageContainer(aImageContainer)
 {
   MOZ_COUNT_CTOR(FFmpegH264Decoder);
-  mExtraData.append(aConfig.extra_data.begin(), aConfig.extra_data.length());
+  mExtraData = aConfig.extra_data;
 }
 
 nsresult
 FFmpegH264Decoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -42,18 +42,18 @@ GonkAudioDecoderManager::GonkAudioDecode
   : mAudioChannels(aConfig.channel_count)
   , mAudioRate(aConfig.samples_per_second)
   , mAudioProfile(aConfig.aac_profile)
   , mAudioBuffer(nullptr)
   , mUseAdts(true)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
-  mUserData.AppendElements(&aConfig.audio_specific_config[0],
-                           aConfig.audio_specific_config.length());
+  mUserData.AppendElements(aConfig.audio_specific_config->Elements(),
+                           aConfig.audio_specific_config->Length());
   // Pass through mp3 without applying an ADTS header.
   if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
       mUseAdts = false;
   }
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
--- a/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -78,18 +78,18 @@ WMFAudioMFTManager::WMFAudioMFTManager(
 {
   MOZ_COUNT_CTOR(WMFAudioMFTManager);
 
   if (!strcmp(aConfig.mime_type, "audio/mpeg")) {
     mStreamType = MP3;
   } else if (!strcmp(aConfig.mime_type, "audio/mp4a-latm")) {
     mStreamType = AAC;
     AACAudioSpecificConfigToUserData(aConfig.aac_profile,
-                                     &aConfig.audio_specific_config[0],
-                                     aConfig.audio_specific_config.length(),
+                                     aConfig.audio_specific_config->Elements(),
+                                     aConfig.audio_specific_config->Length(),
                                      mUserData);
   } else {
     mStreamType = Unknown;
   }
 }
 
 WMFAudioMFTManager::~WMFAudioMFTManager()
 {
--- a/media/libstagefright/binding/AnnexB.cpp
+++ b/media/libstagefright/binding/AnnexB.cpp
@@ -18,73 +18,73 @@ void
 AnnexB::ConvertSample(MP4Sample* aSample)
 {
   MOZ_ASSERT(aSample);
   if (!aSample->size) {
     return;
   }
   MOZ_ASSERT(aSample->data);
   MOZ_ASSERT(aSample->size >= ArrayLength(kAnnexBDelimiter));
-  MOZ_ASSERT(aSample->prefix_data);
+  MOZ_ASSERT(aSample->extra_data);
 
   uint8_t* d = aSample->data;
   while (d + 4 < aSample->data + aSample->size) {
     uint32_t nalLen = (uint32_t(d[0]) << 24) +
                       (uint32_t(d[1]) << 16) +
                       (uint32_t(d[2]) << 8) +
                        uint32_t(d[3]);
     // Overwrite the NAL length with the Annex B separator.
     memcpy(d, kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
     d += 4 + nalLen;
   }
 
   // Prepend the Annex B header with SPS and PPS tables to keyframes.
   if (aSample->is_sync_point) {
-    aSample->Prepend(&(*aSample->prefix_data)[0],
-                     aSample->prefix_data->Length());
+    nsRefPtr<ByteBuffer> annexB = ConvertExtraDataToAnnexB(aSample->extra_data);
+    aSample->Prepend(annexB->Elements(), annexB->Length());
   }
 }
 
-already_AddRefed<nsRcTArray<uint8_t>>
-AnnexB::ConvertExtraDataToAnnexB(mozilla::Vector<uint8_t>& aExtraData)
+already_AddRefed<ByteBuffer>
+AnnexB::ConvertExtraDataToAnnexB(const ByteBuffer* aExtraData)
 {
   // AVCC 6 byte header looks like:
   //     +------+------+------+------+------+------+------+------+
   // [0] |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   1  |
   //     +------+------+------+------+------+------+------+------+
   // [1] | profile                                               |
   //     +------+------+------+------+------+------+------+------+
   // [2] | compatiblity                                          |
   //     +------+------+------+------+------+------+------+------+
   // [3] | level                                                 |
   //     +------+------+------+------+------+------+------+------+
   // [4] | unused                                  | nalLenSiz-1 |
   //     +------+------+------+------+------+------+------+------+
   // [5] | unused             | numSps                           |
   //     +------+------+------+------+------+------+------+------+
 
-  nsRefPtr<nsRcTArray<uint8_t>> annexB = new nsRcTArray<uint8_t>();
+  nsRefPtr<ByteBuffer> annexB = new ByteBuffer;
 
-  ByteReader reader(aExtraData);
+  ByteReader reader(*aExtraData);
   const uint8_t* ptr = reader.Read(5);
   if (ptr && ptr[0] == 1) {
     // Append SPS then PPS
     ConvertSPSOrPPS(reader, reader.ReadU8() & 31, annexB);
     ConvertSPSOrPPS(reader, reader.ReadU8(), annexB);
 
     // MP4Box adds extra bytes that we ignore. I don't know what they do.
   }
   reader.DiscardRemaining();
 
   return annexB.forget();
 }
 
 void
 AnnexB::ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
-                        nsTArray<uint8_t>* aAnnexB)
+                        ByteBuffer* aAnnexB)
 {
   for (int i = 0; i < aCount; i++) {
     uint16_t length = aReader.ReadU16();
 
     const uint8_t* ptr = aReader.Read(length);
     if (!ptr) {
       MOZ_ASSERT(false);
       return;
--- a/media/libstagefright/binding/DecoderData.cpp
+++ b/media/libstagefright/binding/DecoderData.cpp
@@ -70,16 +70,22 @@ FindData(sp<MetaData>& aMetaData, uint32
   if (!aMetaData->findData(aKey, &type, &data, &size) || size % sizeof(T)) {
     return false;
   }
 
   aDest->AppendElements(reinterpret_cast<const T*>(data), size / sizeof(T));
   return true;
 }
 
+static bool
+FindData(sp<MetaData>& aMetaData, uint32_t aKey, ByteBuffer* aDest)
+{
+  return FindData(aMetaData, aKey, static_cast<nsTArray<uint8_t>*>(aDest));
+}
+
 bool
 CryptoFile::DoUpdate(sp<MetaData>& aMetaData)
 {
   const void* data;
   size_t size;
   uint32_t type;
 
   // There's no point in checking that the type matches anything because it
@@ -141,24 +147,24 @@ AudioDecoderConfig::Update(sp<MetaData>&
 {
   TrackConfig::Update(aMetaData, aMimeType);
   channel_count = FindInt32(aMetaData, kKeyChannelCount);
   bits_per_sample = FindInt32(aMetaData, kKeySampleSize);
   samples_per_second = FindInt32(aMetaData, kKeySampleRate);
   frequency_index = Adts::GetFrequencyIndex(samples_per_second);
   aac_profile = FindInt32(aMetaData, kKeyAACProfile);
 
-  if (FindData(aMetaData, kKeyESDS, &extra_data)) {
-    ESDS esds(&extra_data[0], extra_data.length());
+  if (FindData(aMetaData, kKeyESDS, extra_data)) {
+    ESDS esds(extra_data->Elements(), extra_data->Length());
 
     const void* data;
     size_t size;
     if (esds.getCodecSpecificInfo(&data, &size) == OK) {
       const uint8_t* cdata = reinterpret_cast<const uint8_t*>(data);
-      audio_specific_config.append(cdata, size);
+      audio_specific_config->AppendElements(cdata, size);
       if (size > 1) {
         ABitReader br(cdata, size);
         extended_profile = br.getBits(5);
 
         if (extended_profile == 31) {  // AAC-ELD => additional 6 bits
           extended_profile = 32 + br.getBits(6);
         }
       }
@@ -177,21 +183,20 @@ void
 VideoDecoderConfig::Update(sp<MetaData>& aMetaData, const char* aMimeType)
 {
   TrackConfig::Update(aMetaData, aMimeType);
   display_width = FindInt32(aMetaData, kKeyDisplayWidth);
   display_height = FindInt32(aMetaData, kKeyDisplayHeight);
   image_width = FindInt32(aMetaData, kKeyWidth);
   image_height = FindInt32(aMetaData, kKeyHeight);
 
-  if (FindData(aMetaData, kKeyAVCC, &extra_data) && extra_data.length() >= 7) {
+  if (FindData(aMetaData, kKeyAVCC, extra_data) && extra_data->Length() >= 7) {
     // Set size of the NAL length to 4. The demuxer formats its output with
     // this NAL length size.
-    extra_data[4] |= 3;
-    annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
+    (*extra_data)[4] |= 3;
   }
 }
 
 bool
 VideoDecoderConfig::IsValid()
 {
   return display_width > 0 && display_height > 0;
 }
@@ -200,29 +205,30 @@ MP4Sample::MP4Sample()
   : mMediaBuffer(nullptr)
   , decode_timestamp(0)
   , composition_timestamp(0)
   , duration(0)
   , byte_offset(0)
   , is_sync_point(0)
   , data(nullptr)
   , size(0)
+  , extra_data(nullptr)
 {
 }
 
 MP4Sample::MP4Sample(const MP4Sample& copy)
   : mMediaBuffer(nullptr)
   , decode_timestamp(copy.decode_timestamp)
   , composition_timestamp(copy.composition_timestamp)
   , duration(copy.duration)
   , byte_offset(copy.byte_offset)
   , is_sync_point(copy.is_sync_point)
   , size(copy.size)
   , crypto(copy.crypto)
-  , prefix_data(copy.prefix_data)
+  , extra_data(copy.extra_data)
 {
   extra_buffer = data = new uint8_t[size];
   memcpy(data, copy.data, size);
 }
 
 MP4Sample::~MP4Sample()
 {
   if (mMediaBuffer) {
--- a/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
@@ -17,20 +17,20 @@ class MP4Sample;
 class AnnexB
 {
 public:
   // Convert a sample from NAL unit syntax to Annex B.
   // Assumes size of NAL length field is 4 bytes.
   static void ConvertSample(MP4Sample* aSample);
 
   // Parse an AVCC box and construct the Annex B sample header.
-  static already_AddRefed<nsRcTArray<uint8_t>> ConvertExtraDataToAnnexB(
-    mozilla::Vector<uint8_t>& aExtraData);
+  static already_AddRefed<ByteBuffer> ConvertExtraDataToAnnexB(
+    const ByteBuffer* aExtraData);
 
 private:
   // AVCC box parser helper.
   static void ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
-                              nsTArray<uint8_t>* aAnnexB);
+                              ByteBuffer* aAnnexB);
 };
 
 } // namespace mp4_demuxer
 
 #endif // MP4_DEMUXER_ANNEX_B_H_
--- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
@@ -23,16 +23,20 @@ public:
     : mPtr(aData), mRemaining(aSize)
   {
   }
   template<size_t S>
   ByteReader(const nsAutoTArray<uint8_t, S>& aData)
     : mPtr(&aData[0]), mRemaining(aData.Length())
   {
   }
+  explicit ByteReader(const nsTArray<uint8_t>& aData)
+    : mPtr(&aData[0]), mRemaining(aData.Length())
+  {
+  }
 
   void SetData(const nsTArray<uint8_t>& aData)
   {
     MOZ_ASSERT(!mPtr && !mRemaining);
     mPtr = &aData[0];
     mRemaining = aData.Length();
   }
 
--- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
@@ -4,16 +4,17 @@
 
 #ifndef DECODER_DATA_H_
 #define DECODER_DATA_H_
 
 #include "mozilla/Types.h"
 #include "mozilla/Vector.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsRefPtr.h"
 
 namespace stagefright
 {
 template <typename T> class sp;
 class MetaData;
 class MediaBuffer;
 }
 
@@ -25,16 +26,18 @@ class MP4Demuxer;
 template <typename T>
 class nsRcTArray : public nsTArray<T> {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsRcTArray);
 
 private:
   ~nsRcTArray() {}
 };
 
+typedef nsRcTArray<uint8_t> ByteBuffer;
+
 struct PsshInfo
 {
   PsshInfo() {}
   PsshInfo(const PsshInfo& aOther) : uuid(aOther.uuid), data(aOther.data) {}
   nsTArray<uint8_t> uuid;
   nsTArray<uint8_t> data;
 };
 
@@ -94,49 +97,57 @@ class AudioDecoderConfig : public TrackC
 public:
   AudioDecoderConfig()
     : channel_count(0)
     , bits_per_sample(0)
     , samples_per_second(0)
     , frequency_index(0)
     , aac_profile(0)
     , extended_profile(0)
+    , extra_data(new ByteBuffer)
+    , audio_specific_config(new ByteBuffer)
   {
   }
 
   uint32_t channel_count;
   uint32_t bits_per_sample;
   uint32_t samples_per_second;
   int8_t frequency_index;
   int8_t aac_profile;
   int8_t extended_profile;
-  mozilla::Vector<uint8_t> extra_data;
-  mozilla::Vector<uint8_t> audio_specific_config;
+  nsRefPtr<ByteBuffer> extra_data;
+  nsRefPtr<ByteBuffer> audio_specific_config;
 
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData,
               const char* aMimeType);
   bool IsValid();
 
 private:
   friend class MP4Demuxer;
 };
 
 class VideoDecoderConfig : public TrackConfig
 {
 public:
-  VideoDecoderConfig() : display_width(0), display_height(0) {}
+  VideoDecoderConfig()
+    : display_width(0)
+    , display_height(0)
+    , image_width(0)
+    , image_height(0)
+    , extra_data(new ByteBuffer)
+  {
+  }
 
   int32_t display_width;
   int32_t display_height;
 
   int32_t image_width;
   int32_t image_height;
 
-  mozilla::Vector<uint8_t> extra_data;   // Unparsed AVCDecoderConfig payload.
-  nsRefPtr<nsRcTArray<uint8_t>> annex_b; // Parsed version for sample prepend.
+  nsRefPtr<ByteBuffer> extra_data;   // Unparsed AVCDecoderConfig payload.
 
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData,
               const char* aMimeType);
   bool IsValid();
 };
 
 typedef int64_t Microseconds;
 
@@ -156,17 +167,17 @@ public:
   Microseconds duration;
   int64_t byte_offset;
   bool is_sync_point;
 
   uint8_t* data;
   size_t size;
 
   CryptoSample crypto;
-  nsRefPtr<nsRcTArray<uint8_t>> prefix_data;
+  nsRefPtr<ByteBuffer> extra_data;
 
   void Prepend(const uint8_t* aData, size_t aSize);
 
   nsAutoArrayPtr<uint8_t> extra_buffer;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -211,17 +211,17 @@ MP4Demuxer::DemuxAudioSample()
 }
 
 MP4Sample*
 MP4Demuxer::DemuxVideoSample()
 {
   if (mPrivate->mVideoIterator) {
     nsAutoPtr<MP4Sample> sample(mPrivate->mVideoIterator->GetNext());
     if (sample) {
-      sample->prefix_data = mVideoConfig.annex_b;
+      sample->extra_data = mVideoConfig.extra_data;
       if (sample->crypto.valid) {
         sample->crypto.mode = mVideoConfig.crypto.mode;
         sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
       }
     }
     return sample.forget();
   }
 
@@ -230,17 +230,17 @@ MP4Demuxer::DemuxVideoSample()
     mPrivate->mVideo->read(&sample->mMediaBuffer, &mPrivate->mVideoOptions);
   mPrivate->mVideoOptions.clearSeekTo();
 
   if (status < 0) {
     return nullptr;
   }
 
   sample->Update(mVideoConfig.media_time);
-  sample->prefix_data = mVideoConfig.annex_b;
+  sample->extra_data = mVideoConfig.extra_data;
 
   return sample.forget();
 }
 
 void
 MP4Demuxer::UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges)
 {
   for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {