Bug 1019291 - Construct Annex B samples in the decoder. r=cpeace
authorRalph Giles <giles@mozilla.com>
Thu, 19 Jun 2014 15:59:00 -0700
changeset 189874 ccdc4a98cc11e9723b789bd578b8ec88d9142829
parent 189873 c843ae1b1eb2249cf769a4a041ca3acb21369487
child 189875 a5714e1eafca8447ffe7e478974f97610921380a
push id45174
push userrgiles@mozilla.com
push dateFri, 20 Jun 2014 23:52:44 +0000
treeherdermozilla-inbound@ccdc4a98cc11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpeace
bugs1019291
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1019291 - Construct Annex B samples in the decoder. r=cpeace Move Annex B sample formatting from the demuxer to a static utility function. Return NAL unit syntax samples by default, since more platforms prefer to unpack the AVCC data themselves. Pass the raw AVCC payload to ffmpeg through its extradata field. It can handle either sample format, expecting one or the other depending on whether extradata is present. Pass input samples through a new WMFOutputSource::Input method. Save a reference to the VideoDecoderConfig in the WFMVideoOutputSource and use it to convert samples to Annex B before forwarding them to the MFTDecoder.
content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
content/media/fmp4/ffmpeg/FFmpegDataDecoder.h
content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
content/media/fmp4/wmf/WMFAudioOutputSource.cpp
content/media/fmp4/wmf/WMFAudioOutputSource.h
content/media/fmp4/wmf/WMFDecoderModule.cpp
content/media/fmp4/wmf/WMFMediaDataDecoder.cpp
content/media/fmp4/wmf/WMFMediaDataDecoder.h
content/media/fmp4/wmf/WMFVideoOutputSource.cpp
content/media/fmp4/wmf/WMFVideoOutputSource.h
media/libstagefright/binding/AnnexB.cpp
media/libstagefright/binding/DecoderData.cpp
media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
media/libstagefright/binding/mp4_demuxer.cpp
media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
media/libstagefright/moz.build
--- a/content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
@@ -82,16 +82,19 @@ FFmpegDataDecoder::Init()
   mCodecContext.opaque = this;
 
   // FFmpeg takes this as a suggestion for what format to use for audio samples.
   mCodecContext.request_sample_fmt = AV_SAMPLE_FMT_FLT;
 
   // FFmpeg will call back to this to negotiate a video pixel format.
   mCodecContext.get_format = ChoosePixelFormat;
 
+  mCodecContext.extradata = mExtraData.begin();
+  mCodecContext.extradata_size = mExtraData.length();
+
   AVDictionary* opts = nullptr;
   if (avcodec_open2(&mCodecContext, codec, &opts) < 0) {
     NS_WARNING("Couldn't initialise ffmpeg decoder");
     return NS_ERROR_FAILURE;
   }
 
   if (mCodecContext.codec_type == AVMEDIA_TYPE_AUDIO &&
       mCodecContext.sample_fmt != AV_SAMPLE_FMT_FLT &&
--- a/content/media/fmp4/ffmpeg/FFmpegDataDecoder.h
+++ b/content/media/fmp4/ffmpeg/FFmpegDataDecoder.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __FFmpegDataDecoder_h__
 #define __FFmpegDataDecoder_h__
 
 #include "FFmpegDecoderModule.h"
 #include "FFmpegRuntimeLinker.h"
 #include "FFmpegCompat.h"
+#include "mozilla/Vector.h"
 
 namespace mozilla
 {
 
 class FFmpegDataDecoder : public MediaDataDecoder
 {
 public:
   FFmpegDataDecoder(MediaTaskQueue* aTaskQueue, AVCodecID aCodecID);
@@ -26,16 +27,17 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) = 0;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() = 0;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
 protected:
   MediaTaskQueue* mTaskQueue;
   AVCodecContext mCodecContext;
+  Vector<uint8_t> mExtraData;
 
 private:
   static bool sFFmpegInitDone;
 
   AVCodecID mCodecID;
 };
 
 } // namespace mozilla
--- a/content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -28,16 +28,17 @@ FFmpegH264Decoder::FFmpegH264Decoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::VideoDecoderConfig &aConfig,
   ImageContainer* aImageContainer)
   : FFmpegDataDecoder(aTaskQueue, AV_CODEC_ID_H264)
   , mCallback(aCallback)
   , mImageContainer(aImageContainer)
 {
   MOZ_COUNT_CTOR(FFmpegH264Decoder);
+  mExtraData.append(aConfig.extra_data.begin(), aConfig.extra_data.length());
 }
 
 nsresult
 FFmpegH264Decoder::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/media/fmp4/wmf/WMFAudioOutputSource.cpp
