Bug 1195632. Part 1 - Let DecodedStream have a worker thread and asset some funtions on the worker thread. r=roc.
authorJW Wang <jwwang@mozilla.com>
Mon, 24 Aug 2015 09:55:30 +0800
changeset 259015 6521d38bea7a838946c9f2f1d40c985ffd911ff8
parent 259014 2bd4cb790c48d3f6d3da0ea9b03ce5cfb40e6b46
child 259016 d7f6ba1197608932989a0ace028aa4d45fd66331
push id29268
push userryanvm@gmail.com
push dateTue, 25 Aug 2015 00:37:23 +0000
treeherdermozilla-central@08015770c9d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1195632
milestone43.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 1195632. Part 1 - Let DecodedStream have a worker thread and asset some funtions on the worker thread. r=roc.
dom/media/DecodedStream.cpp
dom/media/DecodedStream.h
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/DecodedStream.cpp
+++ b/dom/media/DecodedStream.cpp
@@ -349,34 +349,37 @@ OutputStreamManager::Disconnect()
   for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
     if (!mStreams[i].Disconnect()) {
       // Probably the DOMMediaStream was GCed. Clean up.
       mStreams.RemoveElementAt(i);
     }
   }
 }
 
-DecodedStream::DecodedStream(MediaQueue<MediaData>& aAudioQueue,
+DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
+                             MediaQueue<MediaData>& aAudioQueue,
                              MediaQueue<MediaData>& aVideoQueue)
-  : mMonitor("DecodedStream::mMonitor")
+  : mOwnerThread(aOwnerThread)
+  , mMonitor("DecodedStream::mMonitor")
   , mPlaying(false)
   , mVolume(1.0)
   , mAudioQueue(aAudioQueue)
   , mVideoQueue(aVideoQueue)
 {
 }
 
 DecodedStream::~DecodedStream()
 {
   MOZ_ASSERT(mStartTime.isNothing(), "playback should've ended.");
 }
 
 nsRefPtr<GenericPromise>
 DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
 
   mStartTime.emplace(aStartTime);
   mInfo = aInfo;
 
   class R : public nsRunnable {
     typedef MozPromiseHolder<GenericPromise> Promise;
@@ -403,16 +406,17 @@ DecodedStream::StartPlayback(int64_t aSt
   nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(promise));
   AbstractThread::MainThread()->Dispatch(r.forget());
 
   return rv.forget();
 }
 
 void DecodedStream::StopPlayback()
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   // Playback didn't even start at all.
   if (mStartTime.isNothing()) {
     return;
   }
   mStartTime.reset();
 
   // Clear mData immediately when this playback session ends so we won't
@@ -475,40 +479,44 @@ void
 DecodedStream::RemoveOutput(MediaStream* aStream)
 {
   mOutputStreamManager.Remove(aStream);
 }
 
 void
 DecodedStream::SetPlaying(bool aPlaying)
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mPlaying = aPlaying;
   if (mData) {
     mData->SetPlaying(aPlaying);
   }
 }
 
 void
 DecodedStream::SetVolume(double aVolume)
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mVolume = aVolume;
 }
 
 void
 DecodedStream::SetSameOrigin(bool aSameOrigin)
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mSameOrigin = aSameOrigin;
 }
 
 void
 DecodedStream::InitTracks()
 {
+  AssertOwnerThread();
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (mData->mStreamInitialized) {
     return;
   }
 
   SourceMediaStream* sourceStream = mData->mStream;
 
@@ -579,16 +587,17 @@ SendStreamAudio(DecodedStreamData* aStre
   aOutput->ApplyVolume(aVolume);
 
   aStream->mNextAudioTime = audio->GetEndTime();
 }
 
 void
 DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin)
 {
+  AssertOwnerThread();
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (!mInfo.HasAudio()) {
     return;
   }
 
   AudioSegment output;
   uint32_t rate = mInfo.mAudio.mRate;
@@ -644,16 +653,17 @@ ZeroDurationAtLastChunk(VideoSegment& aI
   StreamTime lastVideoStratTime;
   aInput.GetLastFrame(&lastVideoStratTime);
   return lastVideoStratTime == aInput.GetDuration();
 }
 
 void
 DecodedStream::SendVideo(bool aIsSameOrigin)
 {
+  AssertOwnerThread();
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (!mInfo.HasVideo()) {
     return;
   }
 
   VideoSegment output;
   TrackID videoTrackId = mInfo.mVideo.mTrackId;
@@ -722,16 +732,17 @@ DecodedStream::SendVideo(bool aIsSameOri
     sourceStream->EndTrack(videoTrackId);
     mData->mHaveSentFinishVideo = true;
   }
 }
 
 void
 DecodedStream::AdvanceTracks()
 {
+  AssertOwnerThread();
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   StreamTime endPosition = 0;
 
   if (mInfo.HasAudio()) {
     StreamTime audioEnd = mData->mStream->TicksToTimeRoundDown(
         mInfo.mAudio.mRate, mData->mAudioFramesWritten);
     endPosition = std::max(endPosition, audioEnd);
@@ -746,16 +757,17 @@ DecodedStream::AdvanceTracks()
   if (!mData->mHaveSentFinish) {
     mData->mStream->AdvanceKnownTracksTime(endPosition);
   }
 }
 
 void
 DecodedStream::SendData()
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
 
   // Not yet created on the main thread. MDSM will try again later.
   if (!mData) {
     return;
   }
 
@@ -776,37 +788,40 @@ DecodedStream::SendData()
     mData->mHaveSentFinish = true;
     mData->mStream->Finish();
   }
 }
 
 int64_t
 DecodedStream::AudioEndTime() const
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (mStartTime.isSome() && mInfo.HasAudio() && mData) {
     CheckedInt64 t = mStartTime.ref() +
       FramesToUsecs(mData->mAudioFramesWritten, mInfo.mAudio.mRate);
     if (t.isValid()) {
       return t.value();
     }
   }
   return -1;
 }
 
 int64_t
 DecodedStream::GetPosition() const
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   // This is only called after MDSM starts playback. So mStartTime is
   // guaranteed to be something.
   MOZ_ASSERT(mStartTime.isSome());
   return mStartTime.ref() + (mData ? mData->GetPosition() : 0);
 }
 
 bool
 DecodedStream::IsFinished() const
 {
+  AssertOwnerThread();
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   return mData && mData->IsFinished();
 }
 
 } // namespace mozilla
