Bug 1319987: P4. Refactor H264 Converter. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 30 Dec 2016 21:51:42 +1100
changeset 479282 66f93142128809dc9c49dcc5a9d54f6dd08b6196
parent 479281 1a05ce09ead4d92544fe31cd24639240f60e63f4
child 479283 b2171e3e8b6971c434a1c1424fac1484fe322351
push id44211
push userbmo:hskupin@gmail.com
push dateMon, 06 Feb 2017 12:18:11 +0000
reviewerscpearce
bugs1319987
milestone54.0a1
Bug 1319987: P4. Refactor H264 Converter. r=cpearce We can make some assumptions now that the Input method is only called once and never again while a decode is pending. MozReview-Commit-ID: EmzKEcwNY2J
dom/media/platforms/wrappers/H264Converter.cpp
dom/media/platforms/wrappers/H264Converter.h
xpcom/base/ErrorList.h
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -47,57 +47,48 @@ H264Converter::Init()
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
 void
 H264Converter::Input(MediaRawData* aSample)
 {
+  MOZ_RELEASE_ASSERT(!mInitPromiseRequest.Exists(),
+                     "Still processing previous sample");
+
   if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
     // We need AVCC content to be able to later parse the SPS.
     // This is a no-op if the data is already AVCC.
     mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
                                  RESULT_DETAIL("ConvertSampleToAVCC")));
     return;
   }
 
-  if (mInitPromiseRequest.Exists()) {
-    if (mNeedKeyframe) {
-      if (!aSample->mKeyframe) {
-        // Frames dropped, we need a new one.
-        mCallback->InputExhausted();
-        return;
-      }
-      mNeedKeyframe = false;
-    }
-    mMediaRawSamples.AppendElement(aSample);
-    return;
-  }
-
   nsresult rv;
   if (!mDecoder) {
     // It is not possible to create an AVCC H264 decoder without SPS.
     // As such, creation will fail if the extra_data just extracted doesn't
     // contain a SPS.
     rv = CreateDecoderAndInit(aSample);
     if (rv == NS_ERROR_NOT_INITIALIZED) {
       // We are missing the required SPS to create the decoder.
       // Ignore for the time being, the MediaRawData will be dropped.
       mCallback->InputExhausted();
       return;
     }
   } else {
     rv = CheckForSPSChange(aSample);
-    if (rv == NS_ERROR_NOT_INITIALIZED) {
-      // The decoder is pending initialization.
-      mCallback->InputExhausted();
-      return;
-    }
   }
+
+  if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
+    // The decoder is pending initialization.
+    return;
+  }
+
   if (NS_FAILED(rv)) {
     mCallback->Error(
       MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                   RESULT_DETAIL("Unable to create H264 decoder")));
     return;
   }
 
   if (mNeedKeyframe && !aSample->mKeyframe) {
@@ -224,58 +215,49 @@ H264Converter::CreateDecoderAndInit(Medi
     return NS_ERROR_NOT_INITIALIZED;
   }
   UpdateConfigFromExtraData(extra_data);
 
   nsresult rv = CreateDecoder(/* DecoderDoctorDiagnostics* */ nullptr);
 
   if (NS_SUCCEEDED(rv)) {
     // Queue the incoming sample.
-    mMediaRawSamples.AppendElement(aSample);
+    mPendingSample = aSample;
 
     mDecoder->Init()
       ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
              &H264Converter::OnDecoderInitDone,
              &H264Converter::OnDecoderInitFailed)
       ->Track(mInitPromiseRequest);
-    return NS_ERROR_NOT_INITIALIZED;
+    return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
   }
   return rv;
 }
 
 void
 H264Converter::OnDecoderInitDone(const TrackType aTrackType)
 {
   mInitPromiseRequest.Complete();
-  bool gotInput = false;
-  for (uint32_t i = 0 ; i < mMediaRawSamples.Length(); i++) {
-    const RefPtr<MediaRawData>& sample = mMediaRawSamples[i];
-    if (mNeedKeyframe) {
-      if (!sample->mKeyframe) {
-        continue;
-      }
-      mNeedKeyframe = false;
-    }
-    if (!mNeedAVCC &&
-        !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
-      mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
-                                   RESULT_DETAIL("ConvertSampleToAnnexB")));
-      mMediaRawSamples.Clear();
-      return;
-    }
-    mDecoder->Input(sample);
+  RefPtr<MediaRawData> sample = mPendingSample.forget();
+  if (mNeedKeyframe && !sample->mKeyframe) {
+    mCallback->InputExhausted();
+    return;
   }
-  if (!gotInput) {
-    mCallback->InputExhausted();
+  mNeedKeyframe = false;
+  if (!mNeedAVCC &&
+      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
+    mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY,
+                                  RESULT_DETAIL("ConvertSampleToAnnexB")));
+    return;
   }
-  mMediaRawSamples.Clear();
+  mDecoder->Input(sample);
 }
 
 void
-H264Converter::OnDecoderInitFailed(MediaResult aError)
+H264Converter::OnDecoderInitFailed(const MediaResult& aError)
 {
   mInitPromiseRequest.Complete();
   mCallback->Error(
     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                 RESULT_DETAIL("Unable to initialize H264 decoder")));
 }
 
 nsresult
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -54,24 +54,24 @@ private:
   // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
   // will set mError accordingly.
   nsresult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);
   nsresult CreateDecoderAndInit(MediaRawData* aSample);
   nsresult CheckForSPSChange(MediaRawData* aSample);
   void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
 
   void OnDecoderInitDone(const TrackType aTrackType);
-  void OnDecoderInitFailed(MediaResult aError);
+  void OnDecoderInitFailed(const MediaResult& aError);
 
   RefPtr<PlatformDecoderModule> mPDM;
   VideoInfo mCurrentConfig;
   RefPtr<layers::KnowsCompositor> mKnowsCompositor;
   RefPtr<layers::ImageContainer> mImageContainer;
   const RefPtr<TaskQueue> mTaskQueue;
-  nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
+  RefPtr<MediaRawData> mPendingSample;
   MediaDataDecoderCallback* mCallback;
   RefPtr<MediaDataDecoder> mDecoder;
   MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
   RefPtr<GMPCrashHelper> mGMPCrashHelper;
   bool mNeedAVCC;
   nsresult mLastError;
   bool mNeedKeyframe = true;
 };
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -982,16 +982,17 @@
   ERROR(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,        FAILURE(7)),
   ERROR(NS_ERROR_DOM_MEDIA_END_OF_STREAM,       FAILURE(8)),
   ERROR(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA,    FAILURE(9)),
   ERROR(NS_ERROR_DOM_MEDIA_CANCELED,            FAILURE(10)),
   ERROR(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR,       FAILURE(11)),
   ERROR(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,         FAILURE(12)),
   ERROR(NS_ERROR_DOM_MEDIA_CDM_ERR,             FAILURE(13)),
   ERROR(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,    FAILURE(14)),
+  ERROR(NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER, FAILURE(15)),
 
   /* Internal platform-related errors */
   ERROR(NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR,  FAILURE(101)),
 #undef MODULE
 
   /* ======================================================================= */
   /* 42: NS_ERROR_MODULE_URL_CLASSIFIER */
   /* ======================================================================= */