Bug 1172264 - Mirror duration from the MDSM to the MediaDecoder. r=jww
authorBobby Holley <bobbyholley@gmail.com>
Tue, 09 Jun 2015 12:16:18 -0700
changeset 267541 bc8f5c62dbef51c76a6e3a494840d1546f117fe7
parent 267540 3ead3466f84a2f9b7f6b2ddd47ebd93b425b3691
child 267542 645564f3f35f929fda373de5352263dce1c92e2a
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjww
bugs1172264
milestone41.0a1
Bug 1172264 - Mirror duration from the MDSM to the MediaDecoder. r=jww
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -337,16 +337,17 @@ MediaDecoder::MediaDecoder() :
   mDecoderPosition(0),
   mPlaybackPosition(0),
   mLogicalPosition(0.0),
   mCurrentPosition(AbstractThread::MainThread(), 0, "MediaDecoder::mCurrentPosition (Mirror)"),
   mVolume(AbstractThread::MainThread(), 0.0, "MediaDecoder::mVolume (Canonical)"),
   mPlaybackRate(AbstractThread::MainThread(), 1.0, "MediaDecoder::mPlaybackRate (Canonical)"),
   mPreservesPitch(AbstractThread::MainThread(), true, "MediaDecoder::mPreservesPitch (Canonical)"),
   mDuration(std::numeric_limits<double>::quiet_NaN()),
+  mStateMachineDuration(AbstractThread::MainThread(), NullableTimeUnit(), "MediaDecoder::mStateMachineDuration (Mirror)"),
   mMediaSeekable(true),
   mSameOriginMedia(false),
   mReentrantMonitor("media.decoder"),
   mEstimatedDuration(AbstractThread::MainThread(), NullableTimeUnit(),
                      "MediaDecoder::mEstimatedDuration (Canonical)"),
   mExplicitDuration(AbstractThread::MainThread(), Maybe<double>(),
                    "MediaDecoder::mExplicitDuration (Canonical)"),
   mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING,
@@ -644,21 +645,20 @@ void MediaDecoder::MetadataLoaded(nsAuto
   }
 
   DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
               aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
               aInfo->HasAudio(), aInfo->HasVideo());
 
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-    int64_t stateMachineDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
-    if (stateMachineDuration == -1) {
+    if (mStateMachineDuration.Ref().isNothing() && mStateMachineDuration.Ref().ref().IsInfinite()) {
       SetInfinite(true);
     } else {
-      mDuration = TimeUnit::FromMicroseconds(stateMachineDuration).ToSeconds();
+      mDuration = mStateMachineDuration.Ref().ref().ToSeconds();
     }
 
     // Duration has changed so we should recompute playback rate
     UpdatePlaybackRate();
   }
 
   mInfo = aInfo.forget();
   ConstructMediaTracks();
@@ -1249,19 +1249,21 @@ bool MediaDecoder::OnDecodeTaskQueue() c
 
 void
 MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
 {
   MOZ_ASSERT_IF(aStateMachine, !mDecoderStateMachine);
   mDecoderStateMachine = aStateMachine;
 
   if (mDecoderStateMachine) {
+    mStateMachineDuration.Connect(mDecoderStateMachine->CanonicalDuration());
     mNextFrameStatus.Connect(mDecoderStateMachine->CanonicalNextFrameStatus());
     mCurrentPosition.Connect(mDecoderStateMachine->CanonicalCurrentPosition());
   } else {
+    mStateMachineDuration.DisconnectIfConnected();
     mNextFrameStatus.DisconnectIfConnected();
     mCurrentPosition.DisconnectIfConnected();
   }
 }
 
 ReentrantMonitor& MediaDecoder::GetReentrantMonitor() {
   return mReentrantMonitor;
 }
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -941,16 +941,19 @@ protected:
   Canonical<bool> mPreservesPitch;
 public:
   AbstractCanonical<bool>* CanonicalPreservesPitch() { return &mPreservesPitch; }
 protected:
 
   // Official duration of the media resource as observed by script.
   double mDuration;
 
