Bug 1315144 - Add new non-fatal media error so that we recreate decoders when the GPU process crashes. r=jya
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 08 Nov 2016 15:22:37 +1300
changeset 321733 d76e0d2be865f40a4bf86fddd1d5430f74b7b5bf
parent 321732 95ab9f05b980662a420d6d664c1996c0dfb8e4c8
child 321734 4d4ee97ad221f9700e228d0f75839a680c0ddba5
push id83661
push usermwoodrow@mozilla.com
push dateWed, 09 Nov 2016 02:49:51 +0000
treeherdermozilla-inbound@d76e0d2be865 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1315144
milestone52.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 1315144 - Add new non-fatal media error so that we recreate decoders when the GPU process crashes. r=jya
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/ipc/VideoDecoderChild.cpp
xpcom/base/ErrorList.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1507,26 +1507,30 @@ MediaFormatReader::Update(TrackType aTra
 
   if (decoder.mNeedDraining) {
     DrainDecoder(aTrack);
     return;
   }
 
   if (decoder.mError && !decoder.HasFatalError()) {
     decoder.mDecodePending = false;
-    if (++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
+    bool needsNewDecoder = decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
+    if (!needsNewDecoder && ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
       NotifyError(aTrack, decoder.mError.ref());
       return;
     }
     decoder.mError.reset();
     LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
                                      decoder.mNumOfConsecutiveError);
     media::TimeUnit nextKeyframe;
     if (aTrack == TrackType::kVideoTrack && !decoder.HasInternalSeekPending() &&
         NS_SUCCEEDED(decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe))) {
+      if (needsNewDecoder) {
+        decoder.ShutdownDecoder();
+      }
       SkipVideoDemuxToNextKeyFrame(decoder.mLastSampleTime.refOr(TimeInterval()).Length());
       return;
     } else if (aTrack == TrackType::kAudioTrack) {
       decoder.Flush();
     }
   }
 
   bool needInput = NeedInput(decoder);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -323,19 +323,31 @@ private:
     }
 
     uint32_t mNumOfConsecutiveError;
     uint32_t mMaxConsecutiveError;
 
     Maybe<MediaResult> mError;
     bool HasFatalError() const
     {
-      return mError.isSome() &&
-             (mError.ref() != NS_ERROR_DOM_MEDIA_DECODE_ERR ||
-              mNumOfConsecutiveError > mMaxConsecutiveError);
+      if (!mError.isSome()) {
+        return false;
+      }
+      if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) {
+        // Allow decode errors to be non-fatal, but give up
+        // if we have too many.
+        return mNumOfConsecutiveError > mMaxConsecutiveError;
+      } else if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {
+        // If the caller asked for a new decoder we shouldn't treat
+        // it as fatal.
+        return false;
+      } else {
+        // All other error types are fatal
+        return true;
+      }
     }
 
     // If set, all decoded samples prior mTimeThreshold will be dropped.
     // Used for internal seeking when a change of stream is detected or when
     // encountering data discontinuity.
     Maybe<InternalSeekTarget> mTimeThreshold;
     // Time of last sample returned.
     Maybe<media::TimeInterval> mLastSampleTime;
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -103,19 +103,19 @@ void
 VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (aWhy == AbnormalShutdown) {
     // Defer reporting an error until we've recreated the manager so that
     // it'll be safe for MediaFormatReader to recreate decoders
     RefPtr<VideoDecoderChild> ref = this;
     GetManager()->RunWhenRecreated(NS_NewRunnableFunction([=]() {
       if (ref->mInitialized) {
-        ref->mCallback->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR);
+        ref->mCallback->Error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
       } else {
-        ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__);
+        ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
       }
     }));
   }
   mCanSend = false;
 }
 
 void
 VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback,
--- a/xpcom/base/ErrorList.h
+++ b/xpcom/base/ErrorList.h
@@ -977,16 +977,17 @@
   ERROR(NS_ERROR_DOM_MEDIA_METADATA_ERR,        FAILURE(6)),
   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)),
 
   /* Internal platform-related errors */
   ERROR(NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR,  FAILURE(101)),
 #undef MODULE
 
   /* ======================================================================= */
   /* 51: NS_ERROR_MODULE_GENERAL */
   /* ======================================================================= */