Bug 1062661 - Part 1: Discard decoders that don't have any data in them. r=karlt

This commit is contained in:
Matt Woodrow 2014-11-04 11:16:34 +13:00
parent 35792c7281
commit ca88a23260
2 changed files with 65 additions and 12 deletions

View File

@ -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<AudioData> mAudioQueue;

View File

@ -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<nsIRunnable> task = new ReleaseDecoderTask(mDecoder);
mDecoder = nullptr;
// task now holds the only ref to the decoder.
NS_DispatchToMainThread(task);
return NS_OK;
}
private:
RefPtr<SourceBufferDecoder> mDecoder;
};
void
TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
{
RefPtr<nsIRunnable> task = new ReleaseDecoderTask(aDecoder);
RefPtr<nsIRunnable> task;
nsRefPtr<MediaTaskQueue> 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