Bug 1127641 - Reduce MDSM video frame queue length when hardware accelerated. r=kentuckyfriedtakahe a=lmandel
authorChris Pearce <cpearce@mozilla.com>
Mon, 02 Feb 2015 09:28:41 +1300
changeset 249600 728fd3c8cac4c5110609c3d3d2ae0bfb2fd55a43
parent 249599 119e1958a0cdf5be841c5ee66241908a541c1540
child 249601 47a93c546ccf24c25932d61e5ac5aa8c1a5180ec
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe, lmandel
bugs1127641
milestone37.0a2
Bug 1127641 - Reduce MDSM video frame queue length when hardware accelerated. r=kentuckyfriedtakahe a=lmandel
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaInfo.h
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/PlatformDecoderModule.h
dom/media/fmp4/SharedDecoderManager.cpp
dom/media/fmp4/SharedDecoderManager.h
dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
dom/media/fmp4/wmf/WMFMediaDataDecoder.h
dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
dom/media/fmp4/wmf/WMFVideoMFTManager.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -186,16 +186,22 @@ static const uint64_t ESTIMATED_DURATION
 static TimeDuration UsecsToDuration(int64_t aUsecs) {
   return TimeDuration::FromMicroseconds(aUsecs);
 }
 
 static int64_t DurationToUsecs(TimeDuration aDuration) {
   return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
 }
 
+static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
+static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
+
+static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
+static uint32_t sVideoQueueHWAccelSize = MIN_VIDEO_QUEUE_SIZE;
+
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mScheduler(new MediaDecoderStateMachineScheduler(
       aDecoder->GetReentrantMonitor(),
       &MediaDecoderStateMachine::TimeoutExpired, this, aRealTime)),
   mState(DECODER_STATE_DECODING_NONE),
@@ -211,17 +217,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mAudioStartTime(-1),
   mAudioEndTime(-1),
   mDecodedAudioEndTime(-1),
   mVideoFrameEndTime(-1),
   mDecodedVideoEndTime(-1),
   mVolume(1.0),
   mPlaybackRate(1.0),
   mPreservesPitch(true),
-  mAmpleVideoFrames(2),
+  mAmpleVideoFrames(MIN_VIDEO_QUEUE_SIZE),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
   mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
   mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
   mIsAudioPrerolling(false),
   mIsVideoPrerolling(false),
   mAudioRequestStatus(RequestStatus::Idle),
   mVideoRequestStatus(RequestStatus::Idle),
   mAudioCaptured(false),
@@ -242,18 +248,26 @@ MediaDecoderStateMachine::MediaDecoderSt
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
   mDecodingFrozenAtStateDecoding(false),
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
-  mAmpleVideoFrames =
-    std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
+  static bool sPrefCacheInit = false;
+  if (!sPrefCacheInit) {
+    sPrefCacheInit = true;
+    Preferences::AddUintVarCache(&sVideoQueueDefaultSize,
+                                 "media.video-queue.default-size",
+                                 MAX_VIDEO_QUEUE_SIZE);
+    Preferences::AddUintVarCache(&sVideoQueueHWAccelSize,
+                                 "media.video-queue.hw-accel-size",
+                                 MIN_VIDEO_QUEUE_SIZE);
+  }
 
   mBufferingWait = IsRealTime() ? 0 : 30;
   mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
 
 #ifdef XP_WIN
   // Ensure high precision timers are enabled on Windows, otherwise the state
   // machine thread isn't woken up at reliable intervals to set the next frame,
   // and we drop frames while painting. Note that multiple calls to this
@@ -2198,26 +2212,37 @@ nsresult MediaDecoderStateMachine::Decod
       mState == DECODER_STATE_DECODING_METADATA &&
       isAwaitingResources) {
     // change state to DECODER_STATE_WAIT_FOR_RESOURCES
     StartWaitForResources();
     // affect values only if ReadMetadata succeeds
     return NS_OK;
   }
 
+  if (NS_FAILED(res) || (!info.HasValidMedia())) {
+    DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
+    return NS_ERROR_FAILURE;
+  }
+
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
   mInfo = info;
 
-  if (NS_FAILED(res) || (!info.HasValidMedia())) {
-    DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
-    return NS_ERROR_FAILURE;
+  if (HasVideo()) {
+    mAmpleVideoFrames = (mReader->IsAsync() && mInfo.mVideo.mIsHardwareAccelerated)
+      ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
+      : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
+    DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
+                mReader->IsAsync(),
+                mInfo.mVideo.mIsHardwareAccelerated,
+                mAmpleVideoFrames);
   }