+  // Duration of the media resource according to the state machine.
+  Mirror<media::NullableTimeUnit> mStateMachineDuration;
+
   // True if the media is seekable (i.e. supports random access).
   bool mMediaSeekable;
 
   // True if the media is same-origin with the element. Data can only be
   // passed to MediaStreams when this is true.
   bool mSameOriginMedia;
 
   /******
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -182,18 +182,19 @@ MediaDecoderStateMachine::MediaDecoderSt
   mTaskQueue(new MediaTaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                                 /* aSupportsTailDispatch = */ true)),
   mWatchManager(this, mTaskQueue),
   mRealTime(aRealTime),
   mDispatchedStateMachine(false),
   mDelayedScheduler(this),
   mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
   mPlayDuration(0),
+  mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderStateMachine::mDuration (Canonical"),
   mEstimatedDuration(mTaskQueue, NullableTimeUnit(),
-                    "MediaDecoderStateMachine::EstimatedDuration (Mirror)"),
+                    "MediaDecoderStateMachine::mEstimatedDuration (Mirror)"),
   mExplicitDuration(mTaskQueue, Maybe<double>(),
                     "MediaDecoderStateMachine::mExplicitDuration (Mirror)"),
   mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
   mPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_LOADING,
              "MediaDecoderStateMachine::mPlayState (Mirror)"),
   mNextPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_PAUSED,
                  "MediaDecoderStateMachine::mNextPlayState (Mirror)"),
   mLogicallySeeking(mTaskQueue, false,
@@ -1377,21 +1378,21 @@ void MediaDecoderStateMachine::VolumeCha
 bool MediaDecoderStateMachine::IsRealTime() const
 {
   return mRealTime;
 }
 
 int64_t MediaDecoderStateMachine::GetDuration()
 {
   AssertCurrentThreadInMonitor();
-  if (mDuration.isNothing() || mDuration.ref().IsInfinite()) {
+  if (mDuration.Ref().isNothing() || Duration().IsInfinite()) {
     return -1;
   }
 
-  return mDuration.ref().ToMicroseconds();
+  return Duration().ToMicroseconds();
 }
 
 void MediaDecoderStateMachine::RecomputeDuration()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   // We dispatch DurationChanged to the MediaDecoder when the duration changes
@@ -1418,17 +1419,17 @@ void MediaDecoderStateMachine::Recompute
   } else {
     return;
   }
 
   if (duration < mObservedDuration.Ref()) {
     duration = mObservedDuration;
     fireDurationChanged = true;
   }
-  fireDurationChanged = fireDurationChanged && duration != mDuration.ref();
+  fireDurationChanged = fireDurationChanged && duration != Duration();
 
   MOZ_ASSERT(duration.ToMicroseconds() >= 0);
   mDuration = Some(duration);
 
   if (fireDurationChanged) {
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethodWithArg<TimeUnit>(mDecoder, &MediaDecoder::DurationChanged, duration);
     AbstractThread::MainThread()->Dispatch(event.forget());
@@ -1672,17 +1673,17 @@ void MediaDecoderStateMachine::NotifyDat
   }
 
   media::TimeIntervals buffered{mDecoder->GetBuffered()};
   if (!buffered.IsInvalid()) {
     bool exists;
     media::TimeUnit end{buffered.GetEnd(&exists)};
     if (exists) {
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      mDuration = Some(std::max<TimeUnit>(mDuration.ref(), end));
+      mDuration = Some(std::max<TimeUnit>(Duration(), end));
     }
   }
 }
 
 nsRefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::Seek(SeekTarget aTarget)
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -2187,17 +2188,17 @@ MediaDecoderStateMachine::OnMetadataRead
   mDecoder->StartProgressUpdates();
 
   // In general, we wait until we know the duration before notifying the decoder.
   // However, we notify  unconditionally in this case without waiting for the start
   // time, since the caller might be waiting on metadataloaded to be fired before
   // feeding in the CDM, which we need to decode the first frame (and
   // thus get the metadata). We could fix this if we could compute the start
   // time by demuxing without necessaring decoding.
