Bug 1600063 - Clear future data when the DecodedStream mediasink stops playing. r=padenot
authorAndreas Pehrson <apehrson@mozilla.com>
Tue, 10 Dec 2019 17:22:18 +0000
changeset 506297 b7ef124e4519ff8433b01056a4db60601ddd7377
parent 506296 e183cbb4983cfb3aecf97ab18fad916b91f89e7e
child 506298 0ccc77928faaedb342b869322ace35254fc34e95
push id36902
push useraciure@mozilla.com
push dateWed, 11 Dec 2019 03:34:51 +0000
treeherdermozilla-central@7635669b8d72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1600063
milestone73.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1600063 - Clear future data when the DecodedStream mediasink stops playing. r=padenot Differential Revision: https://phabricator.services.mozilla.com/D55981
dom/media/MediaTrackGraph.cpp
dom/media/MediaTrackGraph.h
dom/media/mediasink/DecodedStream.cpp
dom/media/mediasink/DecodedStream.h
--- a/dom/media/MediaTrackGraph.cpp
+++ b/dom/media/MediaTrackGraph.cpp
@@ -2559,16 +2559,28 @@ TrackTime SourceMediaTrack::AppendData(M
   NotifyDirectConsumers(aRawSegment ? aRawSegment : aSegment);
   appended = aSegment->GetDuration();
   mUpdateTrack->mData->AppendFrom(aSegment);  // note: aSegment is now dead
   graph->EnsureNextIteration();
 
   return appended;
 }
 
