Bug 1112445 - Ignore the audio stream when determining whether we should skip-t-o-next-keyframe for async readers. r=mattwoodrow, a=sledru
authorChris Pearce <cpearce@mozilla.com>
Tue, 13 Jan 2015 22:31:03 +1300
changeset 242882 f82a118e1064
parent 242881 ee9df2674663
child 242883 53ae5eeb6147
push id4328
push userryanvm@gmail.com
push date2015-01-15 22:26 +0000
treeherdermozilla-beta@c8031be76a86 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, sledru
bugs1112445
milestone36.0
Bug 1112445 - Ignore the audio stream when determining whether we should skip-t-o-next-keyframe for async readers. r=mattwoodrow, a=sledru
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/fmp4/MP4Reader.h
dom/media/mediasource/MediaSourceReader.h
dom/media/omx/MediaCodecReader.h
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -238,16 +238,22 @@ public:
   MediaTaskQueue* GetTaskQueue() {
     return mTaskQueue;
   }
 
   void ClearDecoder() {
     mDecoder = nullptr;
   }
 
+  // Returns true if the reader implements RequestAudioData()
+  // and RequestVideoData() asynchronously, rather than using the
+  // implementation in this class to adapt the old synchronous to
+  // the newer async model.
+  virtual bool IsAsync() const { return false; }
+
 protected:
   virtual ~MediaDecoderReader();
 
   // Overrides of this function should decodes an unspecified amount of
   // audio data, enqueuing the audio data in mAudioQueue. Returns true
   // when there's more audio to decode, false if the audio is finished,
   // end of file has been reached, or an un-recoverable read error has
   // occured. This function blocks until the decode is complete.
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -615,25 +615,30 @@ MediaDecoderStateMachine::NeedToSkipToNe
     return false;
   }
 
   // We'll skip the video decode to the nearest keyframe if we're low on
   // audio, or if we're low on video, provided we're not running low on
   // data to decode. If we're running low on downloaded data to decode,
   // we won't start keyframe skipping, as we'll be pausing playback to buffer
   // soon anyway and we'll want to be able to display frames immediately
-  // after buffering finishes.
-  bool isLowOnDecodedAudio = !mIsAudioPrerolling && IsAudioDecoding() &&
+  // after buffering finishes. We ignore the low audio calculations for
+  // readers that are async, as since their audio decode runs on a different
+  // task queue it should never run low and skipping won't help their decode.
+  bool isLowOnDecodedAudio = !mReader->IsAsync() &&
+                             !mIsAudioPrerolling && IsAudioDecoding() &&
                              (GetDecodedAudioDuration() <
                               mLowAudioThresholdUsecs * mPlaybackRate);
   bool isLowOnDecodedVideo = !mIsVideoPrerolling &&
                              (mDecodedVideoEndTime - GetClock() <
                               LOW_VIDEO_THRESHOLD_USECS * mPlaybackRate);
-  if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !HasLowUndecodedData()) {
-    DECODER_LOG("Skipping video decode to the next keyframe");
+  bool lowUndecoded = HasLowUndecodedData();
+  if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowUndecoded) {
+    DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
+                isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReader->IsAsync());
     return true;
   }
 
   return false;
 }
 
 void
 MediaDecoderStateMachine::DecodeVideo()
@@ -995,20 +1000,24 @@ MediaDecoderStateMachine::OnVideoDecoded
     }
 
     case DECODER_STATE_BUFFERING:
       // If we're buffering, this may be the sample we need to stop buffering.
       // Schedule the state machine and then fall through.
       ScheduleStateMachine();
     case DECODER_STATE_DECODING: {
       Push(video);
-      // If the requested video sample was slow to arrive, increase the
-      // amount of audio we buffer to ensure that we don't run out of audio.
-      // TODO: Detect when we're truly async, and don't do this if so, as
-      // it's not necessary.
+      // For non async readers, if the requested video sample was slow to
+      // arrive, increase the amount of audio we buffer to ensure that we
+      // don't run out of audio. This is unnecessary for async readers,
+      // since they decode audio and video on different threads so they
+      // are unlikely to run out of decoded audio.
+      if (mReader->IsAsync()) {
+        return;
+      }
       TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
       if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
           !HasLowUndecodedData())
       {
         mLowAudioThresholdUsecs =
           std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), AMPLE_AUDIO_USECS);
         mAmpleAudioThresholdUsecs = std::max(THRESHOLD_FACTOR * mLowAudioThresholdUsecs,
                                               mAmpleAudioThresholdUsecs);
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -77,16 +77,18 @@ public:
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
   virtual void SetSharedDecoderManager(SharedDecoderManager* aManager)
     MOZ_OVERRIDE;
 
   virtual nsresult ResetDecode() MOZ_OVERRIDE;
 
   virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
 
+  virtual bool IsAsync() const MOZ_OVERRIDE { return true; }
+
 private:
 
   bool InitDemuxer();
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   // Sends input to decoder for aTrack, and output to the state machine,
   // if necessary.
   void Update(TrackType aTrack);
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -125,16 +125,21 @@ public:
 
   // Return true if the Ended method has been called
   bool IsEnded();
 
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
+  virtual bool IsAsync() const MOZ_OVERRIDE {
+    return (!mAudioReader || mAudioReader->IsAsync()) &&
+           (!mVideoReader || mVideoReader->IsAsync());
+  }
+
 private:
   // Switch the current audio/video reader to the reader that
   // contains aTarget (or up to aError after target). Both
   // aTarget and aError are in microseconds.
   bool SwitchAudioReader(int64_t aTarget, int64_t aError = 0);
   bool SwitchVideoReader(int64_t aTarget, int64_t aError = 0);
   void RequestAudioDataComplete(int64_t aTime);
   void RequestAudioDataFailed(nsresult aResult);
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -105,16 +105,18 @@ public:
        int64_t aStartTime,
        int64_t aEndTime,
        int64_t aCurrentTime) MOZ_OVERRIDE;
 
   virtual bool IsMediaSeekable() MOZ_OVERRIDE;
 
   virtual android::sp<android::MediaSource> GetAudioOffloadTrack();
 
+  virtual bool IsAsync() const MOZ_OVERRIDE { return true; }
+
 protected:
   struct TrackInputCopier
   {
     virtual ~TrackInputCopier();
 
     virtual bool Copy(android::MediaBuffer* aSourceBuffer,
                       android::sp<android::ABuffer> aCodecBuffer);
   };