+++ b/content/media/fmp4/wmf/WMFAudioOutputSource.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "WMFAudioOutputSource.h"
+#include "mp4_demuxer/DecoderData.h"
 #include "VideoUtils.h"
 #include "WMFUtils.h"
 #include "nsTArray.h"
 
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetDemuxerLog();
@@ -123,16 +124,24 @@ WMFAudioOutputSource::Init()
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   mDecoder = decoder;
 
   return decoder.forget();
 }
 
 HRESULT
+WMFAudioOutputSource::Input(mp4_demuxer::MP4Sample* aSample)
+{
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
+  uint32_t length = aSample->size;
+  return mDecoder->Input(data, length, aSample->composition_timestamp);
+}
+
+HRESULT
 WMFAudioOutputSource::Output(int64_t aStreamOffset,
                         nsAutoPtr<MediaData>& aOutData)
 {
   aOutData = nullptr;
   RefPtr<IMFSample> sample;
   HRESULT hr = mDecoder->Output(&sample);
   if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
     return MF_E_TRANSFORM_NEED_MORE_INPUT;
--- a/content/media/fmp4/wmf/WMFAudioOutputSource.h
+++ b/content/media/fmp4/wmf/WMFAudioOutputSource.h
@@ -17,16 +17,18 @@ namespace mozilla {
 
 class WMFAudioOutputSource : public WMFOutputSource {
 public:
   WMFAudioOutputSource(const mp4_demuxer::AudioDecoderConfig& aConfig);
   ~WMFAudioOutputSource();
 
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
+  virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
   // Note WMF's AAC decoder sometimes output negatively timestamped samples,
   // presumably they're the preroll samples, and we strip them. We may return
   // a null aOutput in this case.
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 private:
 
   // IMFTransform wrapper that performs the decoding.
--- a/content/media/fmp4/wmf/WMFDecoderModule.cpp
+++ b/content/media/fmp4/wmf/WMFDecoderModule.cpp
@@ -65,17 +65,18 @@ WMFDecoderModule::Shutdown()
 
 MediaDataDecoder*
 WMFDecoderModule::CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                                     mozilla::layers::LayersBackend aLayersBackend,
                                     mozilla::layers::ImageContainer* aImageContainer,
                                     MediaTaskQueue* aVideoTaskQueue,
                                     MediaDataDecoderCallback* aCallback)
 {
-  return new WMFMediaDataDecoder(new WMFVideoOutputSource(aLayersBackend,
+  return new WMFMediaDataDecoder(new WMFVideoOutputSource(aConfig,
+                                                          aLayersBackend,
                                                           aImageContainer,
                                                           sDXVAEnabled),
                                  aVideoTaskQueue,
                                  aCallback);
 }
 
 MediaDataDecoder*
 WMFDecoderModule::CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -62,21 +62,19 @@ WMFMediaDataDecoder::Input(mp4_demuxer::
       &WMFMediaDataDecoder::ProcessDecode,
       nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
   return NS_OK;
 }
 
 void
 WMFMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
 {
-  const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
-  uint32_t length = aSample->size;
-  HRESULT hr = mDecoder->Input(data, length, aSample->composition_timestamp);
+  HRESULT hr = mSource->Input(aSample);
   if (FAILED(hr)) {
-    NS_WARNING("WMFAudioDecoder failed to input data");
+    NS_WARNING("WMFOutputSource rejected sample");
     mCallback->Error();
     return;
   }
 
   mLastStreamOffset = aSample->byte_offset;
 
   ProcessOutput();
 }
--- a/content/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/content/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -8,29 +8,36 @@
 #define WMFMediaDataDecoder_h_
 
 
 #include "WMF.h"
 #include "MP4Reader.h"
 #include "MFTDecoder.h"
 #include "mozilla/RefPtr.h"
 
+class mp4_demuxer::MP4Sample;
+
 namespace mozilla {
 
 // Encapsulates the initialization of the MFTDecoder appropriate for decoding
 // a given stream, and the process of converting the IMFSample produced
 // by the MFT into a MediaData object.
 class WMFOutputSource {
 public:
   virtual ~WMFOutputSource() {}
 
   // Creates an initializs the MFTDecoder.
   // Returns nullptr on failure.
   virtual TemporaryRef<MFTDecoder> Init() = 0;
 
+  // Submit a compressed sample for decoding.
+  // This should forward to the MFTDecoder after performing
+  // any required sample formatting.
+  virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) = 0;
+
   // Produces decoded output, if possible. Blocks until output can be produced,
   // or until no more is able to be produced.
   // Returns S_OK on success, or MF_E_TRANSFORM_NEED_MORE_INPUT if there's not
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsAutoPtr<MediaData>& aOutput) = 0;
--- a/content/media/fmp4/wmf/WMFVideoOutputSource.cpp
+++ b/content/media/fmp4/wmf/WMFVideoOutputSource.cpp
@@ -8,16 +8,18 @@
 #include "MediaDecoderReader.h"
 #include "WMFUtils.h"
 #include "ImageContainer.h"
 #include "VideoUtils.h"
 #include "DXVA2Manager.h"
 #include "nsThreadUtils.h"
 #include "Layers.h"
 #include "mozilla/layers/LayersTypes.h"
+#include "mp4_demuxer/AnnexB.h"
+#include "mp4_demuxer/DecoderData.h"
 #include "prlog.h"
 #include "gfx2DGlue.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
@@ -25,22 +27,25 @@ PRLogModuleInfo* GetDemuxerLog();
 
 using mozilla::gfx::ToIntRect;
 using mozilla::layers::Image;
 using mozilla::layers::LayerManager;
 using mozilla::layers::LayersBackend;
 
 namespace mozilla {
 
-WMFVideoOutputSource::WMFVideoOutputSource(mozilla::layers::LayersBackend aLayersBackend,
-                                 mozilla::layers::ImageContainer* aImageContainer,
-                                 bool aDXVAEnabled)
+WMFVideoOutputSource::WMFVideoOutputSource(
+                            const mp4_demuxer::VideoDecoderConfig& aConfig,
+                            mozilla::layers::LayersBackend aLayersBackend,
+                            mozilla::layers::ImageContainer* aImageContainer,
+                            bool aDXVAEnabled)
   : mVideoStride(0)
   , mVideoWidth(0)
   , mVideoHeight(0)
+  , mConfig(aConfig)
   , mImageContainer(aImageContainer)
   , mDXVAEnabled(aDXVAEnabled)
   , mLayersBackend(aLayersBackend)
   , mUseHwAccel(false)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
   MOZ_ASSERT(mImageContainer);
   MOZ_COUNT_CTOR(WMFVideoOutputSource);
@@ -134,16 +139,27 @@ WMFVideoOutputSource::Init()
 
   mDecoder = decoder;
   LOG("Video Decoder initialized, Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
 
   return decoder.forget();
 }
 
 HRESULT
+WMFVideoOutputSource::Input(mp4_demuxer::MP4Sample* aSample)
+{
+  // We must prepare samples in AVC Annex B.
+  mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
+  // Forward sample data to the decoder.
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
+  uint32_t length = aSample->size;
+  return mDecoder->Input(data, length, aSample->composition_timestamp);
+}
+
+HRESULT
 WMFVideoOutputSource::ConfigureVideoFrameGeometry()
 {
   RefPtr<IMFMediaType> mediaType;
   HRESULT hr = mDecoder->GetOutputMediaType(mediaType);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   // Verify that the video subtype is what we expect it to be.
   // When using hardware acceleration/DXVA2 the video format should
--- a/content/media/fmp4/wmf/WMFVideoOutputSource.h
+++ b/content/media/fmp4/wmf/WMFVideoOutputSource.h
@@ -15,23 +15,26 @@
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 class DXVA2Manager;
 
 class WMFVideoOutputSource : public WMFOutputSource {
 public:
-  WMFVideoOutputSource(mozilla::layers::LayersBackend aLayersBackend,
+  WMFVideoOutputSource(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                       mozilla::layers::LayersBackend aLayersBackend,
                        mozilla::layers::ImageContainer* aImageContainer,
                        bool aDXVAEnabled);
   ~WMFVideoOutputSource();
 
   virtual TemporaryRef<MFTDecoder> Init() MOZ_OVERRIDE;
 
+  virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsAutoPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
 private:
 
   bool InitializeDXVA();
 
   HRESULT ConfigureVideoFrameGeometry();
@@ -46,16 +49,18 @@ private:
 
   // Video frame geometry.
   VideoInfo mVideoInfo;
   uint32_t mVideoStride;
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   nsIntRect mPictureRegion;
 
+  const mp4_demuxer::VideoDecoderConfig& mConfig;
+
   RefPtr<MFTDecoder> mDecoder;
   RefPtr<layers::ImageContainer> mImageContainer;
   nsAutoPtr<DXVA2Manager> mDXVA2Manager;
   RefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   const bool mDXVAEnabled;
   const layers::LayersBackend mLayersBackend;
--- a/media/libstagefright/binding/AnnexB.cpp
+++ b/media/libstagefright/binding/AnnexB.cpp
@@ -1,23 +1,39 @@
 /* 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 "mozilla/ArrayUtils.h"
 #include "mp4_demuxer/AnnexB.h"
 #include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/DecoderData.h"
 
 using namespace mozilla;
 
 namespace mp4_demuxer
 {
 
 static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
 
+void
+AnnexB::ConvertSample(MP4Sample* aSample,
+                      const mozilla::Vector<uint8_t>& annexB)
+{
+  MOZ_ASSERT(aSample);
+  MOZ_ASSERT(aSample->data);
+  MOZ_ASSERT(aSample->size >= ArrayLength(kAnnexBDelimiter));
+  // Overwrite the NAL length with the Annex B separator.
+  memcpy(aSample->data, kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
+  // Prepend the Annex B header with SPS and PPS tables to keyframes.
+  if (aSample->is_sync_point) {
+    aSample->Prepend(annexB.begin(), annexB.length());
+  }
+}
+
 Vector<uint8_t>
 AnnexB::ConvertExtraDataToAnnexB(mozilla::Vector<uint8_t>& aExtraData)
 {
   // AVCC 6 byte header looks like:
   //     +------+------+------+------+------+------+------+------+
   // [0] |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   1  |
   //     +------+------+------+------+------+------+------+------+
   // [1] | profile                                               |
@@ -31,35 +47,36 @@ AnnexB::ConvertExtraDataToAnnexB(mozilla
   // [5] | unused             | numSps                           |
   //     +------+------+------+------+------+------+------+------+
 
   Vector<uint8_t> annexB;
 
   ByteReader reader(aExtraData);
   const uint8_t* ptr = reader.Read(5);
   if (ptr && ptr[0] == 1) {
-    // Append SPS then PSP
-    ConvertSpsOrPsp(reader, reader.ReadU8() & 31, &annexB);
-    ConvertSpsOrPsp(reader, reader.ReadU8(), &annexB);
+    // Append SPS then PPS
+    ConvertSPSOrPPS(reader, reader.ReadU8() & 31, &annexB);
+    ConvertSPSOrPPS(reader, reader.ReadU8(), &annexB);
 
     MOZ_ASSERT(!reader.Remaining());
   }
 
   return annexB;
 }
 
 void
-AnnexB::ConvertSpsOrPsp(ByteReader& aReader, uint8_t aCount,
+AnnexB::ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
                         Vector<uint8_t>* 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;
     }
     aAnnexB->append(kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
     aAnnexB->append(ptr, length);
   }
 }
-}
+
+} // namespace mp4_demuxer
--- a/media/libstagefright/binding/DecoderData.cpp
+++ b/media/libstagefright/binding/DecoderData.cpp
@@ -78,17 +78,17 @@ VideoDecoderConfig::Update(sp<MetaData>&
   display_width = FindInt32(aMetaData, kKeyDisplayWidth);
   display_height = FindInt32(aMetaData, kKeyDisplayHeight);
 
   const void* data;
   size_t size;
   uint32_t type;
 
   if (aMetaData->findData(kKeyAVCC, &type, &data, &size)) {
-    mozilla::Vector<uint8_t> extra_data;
+    extra_data.clear();
     extra_data.append(reinterpret_cast<const uint8_t*>(data), size);
     annex_b = AnnexB::ConvertExtraDataToAnnexB(extra_data);
   }
 }
 
 bool
 VideoDecoderConfig::IsValid()
 {
--- a/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h
@@ -1,25 +1,34 @@
 /* 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/. */
 
-#ifndef ANNEX_B_H_
-#define ANNEX_B_H_
+#ifndef MP4_DEMUXER_ANNEX_B_H_
+#define MP4_DEMUXER_ANNEX_B_H_
 
 #include "mozilla/Vector.h"
 
 namespace mp4_demuxer
 {
 class ByteReader;
+class MP4Sample;
+
 class AnnexB
 {
 public:
+  // Convert a sample from NAL unit syntax to Annex B.
+  static void ConvertSample(MP4Sample* aSample,
+                            const mozilla::Vector<uint8_t>& annexB);
+
+  // Parse an AVCC box and construct the Annex B sample header.
   static mozilla::Vector<uint8_t> ConvertExtraDataToAnnexB(
     mozilla::Vector<uint8_t>& aExtraData);
 
 private:
-  static void ConvertSpsOrPsp(ByteReader& aReader, uint8_t aCount,
+  // AVCC box parser helper.
+  static void ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
                               mozilla::Vector<uint8_t>* aAnnexB);
 };
-}
 
-#endif
+} // namespace mp4_demuxer
+
+#endif // MP4_DEMUXER_ANNEX_B_H_
--- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
@@ -62,17 +62,18 @@ public:
   {
   }
 
   const char* mime_type;
   int64_t duration;
   int32_t display_width;
   int32_t display_height;
 
-  mozilla::Vector<uint8_t> annex_b;
+  mozilla::Vector<uint8_t> extra_data; // Unparsed AVCDecoderConfig payload.
+  mozilla::Vector<uint8_t> annex_b;    // Parsed version for sample prepend.
 
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData, const char* aMimeType);
   bool IsValid();
 };
 
 class MP4Sample
 {
 public:
--- a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
@@ -39,18 +39,18 @@ public:
   bool CanSeek();
 
   bool HasValidAudio();
   bool HasValidVideo();
 
   void SeekAudio(Microseconds aTime);
   void SeekVideo(Microseconds aTime);
 
-  // DemuxAudioSample and DemuxVideoSample functions return nullptr on end of
-  // stream or error.
+  // DemuxAudioSample and DemuxVideoSample functions
+  // return nullptr on end of stream or error.
   MP4Sample* DemuxAudioSample();
   MP4Sample* DemuxVideoSample();
 
   const AudioDecoderConfig& AudioConfig() { return mAudioConfig; }
   const VideoDecoderConfig& VideoConfig() { return mVideoConfig; }
 
 private:
   AudioDecoderConfig mAudioConfig;
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -60,17 +60,18 @@ public:
   virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
 
   virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
 
 private:
   nsAutoPtr<Stream> mSource;
 };
 
-MP4Demuxer::MP4Demuxer(Stream* source) : mPrivate(new StageFrightPrivate())
+MP4Demuxer::MP4Demuxer(Stream* source)
+  : mPrivate(new StageFrightPrivate())
 {
   mPrivate->mExtractor = new MPEG4Extractor(new DataSourceAdapter(source));
 }
 
 MP4Demuxer::~MP4Demuxer()
 {
   if (mPrivate->mAudio.get()) {
     mPrivate->mAudio->stop();
@@ -175,16 +176,12 @@ MP4Demuxer::DemuxVideoSample()
   mPrivate->mVideoOptions.clearSeekTo();
 
   if (status < 0) {
     return nullptr;
   }
 
   sample->Update();
 
-  if (sample->is_sync_point) {
-    sample->Prepend(mVideoConfig.annex_b.begin(),
-                    mVideoConfig.annex_b.length());
-  }
-
   return sample.forget();
 }
-}
+
+} // namespace mp4_demuxer
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -3296,21 +3296,20 @@ status_t MPEG4Source::read(
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 CHECK(dstOffset + 4 <= mBuffer->size());
-
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 1;
+                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;
             }
             CHECK_EQ(srcOffset, size);
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, dstOffset);
         }
@@ -3584,21 +3583,20 @@ status_t MPEG4Source::fragmentedRead(
                     return ERROR_MALFORMED;
                 }
 
                 if (nalLength == 0) {
                     continue;
                 }
 
                 CHECK(dstOffset + 4 <= mBuffer->size());
-
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 0;
-                dstData[dstOffset++] = 1;
+                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;
             }
             CHECK_EQ(srcOffset, size);
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, dstOffset);
         }
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -41,16 +41,17 @@ if CONFIG['OS_TARGET'] != 'Android':
     ]
     UNIFIED_SOURCES += [
         'system/core/libcutils/strdup16to8.c',
         'system/core/liblog/logd_write.c',
         'system/core/liblog/logprint.c',
     ]
 
 EXPORTS.mp4_demuxer += [
+    'binding/include/mp4_demuxer/AnnexB.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
 ]
 
 SOURCES += [
     'frameworks/av/media/libstagefright/foundation/hexdump.cpp',
     'frameworks/av/media/libstagefright/MetaData.cpp',
     'system/core/libutils/RefBase.cpp',