Bug 1297003 - Part1-Store the error information in MediaResult while creating a/v decoders draft
authorJames Cheng <jacheng@mozilla.com>
Thu, 06 Oct 2016 11:19:56 +0800
changeset 421962 422d64feb04074b84b4dd0ad99a8d46f8fcc0d93
parent 421961 6f6801f54179e1b6788ea7c56434f65f1461507d
child 533213 a7ec1ca400e1330a98ce79afe3ff6709a0eed9ba
push id31644
push userbmo:jacheng@mozilla.com
push dateFri, 07 Oct 2016 05:07:34 +0000
bugs1297003
milestone52.0a1
Bug 1297003 - Part1-Store the error information in MediaResult while creating a/v decoders MozReview-Commit-ID: I6R4bX778n7
dom/media/MediaFormatReader.cpp
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/PlatformDecoderModule.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -375,20 +375,23 @@ MediaFormatReader::OnDemuxerInitFailed(c
 }
 
 MediaResult
 MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!IsSuspended());
 
+  auto decoderCreatingError = "error creating decoder";
+  MediaResult result = MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, decoderCreatingError);
   auto& decoder = GetDecoderData(aTrack);
 
   if (decoder.mDecoder) {
-    return NS_OK;
+    result = NS_OK;
+    return result;
   }
 
   if (!mPlatform) {
     mPlatform = new PDMFactory();
     if (IsEncrypted()) {
       MOZ_ASSERT(mCDMProxy);
       mPlatform->SetCDMProxy(mCDMProxy);
     }
@@ -400,44 +403,48 @@ MediaFormatReader::EnsureDecoderCreated(
 
   switch (aTrack) {
     case TrackType::kAudioTrack: {
       decoder.mDecoder = mPlatform->CreateDecoder({
         decoder.mInfo ? *decoder.mInfo->GetAsAudioInfo() : mInfo.mAudio,
         decoder.mTaskQueue,
         decoder.mCallback.get(),
         mCrashHelper,
-        decoder.mIsBlankDecode
+        decoder.mIsBlankDecode,
+        &result
       });
       break;
     }
 
     case TrackType::kVideoTrack: {
       // Decoders use the layers backend to decide if they can use hardware decoding,
       // so specify LAYERS_NONE if we want to forcibly disable it.
       decoder.mDecoder = mPlatform->CreateDecoder({
         mVideo.mInfo ? *mVideo.mInfo->GetAsVideoInfo() : mInfo.mVideo,
         decoder.mTaskQueue,
         decoder.mCallback.get(),
         mLayersBackendType,
         GetImageContainer(),
         mCrashHelper,
-        decoder.mIsBlankDecode
+        decoder.mIsBlankDecode,
+        &result
       });
       break;
     }
     default:
       break;
   }
-  if (decoder.mDecoder ) {
+  if (decoder.mDecoder) {
     decoder.mDescription = decoder.mDecoder->GetDescriptionName();
-    return NS_OK;
+    result = MediaResult(NS_OK);
+    return result;
   }
-  decoder.mDescription = "error creating decoder";
-  return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "error creating decoder");
+
+  decoder.mDescription = decoderCreatingError;
+  return result;
 }
 
 bool
 MediaFormatReader::EnsureDecoderInitialized(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_DIAGNOSTIC_ASSERT(!IsSuspended());
 
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -78,24 +78,40 @@ public:
 };
 
 StaticAutoPtr<PDMFactoryImpl> PDMFactory::sInstance;
 StaticMutex PDMFactory::sMonitor;
 
 class SupportChecker
 {
 public:
-  enum class Result : uint8_t
+  enum class Reason : uint8_t
   {
     kSupported,
     kVideoFormatNotSupported,
     kAudioFormatNotSupported,
     kUnknown,
   };
 
+  struct CheckResult
+  {
+    explicit CheckResult(Reason aReason,
+                         MediaResult aResult = MediaResult(NS_OK))
+      : mReason(aReason),
+        mMediaResult(mozilla::Move(aResult))
+    {}
+    CheckResult(const CheckResult& aOther) = default;
+    CheckResult(CheckResult&& aOther) = default;
+    CheckResult& operator=(const CheckResult& aOther) = default;
+    CheckResult& operator=(CheckResult&& aOther) = default;
+
+    Reason mReason;
+    MediaResult mMediaResult;
+  };
+
   template<class Func>
   void
   AddToCheckList(Func&& aChecker)
   {
     mCheckerList.AppendElement(mozilla::Forward<Func>(aChecker));
   }
 
   void
@@ -108,40 +124,44 @@ public:
       [mimeType, extraData]() {
         if (MP4Decoder::IsH264(mimeType)) {
           mp4_demuxer::SPSData spsdata;
           // WMF H.264 Video Decoder and Apple ATDecoder
           // do not support YUV444 format.
           // For consistency, all decoders should be checked.
           if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) &&
               spsdata.chroma_format_idc == PDMFactory::kYUV444) {
-            return SupportChecker::Result::kVideoFormatNotSupported;
+            return CheckResult(SupportChecker::Reason::kVideoFormatNotSupported,
+                               MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                                           RESULT_DETAIL("Decoder may not have the capability to handle"
+                                                         " the requested video format"
+                                                         " with YUV444 chroma subsampling.")));
           }
         }
