Bug 1160321 - Test whether we can create H.264/AAC decoders before we report we support them. r=mattwoodrow
authorChris Pearce <cpearce@mozilla.com>
Fri, 08 May 2015 13:36:32 +1200
changeset 242915 03dc784d54560da7a828b1b7ec5a3654507a31d5
parent 242914 4923c566a7f2adb0c143be6a2007c7b5735b5df6
child 242916 b0ebc8d237f08cff537ed569a7e7f1a5eb0d6deb
push id28713
push userkwierso@gmail.com
push dateFri, 08 May 2015 17:06:43 +0000
treeherdermozilla-central@fd5e9b7eec13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1160321
milestone40.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 1160321 - Test whether we can create H.264/AAC decoders before we report we support them. r=mattwoodrow
dom/base/nsDOMWindowUtils.cpp
dom/media/eme/MediaKeySystemAccess.cpp
dom/media/fmp4/MP4Decoder.cpp
dom/media/fmp4/MP4Decoder.h
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/MP4Reader.h
dom/media/fmp4/apple/AppleDecoderModule.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -21,17 +21,17 @@
 #include "mozilla/dom/Touch.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsFrame.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "ClientLayerManager.h"
 #include "nsQueryObject.h"
 #ifdef MOZ_FMP4
-#include "MP4Reader.h"
+#include "MP4Decoder.h"
 #endif
 
 #include "nsIScrollableFrame.h"
 
 #include "nsContentUtils.h"
 
 #include "nsIFrame.h"
 #include "nsIWidget.h"
@@ -2248,17 +2248,17 @@ nsDOMWindowUtils::GetSupportsHardwareH26
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   LayerManager *mgr = widget->GetLayerManager();
   if (!mgr)
     return NS_ERROR_FAILURE;
 
-  *retval = MP4Reader::IsVideoAccelerated(mgr->GetCompositorBackendType());
+  *retval = MP4Decoder::IsVideoAccelerated(mgr->GetCompositorBackendType());
 #else
   *retval = false;
 #endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::StartFrameTimeRecording(uint32_t *startIndex)
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -156,17 +156,18 @@ MediaKeySystemAccess::GetKeySystemStatus
        aKeySystem.EqualsLiteral("com.adobe.primetime"))) {
     // Win Vista and later only.
     if (!IsVistaOrLater()) {
       return MediaKeySystemStatus::Cdm_not_supported;
     }
     if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
       return MediaKeySystemStatus::Cdm_disabled;
     }
-    if ((!WMFDecoderModule::HasH264() || !WMFDecoderModule::HasAAC()) ||
+    if (!MP4Decoder::CanCreateH264Decoder() ||
+        !MP4Decoder::CanCreateAACDecoder() ||
         !EMEVoucherFileExists()) {
       // The system doesn't have the codecs that Adobe EME relies
       // on installed, or doesn't have a voucher for the plugin-container.
       // Adobe EME isn't going to work, so don't advertise that it will.
       return MediaKeySystemStatus::Cdm_not_supported;
     }
     return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, true);
   }
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -23,16 +23,17 @@
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "apple/AppleDecoderModule.h"
 #endif
 #ifdef MOZ_WIDGET_ANDROID
 #include "nsIGfxInfo.h"
 #include "AndroidBridge.h"
 #endif
+#include "mozilla/layers/LayersTypes.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
 {
   return new MediaDecoderStateMachine(this, new MP4Reader(this));
 }
 
