Bug 1073805 - Fix HE-AAC regression on windows. r=kinetik,cpearce a=lmandel
authorRalph Giles <giles@mozilla.com>
Thu, 30 Oct 2014 15:43:00 -0700
changeset 225953 decaff6b28c7
parent 225952 6f460d9ed80d
child 225954 d8080081d33a
push id4081
push userrgiles@mozilla.com
push date2014-11-05 22:05 +0000
treeherdermozilla-beta@decaff6b28c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik, cpearce, lmandel
bugs1073805
milestone34.0
Bug 1073805 - Fix HE-AAC regression on windows. r=kinetik,cpearce a=lmandel When we switched to the stagefright mp4 demuxer, we fed aac to the platform decoders with ADTS encapsulation instead of letting the platform's demuxer to handle the mp4 container directly. Unfortunately ADTS only supports AAC profile 1-4, so we stopped supporting profile 5 (HE-AAC with Spectral Band Replication). Windows Media Framework will accept raw aac, so we move the application of the ADTS headers to the individual platform decoder modules, and then pass unframed packets on Windows. All other platforms add the ADTS header so the behaviour and support there will be the same as before.
content/media/fmp4/apple/AppleATDecoder.cpp
content/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
content/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
content/media/fmp4/gonk/GonkAudioDecoderManager.h
content/media/fmp4/wmf/WMFAudioMFTManager.cpp
media/libstagefright/binding/Adts.cpp
media/libstagefright/binding/include/mp4_demuxer/Adts.h
media/libstagefright/binding/mp4_demuxer.cpp
media/libstagefright/moz.build
--- a/content/media/fmp4/apple/AppleATDecoder.cpp
+++ b/content/media/fmp4/apple/AppleATDecoder.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <AudioToolbox/AudioToolbox.h>
 #include "AppleUtils.h"
 #include "MP4Reader.h"
 #include "MP4Decoder.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/ReentrantMonitor.h"
+#include "mp4_demuxer/Adts.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "nsIThread.h"
 #include "AppleATDecoder.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetAppleMediaLog();
 #define LOG(...) PR_LOG(GetAppleMediaLog(), PR_LOG_DEBUG, (__VA_ARGS__))
