зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1104964 - Make MediaDecoderReader own the task queue. r=cpearce
This commit is contained in:
Родитель
e693d3e685
Коммит
dba2651569
|
@ -63,6 +63,7 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
|
|||
, mDecoder(aDecoder)
|
||||
, mIgnoreAudioOutputFormat(false)
|
||||
, mStartTime(-1)
|
||||
, mTaskQueueIsBorrowed(false)
|
||||
, mAudioDiscontinuity(false)
|
||||
, mVideoDiscontinuity(false)
|
||||
, mShutdown(false)
|
||||
|
@ -247,10 +248,18 @@ MediaDecoderReader::SetCallback(RequestSampleCallback* aCallback)
|
|||
mSampleDecodedCallback = aCallback;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderReader::SetTaskQueue(MediaTaskQueue* aTaskQueue)
|
||||
MediaTaskQueue*
|
||||
MediaDecoderReader::EnsureTaskQueue()
|
||||
{
|
||||
mTaskQueue = aTaskQueue;
|
||||
if (!mTaskQueue) {
|
||||
MOZ_ASSERT(!mTaskQueueIsBorrowed);
|
||||
RefPtr<SharedThreadPool> decodePool(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(decodePool, nullptr);
|
||||
|
||||
mTaskQueue = new MediaTaskQueue(decodePool.forget());
|
||||
}
|
||||
|
||||
return mTaskQueue;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -266,9 +275,15 @@ MediaDecoderReader::BreakCycles()
|
|||
void
|
||||
MediaDecoderReader::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(mDecoder->OnDecodeThread());
|
||||
MOZ_ASSERT(OnDecodeThread());
|
||||
mShutdown = true;
|
||||
ReleaseMediaResources();
|
||||
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();
|
||||
}
|
||||
mTaskQueue = nullptr;
|
||||
}
|
||||
|
||||
AudioDecodeRendezvous::AudioDecodeRendezvous()
|
||||
|
|
|
@ -61,7 +61,19 @@ public:
|
|||
virtual void Shutdown();
|
||||
|
||||
virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback);
|
||||
virtual void SetTaskQueue(MediaTaskQueue* aTaskQueue);
|
||||
MediaTaskQueue* EnsureTaskQueue();
|
||||
|
||||
virtual bool OnDecodeThread()
|
||||
{
|
||||
return !GetTaskQueue() || GetTaskQueue()->IsCurrentThreadIn();
|
||||
}
|
||||
|
||||
void SetBorrowedTaskQueue(MediaTaskQueue* aTaskQueue)
|
||||
{
|
||||
MOZ_ASSERT(!mTaskQueue && aTaskQueue);
|
||||
mTaskQueue = aTaskQueue;
|
||||
mTaskQueueIsBorrowed = true;
|
||||
}
|
||||
|
||||
// Resets all state related to decoding, emptying all buffers etc.
|
||||
// Cancels all pending Request*Data() request callbacks, and flushes the
|
||||
|
@ -261,6 +273,7 @@ private:
|
|||
nsRefPtr<RequestSampleCallback> mSampleDecodedCallback;
|
||||
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
bool mTaskQueueIsBorrowed;
|
||||
|
||||
// Flags whether a the next audio/video sample comes after a "gap" or
|
||||
// "discontinuity" in the stream. For example after a seek.
|
||||
|
|
|
@ -244,7 +244,6 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
|||
NS_ASSERTION(!mPendingWakeDecoder.get(),
|
||||
"WakeDecoder should have been revoked already");
|
||||
|
||||
MOZ_ASSERT(!mDecodeTaskQueue, "Should be released in SHUTDOWN");
|
||||
mReader = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -1028,7 +1027,7 @@ MediaDecoderStateMachine::CheckIfSeekComplete()
|
|||
mDecodeToSeekTarget = false;
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_FAILED(rv)) {
|
||||
DecodeError();
|
||||
}
|
||||
|
@ -1081,11 +1080,9 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<SharedThreadPool> decodePool(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(decodePool, NS_ERROR_FAILURE);
|
||||
|
||||
mDecodeTaskQueue = new MediaTaskQueue(decodePool.forget());
|
||||
NS_ENSURE_TRUE(mDecodeTaskQueue, NS_ERROR_FAILURE);
|
||||
if (NS_WARN_IF(!mReader->EnsureTaskQueue())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MediaDecoderReader* cloneReader = nullptr;
|
||||
if (aCloneDonor) {
|
||||
|
@ -1098,9 +1095,8 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
|||
// Note: This creates a cycle, broken in shutdown.
|
||||
mMediaDecodedListener =
|
||||
new MediaDataDecodedListener<MediaDecoderStateMachine>(this,
|
||||
mDecodeTaskQueue);
|
||||
DecodeTaskQueue());
|
||||
mReader->SetCallback(mMediaDecodedListener);
|
||||
mReader->SetTaskQueue(mDecodeTaskQueue);
|
||||
|
||||
rv = mReader->Init(cloneReader);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1439,7 +1435,7 @@ void MediaDecoderStateMachine::NotifyWaitingForResourcesStatusChanged()
|
|||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this,
|
||||
&MediaDecoderStateMachine::DoNotifyWaitingForResourcesStatusChanged));
|
||||
mDecodeTaskQueue->Dispatch(task);
|
||||
DecodeTaskQueue()->Dispatch(task);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::DoNotifyWaitingForResourcesStatusChanged()
|
||||
|
@ -1658,7 +1654,7 @@ MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
|
|||
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1671,7 +1667,7 @@ MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
|
|||
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1749,7 +1745,7 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
|||
if (needIdle) {
|
||||
RefPtr<nsIRunnable> event = NS_NewRunnableMethod(
|
||||
this, &MediaDecoderStateMachine::SetReaderIdle);
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(event.forget());
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(event.forget());
|
||||
if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
|
||||
DECODER_WARN("Failed to dispatch event to set decoder idle state");
|
||||
}
|
||||
|
@ -1775,7 +1771,7 @@ MediaDecoderStateMachine::EnqueueDecodeSeekTask()
|
|||
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeSeek));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_FAILED(rv)) {
|
||||
DECODER_WARN("Dispatch DecodeSeek task failed.");
|
||||
mCurrentSeekTarget.Reset();
|
||||
|
@ -1817,7 +1813,7 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
|
|||
if (IsAudioDecoding() && !mAudioRequestPending && !mWaitingForDecoderSeek) {
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeAudio));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mAudioRequestPending = true;
|
||||
} else {
|
||||
|
@ -1862,7 +1858,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
|
|||
if (IsVideoDecoding() && !mVideoRequestPending && !mWaitingForDecoderSeek) {
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DecodeVideo));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mVideoRequestPending = true;
|
||||
} else {
|
||||
|
@ -2102,12 +2098,12 @@ MediaDecoderStateMachine::DecodeFirstFrame()
|
|||
if (HasAudio()) {
|
||||
RefPtr<nsIRunnable> decodeTask(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
|
||||
AudioQueue().AddPopListener(decodeTask, mDecodeTaskQueue);
|
||||
AudioQueue().AddPopListener(decodeTask, DecodeTaskQueue());
|
||||
}
|
||||
if (HasVideo()) {
|
||||
RefPtr<nsIRunnable> decodeTask(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
|
||||
VideoQueue().AddPopListener(decodeTask, mDecodeTaskQueue);
|
||||
VideoQueue().AddPopListener(decodeTask, DecodeTaskQueue());
|
||||
}
|
||||
|
||||
if (mScheduler->IsRealTime()) {
|
||||
|
@ -2271,7 +2267,7 @@ void MediaDecoderStateMachine::DecodeSeek()
|
|||
|
||||
if (!currentTimeChanged) {
|
||||
DECODER_LOG("Seek !currentTimeChanged...");
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
|
||||
if (NS_FAILED(rv)) {
|
||||
DecodeError();
|
||||
|
@ -2479,17 +2475,16 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
StopAudioThread();
|
||||
FlushDecoding();
|
||||
|
||||
// Put a task in the decode queue to shutdown the reader.
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown);
|
||||
mDecodeTaskQueue->Dispatch(task);
|
||||
|
||||
// Put a task in the decode queue to shutdown the reader and wait for
|
||||
// the queue to spin down.
|
||||
{
|
||||
// Wait for the thread decoding to exit.
|
||||
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());
|
||||
mDecodeTaskQueue->BeginShutdown();
|
||||
mDecodeTaskQueue->AwaitShutdownAndIdle();
|
||||
mDecodeTaskQueue = nullptr;
|
||||
queue->AwaitShutdownAndIdle();
|
||||
}
|
||||
|
||||
// The reader's listeners hold references to the state machine,
|
||||
|
@ -2536,7 +2531,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
// Wait for the thread decoding, if any, to exit.
|
||||
mDecodeTaskQueue->AwaitIdle();
|
||||
DecodeTaskQueue()->AwaitIdle();
|
||||
mReader->ReleaseMediaResources();
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -2703,7 +2698,7 @@ MediaDecoderStateMachine::FlushDecoding()
|
|||
// and shutdown on B2G will fail as there are outstanding video frames
|
||||
// alive.
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
mDecodeTaskQueue->FlushAndDispatch(task);
|
||||
DecodeTaskQueue()->FlushAndDispatch(task);
|
||||
}
|
||||
|
||||
// We must reset playback so that all references to frames queued
|
||||
|
@ -3202,7 +3197,7 @@ nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) {
|
|||
|
||||
bool MediaDecoderStateMachine::OnDecodeThread() const
|
||||
{
|
||||
return mDecodeTaskQueue->IsCurrentThreadIn();
|
||||
return !DecodeTaskQueue() || DecodeTaskQueue()->IsCurrentThreadIn();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::OnStateMachineThread() const
|
||||
|
@ -3329,7 +3324,7 @@ void MediaDecoderStateMachine::OnAudioSinkError()
|
|||
// no sense to play an audio-only file without sound output.
|
||||
RefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::AcquireMonitorAndInvokeDecodeError));
|
||||
nsresult rv = mDecodeTaskQueue->Dispatch(task);
|
||||
nsresult rv = DecodeTaskQueue()->Dispatch(task);
|
||||
if (NS_FAILED(rv)) {
|
||||
DECODER_WARN("Failed to dispatch AcquireMonitorAndInvokeDecodeError");
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ public:
|
|||
// be held.
|
||||
bool IsPlaying() const;
|
||||
|
||||
// Dispatch DoNotifyWaitingForResourcesStatusChanged task to mDecodeTaskQueue.
|
||||
// Dispatch DoNotifyWaitingForResourcesStatusChanged task to the task queue.
|
||||
// Called when the reader may have acquired the hardware resources required
|
||||
// to begin decoding. The decoder monitor must be held while calling this.
|
||||
void NotifyWaitingForResourcesStatusChanged();
|
||||
|
@ -731,7 +731,7 @@ protected:
|
|||
// The task queue in which we run decode tasks. This is referred to as
|
||||
// the "decode thread", though in practise tasks can run on a different
|
||||
// thread every time they're called.
|
||||
RefPtr<MediaTaskQueue> mDecodeTaskQueue;
|
||||
MediaTaskQueue* DecodeTaskQueue() const { return mReader->GetTaskQueue(); }
|
||||
|
||||
// The time that playback started from the system clock. This is used for
|
||||
// timing the presentation of video frames when there's no audio.
|
||||
|
|
|
@ -36,8 +36,7 @@ public:
|
|||
decoder->SetResource(resource);
|
||||
|
||||
reader->Init(nullptr);
|
||||
reader->SetTaskQueue(
|
||||
new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("TestMP4Reader"))));
|
||||
reader->EnsureTaskQueue();
|
||||
{
|
||||
// This needs to be done before invoking GetBuffered. This is normally
|
||||
// done by MediaDecoderStateMachine.
|
||||
|
@ -57,11 +56,11 @@ public:
|
|||
private:
|
||||
virtual ~TestBinding()
|
||||
{
|
||||
reader->GetTaskQueue()->Dispatch(NS_NewRunnableMethod(reader,
|
||||
&MP4Reader::Shutdown));
|
||||
reader->GetTaskQueue()->BeginShutdown();
|
||||
reader->GetTaskQueue()->AwaitShutdownAndIdle();
|
||||
|
||||
{
|
||||
nsRefPtr<MediaTaskQueue> queue = reader->GetTaskQueue();
|
||||
queue->Dispatch(NS_NewRunnableMethod(reader, &MP4Reader::Shutdown));
|
||||
queue->AwaitShutdownAndIdle();
|
||||
}
|
||||
decoder = nullptr;
|
||||
resource = nullptr;
|
||||
reader = nullptr;
|
||||
|
|
|
@ -367,13 +367,22 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType)
|
|||
reader->SetStartTime(0);
|
||||
}
|
||||
|
||||
// This part is icky. It would be nicer to just give each subreader its own
|
||||
// task queue. Unfortunately though, Request{Audio,Video}Data implementations
|
||||
// currently assert that they're on "the decode thread", and so having
|
||||
// separate task queues makes MediaSource stuff unnecessarily cumbersome. We
|
||||
// should remove the need for these assertions (which probably involves making
|
||||
// all Request*Data implementations fully async), and then get rid of the
|
||||
// borrowing.
|
||||
reader->SetBorrowedTaskQueue(GetTaskQueue());
|
||||
|
||||
// Set a callback on the subreader that forwards calls to this reader.
|
||||
// This reader will then forward them onto the state machine via this
|
||||
// reader's callback.
|
||||
RefPtr<MediaDataDecodedListener<MediaSourceReader>> callback =
|
||||
new MediaDataDecodedListener<MediaSourceReader>(this, GetTaskQueue());
|
||||
new MediaDataDecodedListener<MediaSourceReader>(this, reader->GetTaskQueue());
|
||||
reader->SetCallback(callback);
|
||||
reader->SetTaskQueue(GetTaskQueue());
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
reader->SetSharedDecoderManager(mSharedDecoderManager);
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче