Bug 1388228. P5 - move some more members to ChannelMediaDecoder. draft
authorJW Wang <jwwang@mozilla.com>
Mon, 07 Aug 2017 13:23:43 +0800
changeset 642348 1b0b81079f6017ba679b60e16d6452973ac3d452
parent 642347 28af604ef8701f57f108c6c7283077798bf7e32e
child 642349 64f23dd2b09076000e43cbcad92cfddddc349438
push id72707
push userjwwang@mozilla.com
push dateTue, 08 Aug 2017 02:32:36 +0000
bugs1388228
milestone57.0a1
Bug 1388228. P5 - move some more members to ChannelMediaDecoder. Those members only make sense for ChannelMediaResource. MozReview-Commit-ID: 2z6WPQeJnIT
dom/media/ChannelMediaDecoder.cpp
dom/media/ChannelMediaDecoder.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
--- a/dom/media/ChannelMediaDecoder.cpp
+++ b/dom/media/ChannelMediaDecoder.cpp
@@ -336,12 +336,139 @@ ChannelMediaDecoder::SeekingChanged()
 bool
 ChannelMediaDecoder::CanPlayThroughImpl()
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE(GetStateMachine(), false);
   return GetStatistics().CanPlayThrough();
 }
 
+void
+ChannelMediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MediaDecoder::OnPlaybackEvent(aEvent);
+  switch (aEvent) {
+    case MediaEventType::PlaybackStarted:
+      mPlaybackStatistics.Start();
+      break;
+    case MediaEventType::PlaybackStopped:
+      mPlaybackStatistics.Stop();
+      ComputePlaybackRate();
+      break;
+    default:
+      break;
+  }
+}
+
+void
+ChannelMediaDecoder::DurationChanged()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  AbstractThread::AutoEnter context(AbstractMainThread());
+  MediaDecoder::DurationChanged();
+  // Duration has changed so we should recompute playback rate
+  UpdatePlaybackRate();
+}
+
+void
+ChannelMediaDecoder::DownloadProgressed()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  AbstractThread::AutoEnter context(AbstractMainThread());
+  MediaDecoder::DownloadProgressed();
+  UpdatePlaybackRate();
+  mResource->ThrottleReadahead(ShouldThrottleDownload());
+}
+
+void
+ChannelMediaDecoder::ComputePlaybackRate()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mResource);
+
+  int64_t length = mResource->GetLength();
+  if (mozilla::IsFinite<double>(mDuration) && mDuration > 0 && length >= 0) {
+    mPlaybackRateReliable = true;
+    mPlaybackBytesPerSecond = length / mDuration;
+    return;
+  }
+
+  bool reliable = false;
+  mPlaybackBytesPerSecond = mPlaybackStatistics.GetRateAtLastStop(&reliable);
+  mPlaybackRateReliable = reliable;
+}
+
+void
+ChannelMediaDecoder::UpdatePlaybackRate()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mResource);
+
+  ComputePlaybackRate();
+  uint32_t rate = mPlaybackBytesPerSecond;
+
+  if (mPlaybackRateReliable) {
+    // Avoid passing a zero rate
+    rate = std::max(rate, 1u);
+  } else {
+    // Set a minimum rate of 10,000 bytes per second ... sometimes we just
+    // don't have good data
+    rate = std::max(rate, 10000u);
+  }
+
+  mResource->SetPlaybackRate(rate);
+}
+
+MediaStatistics
+ChannelMediaDecoder::GetStatistics()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mResource);
+
+  MediaStatistics result;
+  result.mDownloadRate =
+    mResource->GetDownloadRate(&result.mDownloadRateReliable);
+  result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
+  result.mTotalBytes = mResource->GetLength();
+  result.mPlaybackRate = mPlaybackBytesPerSecond;
+  result.mPlaybackRateReliable = mPlaybackRateReliable;
+  result.mDecoderPosition = mDecoderPosition;
+  result.mPlaybackPosition = mPlaybackPosition;
+  return result;
+}
+
+bool
+ChannelMediaDecoder::ShouldThrottleDownload()
+{
+  // We throttle the download if either the throttle override pref is set
+  // (so that we can always throttle in Firefox on mobile) or if the download
+  // is fast enough that there's no concern about playback being interrupted.
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE(GetStateMachine(), false);
+
+  int64_t length = mResource->GetLength();
+  if (length > 0 &&
+      length <= int64_t(MediaPrefs::MediaMemoryCacheMaxSize()) * 1024) {
+    // Don't throttle the download of small resources. This is to speed
+    // up seeking, as seeks into unbuffered ranges would require starting
+    // up a new HTTP transaction, which adds latency.
+    return false;
+  }
+
+  if (Preferences::GetBool("media.throttle-regardless-of-download-rate",
+                           false)) {
+    return true;
+  }
+
+  MediaStatistics stats = GetStatistics();
+  if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
+    return false;
+  }
+  uint32_t factor =
+    std::max(2u, Preferences::GetUint("media.throttle-factor", 2));
+  return stats.mDownloadRate > factor * stats.mPlaybackRate;
+}
+
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef LOG
--- a/dom/media/ChannelMediaDecoder.h
+++ b/dom/media/ChannelMediaDecoder.h
@@ -49,16 +49,19 @@ class ChannelMediaDecoder : public Media
     // The decoder to send notifications. Main-thread only.
     ChannelMediaDecoder* mDecoder = nullptr;
     nsCOMPtr<nsITimer> mTimer;
     bool mTimerArmed = false;
     const RefPtr<AbstractThread> mAbstractMainThread;
   };
 
 protected:
+  void OnPlaybackEvent(MediaEventType aEvent) override;
+  void DurationChanged() override;
+  void DownloadProgressed() override;
   RefPtr<ResourceCallback> mResourceCallback;
   RefPtr<BaseMediaResource> mResource;
 
 public:
   explicit ChannelMediaDecoder(MediaDecoderInit& aInit);
 
   MediaDecoderStateMachine* CreateStateMachine() override;
 
@@ -88,20 +91,46 @@ private:
   // from the resource. Called on the main by an event runner dispatched
   // by the MediaResource read functions.
   void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
 
   void SeekingChanged();
 
   bool CanPlayThroughImpl() override final;
 
+  // The actual playback rate computation.
+  void ComputePlaybackRate();
+
+  // Something has changed that could affect the computed playback rate,
+  // so recompute it.
+  void UpdatePlaybackRate();
+
+  // Return statistics. This is used for progress events and other things.
+  // This can be called from any thread. It's only a snapshot of the
+  // current state, since other threads might be changing the state
+  // at any time.
+  MediaStatistics GetStatistics();
+
+  bool ShouldThrottleDownload();
+
   WatchManager<ChannelMediaDecoder> mWatchManager;
 
   // True when seeking or otherwise moving the play position around in
   // such a manner that progress event data is inaccurate. This is set
   // during seek and duration operations to prevent the progress indicator
   // from jumping around. Read/Write on the main thread only.
   bool mIgnoreProgressData = false;
+
+  // Data needed to estimate playback data rate. The timeline used for
+  // this estimate is "decode time" (where the "current time" is the
+  // time of the last decoded video frame).
+  MediaChannelStatistics mPlaybackStatistics;
+
+  // Estimate of the current playback rate (bytes/second).
+  double mPlaybackBytesPerSecond = 0;
+
+  // True if mPlaybackBytesPerSecond is a reliable estimate.
+  bool mPlaybackRateReliable = true;
 };
 
 } // namespace mozilla
 
 #endif // ChannelMediaDecoder_h_
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -512,23 +512,16 @@ MediaDecoder::~MediaDecoder()
   MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
   MediaMemoryTracker::RemoveMediaDecoder(this);
 }
 
 void
 MediaDecoder::OnPlaybackEvent(MediaEventType aEvent)
 {
   switch (aEvent) {
-    case MediaEventType::PlaybackStarted:
-      mPlaybackStatistics.Start();
-      break;
-    case MediaEventType::PlaybackStopped:
-      mPlaybackStatistics.Stop();
-      ComputePlaybackRate();
-      break;
     case MediaEventType::PlaybackEnded:
       PlaybackEnded();
       break;
     case MediaEventType::SeekStarted:
       SeekingStarted();
       break;
     case MediaEventType::Invalidate:
       Invalidate();
@@ -545,16 +538,19 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
     case MediaEventType::CancelVideoSuspendTimer:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
       break;
     case MediaEventType::VideoOnlySeekBegin:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekbegin"));
       break;
     case MediaEventType::VideoOnlySeekCompleted:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
+      break;
+    default:
+      break;
   }
 }
 
 void
 MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
 {
   DecodeError(aError);
 }
@@ -915,129 +911,35 @@ MediaDecoder::PlaybackEnded()
 
   LOG("MediaDecoder::PlaybackEnded");
 
   ChangeState(PLAY_STATE_ENDED);
   InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
   GetOwner()->PlaybackEnded();
 }
 
-MediaStatistics
-MediaDecoder::GetStatistics()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MediaResource* r = GetResource();
-  MOZ_ASSERT(r);
-
-  MediaStatistics result;
-  result.mDownloadRate =
-    r->GetDownloadRate(&result.mDownloadRateReliable);
-  result.mDownloadPosition = r->GetCachedDataEnd(mDecoderPosition);
-  result.mTotalBytes = r->GetLength();
-  result.mPlaybackRate = mPlaybackBytesPerSecond;
-  result.mPlaybackRateReliable = mPlaybackRateReliable;
-  result.mDecoderPosition = mDecoderPosition;
-  result.mPlaybackPosition = mPlaybackPosition;
-  return result;
-}
-
-void
-MediaDecoder::ComputePlaybackRate()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(GetResource());
-
-  int64_t length = GetResource()->GetLength();
-  if (mozilla::IsFinite<double>(mDuration)
-      && mDuration > 0
-      && length >= 0) {
-    mPlaybackRateReliable = true;
-    mPlaybackBytesPerSecond = length / mDuration;
-    return;
-  }
-
-  bool reliable = false;
-  mPlaybackBytesPerSecond = mPlaybackStatistics.GetRateAtLastStop(&reliable);
-  mPlaybackRateReliable = reliable;
-}
-
-void
-MediaDecoder::UpdatePlaybackRate()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(GetResource());
-
-  ComputePlaybackRate();
-  uint32_t rate = mPlaybackBytesPerSecond;
-
-  if (mPlaybackRateReliable) {
-    // Avoid passing a zero rate
-    rate = std::max(rate, 1u);
-  } else {
-    // Set a minimum rate of 10,000 bytes per second ... sometimes we just
-    // don't have good data
-    rate = std::max(rate, 10000u);
-  }
-
-  GetResource()->SetPlaybackRate(rate);
-}
-
 void
 MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
   if (MediaResource* r = GetResource()) {
     bool suspended = r->IsSuspendedByCache();
     GetOwner()->NotifySuspendedByCache(suspended);
   }
 }
 
-bool
-MediaDecoder::ShouldThrottleDownload()
-{
-  // We throttle the download if either the throttle override pref is set
-  // (so that we can always throttle in Firefox on mobile) or if the download
-  // is fast enough that there's no concern about playback being interrupted.
-  MOZ_ASSERT(NS_IsMainThread());
-  NS_ENSURE_TRUE(mDecoderStateMachine, false);
-
-  int64_t length = GetResource()->GetLength();
-  if (length > 0 &&
-      length <= int64_t(MediaPrefs::MediaMemoryCacheMaxSize()) * 1024) {
-    // Don't throttle the download of small resources. This is to speed
-    // up seeking, as seeks into unbuffered ranges would require starting
-    // up a new HTTP transaction, which adds latency.
-    return false;
-  }
-
-  if (Preferences::GetBool("media.throttle-regardless-of-download-rate",
-                           false)) {
-    return true;
-  }
-
-  MediaStatistics stats = GetStatistics();
-  if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
-    return false;
-  }
-  uint32_t factor =
-    std::max(2u, Preferences::GetUint("media.throttle-factor", 2));
-  return stats.mDownloadRate > factor * stats.mPlaybackRate;
-}
-
 void
 MediaDecoder::DownloadProgressed()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
-  UpdatePlaybackRate();
   GetOwner()->DownloadProgressed();
-  GetResource()->ThrottleReadahead(ShouldThrottleDownload());
 }
 
 void
 MediaDecoder::NotifyPrincipalChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
@@ -1148,19 +1050,16 @@ MediaDecoder::DurationChanged()
   }
 
   if (mDuration == oldDuration || IsNaN(mDuration)) {
     return;
   }
 
   LOG("Duration changed to %f", mDuration);
 
-  // Duration has changed so we should recompute playback rate
-  UpdatePlaybackRate();
-
   // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28822 for a discussion
   // of whether we should fire durationchange on explicit infinity.
   if (mFiredMetadataLoaded &&
       (!mozilla::IsInfinite<double>(mDuration) || mExplicitDuration.isSome())) {
     GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   }
 
   if (CurrentPosition() > TimeUnit::FromSeconds(mDuration)) {
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -301,23 +301,16 @@ private:
   }
 
   layers::ImageContainer* GetImageContainer();
 
   // Fire timeupdate events if needed according to the time constraints
   // outlined in the specification.
   void FireTimeUpdate();
 
-  // Something has changed that could affect the computed playback rate,
-  // so recompute it. The monitor must be held.
-  virtual void UpdatePlaybackRate();
-
-  // The actual playback rate computation. The monitor must be held.
-  void ComputePlaybackRate();
-
   // Returns true if we can play the entire media through without stopping
   // to buffer, given the current download and playback rates.
   bool CanPlayThrough();
 
   dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
 
   // Called from HTMLMediaElement when owner document activity changes
   virtual void SetElementVisibility(bool aIsDocumentVisible,
@@ -401,22 +394,16 @@ private:
   static bool IsOpusEnabled();
   static bool IsWaveEnabled();
   static bool IsWebMEnabled();
 
 #ifdef MOZ_WMF
   static bool IsWMFEnabled();
 #endif
 
-  // Return statistics. This is used for progress events and other things.
-  // This can be called from any thread. It's only a snapshot of the
-  // current state, since other threads might be changing the state
-  // at any time.
-  MediaStatistics GetStatistics();
-
   // Return the frame decode/paint related statistics.
   FrameStatistics& GetFrameStatistics() { return *mFrameStats; }
 
   void UpdateReadyState()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     GetOwner()->UpdateReadyState();
@@ -444,35 +431,36 @@ protected:
   // by the state machine. Call on the main thread only.
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility);
 
   void SetStateMachineParameters();
 
   bool IsShutdown() const;
 
