Bug 943461. Part 8: When a MediaDecoder is decoding to a stream, run PlaybackEnded when the stream finishes. r=padenot

--HG--
extra : rebase_source : 92c8b55c5d8330bcf8242d379bc608fa3d30bc6b
This commit is contained in:
Robert O'Callahan 2013-12-07 01:01:33 +13:00
Родитель bffdca06e1
Коммит 8db811d2b5
4 изменённых файлов: 50 добавлений и 50 удалений

Просмотреть файл

@ -200,29 +200,20 @@ MediaDecoder::DecodedStreamData::DecodedStreamData(MediaDecoder* aDecoder,
mHaveBlockedForPlayState(false),
mHaveBlockedForStateMachineNotPlaying(false)
{
mStream->AddMainThreadListener(this);
mListener = new DecodedStreamGraphListener(mStream);
mListener = new DecodedStreamGraphListener(mStream, this);
mStream->AddListener(mListener);
}
MediaDecoder::DecodedStreamData::~DecodedStreamData()
{
mStream->RemoveMainThreadListener(this);
mListener->Forget();
mStream->Destroy();
}
void
MediaDecoder::DecodedStreamData::NotifyMainThreadStateChanged()
{
mDecoder->NotifyDecodedStreamMainThreadStateChanged();
if (mStream->IsFinished()) {
mListener->SetFinishedOnMainThread(true);
}
}
MediaDecoder::DecodedStreamGraphListener::DecodedStreamGraphListener(MediaStream* aStream)
: mMutex("MediaDecoder::DecodedStreamData::mMutex"),
MediaDecoder::DecodedStreamGraphListener::DecodedStreamGraphListener(MediaStream* aStream,
DecodedStreamData* aData)
: mData(aData),
mMutex("MediaDecoder::DecodedStreamData::mMutex"),
mStream(aStream),
mLastOutputTime(aStream->GetCurrentTime()),
mStreamFinishedOnMainThread(false)
@ -239,6 +230,29 @@ MediaDecoder::DecodedStreamGraphListener::NotifyOutput(MediaStreamGraph* aGraph,
}
}
void
MediaDecoder::DecodedStreamGraphListener::DoNotifyFinished()
{
if (mData && mData->mDecoder) {
if (mData->mDecoder->GetState() == PLAY_STATE_PLAYING) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mData->mDecoder, &MediaDecoder::PlaybackEnded);
NS_DispatchToCurrentThread(event);
}
}
MutexAutoLock lock(mMutex);
mStreamFinishedOnMainThread = true;
}
void
MediaDecoder::DecodedStreamGraphListener::NotifyFinished(MediaStreamGraph* aGraph)
{
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
void MediaDecoder::DestroyDecodedStream()
{
MOZ_ASSERT(NS_IsMainThread());
@ -326,19 +340,6 @@ void MediaDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs)
}
}
void MediaDecoder::NotifyDecodedStreamMainThreadStateChanged()
{
if (mTriggerPlaybackEndedWhenSourceStreamFinishes && mDecodedStream &&
mDecodedStream->mStream->IsFinished()) {
mTriggerPlaybackEndedWhenSourceStreamFinishes = false;
if (GetState() == PLAY_STATE_PLAYING) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &MediaDecoder::PlaybackEnded);
NS_DispatchToCurrentThread(event);
}
}
}
void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
bool aFinishWhenEnded)
{
@ -421,7 +422,6 @@ MediaDecoder::MediaDecoder() :
mCalledResourceLoaded(false),
mIgnoreProgressData(false),
mInfiniteStream(false),
mTriggerPlaybackEndedWhenSourceStreamFinishes(false),
mOwner(nullptr),
mFrameBufferLength(0),
mPinnedForSeek(false),
@ -936,12 +936,6 @@ void MediaDecoder::PlaybackEnded()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mDecodedStream && !mDecodedStream->mStream->IsFinished()) {
// Wait for it to finish before firing PlaybackEnded()
mTriggerPlaybackEndedWhenSourceStreamFinishes = true;
return;
}
for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
OutputStreamData& os = mOutputStreams[i];
if (os.mStream->IsDestroyed()) {

Просмотреть файл

@ -350,13 +350,11 @@ public:
// replaying after the input as ended. In the latter case, the new source is
// not connected to streams created by captureStreamUntilEnded.
struct DecodedStreamData MOZ_FINAL : public MainThreadMediaStreamListener {
struct DecodedStreamData {
DecodedStreamData(MediaDecoder* aDecoder,
int64_t aInitialTime, SourceMediaStream* aStream);
~DecodedStreamData();
virtual void NotifyMainThreadStateChanged() MOZ_OVERRIDE;
StreamTime GetLastOutputTime() { return mListener->GetLastOutputTime(); }
bool IsFinished() { return mListener->IsFinishedOnMainThread(); }
@ -400,8 +398,11 @@ public:
class DecodedStreamGraphListener : public MediaStreamListener {
public:
DecodedStreamGraphListener(MediaStream* aStream);
DecodedStreamGraphListener(MediaStream* aStream, DecodedStreamData* aData);
virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) MOZ_OVERRIDE;
virtual void NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE;
void DoNotifyFinished();
StreamTime GetLastOutputTime()
{
@ -410,13 +411,18 @@ public:
}
void Forget()
{
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
mData = nullptr;
MutexAutoLock lock(mMutex);
mStream = nullptr;
}
void SetFinishedOnMainThread(bool aFinished)
bool SetFinishedOnMainThread(bool aFinished)
{
MutexAutoLock lock(mMutex);
bool result = !mStreamFinishedOnMainThread;
mStreamFinishedOnMainThread = aFinished;
return result;
}
bool IsFinishedOnMainThread()
{
@ -424,6 +430,9 @@ public:
return mStreamFinishedOnMainThread;
}
private:
// Main thread only
DecodedStreamData* mData;
Mutex mMutex;
// Protected by mMutex
nsRefPtr<MediaStream> mStream;
@ -465,12 +474,6 @@ public:
* Decoder monitor must be held.
*/
void UpdateStreamBlockingForStateMachinePlaying();
/**
* Called when the state of mDecodedStream as visible on the main thread
* has changed. In particular we want to know when the stream has finished
* so we can call PlaybackEnded.
*/
void NotifyDecodedStreamMainThreadStateChanged();
nsTArray<OutputStreamData>& OutputStreams()
{
GetReentrantMonitor().AssertCurrentThreadIn();
@ -1134,10 +1137,6 @@ protected:
// True if the stream is infinite (e.g. a webradio).
bool mInfiniteStream;
// True if NotifyDecodedStreamMainThreadStateChanged should retrigger
// PlaybackEnded when mDecodedStream->mStream finishes.
bool mTriggerPlaybackEndedWhenSourceStreamFinishes;
// Start timer to update download progress information.
nsresult StartProgress();

Просмотреть файл

@ -2369,10 +2369,14 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
}
StopAudioThread();
if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING) {
// When we're decoding to a stream, the stream's main-thread finish signal
// will take care of calling MediaDecoder::PlaybackEnded.
if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
!mDecoder->GetDecodedStream()) {
int64_t videoTime = HasVideo() ? mVideoFrameEndTime : 0;
int64_t clockTime = std::max(mEndTime, std::max(videoTime, GetAudioClock()));
UpdatePlaybackPosition(clockTime);
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &MediaDecoder::PlaybackEnded);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);

Просмотреть файл

@ -52,6 +52,9 @@ public:
for (uint32_t i = 0; i < mInputs.Length(); ++i) {
MediaStream* stream = mInputs[i]->GetSource();
if (!stream->IsFinishedOnGraphThread()) {
// XXX we really should check whether 'stream' has finished within time aTo,
// not just that it's finishing when all its queued data eventually runs
// out.
allFinished = false;
}
if (!stream->HasCurrentData()) {