-  mNotifyMetadataBeforeFirstFrame = mDuration.isSome() || mReader->IsWaitingOnCDMResource();
+  mNotifyMetadataBeforeFirstFrame = mDuration.Ref().isSome() || mReader->IsWaitingOnCDMResource();
   if (mNotifyMetadataBeforeFirstFrame) {
     EnqueueLoadedMetadataEvent();
   }
 
   if (mReader->IsWaitingOnCDMResource()) {
     // Metadata parsing was successful but we're still waiting for CDM caps
     // to become available so that we can build the correct decryptor/decoder.
     SetState(DECODER_STATE_WAIT_FOR_CDM);
@@ -2333,18 +2334,18 @@ MediaDecoderStateMachine::FinishDecodeFi
   if (!IsRealTime() && !mSentFirstFrameLoadedEvent) {
     if (VideoQueue().GetSize()) {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       RenderVideoFrame(VideoQueue().PeekFront(), TimeStamp::Now());
     }
   }
 
   // If we don't know the duration by this point, we assume infinity, per spec.
-  if (mDuration.isNothing()) {
-    mDuration.emplace(TimeUnit::FromInfinity());
+  if (mDuration.Ref().isNothing()) {
+    mDuration = Some(TimeUnit::FromInfinity());
   }
 
   DECODER_LOG("Media duration %lld, "
               "transportSeekable=%d, mediaSeekable=%d",
               Duration().ToMicroseconds(), mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
 
   if (HasAudio() && !HasVideo()) {
     // We're playing audio only. We don't need to worry about slow video
@@ -2508,16 +2509,17 @@ MediaDecoderStateMachine::FinishShutdown
   mEstimatedDuration.DisconnectIfConnected();
   mExplicitDuration.DisconnectIfConnected();
   mPlayState.DisconnectIfConnected();
   mNextPlayState.DisconnectIfConnected();
   mLogicallySeeking.DisconnectIfConnected();
   mVolume.DisconnectIfConnected();
   mLogicalPlaybackRate.DisconnectIfConnected();
   mPreservesPitch.DisconnectIfConnected();
+  mDuration.DisconnectAll();
   mNextFrameStatus.DisconnectAll();
   mCurrentPosition.DisconnectAll();
 
   // Shut down the watch manager before shutting down our task queue.
   mWatchManager.Shutdown();
 
   MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
              "How did we escape from the shutdown state?");
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -683,16 +683,17 @@ private:
   void OnAudioSinkComplete();
 public:
   void DispatchOnAudioSinkComplete()
   {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioSinkComplete);
     TaskQueue()->Dispatch(runnable.forget());
   }
+private:
 
   // Called by the AudioSink to signal errors.
   void OnAudioSinkError();
 
   void DispatchOnAudioSinkError()
   {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioSinkError);
@@ -938,18 +939,21 @@ public:
 
   // Time that buffering started. Used for buffering timeout and only
   // accessed on the state machine thread. This is null while we're not
   // buffering.
   TimeStamp mBufferingStart;
 
   // Duration of the media. This is guaranteed to be non-null after we finish
   // decoding the first frame.
-  media::NullableTimeUnit mDuration;
-  media::TimeUnit Duration() const { MOZ_ASSERT(OnTaskQueue()); return mDuration.ref(); }
+  Canonical<media::NullableTimeUnit> mDuration;
+  media::TimeUnit Duration() const { MOZ_ASSERT(OnTaskQueue()); return mDuration.Ref().ref(); }
+public:
+  AbstractCanonical<media::NullableTimeUnit>* CanonicalDuration() { return &mDuration; }
+protected:
 
   // Recomputes the canonical duration from various sources.
   void RecomputeDuration();
 
   // The duration according to the demuxer's current estimate, mirrored from the main thread.
   Mirror<media::NullableTimeUnit> mEstimatedDuration;
 
   // The duration explicitly set by JS, mirrored from the main thread.