-  // Called by the state machine to notify the decoder that the duration
-  // has changed.
-  void DurationChanged();
+  // Called to notify the decoder that the duration has changed.
+  virtual void DurationChanged();
 
   // State-watching manager.
   WatchManager<MediaDecoder> mWatchManager;
 
   double ExplicitDuration() { return mExplicitDuration.ref(); }
 
   void SetExplicitDuration(double aValue)
   {
     MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
     mExplicitDuration = Some(aValue);
 
     // We Invoke DurationChanged explicitly, rather than using a watcher, so
     // that it takes effect immediately, rather than at the end of the current task.
     DurationChanged();
   }
 
+  virtual void OnPlaybackEvent(MediaEventType aEvent);
+
   /******
    * The following members should be accessed with the decoder lock held.
    ******/
 
   // The logical playback position of the media resource in units of
   // seconds. This corresponds to the "official position" in HTML5. Note that
   // we need to store this as a double, rather than an int64_t (like
   // mCurrentPosition), so that |v.currentTime = foo; v.currentTime == foo|
@@ -512,17 +500,16 @@ private:
   // state machine. Call on the main thread only.
   void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
                       UniquePtr<MetadataTags> aTags,
                       MediaDecoderEventVisibility aEventVisibility);
 
   // Called when the owner's activity changed.
   void NotifyCompositor();
 
-  void OnPlaybackEvent(MediaEventType aEvent);
   void OnPlaybackErrorEvent(const MediaResult& aError);
 
   void OnDecoderDoctorEvent(DecoderDoctorEvent aEvent);
 
   void OnMediaNotSeekable()
   {
     mMediaSeekable = false;
   }
@@ -546,19 +533,19 @@ private:
   MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
   RefPtr<CDMProxyPromise> mCDMProxyPromise;
 
 protected:
   void NotifyDataArrivedInternal();
   void DiscardOngoingSeekIfExists();
   virtual void CallSeek(const SeekTarget& aTarget);
 
-  // Called to recompute playback rate and notify 'progress' event.
-  // Call on the main thread only.
-  void DownloadProgressed();
+  // Called to notify fetching media data is in progress.
+  // Called on the main thread only.
+  virtual void DownloadProgressed();
 
   // Called by MediaResource when the "cache suspended" status changes.
   // If MediaResource::IsSuspendedByCache returns true, then the decoder
   // should stop buffering or otherwise waiting for download progress and
   // start consuming data, if possible, because the cache is full.
   void NotifySuspendedStatusChanged();
 
   // Called by MediaResource when the principal of the resource has
@@ -572,36 +559,29 @@ protected:
 
   // Ensures our media stream has been unpinned.
   void UnpinForSeek();
 
   const char* PlayStateStr();
 
   void OnMetadataUpdate(TimedMetadata&& aMetadata);
 
-  bool ShouldThrottleDownload();
-
   // This should only ever be accessed from the main thread.
   // It is set in the constructor and cleared in Shutdown when the element goes
   // away. The decoder does not add a reference the element.
   MediaDecoderOwner* mOwner;
 
   // The AbstractThread from mOwner.
   const RefPtr<AbstractThread> mAbstractMainThread;
 
   // Counters related to decode and presentation of frames.
   const RefPtr<FrameStatistics> mFrameStats;
 
   RefPtr<VideoFrameContainer> mVideoFrameContainer;
 
-  // Data needed to estimate playback data rate. The timeline used for
-  // this estimate is "decode time" (where the "current time" is the
-  // time of the last decoded video frame).
-  MediaChannelStatistics mPlaybackStatistics;
-
   // True when our media stream has been pinned. We pin the stream
   // while seeking.
   bool mPinnedForSeek;
 
   // Be assigned from media element during the initialization and pass to
   // AudioStream Class.
   const dom::AudioChannel mAudioChannel;
 
@@ -753,19 +733,13 @@ public:
 
 private:
   // Notify owner when the audible state changed
   void NotifyAudibleStateChanged();
 
   bool mTelemetryReported;
   const MediaContainerType mContainerType;
   bool mCanPlayThrough = false;
-
-  // Estimate of the current playback rate (bytes/second).
-  double mPlaybackBytesPerSecond = 0;
-
-  // True if mPlaybackBytesPerSecond is a reliable estimate.
-  bool mPlaybackRateReliable = true;
 };
 
 } // namespace mozilla
 
 #endif