--- a/dom/media/DecodedStream.h
+++ b/dom/media/DecodedStream.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DecodedStream_h_
 #define DecodedStream_h_
 
 #include "nsTArray.h"
 #include "MediaInfo.h"
 
+#include "mozilla/AbstractThread.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/nsRefPtr.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/gfx/Point.h"
 
@@ -95,17 +96,18 @@ private:
   // are added after Connect().
   nsRefPtr<MediaStream> mInputStream;
   nsTArray<OutputStreamData> mStreams;
 };
 
 class DecodedStream {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
 public:
-  DecodedStream(MediaQueue<MediaData>& aAudioQueue,
+  DecodedStream(AbstractThread* aOwnerThread,
+                MediaQueue<MediaData>& aAudioQueue,
                 MediaQueue<MediaData>& aVideoQueue);
 
   // Mimic MDSM::StartAudioThread.
   // Must be called before any calls to SendData().
   //
   // Return a promise which will be resolved when the stream is finished
   // or rejected if any error.
   nsRefPtr<GenericPromise> StartPlayback(int64_t aStartTime,
@@ -133,16 +135,22 @@ protected:
 private:
   ReentrantMonitor& GetReentrantMonitor() const;
   void CreateData(MozPromiseHolder<GenericPromise>&& aPromise);
   void InitTracks();
   void AdvanceTracks();
   void SendAudio(double aVolume, bool aIsSameOrigin);
   void SendVideo(bool aIsSameOrigin);
 
+  void AssertOwnerThread() const {
+    MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  }
+
+  const nsRefPtr<AbstractThread> mOwnerThread;
+
   UniquePtr<DecodedStreamData> mData;
   // Data about MediaStreams that are being fed by the decoder.
   OutputStreamManager mOutputStreamManager;
 
   // TODO: This is a temp solution to get rid of decoder monitor on the main
   // thread in MDSM::AddOutputStream and MDSM::RecreateDecodedStream as
   // required by bug 1146482. DecodedStream needs to release monitor before
   // calling back into MDSM functions in order to prevent deadlocks.
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -216,17 +216,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
   mCurrentTimeBeforeSeek(0),
   mCorruptFrames(30),
   mDecodingFirstFrame(true),
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false),
   mSentPlaybackEndedEvent(false),
-  mDecodedStream(new DecodedStream(mAudioQueue, mVideoQueue)),
+  mDecodedStream(new DecodedStream(mTaskQueue, mAudioQueue, mVideoQueue)),
   mResource(aDecoder->GetResource()),
   mBuffered(mTaskQueue, TimeIntervals(),
             "MediaDecoderStateMachine::mBuffered (Mirror)"),
   mEstimatedDuration(mTaskQueue, NullableTimeUnit(),
                     "MediaDecoderStateMachine::mEstimatedDuration (Mirror)"),
   mExplicitDuration(mTaskQueue, Maybe<double>(),
                     "MediaDecoderStateMachine::mExplicitDuration (Mirror)"),
   mPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_LOADING,