+TrackTime SourceMediaTrack::ClearFutureData() {
+  MutexAutoLock lock(mMutex);
+  auto graph = GraphImpl();
+  if (!mUpdateTrack || !graph) {
+    return 0;
+  }
+
+  TrackTime duration = mUpdateTrack->mData->GetDuration();
+  mUpdateTrack->mData->Clear();
+  return duration;
+}
+
 void SourceMediaTrack::NotifyDirectConsumers(MediaSegment* aSegment) {
   mMutex.AssertCurrentThreadOwns();
 
   for (const auto& l : mDirectTrackListeners) {
     TrackTime offset = 0;  // FIX! need a separate TrackTime.... or the end of
                            // the internal buffer
     l->NotifyRealtimeTrackDataAndApplyTrackDisabling(Graph(), offset,
                                                      *aSegment);
--- a/dom/media/MediaTrackGraph.h
+++ b/dom/media/MediaTrackGraph.h
@@ -648,18 +648,25 @@ class SourceMediaTrack : public MediaTra
   void SetAppendDataSourceRate(TrackRate aRate);
 
   /**
    * Append media data to this track. Ownership of aSegment remains with the
    * caller, but aSegment is emptied. Returns 0 if the data was not appended
    * because the stream has ended. Returns the duration of the appended data in
    * the graph's track rate otherwise.
    */
-  virtual TrackTime AppendData(MediaSegment* aSegment,
-                               MediaSegment* aRawSegment = nullptr);
+  TrackTime AppendData(MediaSegment* aSegment,
+                       MediaSegment* aRawSegment = nullptr);
+
+  /**
+   * Clear any data appended with AppendData() that hasn't entered the graph
+   * yet. Returns the duration of the cleared data in the graph's track rate.
+   */
+  TrackTime ClearFutureData();
+
   /**
    * Indicate that this track has ended. Do not do any more API calls affecting
    * this track.
    */
   void End();
 
   // Overriding allows us to hold the mMutex lock while changing the track
   // enable status
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -489,16 +489,17 @@ nsresult DecodedStream::Start(const Time
 }
 
 void DecodedStream::Stop() {
   AssertOwnerThread();
   MOZ_ASSERT(mStartTime.isSome(), "playback not started.");
 
   DisconnectListener();
   ResetVideo(mPrincipalHandle);
+  ResetAudio();
   mStartTime.reset();
   mAudioEndedPromise = nullptr;
   mVideoEndedPromise = nullptr;
 
   // Clear mData immediately when this playback session ends so we won't
   // send data to the wrong track in SendData() in next playback session.
   DestroyData(std::move(mData));
 }
@@ -674,27 +675,56 @@ static bool ZeroDurationAtLastChunk(Vide
   // Get the last video frame's start time in VideoSegment aInput.
   // If the start time is equal to the duration of aInput, means the last video
   // frame's duration is zero.
   TrackTime lastVideoStratTime;
   aInput.GetLastFrame(&lastVideoStratTime);
   return lastVideoStratTime == aInput.GetDuration();
 }
 
+void DecodedStream::ResetAudio() {
+  AssertOwnerThread();
+
+  if (!mData) {
+    return;
+  }
+
+  if (!mInfo.HasAudio()) {
+    return;
+  }
+
+  TrackTime cleared = mData->mAudioTrack->ClearFutureData();
+  mData->mAudioTrackWritten -= cleared;
+  if (const RefPtr<AudioData>& v = mAudioQueue.PeekFront()) {
+    mData->mNextAudioTime = v->mTime;
+  }
+  if (mData->mHaveSentFinishAudio && cleared > 0) {
+    mData->mHaveSentFinishAudio = false;
+    mData->mListener->EndTrackAt(mData->mAudioTrack, TRACK_TIME_MAX);
+  }
+}
+
 void DecodedStream::ResetVideo(const PrincipalHandle& aPrincipalHandle) {
   AssertOwnerThread();
 
   if (!mData) {
     return;
   }
 
   if (!mInfo.HasVideo()) {
     return;
   }
 
+  TrackTime cleared = mData->mVideoTrack->ClearFutureData();
+  mData->mVideoTrackWritten -= cleared;
+  if (mData->mHaveSentFinishVideo && cleared > 0) {
+    mData->mHaveSentFinishVideo = false;
+    mData->mListener->EndTrackAt(mData->mVideoTrack, TRACK_TIME_MAX);
+  }
+
   VideoSegment resetter;
   TimeStamp currentTime;
   TimeUnit currentPosition = GetPosition(&currentTime);
 
   // Giving direct consumers a frame (really *any* frame, so in this case:
   // nullptr) at an earlier time than the previous, will signal to that consumer
   // to discard any frames ahead in time of the new frame. To be honest, this is
   // an ugly hack because the direct listeners of the MediaTrackGraph do not
@@ -887,28 +917,29 @@ void DecodedStream::NotifyOutput(int64_t
     return;
   }
   MOZ_ASSERT(mLastOutputTime < time);
   mLastOutputTime = time;
   auto currentTime = GetPosition();
 
   // Remove audio samples that have been played by MTG from the queue.
   RefPtr<AudioData> a = mAudioQueue.PeekFront();
-  for (; a && a->mTime < currentTime;) {
+  for (; a && a->GetEndTime() < currentTime;) {
     RefPtr<AudioData> releaseMe = mAudioQueue.PopFront();
     a = mAudioQueue.PeekFront();
   }
 }
 
 void DecodedStream::PlayingChanged() {
   AssertOwnerThread();
 
   if (!mPlaying) {
     // On seek or pause we discard future frames.
     ResetVideo(mPrincipalHandle);
+    ResetAudio();
   }
 }
 
 void DecodedStream::ConnectListener() {
   AssertOwnerThread();
 
   mAudioPushListener = mAudioQueue.PushEvent().Connect(
       mOwnerThread, this, &DecodedStream::SendData);
--- a/dom/media/mediasink/DecodedStream.h
+++ b/dom/media/mediasink/DecodedStream.h
@@ -65,16 +65,17 @@ class DecodedStream : public MediaSink {
 
  protected:
   virtual ~DecodedStream();
 
  private:
   void DestroyData(UniquePtr<DecodedStreamData>&& aData);
   void SendAudio(double aVolume, const PrincipalHandle& aPrincipalHandle);
   void SendVideo(const PrincipalHandle& aPrincipalHandle);
+  void ResetAudio();
   void ResetVideo(const PrincipalHandle& aPrincipalHandle);
   void SendData();
   void NotifyOutput(int64_t aTime);
 
   void AssertOwnerThread() const {
     MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   }