Bug 1319987: P4. Refactor H264 Converter. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 30 Dec 2016 21:51:42 +1100
changeset 340858 66f93142128809dc9c49dcc5a9d54f6dd08b6196
parent 340857 1a05ce09ead4d92544fe31cd24639240f60e63f4
child 340859 b2171e3e8b6971c434a1c1424fac1484fe322351
push id31317
push usercbook@mozilla.com
push dateMon, 06 Feb 2017 11:55:02 +0000
treeherdermozilla-central@c5621cb6f907 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1319987
milestone54.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 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 */
   /* ======================================================================= */