Bug 1172390 - Align stream blocking of decoded stream with play state of MDSM. r=roc.

This commit is contained in:
JW Wang 2015-06-08 16:51:39 +08:00
parent 1bf24e0cc5
commit 9b52f419be
6 changed files with 45 additions and 92 deletions

View File

@ -165,18 +165,10 @@ AudioSink::SetPreservesPitch(bool aPreservesPitch)
}
void
AudioSink::StartPlayback()
AudioSink::SetPlaying(bool aPlaying)
{
AssertCurrentThreadInMonitor();
mPlaying = true;
GetReentrantMonitor().NotifyAll();
}
void
AudioSink::StopPlayback()
{
AssertCurrentThreadInMonitor();
mPlaying = false;
mPlaying = aPlaying;
GetReentrantMonitor().NotifyAll();
}

View File

@ -42,8 +42,7 @@ public:
void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
void StartPlayback();
void StopPlayback();
void SetPlaying(bool aPlaying);
private:
~AudioSink() {}

View File

@ -69,6 +69,19 @@ private:
bool mStreamFinishedOnMainThread;
};
static void
UpdateStreamBlocking(MediaStream* aStream, bool aBlocking)
{
int32_t delta = aBlocking ? 1 : -1;
if (NS_IsMainThread()) {
aStream->ChangeExplicitBlockerCount(delta);
} else {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<int32_t>(
aStream, &MediaStream::ChangeExplicitBlockerCount, delta);
AbstractThread::MainThread()->Dispatch(r.forget());
}
}
DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream)
: mAudioFramesWritten(0)
, mNextVideoTime(-1)
@ -78,14 +91,13 @@ DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream)
, mHaveSentFinishAudio(false)
, mHaveSentFinishVideo(false)
, mStream(aStream)
, mHaveBlockedForPlayState(false)
, mHaveBlockedForStateMachineNotPlaying(false)
, mPlaying(false)
, mEOSVideoCompensation(false)
{
mListener = new DecodedStreamGraphListener(mStream);
mStream->AddListener(mListener);
// Block the stream until the initialization is done.
mStream->ChangeExplicitBlockerCount(1);
// Block the stream as mPlaying is initially false.
UpdateStreamBlocking(mStream, true);
}
DecodedStreamData::~DecodedStreamData()
@ -106,6 +118,15 @@ DecodedStreamData::GetPosition() const
return mListener->GetLastOutputTime();
}
void
DecodedStreamData::SetPlaying(bool aPlaying)
{
if (mPlaying != aPlaying) {
mPlaying = aPlaying;
UpdateStreamBlocking(mStream, !mPlaying);
}
}
class OutputStreamListener : public MediaStreamListener {
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
public:
@ -290,4 +311,12 @@ DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
}
}
void
DecodedStream::SetPlaying(bool aPlaying)
{
GetReentrantMonitor().AssertCurrentThreadIn();
MOZ_ASSERT(mData);
mData->SetPlaying(aPlaying);
}
} // namespace mozilla

View File

@ -41,6 +41,7 @@ public:
~DecodedStreamData();
bool IsFinished() const;
int64_t GetPosition() const;
void SetPlaying(bool aPlaying);
/* The following group of fields are protected by the decoder's monitor
* and can be read or written on any thread.
@ -66,12 +67,7 @@ public:
// The decoder is responsible for calling Destroy() on this stream.
const nsRefPtr<SourceMediaStream> mStream;
nsRefPtr<DecodedStreamGraphListener> mListener;
// True when we've explicitly blocked this stream because we're
// not in PLAY_STATE_PLAYING. Used on the main thread only.
bool mHaveBlockedForPlayState;
// We also have an explicit blocker on the stream when
// mDecoderStateMachine is non-null and MediaDecoderStateMachine is false.
bool mHaveBlockedForStateMachineNotPlaying;
bool mPlaying;
// True if we need to send a compensation video frame to ensure the
// StreamTime going forward.
bool mEOSVideoCompensation;
@ -96,6 +92,7 @@ public:
nsTArray<OutputStreamData>& OutputStreams();
ReentrantMonitor& GetReentrantMonitor() const;
void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
void SetPlaying(bool aPlaying);
private:
void Connect(OutputStreamData* aStream);

View File

@ -314,8 +314,6 @@ MediaDecoderStateMachine::InitializationTask()
mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::UpdateStreamBlockingForPlayState);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::UpdateStreamBlockingForPlayState);
}
bool MediaDecoderStateMachine::HasFutureAudio()
@ -430,19 +428,6 @@ static bool ZeroDurationAtLastChunk(VideoSegment& aInput)
return lastVideoStratTime == aInput.GetDuration();
}
static void
UpdateStreamBlocking(MediaStream* aStream, bool aBlocking)
{
int32_t delta = aBlocking ? 1 : -1;
if (NS_IsMainThread()) {
aStream->ChangeExplicitBlockerCount(delta);
} else {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<int32_t>(
aStream, &MediaStream::ChangeExplicitBlockerCount, delta);
AbstractThread::MainThread()->Dispatch(r.forget());
}
}
void MediaDecoderStateMachine::SendStreamData()
{
MOZ_ASSERT(OnTaskQueue());
@ -481,12 +466,6 @@ void MediaDecoderStateMachine::SendStreamData()
}
mediaStream->FinishAddTracks();
stream->mStreamInitialized = true;
// Make sure stream blocking is updated before sending stream data so we
// don't 'leak' data when the stream is supposed to be blocked.
UpdateStreamBlockingForPlayState();
UpdateStreamBlockingForStateMachinePlaying();
UpdateStreamBlocking(mediaStream, false);
}
if (mInfo.HasAudio()) {
@ -1295,7 +1274,6 @@ void MediaDecoderStateMachine::StopPlayback()
// so it can pause audio playback.
mDecoder->GetReentrantMonitor().NotifyAll();
NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()");
UpdateStreamBlockingForStateMachinePlaying();
DispatchDecodeTasksIfNeeded();
}
@ -1333,7 +1311,6 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
NS_ENSURE_SUCCESS_VOID(rv);
mDecoder->GetReentrantMonitor().NotifyAll();
UpdateStreamBlockingForStateMachinePlaying();
DispatchDecodeTasksIfNeeded();
}
@ -3296,13 +3273,11 @@ void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
{
AssertCurrentThreadInMonitor();
mPlayStartTime = aTimeStamp;
if (!mAudioSink) {
return;
}
if (!mPlayStartTime.IsNull()) {
mAudioSink->StartPlayback();
} else {
mAudioSink->StopPlayback();
if (mAudioSink) {
mAudioSink->SetPlaying(!mPlayStartTime.IsNull());
} else if (mAudioCaptured) {
mDecodedStream.SetPlaying(!mPlayStartTime.IsNull());
}
}
@ -3526,44 +3501,12 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
DispatchAudioCaptured();
}
void MediaDecoderStateMachine::UpdateStreamBlockingForPlayState()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
auto stream = GetDecodedStream();
if (!stream) {
return;
}
bool blocking = mPlayState != MediaDecoder::PLAY_STATE_PLAYING ||
mLogicallySeeking;
if (blocking != stream->mHaveBlockedForPlayState) {
stream->mHaveBlockedForPlayState = blocking;
UpdateStreamBlocking(stream->mStream, blocking);
}
}
void MediaDecoderStateMachine::UpdateStreamBlockingForStateMachinePlaying()
{
AssertCurrentThreadInMonitor();
auto stream = GetDecodedStream();
if (!stream) {
return;
}
bool blocking = !IsPlaying();
if (blocking != stream->mHaveBlockedForStateMachineNotPlaying) {
stream->mHaveBlockedForStateMachineNotPlaying = blocking;
UpdateStreamBlocking(stream->mStream, blocking);
}
}
void MediaDecoderStateMachine::RecreateDecodedStream(MediaStreamGraph* aGraph)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecodedStream.RecreateData(aGraph);
mDecodedStream.SetPlaying(IsPlaying());
}
} // namespace mozilla

View File

@ -162,13 +162,6 @@ private:
void DispatchAudioCaptured();
// Update blocking state of mDecodedStream when mPlayState or
// mLogicallySeeking change. Decoder monitor must be held.
void UpdateStreamBlockingForPlayState();
// Call this IsPlaying() changes. Decoder monitor must be held.
void UpdateStreamBlockingForStateMachinePlaying();
// Recreates mDecodedStream. Call this to create mDecodedStream at first,
// and when seeking, to ensure a new stream is set up with fresh buffers.
// Decoder monitor must be held.