@@ -350,16 +351,29 @@ AppleATDecoder::SetupDecoder()
     mConverter = nullptr;
     mCallback->Error();
   }
 }
 
 void
 AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
 {
+  // Prepend ADTS header to AAC audio.
+  if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
+    bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
+                                               mConfig.frequency_index,
+                                               mConfig.aac_profile,
+                                               aSample);
+    if (!rv) {
+      NS_ERROR("Failed to apply ADTS header");
+      mCallback->Error();
+      return;
+    }
+  }
+  // Push the sample to the AudioFileStream for parsing.
   mSamplePosition = aSample->byte_offset;
   mCurrentAudioTimestamp = aSample->composition_timestamp;
   uint32_t flags = mFlushed ? kAudioFileStreamParseFlag_Discontinuity : 0;
   OSStatus rv = AudioFileStreamParseBytes(mStream,
                                           aSample->size,
                                           aSample->data,
                                           flags);
   if (rv != noErr) {
--- a/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -3,29 +3,31 @@
 /* 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 "MediaTaskQueue.h"
 #include "FFmpegRuntimeLinker.h"
 
 #include "FFmpegAudioDecoder.h"
+#include "mp4_demuxer/Adts.h"
 
 #define MAX_CHANNELS 16
 
 typedef mp4_demuxer::MP4Sample MP4Sample;
 
 namespace mozilla
 {
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
+  , mConfig(aConfig)
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
 }
 
 nsresult
 FFmpegAudioDecoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
@@ -78,16 +80,29 @@ CopyAndPackAudio(AVFrame* aFrame, uint32
   }
 
   return audio.forget();
 }
 
 void
 FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
 {
+  // Prepend ADTS header to AAC audio.
+  if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
+    bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
+                                               mConfig.frequency_index,
+                                               mConfig.aac_profile,
+                                               aSample);
+    if (!rv) {
+      NS_ERROR("Failed to apply ADTS header");
+      mCallback->Error();
+      return;
+    }
+  }
+
   AVPacket packet;
   av_init_packet(&packet);
 
   aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
   packet.data = aSample->data;
   packet.size = aSample->size;
   packet.pos = aSample->byte_offset;
 
--- a/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
+++ b/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
@@ -30,13 +30,14 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   static AVCodecID GetCodecId(const char* aMimeType);
 
 private:
   void DecodePacket(mp4_demuxer::MP4Sample* aSample);
 
   MediaDataDecoderCallback* mCallback;
+  const mp4_demuxer::AudioDecoderConfig& mConfig;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegAACDecoder_h__
--- a/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -4,16 +4,17 @@
  * 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 "MediaCodecProxy.h"
 #include <OMX_IVCommon.h>
 #include <gui/Surface.h>
 #include <ICrypto.h>
 #include "GonkAudioDecoderManager.h"
 #include "MediaDecoderReader.h"
+#include "mp4_demuxer/Adts.h"
 #include "VideoUtils.h"
 #include "nsTArray.h"
 #include "prlog.h"
 #include "stagefright/MediaBuffer.h"
 #include "stagefright/MetaData.h"
 #include "stagefright/MediaErrors.h"
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/foundation/ALooper.h>
@@ -37,21 +38,26 @@ typedef android::MediaCodecProxy MediaCo
 namespace mozilla {
 
 GonkAudioDecoderManager::GonkAudioDecoderManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : 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());
+  // Pass through mp3 without applying an ADTS header.
+  if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
+      mUseAdts = false;
+  }
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
   MOZ_COUNT_DTOR(GonkAudioDecoderManager);
 }
 
 android::sp<MediaCodecProxy>
@@ -215,16 +221,28 @@ void GonkAudioDecoderManager::ReleaseAud
 
 nsresult
 GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   if (mDecoder == nullptr) {
     ALOG("Decoder is not inited");
     return NS_ERROR_UNEXPECTED;
   }
+  if (aSample && mUseAdts) {
+    int8_t frequency_index =
+        mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
+    bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
+                                               frequency_index,
+                                               mAudioProfile,
+                                               aSample);
+    if (!rv) {
+      ALOG("Failed to apply ADTS header");
+      return NS_ERROR_FAILURE;
+    }
+  }
 
   status_t rv;
   if (aSample) {
     const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
     uint32_t length = aSample->size;
     rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
   } else {
     // Inputted data is null, so it is going to notify decoder EOS
--- a/content/media/fmp4/gonk/GonkAudioDecoderManager.h
+++ b/content/media/fmp4/gonk/GonkAudioDecoderManager.h
@@ -40,16 +40,17 @@ private:
   void ReleaseAudioBuffer();
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<MediaCodecProxy> mDecoder;
 
   const uint32_t mAudioChannels;
   const uint32_t mAudioRate;
   const uint32_t mAudioProfile;
   nsTArray<uint8_t> mUserData;
+  bool mUseAdts;
 
   MediaDataDecoderCallback*  mReaderCallback;
   android::MediaBuffer* mAudioBuffer;
   android::sp<ALooper> mLooper;
 };
 
 } // namespace mozilla
 
--- a/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -17,17 +17,18 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
 #endif
 
 namespace mozilla {
 
 static void
-AACAudioSpecificConfigToUserData(const uint8_t* aAudioSpecConfig,
+AACAudioSpecificConfigToUserData(uint8_t aAACProfileLevelIndication,
+                                 const uint8_t* aAudioSpecConfig,
                                  uint32_t aConfigLength,
                                  nsTArray<BYTE>& aOutUserData)
 {
   MOZ_ASSERT(aOutUserData.IsEmpty());
 
   // The MF_MT_USER_DATA for AAC is defined here:
   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx
   //
@@ -54,18 +55,18 @@ AACAudioSpecificConfigToUserData(const u
   //      DWORD        dwReserved2;
   //    }
   const UINT32 heeInfoLen = 4 * sizeof(WORD) + sizeof(DWORD);
 
   // The HEAACWAVEINFO must have payload and profile set,
   // the rest can be all 0x00.
   BYTE heeInfo[heeInfoLen] = {0};
   WORD* w = (WORD*)heeInfo;
-  w[0] = 0x1; // Payload type ADTS
-  w[1] = 0xFE; // Profile level indication, none specified.
+  w[0] = 0x0; // Payload type raw AAC packet
+  w[1] = aAACProfileLevelIndication;
 
   aOutUserData.AppendElements(heeInfo, heeInfoLen);
   aOutUserData.AppendElements(aAudioSpecConfig, aConfigLength);
 }
 
 WMFAudioMFTManager::WMFAudioMFTManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : mAudioChannels(aConfig.channel_count)
@@ -76,17 +77,18 @@ WMFAudioMFTManager::WMFAudioMFTManager(
   , mMustRecaptureAudioPosition(true)
 {
   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.audio_specific_config[0],
+    AACAudioSpecificConfigToUserData(aConfig.aac_profile,
+                                     &aConfig.audio_specific_config[0],
                                      aConfig.audio_specific_config.length(),
                                      mUserData);
   } else {
     mStreamType = Unknown;
   }
 }
 
 WMFAudioMFTManager::~WMFAudioMFTManager()
@@ -140,17 +142,17 @@ WMFAudioMFTManager::Init()
 
   hr = type->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, mAudioRate);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   hr = type->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, mAudioChannels);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   if (mStreamType == AAC) {
-    hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x1); // ADTS
+    hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x0); // Raw AAC packet
     NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
     hr = type->SetBlob(MF_MT_USER_DATA,
                        mUserData.Elements(),
                        mUserData.Length());
     NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
   }
 
--- a/media/libstagefright/binding/Adts.cpp
+++ b/media/libstagefright/binding/Adts.cpp
@@ -28,18 +28,18 @@ Adts::GetFrequencyIndex(uint16_t aSample
   if (!freq_lookup[i]) {
     return -1;
   }
 
   return i;
 }
 
 bool
-Adts::ConvertEsdsToAdts(uint16_t aChannelCount, int8_t aFrequencyIndex,
-                        int8_t aProfile, MP4Sample* aSample)
+Adts::ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
+                    int8_t aProfile, MP4Sample* aSample)
 {
   static const int kADTSHeaderSize = 7;
 
   size_t newSize = aSample->size + kADTSHeaderSize;
 
   // ADTS header uses 13 bits for packet size.
   if (newSize >= (1 << 13) || aChannelCount > 15 ||
       aFrequencyIndex < 0 || aProfile < 1 || aProfile > 4)
--- a/media/libstagefright/binding/include/mp4_demuxer/Adts.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Adts.h
@@ -11,14 +11,14 @@ namespace mp4_demuxer
 {
 
 class MP4Sample;
 
 class Adts
 {
 public:
   static int8_t GetFrequencyIndex(uint16_t aSamplesPerSecond);
-  static bool ConvertEsdsToAdts(uint16_t aChannelCount, int8_t aFrequencyIndex,
-                                int8_t aProfile, MP4Sample* aSample);
+  static bool ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
+                            int8_t aProfile, MP4Sample* aSample);
 };
 }
 
 #endif
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -2,17 +2,16 @@
  * 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 "include/MPEG4Extractor.h"
 #include "media/stagefright/DataSource.h"
 #include "media/stagefright/MediaDefs.h"
 #include "media/stagefright/MediaSource.h"
 #include "media/stagefright/MetaData.h"
-#include "mp4_demuxer/Adts.h"
 #include "mp4_demuxer/mp4_demuxer.h"
 #include "mp4_demuxer/Index.h"
 #include "MediaResource.h"
 
 #include <stdint.h>
 #include <algorithm>
 #include <limits>
 
@@ -170,23 +169,16 @@ MP4Demuxer::DemuxAudioSample()
     mPrivate->mAudio->read(&sample->mMediaBuffer, &mPrivate->mAudioOptions);
   mPrivate->mAudioOptions.clearSeekTo();
 
   if (status < 0) {
     return nullptr;
   }
 
   sample->Update();
-  if (!strcmp(mAudioConfig.mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
-    if (!Adts::ConvertEsdsToAdts(mAudioConfig.channel_count,
-                                 mAudioConfig.frequency_index,
-                                 mAudioConfig.aac_profile, sample)) {
-      return nullptr;
-    }
-  }
 
   return sample.forget();
 }
 
 MP4Sample*
 MP4Demuxer::DemuxVideoSample()
 {
   nsAutoPtr<MP4Sample> sample(new MP4Sample());
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -43,16 +43,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/Adts.h',
     'binding/include/mp4_demuxer/AnnexB.h',
     'binding/include/mp4_demuxer/BufferStream.h',
     'binding/include/mp4_demuxer/ByteReader.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
 ]