-        return SupportChecker::Result::kSupported;
+        return CheckResult(SupportChecker::Reason::kSupported);
       });
     }
   }
 
-  SupportChecker::Result
+  SupportChecker::CheckResult
   Check()
   {
     for (auto& checker : mCheckerList) {
       auto result = checker();
-        if (result != SupportChecker::Result::kSupported) {
+        if (result.mReason != SupportChecker::Reason::kSupported) {
           return result;
       }
     }
-    return SupportChecker::Result::kSupported;
+    return CheckResult(SupportChecker::Reason::kSupported);
   }
 
   void Clear() { mCheckerList.Clear(); }
 
 private:
-  nsTArray<mozilla::function<SupportChecker::Result()>> mCheckerList;
+  nsTArray<mozilla::function<CheckResult()>> mCheckerList;
 }; // SupportChecker
 
 PDMFactory::PDMFactory()
 {
   EnsureInit();
   CreatePDMs();
   CreateBlankPDM();
 }
@@ -224,40 +244,51 @@ PDMFactory::CreateDecoder(const CreateDe
 }
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                                  const CreateDecoderParams& aParams)
 {
   MOZ_ASSERT(aPDM);
   RefPtr<MediaDataDecoder> m;
+  MediaResult* result = aParams.mError;
 
   SupportChecker supportChecker;
   const TrackInfo& config = aParams.mConfig;
   supportChecker.AddMediaFormatChecker(config);
 
-  auto reason = supportChecker.Check();
-  if (reason != SupportChecker::Result::kSupported) {
+  auto checkResult = supportChecker.Check();
+  if (checkResult.mReason != SupportChecker::Reason::kSupported) {
     DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
-    if (diagnostics) {
-      if (reason == SupportChecker::Result::kVideoFormatNotSupported) {
+    if (checkResult.mReason == SupportChecker::Reason::kVideoFormatNotSupported) {
+      if (diagnostics) {
         diagnostics->SetVideoNotSupported();
-      } else if (reason == SupportChecker::Result::kAudioFormatNotSupported) {
+      }
+      if (result) {
+        *result = checkResult.mMediaResult;
+      }
+    } else if (checkResult.mReason == SupportChecker::Reason::kAudioFormatNotSupported) {
+      if (diagnostics) {
         diagnostics->SetAudioNotSupported();
       }
+      if (result) {
+        *result = checkResult.mMediaResult;
+      }
     }
     return nullptr;
   }
 
   if (config.IsAudio()) {
     m = aPDM->CreateAudioDecoder(aParams);
     return m.forget();
   }
 
   if (!config.IsVideo()) {
+    *result = MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                          RESULT_DETAIL("Decoder configuration error, expected audio or video."));
     return nullptr;
   }
 
   MediaDataDecoderCallback* callback = aParams.mCallback;
   RefPtr<DecoderCallbackFuzzingWrapper> callbackWrapper;
   if (MediaPrefs::PDMFuzzingEnabled()) {
     callbackWrapper = new DecoderCallbackFuzzingWrapper(callback);
     callbackWrapper->SetVideoOutputMinimumInterval(
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -29,17 +29,17 @@ class ImageContainer;
 
 class MediaDataDecoder;
 class MediaDataDecoderCallback;
 class TaskQueue;
 class CDMProxy;
 
 static LazyLogModule sPDMLog("PlatformDecoderModule");
 
-struct CreateDecoderParams {
+struct MOZ_STACK_CLASS CreateDecoderParams final {
   explicit CreateDecoderParams(const TrackInfo& aConfig)
     : mConfig(aConfig)
   {}
 
   template <typename T1, typename... Ts>
   CreateDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args)
     : mConfig(aConfig)
   {
@@ -58,25 +58,27 @@ struct CreateDecoderParams {
     return *mConfig.GetAsAudioInfo();
   }
 
   const TrackInfo& mConfig;
   TaskQueue* mTaskQueue = nullptr;
   MediaDataDecoderCallback* mCallback = nullptr;
   DecoderDoctorDiagnostics* mDiagnostics = nullptr;
   layers::ImageContainer* mImageContainer = nullptr;
+  MediaResult* mError = nullptr;
   layers::LayersBackend mLayersBackend = layers::LayersBackend::LAYERS_NONE;
   RefPtr<GMPCrashHelper> mCrashHelper;
   bool mUseBlankDecoder = false;
 
 private:
   void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
   void Set(MediaDataDecoderCallback* aCallback) { mCallback = aCallback; }
   void Set(DecoderDoctorDiagnostics* aDiagnostics) { mDiagnostics = aDiagnostics; }
   void Set(layers::ImageContainer* aImageContainer) { mImageContainer = aImageContainer; }
+  void Set(MediaResult* aError) { mError = aError; }
   void Set(layers::LayersBackend aLayersBackend) { mLayersBackend = aLayersBackend; }
   void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
   void Set(bool aUseBlankDecoder) { mUseBlankDecoder = aUseBlankDecoder; }
   template <typename T1, typename T2, typename... Ts>
   void Set(T1&& a1, T2&& a2, Ts&&... args)
   {
     Set(mozilla::Forward<T1>(a1));
     Set(mozilla::Forward<T2>(a2), mozilla::Forward<Ts>(args)...);