From ca88a23260a93b040549871088372193146566bc Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 4 Nov 2014 11:16:34 +1300 Subject: [PATCH] Bug 1062661 - Part 1: Discard decoders that don't have any data in them. r=karlt --- dom/media/MediaDecoderReader.h | 12 +++-- dom/media/mediasource/TrackBuffer.cpp | 65 +++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index 576539680d9..4341b7056e9 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -180,6 +180,14 @@ public: // ReadMetada should be called before calling this method. virtual bool IsMediaSeekable() = 0; + MediaTaskQueue* GetTaskQueue() { + return mTaskQueue; + } + + void ClearDecoder() { + mDecoder = nullptr; + } + protected: virtual ~MediaDecoderReader(); @@ -206,10 +214,6 @@ protected: return mSampleDecodedCallback; } - virtual MediaTaskQueue* GetTaskQueue() { - return mTaskQueue; - } - // Queue of audio frames. This queue is threadsafe, and is accessed from // the audio, decoder, state machine, and main threads. MediaQueue mAudioQueue; diff --git a/dom/media/mediasource/TrackBuffer.cpp b/dom/media/mediasource/TrackBuffer.cpp index f8e2a40fa42..32e0d4b9ba0 100644 --- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -59,6 +59,7 @@ public: } NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL { + mDecoder->GetReader()->BreakCycles(); mDecoder = nullptr; return NS_OK; } @@ -155,6 +156,7 @@ bool TrackBuffer::EvictData(uint32_t aThreshold) { MOZ_ASSERT(NS_IsMainThread()); + ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); int64_t totalSize = 0; for (uint32_t i = 0; i < mDecoders.Length(); ++i) { @@ -166,10 +168,14 @@ TrackBuffer::EvictData(uint32_t aThreshold) return false; } - for (uint32_t i = 0; i < mDecoders.Length(); ++i) { + for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { MSE_DEBUG("TrackBuffer(%p)::EvictData decoder=%u threshold=%u toEvict=%lld", this, i, aThreshold, toEvict); - toEvict -= mDecoders[i]->GetResource()->EvictData(toEvict); + toEvict -= mInitializedDecoders[i]->GetResource()->EvictData(toEvict); + if (!mInitializedDecoders[i]->GetResource()->GetSize() && + mInitializedDecoders[i] != mCurrentDecoder) { + RemoveDecoder(mInitializedDecoders[i]); + } } return toEvict < (totalSize - aThreshold); } @@ -178,11 +184,16 @@ void TrackBuffer::EvictBefore(double aTime) { MOZ_ASSERT(NS_IsMainThread()); - for (uint32_t i = 0; i < mDecoders.Length(); ++i) { - int64_t endOffset = mDecoders[i]->ConvertToByteOffset(aTime); + ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); + for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { + int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime); if (endOffset > 0) { MSE_DEBUG("TrackBuffer(%p)::EvictBefore decoder=%u offset=%lld", this, i, endOffset); - mDecoders[i]->GetResource()->EvictBefore(endOffset); + mInitializedDecoders[i]->GetResource()->EvictBefore(endOffset); + if (!mInitializedDecoders[i]->GetResource()->GetSize() && + mInitializedDecoders[i] != mCurrentDecoder) { + RemoveDecoder(mInitializedDecoders[i]); + } } } } @@ -458,20 +469,58 @@ TrackBuffer::Dump(const char* aPath) } #endif +class DelayedDispatchToMainThread : public nsRunnable { +public: + explicit DelayedDispatchToMainThread(SourceBufferDecoder* aDecoder) + : mDecoder(aDecoder) + { + } + + NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL { + // Shutdown the reader, and remove its reference to the decoder + // so that it can't accidentally read it after the decoder + // is destroyed. + mDecoder->GetReader()->Shutdown(); + mDecoder->GetReader()->ClearDecoder(); + RefPtr task = new ReleaseDecoderTask(mDecoder); + mDecoder = nullptr; + // task now holds the only ref to the decoder. + NS_DispatchToMainThread(task); + return NS_OK; + } + +private: + RefPtr mDecoder; +}; + void TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder) { - RefPtr task = new ReleaseDecoderTask(aDecoder); + RefPtr task; + nsRefPtr taskQueue; { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - MOZ_ASSERT(!mInitializedDecoders.Contains(aDecoder)); + if (mInitializedDecoders.RemoveElement(aDecoder)) { + taskQueue = aDecoder->GetReader()->GetTaskQueue(); + task = new DelayedDispatchToMainThread(aDecoder); + } else { + task = new ReleaseDecoderTask(aDecoder); + } mDecoders.RemoveElement(aDecoder); + if (mCurrentDecoder == aDecoder) { DiscardDecoder(); } } // At this point, task should be holding the only reference to aDecoder. - NS_DispatchToMainThread(task); + if (taskQueue) { + // If we were initialized, post the task via the reader's + // task queue to ensure that the reader isn't in the middle + // of an existing task. + taskQueue->Dispatch(task); + } else { + NS_DispatchToMainThread(task); + } } } // namespace mozilla