Bug 1106963 - Resync media stream clock before destroying decoded stream. r=roc, a=sledru
authorAndreas Pehrson <pehrsons@gmail.com>
Thu, 04 Dec 2014 19:29:00 +0100
changeset 242987 cdffc642c9b9
parent 242986 a48f8c55a98c
child 242988 c16ed656a43b
push id4355
push userryanvm@gmail.com
push date2015-01-22 18:54 +0000
treeherdermozilla-beta@ba67c22c1427 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, sledru
bugs1106963
milestone36.0
Bug 1106963 - Resync media stream clock before destroying decoded stream. r=roc, a=sledru
dom/media/MediaDecoder.cpp
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -265,16 +265,20 @@ MediaDecoder::DecodedStreamGraphListener
     aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
   }
 }
 void MediaDecoder::DestroyDecodedStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
 
+  if (GetDecodedStream()) {
+    GetStateMachine()->ResyncMediaStreamClock();
+  }
+
   // All streams are having their SourceMediaStream disconnected, so they
   // need to be explicitly blocked again.
   for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
     OutputStreamData& os = mOutputStreams[i];
     // During cycle collection, nsDOMMediaStream can be destroyed and send
     // its Destroy message before this decoder is destroyed. So we have to
     // be careful not to send any messages after the Destroy().
     if (os.mStream->IsDestroyed()) {
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1216,16 +1216,27 @@ void MediaDecoderStateMachine::SetSyncPo
                                     TimeStamp::Now() - mPlayStartTime;
   mSyncPointInDecodedStream = mStartTime + mPlayDuration +
                               timeSincePlayStart.ToMicroseconds();
 
   DECODER_LOG("SetSyncPointForMediaStream MediaStream=%lldus, DecodedStream=%lldus",
               mSyncPointInMediaStream, mSyncPointInDecodedStream);
 }
 
+void MediaDecoderStateMachine::ResyncMediaStreamClock()
+{
+  AssertCurrentThreadInMonitor();
+  MOZ_ASSERT(mDecoder->GetDecodedStream());
+
+  if (IsPlaying()) {
+    SetPlayStartTime(TimeStamp::Now());
+    mPlayDuration = GetCurrentTimeViaMediaStreamSync() - mStartTime;
+  }
+}
+
 int64_t MediaDecoderStateMachine::GetCurrentTimeViaMediaStreamSync() const
 {
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(mSyncPointInDecodedStream >= 0, "Should have set up sync point");
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
   int64_t streamDelta = stream->GetLastOutputTime() - mSyncPointInMediaStream;
   return mSyncPointInDecodedStream + streamDelta;
 }
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -338,16 +338,21 @@ public:
   }
 
   // If we're playing into a MediaStream, record the current point in the
   // MediaStream and the current point in our media resource so later we can
   // convert MediaStream playback positions to media resource positions. Best to
   // call this while we're not playing (while the MediaStream is blocked). Can
   // be called on any thread with the decoder monitor held.
   void SetSyncPointForMediaStream();
+
+  // Called when the decoded stream is destroyed. |mPlayStartTime| and
+  // |mPlayDuration| are updated to provide a good base for calculating video
+  // stream time using the system clock.
+  void ResyncMediaStreamClock();
   int64_t GetCurrentTimeViaMediaStreamSync() const;
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
   void SendStreamData();
   void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   bool HaveEnoughDecodedVideo();
@@ -800,17 +805,18 @@ protected:
   // restart writing due to PlaybackStarted(), we record where we are in the
   // MediaStream and what that corresponds to in the media.
   int64_t mSyncPointInMediaStream; // microseconds
   int64_t mSyncPointInDecodedStream; // microseconds
 
   // The amount of time we've spent playing already the media. The current
   // playback position is therefore |Now() - mPlayStartTime +
   // mPlayDuration|, which must be adjusted by mStartTime if used with media
-  // timestamps.  Accessed only via the state machine thread.
+  // timestamps. Accessed on state machine and main threads. Access controlled
+  // by decoder monitor.
   int64_t mPlayDuration;
 
   // 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;
 
   // Start time of the media, in microseconds. This is the presentation