+
   mDecoder->StartProgressUpdates();
   mGotDurationFromMetaData = (GetDuration() != -1) || mDurationSet;
 
   if (mGotDurationFromMetaData) {
     // We have all the information required: duration and size
     // Inform the element that we've loaded the metadata.
     EnqueueLoadedMetadataEvent();
   }
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -36,16 +36,17 @@ struct TrackInfo {
 
 // Stores info relevant to presenting media frames.
 class VideoInfo {
 public:
   VideoInfo()
     : mDisplay(0,0)
     , mStereoMode(StereoMode::MONO)
     , mHasVideo(false)
+    , mIsHardwareAccelerated(false)
   {
     // TODO: TrackInfo should be initialized by its specific codec decoder.
     // This following call should be removed once we have that implemented.
     mTrackInfo.Init(NS_LITERAL_STRING("2"), NS_LITERAL_STRING("main"),
     EmptyString(), EmptyString(), true);
   }
 
   // Size in pixels at which the video is rendered. This is after it has
@@ -54,16 +55,18 @@ public:
 
   // Indicates the frame layout for single track stereo videos.
   StereoMode mStereoMode;
 
   // True if we have an active video bitstream.
   bool mHasVideo;
 
   TrackInfo mTrackInfo;
+
+  bool mIsHardwareAccelerated;
 };
 
 class AudioInfo {
 public:
   AudioInfo()
     : mRate(44100)
     , mChannels(2)
     , mHasAudio(false)
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -460,16 +460,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
                                                       mLayersBackendType,
                                                       mDecoder->GetImageContainer(),
                                                       mVideo.mTaskQueue,
                                                       mVideo.mCallback);
     }
     NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, NS_ERROR_FAILURE);
     nsresult rv = mVideo.mDecoder->Init();
     NS_ENSURE_SUCCESS(rv, rv);
+    mInfo.mVideo.mIsHardwareAccelerated = mVideo.mDecoder->IsHardwareAccelerated();
   }
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration;
   {
     MonitorAutoLock lock(mDemuxerMonitor);
     duration = mDemuxer->Duration();
   }
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -240,13 +240,14 @@ public:
     return false;
   };
   virtual bool IsDormantNeeded() {
     return false;
   };
   virtual void AllocateMediaResources() {}
   virtual void ReleaseMediaResources() {}
   virtual void ReleaseDecoder() {}
+  virtual bool IsHardwareAccelerated() const { return false; }
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/fmp4/SharedDecoderManager.cpp
+++ b/dom/media/fmp4/SharedDecoderManager.cpp
@@ -232,9 +232,16 @@ SharedDecoderProxy::ReleaseMediaResource
 
 void
 SharedDecoderProxy::ReleaseDecoder()
 {
   if (mManager->mActiveProxy == this) {
     mManager->mDecoder->ReleaseMediaResources();
   }
 }
+
+bool
+SharedDecoderProxy::IsHardwareAccelerated() const
+{
+  return mManager->mDecoder->IsHardwareAccelerated();
 }
+
+}
--- a/dom/media/fmp4/SharedDecoderManager.h
+++ b/dom/media/fmp4/SharedDecoderManager.h
@@ -65,16 +65,17 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
   virtual bool IsWaitingMediaResources() MOZ_OVERRIDE;
   virtual bool IsDormantNeeded() MOZ_OVERRIDE;
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseDecoder() MOZ_OVERRIDE;
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
 
   friend class SharedDecoderManager;
 
 private:
   nsRefPtr<SharedDecoderManager> mManager;
   MediaDataDecoderCallback* mCallback;
 };
 }
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -174,9 +174,14 @@ WMFMediaDataDecoder::ReleaseMediaResourc
 }
 
 void
 WMFMediaDataDecoder::ReleaseDecoder()
 {
   ReleaseMediaResources();
 }
 
+bool
+WMFMediaDataDecoder::IsHardwareAccelerated() const {
+  return mMFTManager && mMFTManager->IsHardwareAccelerated();
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -41,16 +41,19 @@ public:
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsRefPtr<MediaData>& aOutput) = 0;
 
   // Destroys all resources.
   virtual void Shutdown() = 0;
+
+  virtual bool IsHardwareAccelerated() const { return false; }
+
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
 // using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by MFTManager and the MFTDecoder it creates.
 class WMFMediaDataDecoder : public MediaDataDecoder {
@@ -70,16 +73,17 @@ public:
 
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual bool IsWaitingMediaResources() { return false; };
   virtual bool IsDormantNeeded() { return true; };
   virtual void AllocateMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseMediaResources() MOZ_OVERRIDE;
   virtual void ReleaseDecoder() MOZ_OVERRIDE;
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
 
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available.
   void ProcessDecode(mp4_demuxer::MP4Sample* aSample);
 
   // Called on the task queue. Extracts output if available, and delivers
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -490,9 +490,15 @@ WMFVideoMFTManager::Output(int64_t aStre
 
 void
 WMFVideoMFTManager::Shutdown()
 {
   mDecoder = nullptr;
   DeleteOnMainThread(mDXVA2Manager);
 }
 
+bool
+WMFVideoMFTManager::IsHardwareAccelerated() const
+{
+  return mUseHwAccel;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.h
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.h
@@ -30,16 +30,18 @@ public:
 
   virtual HRESULT Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
 
   virtual HRESULT Output(int64_t aStreamOffset,
                          nsRefPtr<MediaData>& aOutput) MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
+  virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
+
 private:
 
   bool InitializeDXVA();
 
   HRESULT ConfigureVideoFrameGeometry();
 
   HRESULT CreateBasicVideoFrame(IMFSample* aSample,
                                 int64_t aStreamOffset,