зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1108707 - Make reader shutdown asynchronous. r=cpearce (relanding on a CLOSED TREE because it wasn't the source of the leaks)
This commit is contained in:
Родитель
1f717c46d2
Коммит
312651fc98
|
@ -283,18 +283,28 @@ MediaDecoderReader::BreakCycles()
|
|||
mTaskQueue = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaDecoderReader::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(OnDecodeThread());
|
||||
mShutdown = true;
|
||||
ReleaseMediaResources();
|
||||
nsRefPtr<ShutdownPromise> 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()
|
||||
|
|
|
@ -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<ShutdownPromise> Shutdown();
|
||||
|
||||
virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback);
|
||||
MediaTaskQueue* EnsureTaskQueue();
|
||||
|
|
|
@ -2470,6 +2470,53 @@ private:
|
|||
nsRefPtr<MediaDecoderStateMachine> 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<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown);
|
||||
nsRefPtr<MediaTaskQueue> queue = DecodeTaskQueue();
|
||||
DebugOnly<nsresult> rv = queue->Dispatch(task);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
queue->AwaitShutdownAndIdle();
|
||||
}
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ShutdownReader);
|
||||
DebugOnly<nsresult> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -134,12 +134,17 @@ MediaTaskQueue::AwaitShutdownAndIdle()
|
|||
AwaitIdleLocked();
|
||||
}
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaTaskQueue::BeginShutdown()
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
mIsShutdown = true;
|
||||
nsRefPtr<ShutdownPromise> 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;
|
||||
|
|
|
@ -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<bool, bool> 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<ShutdownPromise> 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<ShutdownPromise> mShutdownPromise;
|
||||
|
||||
class MOZ_STACK_CLASS AutoSetFlushing
|
||||
{
|
||||
|
|
|
@ -99,7 +99,8 @@ nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void AndroidMediaReader::Shutdown()
|
||||
nsRefPtr<ShutdownPromise>
|
||||
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.
|
||||
|
|
|
@ -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<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
class ImageBufferCallback : public MPAPI::BufferCallback {
|
||||
typedef mozilla::layers::Image Image;
|
||||
|
|
|
@ -139,7 +139,7 @@ MP4Reader::~MP4Reader()
|
|||
MOZ_COUNT_DTOR(MP4Reader);
|
||||
}
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MP4Reader::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
|
@ -172,7 +172,7 @@ MP4Reader::Shutdown()
|
|||
mPlatform = nullptr;
|
||||
}
|
||||
|
||||
MediaDecoderReader::Shutdown();
|
||||
return MediaDecoderReader::Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -71,7 +71,7 @@ public:
|
|||
|
||||
virtual nsresult ResetDecode() MOZ_OVERRIDE;
|
||||
|
||||
virtual void Shutdown() MOZ_OVERRIDE;
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -236,17 +236,35 @@ MediaSourceReader::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason)
|
|||
GetCallback()->OnNotDecoded(aType, WAITING_FOR_DATA);
|
||||
}
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaSourceReader::Shutdown()
|
||||
{
|
||||
MediaDecoderReader::Shutdown();
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->Shutdown();
|
||||
MOZ_ASSERT(mMediaSourceShutdownPromise.IsEmpty());
|
||||
nsRefPtr<ShutdownPromise> 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<MediaDecoderReader>
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
|
||||
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
|
||||
|
||||
void Shutdown();
|
||||
nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
virtual void BreakCycles();
|
||||
|
||||
|
@ -135,6 +135,7 @@ private:
|
|||
nsRefPtr<MediaDecoderReader> mVideoReader;
|
||||
|
||||
nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
|
||||
nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
|
||||
nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
|
||||
nsRefPtr<TrackBuffer> mAudioTrack;
|
||||
nsRefPtr<TrackBuffer> mVideoTrack;
|
||||
|
@ -176,6 +177,9 @@ private:
|
|||
bool mVideoIsSeeking;
|
||||
|
||||
bool mHasEssentialTrackBuffers;
|
||||
|
||||
void ContinueShutdown(bool aSuccess);
|
||||
MediaPromiseHolder<ShutdownPromise> mMediaSourceShutdownPromise;
|
||||
#ifdef MOZ_FMP4
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
#endif
|
||||
|
|
|
@ -96,23 +96,39 @@ private:
|
|||
nsAutoTArray<nsRefPtr<SourceBufferDecoder>,2> mDecoders;
|
||||
};
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
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<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
|
||||
|
||||
RefPtr<MediaTaskQueue> 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);
|
||||
}
|
||||
|
|
|
@ -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<ShutdownPromise> 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<nsRefPtr<SourceBufferDecoder>> 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<nsRefPtr<SourceBufferDecoder>> mShutdownDecoders;
|
||||
|
||||
// Contains only the initialized decoders managed by this TrackBuffer.
|
||||
// Access protected by mParentDecoder's monitor.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> 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<ShutdownPromise> mShutdownPromise;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -8,6 +8,7 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
|||
EXPORTS += [
|
||||
'AsyncEventRunner.h',
|
||||
'MediaSourceDecoder.h',
|
||||
'MediaSourceReader.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
|
|
|
@ -344,11 +344,11 @@ MediaCodecReader::ReleaseMediaResources()
|
|||
ReleaseCriticalResources();
|
||||
}
|
||||
|
||||
void
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaCodecReader::Shutdown()
|
||||
{
|
||||
ReleaseResources();
|
||||
MediaDecoderReader::Shutdown();
|
||||
return MediaDecoderReader::Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -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<ShutdownPromise> Shutdown();
|
||||
|
||||
// Used to retrieve some special information that can only be retrieved after
|
||||
// all contents have been continuously parsed. (ex. total duration of some
|
||||
|
|
|
@ -175,17 +175,20 @@ void MediaOmxReader::ReleaseDecoder()
|
|||
mOmxDecoder.clear();
|
||||
}
|
||||
|
||||
void MediaOmxReader::Shutdown()
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaOmxReader::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> cancelEvent =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
|
||||
NS_DispatchToMainThread(cancelEvent);
|
||||
|
||||
MediaDecoderReader::Shutdown();
|
||||
nsRefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder);
|
||||
NS_DispatchToMainThread(event);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool MediaOmxReader::IsWaitingMediaResources()
|
||||
|
|
|
@ -104,7 +104,7 @@ public:
|
|||
|
||||
virtual void SetIdle() MOZ_OVERRIDE;
|
||||
|
||||
virtual void Shutdown() MOZ_OVERRIDE;
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
|
||||
bool IsShutdown() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
|
|
@ -218,7 +218,8 @@ WebMReader::~WebMReader()
|
|||
MOZ_COUNT_DTOR(WebMReader);
|
||||
}
|
||||
|
||||
void WebMReader::Shutdown()
|
||||
nsRefPtr<ShutdownPromise>
|
||||
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)
|
||||
|
|
|
@ -133,7 +133,7 @@ protected:
|
|||
~WebMReader();
|
||||
|
||||
public:
|
||||
virtual void Shutdown() MOZ_OVERRIDE;
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
|
||||
virtual nsresult ResetDecode();
|
||||
virtual bool DecodeAudioData();
|
||||
|
|
Загрузка…
Ссылка в новой задаче