diff --git a/dom/media/DecodedStream.cpp b/dom/media/DecodedStream.cpp index 353d88e44c7..4a549642fd4 100644 --- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -10,7 +10,6 @@ #include "VideoSegment.h" #include "MediaQueue.h" #include "MediaData.h" -#include "MediaInfo.h" #include "SharedBuffer.h" #include "VideoUtils.h" @@ -195,6 +194,22 @@ DecodedStream::DecodedStream(MediaQueue& aAudioQueue, // } +void +DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo) +{ + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + if (mStartTime.isNothing()) { + mStartTime.emplace(aStartTime); + mInfo = aInfo; + } +} + +void DecodedStream::StopPlayback() +{ + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + mStartTime.reset(); +} + void DecodedStream::DestroyData() { @@ -347,7 +362,7 @@ DecodedStream::SetPlaying(bool aPlaying) } void -DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo) +DecodedStream::InitTracks() { GetReentrantMonitor().AssertCurrentThreadIn(); @@ -357,20 +372,20 @@ DecodedStream::InitTracks(int64_t aStartTime, const MediaInfo& aInfo) SourceMediaStream* sourceStream = mData->mStream; - if (aInfo.HasAudio()) { - TrackID audioTrackId = aInfo.mAudio.mTrackId; + if (mInfo.HasAudio()) { + TrackID audioTrackId = mInfo.mAudio.mTrackId; AudioSegment* audio = new AudioSegment(); - sourceStream->AddAudioTrack(audioTrackId, aInfo.mAudio.mRate, 0, audio, + sourceStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio, SourceMediaStream::ADDTRACK_QUEUED); - mData->mNextAudioTime = aStartTime; + mData->mNextAudioTime = mStartTime.ref(); } - if (aInfo.HasVideo()) { - TrackID videoTrackId = aInfo.mVideo.mTrackId; + if (mInfo.HasVideo()) { + TrackID videoTrackId = mInfo.mVideo.mTrackId; VideoSegment* video = new VideoSegment(); sourceStream->AddTrack(videoTrackId, 0, video, SourceMediaStream::ADDTRACK_QUEUED); - mData->mNextVideoTime = aStartTime; + mData->mNextVideoTime = mStartTime.ref(); } sourceStream->FinishAddTracks(); @@ -425,27 +440,25 @@ SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime, } void -DecodedStream::SendAudio(int64_t aStartTime, - const MediaInfo& aInfo, - double aVolume, bool aIsSameOrigin) +DecodedStream::SendAudio(double aVolume, bool aIsSameOrigin) { GetReentrantMonitor().AssertCurrentThreadIn(); - if (!aInfo.HasAudio()) { + if (!mInfo.HasAudio()) { return; } AudioSegment output; - uint32_t rate = aInfo.mAudio.mRate; + uint32_t rate = mInfo.mAudio.mRate; nsAutoTArray,10> audio; - TrackID audioTrackId = aInfo.mAudio.mTrackId; + TrackID audioTrackId = mInfo.mAudio.mTrackId; SourceMediaStream* sourceStream = mData->mStream; // It's OK to hold references to the AudioData because AudioData // is ref-counted. mAudioQueue.GetElementsAfter(mData->mNextAudioTime, &audio); for (uint32_t i = 0; i < audio.Length(); ++i) { - SendStreamAudio(mData.get(), aStartTime, audio[i], &output, rate, aVolume); + SendStreamAudio(mData.get(), mStartTime.ref(), audio[i], &output, rate, aVolume); } if (!aIsSameOrigin) { @@ -492,18 +505,16 @@ ZeroDurationAtLastChunk(VideoSegment& aInput) } void -DecodedStream::SendVideo(int64_t aStartTime, - const MediaInfo& aInfo, - bool aIsSameOrigin) +DecodedStream::SendVideo(bool aIsSameOrigin) { GetReentrantMonitor().AssertCurrentThreadIn(); - if (!aInfo.HasVideo()) { + if (!mInfo.HasVideo()) { return; } VideoSegment output; - TrackID videoTrackId = aInfo.mVideo.mTrackId; + TrackID videoTrackId = mInfo.mVideo.mTrackId; nsAutoTArray, 10> video; SourceMediaStream* sourceStream = mData->mStream; @@ -572,21 +583,21 @@ DecodedStream::SendVideo(int64_t aStartTime, } void -DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo) +DecodedStream::AdvanceTracks() { GetReentrantMonitor().AssertCurrentThreadIn(); StreamTime endPosition = 0; - if (aInfo.HasAudio()) { + if (mInfo.HasAudio()) { StreamTime audioEnd = mData->mStream->TicksToTimeRoundDown( - aInfo.mAudio.mRate, mData->mAudioFramesWritten); + mInfo.mAudio.mRate, mData->mAudioFramesWritten); endPosition = std::max(endPosition, audioEnd); } - if (aInfo.HasVideo()) { + if (mInfo.HasVideo()) { StreamTime videoEnd = mData->mStream->MicrosecondsToStreamTimeRoundDown( - mData->mNextVideoTime - aStartTime); + mData->mNextVideoTime - mStartTime.ref()); endPosition = std::max(endPosition, videoEnd); } @@ -596,19 +607,18 @@ DecodedStream::AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo) } bool -DecodedStream::SendData(int64_t aStartTime, - const MediaInfo& aInfo, - double aVolume, bool aIsSameOrigin) +DecodedStream::SendData(double aVolume, bool aIsSameOrigin) { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()"); - InitTracks(aStartTime, aInfo); - SendAudio(aStartTime, aInfo, aVolume, aIsSameOrigin); - SendVideo(aStartTime, aInfo, aIsSameOrigin); - AdvanceTracks(aStartTime, aInfo); + InitTracks(); + SendAudio(aVolume, aIsSameOrigin); + SendVideo(aIsSameOrigin); + AdvanceTracks(); - bool finished = (!aInfo.HasAudio() || mAudioQueue.IsFinished()) && - (!aInfo.HasVideo() || mVideoQueue.IsFinished()); + bool finished = (!mInfo.HasAudio() || mAudioQueue.IsFinished()) && + (!mInfo.HasVideo() || mVideoQueue.IsFinished()); if (finished && !mData->mHaveSentFinish) { mData->mHaveSentFinish = true; @@ -619,10 +629,12 @@ DecodedStream::SendData(int64_t aStartTime, } CheckedInt64 -DecodedStream::AudioEndTime(int64_t aStartTime, uint32_t aRate) const +DecodedStream::AudioEndTime() const { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - return aStartTime + FramesToUsecs(mData->mAudioFramesWritten, aRate); + MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()"); + return mStartTime.ref() + + FramesToUsecs(mData->mAudioFramesWritten, mInfo.mAudio.mRate); } int64_t diff --git a/dom/media/DecodedStream.h b/dom/media/DecodedStream.h index e8438846c3e..edba87cebc3 100644 --- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -9,17 +9,18 @@ #include "nsRefPtr.h" #include "nsTArray.h" +#include "MediaInfo.h" #include "mozilla/UniquePtr.h" #include "mozilla/gfx/Point.h" #include "mozilla/CheckedInt.h" #include "mozilla/ReentrantMonitor.h" +#include "mozilla/Maybe.h" namespace mozilla { class AudioData; class VideoData; -class MediaInfo; class AudioSegment; class MediaStream; class MediaInputPort; @@ -98,19 +99,24 @@ class DecodedStream { public: DecodedStream(MediaQueue& aAudioQueue, MediaQueue& aVideoQueue); + + // Mimic MDSM::StartAudioThread. + // Must be called before any calls to SendData(). + void StartPlayback(int64_t aStartTime, const MediaInfo& aInfo); + // Mimic MDSM::StopAudioThread. + void StopPlayback(); + void DestroyData(); void RecreateData(); void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded); void Remove(MediaStream* aStream); void SetPlaying(bool aPlaying); - CheckedInt64 AudioEndTime(int64_t aStartTime, uint32_t aRate) const; + CheckedInt64 AudioEndTime() const; int64_t GetPosition() const; bool IsFinished() const; // Return true if stream is finished. - bool SendData(int64_t aStartTime, - const MediaInfo& aInfo, - double aVolume, bool aIsSameOrigin); + bool SendData(double aVolume, bool aIsSameOrigin); protected: virtual ~DecodedStream() {} @@ -120,16 +126,10 @@ private: void RecreateData(MediaStreamGraph* aGraph); void Connect(OutputStreamData* aStream); nsTArray& OutputStreams(); - void InitTracks(int64_t aStartTime, const MediaInfo& aInfo); - void AdvanceTracks(int64_t aStartTime, const MediaInfo& aInfo); - - void SendAudio(int64_t aStartTime, - const MediaInfo& aInfo, - double aVolume, bool aIsSameOrigin); - - void SendVideo(int64_t aStartTime, - const MediaInfo& aInfo, - bool aIsSameOrigin); + void InitTracks(); + void AdvanceTracks(); + void SendAudio(double aVolume, bool aIsSameOrigin); + void SendVideo(bool aIsSameOrigin); UniquePtr mData; // Data about MediaStreams that are being fed by the decoder. @@ -145,6 +145,9 @@ private: mutable ReentrantMonitor mMonitor; bool mPlaying; + Maybe mStartTime; + MediaInfo mInfo; + MediaQueue& mAudioQueue; MediaQueue& mVideoQueue; }; diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index bcd300bda7c..25b09a1aec6 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -371,12 +371,10 @@ void MediaDecoderStateMachine::SendStreamData() AssertCurrentThreadInMonitor(); MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()"); - bool finished = mDecodedStream->SendData( - mStreamStartTime, mInfo, mVolume, mDecoder->IsSameOriginMedia()); + bool finished = mDecodedStream->SendData(mVolume, mDecoder->IsSameOriginMedia()); if (mInfo.HasAudio()) { - CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime( - mStreamStartTime, mInfo.mAudio.mRate); + CheckedInt64 playedUsecs = mDecodedStream->AudioEndTime(); if (playedUsecs.isValid()) { OnAudioEndTimeUpdate(playedUsecs.value()); } @@ -1094,6 +1092,12 @@ void MediaDecoderStateMachine::MaybeStartPlayback() nsresult rv = StartAudioThread(); NS_ENSURE_SUCCESS_VOID(rv); + // Tell DecodedStream to start playback with specified start time and media + // info. This is consistent with how we create AudioSink in StartAudioThread(). + if (mAudioCaptured) { + mDecodedStream->StartPlayback(GetMediaTime(), mInfo); + } + mDecoder->GetReentrantMonitor().NotifyAll(); DispatchDecodeTasksIfNeeded(); } @@ -2421,6 +2425,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine() } StopAudioThread(); + mDecodedStream->StopPlayback(); if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING && !mSentPlaybackEndedEvent) @@ -2462,6 +2467,7 @@ MediaDecoderStateMachine::Reset() // outside of the decoder monitor while we are clearing the queue and causes // crash for no samples to be popped. StopAudioThread(); + mDecodedStream->StopPlayback(); mVideoFrameEndTime = -1; mDecodedVideoEndTime = -1; @@ -3141,6 +3147,11 @@ void MediaDecoderStateMachine::DispatchAudioCaptured() // stream. Otherwise it will remain -1 if we don't have audio. self->mAudioEndTime = -1; self->mAudioCaptured = true; + // Start DecodedStream if we are already playing. Otherwise it will be + // handled in MaybeStartPlayback(). + if (self->IsPlaying()) { + self->mDecodedStream->StartPlayback(self->GetMediaTime(), self->mInfo); + } self->ScheduleStateMachine(); } });