diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index 44ca2d92278..26698623d5b 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -283,18 +283,28 @@ MediaDecoderReader::BreakCycles() mTaskQueue = nullptr; } -void +nsRefPtr MediaDecoderReader::Shutdown() { MOZ_ASSERT(OnDecodeThread()); mShutdown = true; ReleaseMediaResources(); + nsRefPtr p; + + // Spin down the task queue if necessary. We wait until BreakCycles to null + // out mTaskQueue, since otherwise any remaining tasks could crash when they + // invoke GetTaskQueue()->IsCurrentThreadIn(). if (mTaskQueue && !mTaskQueueIsBorrowed) { - // We may be running in the task queue ourselves, so we don't block this - // thread on task queue draining, since that would deadlock. - mTaskQueue->BeginShutdown(); + // If we own our task queue, shutdown ends when the task queue is done. + p = mTaskQueue->BeginShutdown(); + } else { + // If we don't own our task queue, we resolve immediately (though + // asynchronously). + p = new ShutdownPromise(__func__); + p->Resolve(true, __func__); } - mTaskQueue = nullptr; + + return p; } AudioDecodeRendezvous::AudioDecodeRendezvous() diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index 508ee8fa8bd..eaee9c0c33a 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -65,7 +65,7 @@ public: // This is different from ReleaseMediaResources() as it is irreversable, // whereas ReleaseMediaResources() is. Must be called on the decode // thread. - virtual void Shutdown(); + virtual nsRefPtr Shutdown(); virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback); MediaTaskQueue* EnsureTaskQueue(); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 798f0860ba3..9f899eb2215 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2470,6 +2470,53 @@ private: nsRefPtr mStateMachine; }; +void +MediaDecoderStateMachine::ShutdownReader() +{ + MOZ_ASSERT(OnDecodeThread()); + mReader->Shutdown()->Then(GetStateMachineThread(), __func__, this, + &MediaDecoderStateMachine::FinishShutdown, + &MediaDecoderStateMachine::FinishShutdown); +} + +void +MediaDecoderStateMachine::FinishShutdown(bool aSuccess) +{ + MOZ_ASSERT(OnStateMachineThread()); + MOZ_ASSERT(aSuccess); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + + // The reader's listeners hold references to the state machine, + // creating a cycle which keeps the state machine and its shared + // thread pools alive. So break it here. + AudioQueue().ClearListeners(); + VideoQueue().ClearListeners(); + + // Now that those threads are stopped, there's no possibility of + // mPendingWakeDecoder being needed again. Revoke it. + mPendingWakeDecoder = nullptr; + + MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN, + "How did we escape from the shutdown state?"); + // We must daisy-chain these events to destroy the decoder. We must + // destroy the decoder on the main thread, but we can't destroy the + // decoder while this thread holds the decoder monitor. We can't + // dispatch an event to the main thread to destroy the decoder from + // here, as the event may run before the dispatch returns, and we + // hold the decoder monitor here. We also want to guarantee that the + // state machine is destroyed on the main thread, and so the + // event runner running this function (which holds a reference to the + // state machine) needs to finish and be released in order to allow + // that. So we dispatch an event to run after this event runner has + // finished and released its monitor/references. That event then will + // dispatch an event to the main thread to release the decoder and + // state machine. + GetStateMachineThread()->Dispatch( + new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL); + + DECODER_LOG("Dispose Event Dispatched"); +} + nsresult MediaDecoderStateMachine::RunStateMachine() { AssertCurrentThreadInMonitor(); @@ -2486,47 +2533,14 @@ nsresult MediaDecoderStateMachine::RunStateMachine() StopAudioThread(); FlushDecoding(); - // Put a task in the decode queue to shutdown the reader and wait for + // Put a task in the decode queue to shutdown the reader. // the queue to spin down. - { - RefPtr task; - task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown); - nsRefPtr queue = DecodeTaskQueue(); - DebugOnly rv = queue->Dispatch(task); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); - queue->AwaitShutdownAndIdle(); - } + RefPtr task; + task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ShutdownReader); + DebugOnly rv = DecodeTaskQueue()->Dispatch(task); + MOZ_ASSERT(NS_SUCCEEDED(rv)); - // The reader's listeners hold references to the state machine, - // creating a cycle which keeps the state machine and its shared - // thread pools alive. So break it here. - AudioQueue().ClearListeners(); - VideoQueue().ClearListeners(); - - // Now that those threads are stopped, there's no possibility of - // mPendingWakeDecoder being needed again. Revoke it. - mPendingWakeDecoder = nullptr; - - MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN, - "How did we escape from the shutdown state?"); - // We must daisy-chain these events to destroy the decoder. We must - // destroy the decoder on the main thread, but we can't destroy the - // decoder while this thread holds the decoder monitor. We can't - // dispatch an event to the main thread to destroy the decoder from - // here, as the event may run before the dispatch returns, and we - // hold the decoder monitor here. We also want to guarantee that the - // state machine is destroyed on the main thread, and so the - // event runner running this function (which holds a reference to the - // state machine) needs to finish and be released in order to allow - // that. So we dispatch an event to run after this event runner has - // finished and released its monitor/references. That event then will - // dispatch an event to the main thread to release the decoder and - // state machine. - GetStateMachineThread()->Dispatch( - new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL); - - DECODER_LOG("SHUTDOWN OK"); + DECODER_LOG("Shutdown started"); return NS_OK; } diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index dfcbf5734a4..d99195c703a 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -162,6 +162,8 @@ public: // Set/Unset dormant state. void SetDormant(bool aDormant); void Shutdown(); + void ShutdownReader(); + void FinishShutdown(bool aSuccess); // Called from the main thread to get the duration. The decoder monitor // must be obtained before calling this. It is in units of microseconds. diff --git a/dom/media/MediaTaskQueue.cpp b/dom/media/MediaTaskQueue.cpp index 7afd582da4a..78235612138 100644 --- a/dom/media/MediaTaskQueue.cpp +++ b/dom/media/MediaTaskQueue.cpp @@ -134,12 +134,17 @@ MediaTaskQueue::AwaitShutdownAndIdle() AwaitIdleLocked(); } -void +nsRefPtr MediaTaskQueue::BeginShutdown() { MonitorAutoLock mon(mQueueMonitor); mIsShutdown = true; + nsRefPtr p = mShutdownPromise.Ensure(__func__); + if (!mIsRunning) { + mShutdownPromise.Resolve(true, __func__); + } mon.NotifyAll(); + return p; } nsresult @@ -208,6 +213,7 @@ MediaTaskQueue::Runner::Run() mQueue->mRunningThread = NS_GetCurrentThread(); if (mQueue->mTasks.size() == 0) { mQueue->mIsRunning = false; + mQueue->mShutdownPromise.ResolveIfExists(true, __func__); mon.NotifyAll(); return NS_OK; } @@ -235,6 +241,7 @@ MediaTaskQueue::Runner::Run() if (mQueue->mTasks.size() == 0) { // No more events to run. Exit the task runner. mQueue->mIsRunning = false; + mQueue->mShutdownPromise.ResolveIfExists(true, __func__); mon.NotifyAll(); mQueue->mRunningThread = nullptr; return NS_OK; diff --git a/dom/media/MediaTaskQueue.h b/dom/media/MediaTaskQueue.h index 1027ed56ef1..ce3827b52cf 100644 --- a/dom/media/MediaTaskQueue.h +++ b/dom/media/MediaTaskQueue.h @@ -12,6 +12,7 @@ #include "mozilla/Monitor.h" #include "SharedThreadPool.h" #include "nsThreadUtils.h" +#include "MediaPromise.h" class nsIRunnable; @@ -19,6 +20,8 @@ namespace mozilla { class SharedThreadPool; +typedef MediaPromise ShutdownPromise; + // Abstracts executing runnables in order in a thread pool. The runnables // dispatched to the MediaTaskQueue will be executed in the order in which // they're received, and are guaranteed to not be executed concurrently. @@ -50,7 +53,9 @@ public: // remain alive at least until all the events are drained, because the Runners // hold a strong reference to the task queue, and one of them is always held // by the threadpool event queue when the task queue is non-empty. - void BeginShutdown(); + // + // The returned promise is resolved when the queue goes empty. + nsRefPtr BeginShutdown(); // Blocks until all task finish executing. void AwaitIdle(); @@ -105,6 +110,7 @@ private: // True if we've started our shutdown process. bool mIsShutdown; + MediaPromiseHolder mShutdownPromise; class MOZ_STACK_CLASS AutoSetFlushing { diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index bd2d32ca8f2..cf8c463f1ad 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -99,7 +99,8 @@ nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo, return NS_OK; } -void AndroidMediaReader::Shutdown() +nsRefPtr +AndroidMediaReader::Shutdown() { ResetDecode(); if (mPlugin) { @@ -107,7 +108,7 @@ void AndroidMediaReader::Shutdown() mPlugin = nullptr; } - MediaDecoderReader::Shutdown(); + return MediaDecoderReader::Shutdown(); } // Resets all state related to decoding, emptying all buffers etc. diff --git a/dom/media/android/AndroidMediaReader.h b/dom/media/android/AndroidMediaReader.h index 90c4c929abe..4738cfa7b6a 100644 --- a/dom/media/android/AndroidMediaReader.h +++ b/dom/media/android/AndroidMediaReader.h @@ -71,7 +71,7 @@ public: MetadataTags** aTags); virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); - virtual void Shutdown() MOZ_OVERRIDE; + virtual nsRefPtr Shutdown() MOZ_OVERRIDE; class ImageBufferCallback : public MPAPI::BufferCallback { typedef mozilla::layers::Image Image; diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index 0482ae5400a..b54a8b80eba 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -139,7 +139,7 @@ MP4Reader::~MP4Reader() MOZ_COUNT_DTOR(MP4Reader); } -void +nsRefPtr MP4Reader::Shutdown() { MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); @@ -172,7 +172,7 @@ MP4Reader::Shutdown() mPlatform = nullptr; } - MediaDecoderReader::Shutdown(); + return MediaDecoderReader::Shutdown(); } void diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index 0c425a98fad..bead54a72c5 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -71,7 +71,7 @@ public: virtual nsresult ResetDecode() MOZ_OVERRIDE; - virtual void Shutdown() MOZ_OVERRIDE; + virtual nsRefPtr Shutdown() MOZ_OVERRIDE; private: diff --git a/dom/media/mediasource/MediaSourceDecoder.h b/dom/media/mediasource/MediaSourceDecoder.h index 4d1f724e470..efb61a0caef 100644 --- a/dom/media/mediasource/MediaSourceDecoder.h +++ b/dom/media/mediasource/MediaSourceDecoder.h @@ -11,6 +11,7 @@ #include "nsCOMPtr.h" #include "nsError.h" #include "MediaDecoder.h" +#include "MediaSourceReader.h" class nsIStreamListener; @@ -18,7 +19,6 @@ namespace mozilla { class MediaResource; class MediaDecoderStateMachine; -class MediaSourceReader; class SourceBufferDecoder; class TrackBuffer; @@ -71,6 +71,8 @@ public: virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE; #endif + MediaSourceReader* GetReader() { return mReader; } + private: // The owning MediaSource holds a strong reference to this decoder, and // calls Attach/DetachMediaSource on this decoder to set and clear diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index d6770e640e4..269794a840e 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -236,17 +236,35 @@ MediaSourceReader::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) GetCallback()->OnNotDecoded(aType, WAITING_FOR_DATA); } -void +nsRefPtr MediaSourceReader::Shutdown() { - MediaDecoderReader::Shutdown(); - for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { - mTrackBuffers[i]->Shutdown(); + MOZ_ASSERT(mMediaSourceShutdownPromise.IsEmpty()); + nsRefPtr p = mMediaSourceShutdownPromise.Ensure(__func__); + + ContinueShutdown(true); + return p; +} + +void +MediaSourceReader::ContinueShutdown(bool aSuccess) +{ + MOZ_ASSERT(aSuccess); + if (mTrackBuffers.Length()) { + mTrackBuffers[0]->Shutdown()->Then(GetTaskQueue(), __func__, this, + &MediaSourceReader::ContinueShutdown, + &MediaSourceReader::ContinueShutdown); + mShutdownTrackBuffers.AppendElement(mTrackBuffers[0]); + mTrackBuffers.RemoveElementAt(0); + return; } + mAudioTrack = nullptr; mAudioReader = nullptr; mVideoTrack = nullptr; mVideoReader = nullptr; + + MediaDecoderReader::Shutdown()->ChainTo(mMediaSourceShutdownPromise.Steal(), __func__); } void @@ -259,11 +277,12 @@ MediaSourceReader::BreakCycles() MOZ_ASSERT(!mAudioReader); MOZ_ASSERT(!mVideoTrack); MOZ_ASSERT(!mVideoReader); + MOZ_ASSERT(!mTrackBuffers.Length()); - for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { - mTrackBuffers[i]->BreakCycles(); + for (uint32_t i = 0; i < mShutdownTrackBuffers.Length(); ++i) { + mShutdownTrackBuffers[i]->BreakCycles(); } - mTrackBuffers.Clear(); + mShutdownTrackBuffers.Clear(); } already_AddRefed diff --git a/dom/media/mediasource/MediaSourceReader.h b/dom/media/mediasource/MediaSourceReader.h index fdeb09b21d3..eabc1e93c7a 100644 --- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -97,7 +97,7 @@ public: void RemoveTrackBuffer(TrackBuffer* aTrackBuffer); void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo); - void Shutdown(); + nsRefPtr Shutdown() MOZ_OVERRIDE; virtual void BreakCycles(); @@ -135,6 +135,7 @@ private: nsRefPtr mVideoReader; nsTArray> mTrackBuffers; + nsTArray> mShutdownTrackBuffers; nsTArray> mEssentialTrackBuffers; nsRefPtr mAudioTrack; nsRefPtr mVideoTrack; @@ -176,6 +177,9 @@ private: bool mVideoIsSeeking; bool mHasEssentialTrackBuffers; + + void ContinueShutdown(bool aSuccess); + MediaPromiseHolder mMediaSourceShutdownPromise; #ifdef MOZ_FMP4 nsRefPtr mSharedDecoderManager; #endif diff --git a/dom/media/mediasource/TrackBuffer.cpp b/dom/media/mediasource/TrackBuffer.cpp index e19dcea290e..73a4030e1f9 100644 --- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -96,23 +96,39 @@ private: nsAutoTArray,2> mDecoders; }; -void +nsRefPtr TrackBuffer::Shutdown() { - // Finish any decoder initialization, which may add to mInitializedDecoders. - // Shutdown waits for any pending events, which may require the monitor, - // so we must not hold the monitor during this call. - mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn(); - mTaskQueue->BeginShutdown(); - mTaskQueue->AwaitShutdownAndIdle(); - mTaskQueue = nullptr; + MOZ_ASSERT(mShutdownPromise.IsEmpty()); + nsRefPtr p = mShutdownPromise.Ensure(__func__); + RefPtr queue = mTaskQueue; + mTaskQueue = nullptr; + queue->BeginShutdown() + ->Then(mParentDecoder->GetReader()->GetTaskQueue(), __func__, this, + &TrackBuffer::ContinueShutdown, &TrackBuffer::ContinueShutdown); + + return p; +} + +void +TrackBuffer::ContinueShutdown(bool aSuccess) +{ + MOZ_ASSERT(aSuccess); ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - for (uint32_t i = 0; i < mDecoders.Length(); ++i) { - mDecoders[i]->GetReader()->Shutdown(); + if (mDecoders.Length()) { + mDecoders[0]->GetReader()->Shutdown() + ->Then(mParentDecoder->GetReader()->GetTaskQueue(), __func__, this, + &TrackBuffer::ContinueShutdown, &TrackBuffer::ContinueShutdown); + mShutdownDecoders.AppendElement(mDecoders[0]); + mDecoders.RemoveElementAt(0); + return; } + mInitializedDecoders.Clear(); mParentDecoder = nullptr; + + mShutdownPromise.Resolve(true, __func__); } bool @@ -433,12 +449,13 @@ TrackBuffer::BreakCycles() { MOZ_ASSERT(NS_IsMainThread()); - for (uint32_t i = 0; i < mDecoders.Length(); ++i) { - mDecoders[i]->BreakCycles(); + for (uint32_t i = 0; i < mShutdownDecoders.Length(); ++i) { + mShutdownDecoders[i]->BreakCycles(); } - mDecoders.Clear(); + mShutdownDecoders.Clear(); // These are cleared in Shutdown() + MOZ_ASSERT(!mDecoders.Length()); MOZ_ASSERT(mInitializedDecoders.IsEmpty()); MOZ_ASSERT(!mParentDecoder); } diff --git a/dom/media/mediasource/TrackBuffer.h b/dom/media/mediasource/TrackBuffer.h index 0e4770f1181..ef2ee18dd94 100644 --- a/dom/media/mediasource/TrackBuffer.h +++ b/dom/media/mediasource/TrackBuffer.h @@ -8,6 +8,7 @@ #define MOZILLA_TRACKBUFFER_H_ #include "SourceBufferDecoder.h" +#include "MediaPromise.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/mozalloc.h" @@ -33,7 +34,7 @@ public: TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType); - void Shutdown(); + nsRefPtr Shutdown(); // Append data to the current decoder. Also responsible for calling // NotifyDataArrived on the decoder to keep buffered range computation up @@ -131,6 +132,11 @@ private: // mParentDecoder's monitor. nsTArray> mDecoders; + // During shutdown, we move decoders from mDecoders to mShutdownDecoders after + // invoking Shutdown. This is all so that we can avoid destroying the decoders + // off-main-thread. :-( + nsTArray> mShutdownDecoders; + // Contains only the initialized decoders managed by this TrackBuffer. // Access protected by mParentDecoder's monitor. nsTArray> mInitializedDecoders; @@ -153,6 +159,9 @@ private: // Set when the first decoder used by this TrackBuffer is initialized. // Protected by mParentDecoder's monitor. MediaInfo mInfo; + + void ContinueShutdown(bool aSuccess); + MediaPromiseHolder mShutdownPromise; }; } // namespace mozilla diff --git a/dom/media/mediasource/moz.build b/dom/media/mediasource/moz.build index 1bf57102a45..4365bc99190 100644 --- a/dom/media/mediasource/moz.build +++ b/dom/media/mediasource/moz.build @@ -8,6 +8,7 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini'] EXPORTS += [ 'AsyncEventRunner.h', 'MediaSourceDecoder.h', + 'MediaSourceReader.h', ] EXPORTS.mozilla.dom += [ diff --git a/dom/media/omx/MediaCodecReader.cpp b/dom/media/omx/MediaCodecReader.cpp index 634a62ab198..c78b7c19fe1 100644 --- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -344,11 +344,11 @@ MediaCodecReader::ReleaseMediaResources() ReleaseCriticalResources(); } -void +nsRefPtr MediaCodecReader::Shutdown() { ReleaseResources(); - MediaDecoderReader::Shutdown(); + return MediaDecoderReader::Shutdown(); } void diff --git a/dom/media/omx/MediaCodecReader.h b/dom/media/omx/MediaCodecReader.h index 3f51e34da08..b82531058e4 100644 --- a/dom/media/omx/MediaCodecReader.h +++ b/dom/media/omx/MediaCodecReader.h @@ -68,7 +68,7 @@ public: // Destroys the decoding state. The reader cannot be made usable again. // This is different from ReleaseMediaResources() as Shutdown() is // irreversible, whereas ReleaseMediaResources() is reversible. - virtual void Shutdown(); + virtual nsRefPtr Shutdown(); // Used to retrieve some special information that can only be retrieved after // all contents have been continuously parsed. (ex. total duration of some diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 309d11d4f68..4d9b69177a7 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -175,17 +175,20 @@ void MediaOmxReader::ReleaseDecoder() mOmxDecoder.clear(); } -void MediaOmxReader::Shutdown() +nsRefPtr +MediaOmxReader::Shutdown() { nsCOMPtr cancelEvent = NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData); NS_DispatchToMainThread(cancelEvent); - MediaDecoderReader::Shutdown(); + nsRefPtr p = MediaDecoderReader::Shutdown(); nsCOMPtr event = NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder); NS_DispatchToMainThread(event); + + return p; } bool MediaOmxReader::IsWaitingMediaResources() diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h index 0a0d6719235..cbe88c09c72 100644 --- a/dom/media/omx/MediaOmxReader.h +++ b/dom/media/omx/MediaOmxReader.h @@ -104,7 +104,7 @@ public: virtual void SetIdle() MOZ_OVERRIDE; - virtual void Shutdown() MOZ_OVERRIDE; + virtual nsRefPtr Shutdown() MOZ_OVERRIDE; bool IsShutdown() { MutexAutoLock lock(mMutex); diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 5b47c331a1e..e9c3bdac1ea 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -218,7 +218,8 @@ WebMReader::~WebMReader() MOZ_COUNT_DTOR(WebMReader); } -void WebMReader::Shutdown() +nsRefPtr +WebMReader::Shutdown() { #if defined(MOZ_PDM_VPX) if (mVideoTaskQueue) { @@ -232,7 +233,7 @@ void WebMReader::Shutdown() mVideoDecoder = nullptr; } - MediaDecoderReader::Shutdown(); + return MediaDecoderReader::Shutdown(); } nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor) diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index 2e19bc8f0b0..94b4f5d42d1 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -133,7 +133,7 @@ protected: ~WebMReader(); public: - virtual void Shutdown() MOZ_OVERRIDE; + virtual nsRefPtr Shutdown() MOZ_OVERRIDE; virtual nsresult Init(MediaDecoderReader* aCloneDonor); virtual nsresult ResetDecode(); virtual bool DecodeAudioData();