@@ -59,22 +60,16 @@ static bool
 IsSupportedAudioCodec(const nsAString& aCodec,
                       bool& aOutContainsAAC,
                       bool& aOutContainsMP3)
 {
   // AAC-LC or HE-AAC in M4A.
   aOutContainsAAC = aCodec.EqualsASCII("mp4a.40.2") ||
                     aCodec.EqualsASCII("mp4a.40.5");
   if (aOutContainsAAC) {
-#ifdef XP_WIN
-    if (!Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") &&
-        !WMFDecoderModule::HasAAC()) {
-      return false;
-    }
-#endif
     return true;
   }
 #ifndef MOZ_GONK_MEDIACODEC // B2G doesn't support MP3 in MP4 yet.
   aOutContainsMP3 = aCodec.EqualsASCII("mp3");
   if (aOutContainsMP3) {
     return true;
   }
 #else
@@ -88,21 +83,16 @@ IsSupportedH264Codec(const nsAString& aC
 {
   int16_t profile = 0, level = 0;
 
   if (!ExtractH264CodecDetails(aCodec, profile, level)) {
     return false;
   }
 
 #ifdef XP_WIN
-  if (!Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") &&
-      !WMFDecoderModule::HasH264()) {
-    return false;
-  }
-
   // Disable 4k video on windows vista since it performs poorly.
   if (!IsWin7OrLater() &&
       level >= H264_LEVEL_5) {
     return false;
   }
 #endif
 
   // Just assume what we can play on all platforms the codecs/formats that
@@ -129,23 +119,25 @@ MP4Decoder::CanHandleMediaType(const nsA
                                bool& aOutContainsH264,
                                bool& aOutContainsMP3)
 {
   if (!IsEnabled()) {
     return false;
   }
 
   if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
-    return aCodecs.IsEmpty() ||
-           IsSupportedAudioCodec(aCodecs,
-                                 aOutContainsAAC,
-                                 aOutContainsMP3);
+    return MP4Decoder::CanCreateAACDecoder() &&
+           (aCodecs.IsEmpty() ||
+            IsSupportedAudioCodec(aCodecs,
+                                  aOutContainsAAC,
+                                  aOutContainsMP3));
   }
 
-  if (!aType.EqualsASCII("video/mp4")) {
+  if (!aType.EqualsASCII("video/mp4") ||
+      !MP4Decoder::CanCreateH264Decoder()) {
     return false;
   }
 
   // Verify that all the codecs specifed are ones that we expect that
   // we can play.
   nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
   bool expectMoreTokens = false;
   while (tokenizer.hasMoreTokens()) {
@@ -248,10 +240,138 @@ HavePlatformMPEGDecoders()
 /* static */
 bool
 MP4Decoder::IsEnabled()
 {
   return Preferences::GetBool("media.fragmented-mp4.enabled") &&
          HavePlatformMPEGDecoders();
 }
 
+static const uint8_t sTestH264ExtraData[] = {
+  0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64,
+  0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03,
+  0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc8, 0x3c, 0x48, 0x96,
+  0x58, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0
+};
+
+static already_AddRefed<MediaDataDecoder>
+CreateTestH264Decoder(layers::LayersBackend aBackend,
+                      VideoInfo& aConfig)
+{
+  aConfig.mMimeType = "video/avc";
+  aConfig.mId = 1;
+  aConfig.mDuration = 40000;
+  aConfig.mMediaTime = 0;
+  aConfig.mDisplay = aConfig.mImage = nsIntSize(64, 64);
+  aConfig.mExtraData = new MediaByteBuffer();
+  aConfig.mExtraData->AppendElements(sTestH264ExtraData,
+                                     MOZ_ARRAY_LENGTH(sTestH264ExtraData));
+
+  PlatformDecoderModule::Init();
+
+  nsRefPtr<PlatformDecoderModule> platform = PlatformDecoderModule::Create();
+  if (!platform) {
+    return nullptr;
+  }
+
+  nsRefPtr<MediaDataDecoder> decoder(
+    platform->CreateDecoder(aConfig, nullptr, nullptr, aBackend, nullptr));
+  if (!decoder) {
+    return nullptr;
+  }
+  nsresult rv = decoder->Init();
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return decoder.forget();
+}
+
+/* static */ bool
+MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend)
+{
+  VideoInfo config;
+  nsRefPtr<MediaDataDecoder> decoder(CreateTestH264Decoder(aBackend, config));
+  if (!decoder) {
+    return false;
+  }
+  bool result = decoder->IsHardwareAccelerated();
+  decoder->Shutdown();
+  return result;
+}
+
+/* static */ bool
+MP4Decoder::CanCreateH264Decoder()
+{
+  static bool haveCachedResult = false;
+  static bool result = false;
+  if (haveCachedResult) {
+    return result;
+  }
+  VideoInfo config;
+  nsRefPtr<MediaDataDecoder> decoder(
+    CreateTestH264Decoder(layers::LayersBackend::LAYERS_BASIC, config));
+  if (decoder) {
+    decoder->Shutdown();
+    result = true;
+  }
+  haveCachedResult = true;
+  return result;
+}
+
+static already_AddRefed<MediaDataDecoder>
+CreateTestAACDecoder(AudioInfo& aConfig)
+{
+  PlatformDecoderModule::Init();
+
+  nsRefPtr<PlatformDecoderModule> platform = PlatformDecoderModule::Create();
+  if (!platform) {
+    return nullptr;
+  }
+
+  nsRefPtr<MediaDataDecoder> decoder(
+    platform->CreateDecoder(aConfig, nullptr, nullptr));
+  if (!decoder) {
+    return nullptr;
+  }
+  nsresult rv = decoder->Init();
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return decoder.forget();
+}
+
+// bipbop.mp4's extradata/config...
+static const uint8_t sTestAACExtraData[] = {
+  0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80,
+  0x80, 0x80, 0x14, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x51, 0x00, 0x00, 0x11, 0x51, 0x05, 0x80, 0x80, 0x80,
+  0x02, 0x13, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02
+};
+
+static const uint8_t sTestAACConfig[] = { 0x13, 0x90 };
+
+/* static */ bool
+MP4Decoder::CanCreateAACDecoder()
+{
+  static bool haveCachedResult = false;
+  static bool result = false;
+  if (haveCachedResult) {
+    return result;
+  }
+  AudioInfo config;
+  config.mMimeType = "audio/mp4a-latm";
+  config.mRate = 22050;
+  config.mChannels = 2;
+  config.mBitDepth = 16;
+  config.mProfile = 2;
+  config.mExtendedProfile = 2;
+  config.mCodecSpecificConfig->AppendElements(sTestAACConfig,
+                                              MOZ_ARRAY_LENGTH(sTestAACConfig));
+  config.mExtraData->AppendElements(sTestAACExtraData,
+                                    MOZ_ARRAY_LENGTH(sTestAACExtraData));
+  nsRefPtr<MediaDataDecoder> decoder(CreateTestAACDecoder(config));
+  if (decoder) {
+    decoder->Shutdown();
+    result = true;
+  }
+  haveCachedResult = true;
+  return result;
+}
+
 } // namespace mozilla
-
--- a/dom/media/fmp4/MP4Decoder.h
+++ b/dom/media/fmp4/MP4Decoder.h
@@ -36,13 +36,17 @@ public:
                                  const nsAString& aCodecs,
                                  bool& aOutContainsAAC,
                                  bool& aOutContainsH264,
                                  bool& aOutContainsMP3);
 
   // Returns true if the MP4 backend is preffed on, and we're running on a
   // platform that is likely to have decoders for the contained formats.
   static bool IsEnabled();
+
+  static bool IsVideoAccelerated(layers::LayersBackend aBackend);
+  static bool CanCreateAACDecoder();
+  static bool CanCreateH264Decoder();
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -68,53 +68,16 @@ TrackTypeToStr(TrackInfo::TrackType aTra
   case TrackInfo::kVideoTrack:
     return "Video";
   default:
     return "Unknown";
   }
 }
 #endif
 
-uint8_t sTestExtraData[40] = { 0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03,
-                               0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc8, 0x3c, 0x48, 0x96, 0x58, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0 };
-
-/* static */ bool
-MP4Reader::IsVideoAccelerated(LayersBackend aBackend)
-{
-  VideoInfo config;
-  config.mMimeType = "video/avc";
-  config.mId = 1;
-  config.mDuration = 40000;
-  config.mMediaTime = 0;
-  config.mDisplay = config.mImage = nsIntSize(64, 64);
-  config.mExtraData = new MediaByteBuffer();
-  config.mExtraData->AppendElements(sTestExtraData, 40);
-
-  PlatformDecoderModule::Init();
-
-  nsRefPtr<PlatformDecoderModule> platform = PlatformDecoderModule::Create();
-  if (!platform) {
-    return false;
-  }
-
-  nsRefPtr<MediaDataDecoder> decoder =
-    platform->CreateDecoder(config, nullptr, nullptr, aBackend, nullptr);
-  if (!decoder) {
-    return false;
-  }
-  nsresult rv = decoder->Init();
-  NS_ENSURE_SUCCESS(rv, false);
-
-  bool result = decoder->IsHardwareAccelerated();
-
-  decoder->Shutdown();
-
-  return result;
-}
-
 bool
 AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
 {
   SPSData spsdata;
   if (H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
    uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
                          (spsdata.constraint_set1_flag ? (1 << 1) : 0) |
                          (spsdata.constraint_set2_flag ? (1 << 2) : 0) |
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -82,18 +82,16 @@ public:
   virtual nsRefPtr<ShutdownPromise> Shutdown() override;
 
   virtual bool IsAsync() const override { return true; }
 
   virtual bool VideoIsHardwareAccelerated() const override;
 
   virtual void DisableHardwareAcceleration() override;
 
-  static bool IsVideoAccelerated(layers::LayersBackend aBackend);
-
 private:
 
   bool InitDemuxer();
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   bool EnsureDecodersSetup();
 
   // Sends input to decoder for aTrack, and output to the state machine,
--- a/dom/media/fmp4/apple/AppleDecoderModule.cpp
+++ b/dom/media/fmp4/apple/AppleDecoderModule.cpp
@@ -67,17 +67,21 @@ public:
 
 AppleDecoderModule::AppleDecoderModule()
 {
 }
 
 AppleDecoderModule::~AppleDecoderModule()
 {
   nsCOMPtr<nsIRunnable> task(new UnlinkTask());
-  NS_DispatchToMainThread(task);
+  if (!NS_IsMainThread()) {
+    NS_DispatchToMainThread(task);
+  } else {
+    task->Run();
+  }
 }
 
 /* static */
 void
 AppleDecoderModule::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
 
@@ -119,16 +123,17 @@ public:
   }
 };
 
 /* static */
 nsresult
 AppleDecoderModule::CanDecode()
 {
   if (!sInitialized) {
+    // Note: We can be called on the main thread from MP4Decoder::CanHandleMediaType().
     if (NS_IsMainThread()) {
       Init();
     } else {
       nsCOMPtr<nsIRunnable> task(new InitTask());
       NS_DispatchToMainThread(task, NS_DISPATCH_SYNC);
     }
   }
 
@@ -137,18 +142,23 @@ AppleDecoderModule::CanDecode()
 
 nsresult
 AppleDecoderModule::Startup()
 {
   if (!sIsVDAAvailable && !sIsVTAvailable) {
     return NS_ERROR_FAILURE;
   }
 
+  // Note: We can be called on the main thread from MP4Decoder::CanHandleMediaType().
   nsCOMPtr<nsIRunnable> task(new LinkTask());
-  NS_DispatchToMainThread(task, NS_DISPATCH_SYNC);
+  if (!NS_IsMainThread()) {
+    NS_DispatchToMainThread(task, NS_DISPATCH_SYNC);
+  } else {
+    task->Run();
+  }
 
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
 AppleDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                        layers::LayersBackend aLayersBackend,
                                        layers::ImageContainer* aImageContainer,