Bug 1299105 - Part1 - Check if the decoder support recycling to prevent from recreating decoder. draft
authorJames Cheng <jacheng@mozilla.com>
Fri, 25 Nov 2016 14:22:40 +0800
changeset 445723 ddad57dc971a5bc879909dc9b17a51353966610f
parent 445717 a69583d2dbc6fdc18f63761a89cf539c356668be
child 445724 03ba6c7d043dee69e44c18d61a1794862a589b9b
child 445731 0a7bb68ddccee95c6f2e7a5e906caa32a6dd34eb
push id37594
push userbmo:jacheng@mozilla.com
push dateWed, 30 Nov 2016 05:29:49 +0000
bugs1299105
milestone53.0a1
Bug 1299105 - Part1 - Check if the decoder support recycling to prevent from recreating decoder. MozReview-Commit-ID: 7Xj6tSnGM81
dom/media/MediaFormatReader.cpp
dom/media/platforms/PlatformDecoderModule.h
dom/media/platforms/android/MediaCodecDataDecoder.cpp
dom/media/platforms/android/RemoteDataDecoder.cpp
dom/media/platforms/wrappers/H264Converter.cpp
dom/media/platforms/wrappers/H264Converter.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -259,16 +259,20 @@ public:
   const char* GetDescriptionName() const override
   {
     return mDecoder->GetDescriptionName();
   }
   void SetSeekThreshold(const media::TimeUnit& aTime) override
   {
     mDecoder->SetSeekThreshold(aTime);
   }
+  bool SupportDecoderRecycling() const override
+  {
+    return mDecoder->SupportDecoderRecycling();
+  }
   void Shutdown() override
   {
     mDecoder->Shutdown();
     mDecoder = nullptr;
     mToken = nullptr;
   }
 
 private:
@@ -1297,39 +1301,48 @@ MediaFormatReader::HandleDemuxedSamples(
     RefPtr<SharedTrackInfo> info = sample->mTrackInfo;
 
     if (info && decoder.mLastStreamSourceID != info->GetID()) {
       if (samplesPending) {
         // Let existing samples complete their decoding. We'll resume later.
         return;
       }
 
+      bool supportRecycling = decoder.mDecoder->SupportDecoderRecycling();
       if (decoder.mNextStreamSourceID.isNothing() ||
           decoder.mNextStreamSourceID.ref() != info->GetID()) {
-        LOG("%s stream id has changed from:%d to:%d, draining decoder.",
+        if (!supportRecycling) {
+          LOG("%s stream id has changed from:%d to:%d, draining decoder.",
             TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
             info->GetID());
-        decoder.mNeedDraining = true;
-        decoder.mNextStreamSourceID = Some(info->GetID());
-        ScheduleUpdate(aTrack);
-        return;
+          decoder.mNeedDraining = true;
+          decoder.mNextStreamSourceID = Some(info->GetID());
+          ScheduleUpdate(aTrack);
+          return;
+        }
       }
 
-      LOG("%s stream id has changed from:%d to:%d, recreating decoder.",
+      LOG("%s stream id has changed from:%d to:%d.",
           TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
           info->GetID());
       decoder.mLastStreamSourceID = info->GetID();
       decoder.mNextStreamSourceID.reset();
-      // Reset will clear our array of queued samples. So make a copy now.
-      nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
-      Reset(aTrack);
-      decoder.ShutdownDecoder();
+      if (!supportRecycling) {
+        LOG("Decoder does not support recycling, recreate decoder.");
+        // Reset will clear our array of queued samples. So make a copy now.
+        nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
+        Reset(aTrack);
+        decoder.ShutdownDecoder();
+        if (sample->mKeyframe) {
+          decoder.mQueuedSamples.AppendElements(Move(samples));
+        }
+      }
+
       decoder.mInfo = info;
       if (sample->mKeyframe) {
-        decoder.mQueuedSamples.AppendElements(Move(samples));
         ScheduleUpdate(aTrack);
       } else {
         TimeInterval time =
           TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
                        TimeUnit::FromMicroseconds(sample->GetEndTime()));
         InternalSeekTarget seekTarget =
           decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
         LOG("Stream change occurred on a non-keyframe. Seeking to:%lld",
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -292,13 +292,19 @@ public:
 
   // Set a hint of seek target time to decoder. Decoder will drop any decoded
   // data which pts is smaller than this value. This threshold needs to be clear
   // after reset decoder.
   // Decoder may not honor this value. However, it'd be better that
   // video decoder implements this API to improve seek performance.
   // Note: it should be called before Input() or after Flush().
   virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
+
+  // When playing adaptive playback, recreating an Android video decoder will
+  // cause the transition not smooth during resolution change.
+  // Reuse the decoder if the decoder support recycling.
+  // Currently, only Android video decoder will return true.
+  virtual bool SupportDecoderRecycling() const { return false; }
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/platforms/android/MediaCodecDataDecoder.cpp
+++ b/dom/media/platforms/android/MediaCodecDataDecoder.cpp
@@ -118,16 +118,18 @@ public:
                                  presentationTimeUs,
                                  gfx::IntRect(0, 0,
                                               mConfig.mDisplay.width,
                                               mConfig.mDisplay.height));
     INVOKE_CALLBACK(Output, v);
     return NS_OK;
   }
 
+  bool SupportDecoderRecycling() const override { return true; }
+
 protected:
   layers::ImageContainer* mImageContainer;
   const VideoInfo& mConfig;
   RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
   RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
 };
 
 
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -240,16 +240,18 @@ public:
   }
 
   void Input(MediaRawData* aSample) override
   {
     RemoteDataDecoder::Input(aSample);
     mInputDurations.Put(aSample->mDuration);
   }
 
+  bool SupportDecoderRecycling() const override { return true; }
+
 private:
   class DurationQueue {
   public:
 
     void Clear()
     {
       mValues.clear();
     }
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -280,16 +280,23 @@ H264Converter::CheckForSPSChange(MediaRa
 {
   RefPtr<MediaByteBuffer> extra_data =
     mp4_demuxer::AnnexB::ExtractExtraData(aSample);
   if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
       mp4_demuxer::AnnexB::CompareExtraData(extra_data,
                                             mCurrentConfig.mExtraData)) {
         return NS_OK;
       }
+
+   if (mDecoder->SupportDecoderRecycling()) {
+    // Do not recreate the decoder, reuse it.
+    UpdateConfigFromExtraData(extra_data);
+    mNeedKeyframe = true;
+    return NS_OK;
+  }
   // The SPS has changed, signal to flush the current decoder and create a
   // new one.
   mDecoder->Flush();
   Shutdown();
   return CreateDecoderAndInit(aSample);
 }
 
 void
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -34,16 +34,23 @@ public:
   const char* GetDescriptionName() const override
   {
     if (mDecoder) {
       return mDecoder->GetDescriptionName();
     }
     return "H264Converter decoder (pending)";
   }
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
+  bool SupportDecoderRecycling() const override
+  {
+    if (mDecoder) {
+      return mDecoder->SupportDecoderRecycling();
+    }
+    return false;
+  }
 
   nsresult GetLastError() const { return mLastError; }
 
 private:
   // Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
   // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
   // will set mError accordingly.
   nsresult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);