Bug 1155432 - Don't flush WMF PDM task queues. r=jya

This commit is contained in:
Chris Pearce 2015-04-20 20:03:41 +12:00
parent cea2379e64
commit 0eafa8396e
2 changed files with 90 additions and 36 deletions

View File

@ -27,13 +27,14 @@ WMFMediaDataDecoder::WMFMediaDataDecoder(MFTManager* aMFTManager,
: mTaskQueue(aTaskQueue) : mTaskQueue(aTaskQueue)
, mCallback(aCallback) , mCallback(aCallback)
, mMFTManager(aMFTManager) , mMFTManager(aMFTManager)
, mMonitor("WMFMediaDataDecoder")
, mIsDecodeTaskDispatched(false)
, mIsFlushing(false)
{ {
MOZ_COUNT_CTOR(WMFMediaDataDecoder);
} }
WMFMediaDataDecoder::~WMFMediaDataDecoder() WMFMediaDataDecoder::~WMFMediaDataDecoder()
{ {
MOZ_COUNT_DTOR(WMFMediaDataDecoder);
} }
nsresult nsresult
@ -48,11 +49,13 @@ WMFMediaDataDecoder::Init()
nsresult nsresult
WMFMediaDataDecoder::Shutdown() WMFMediaDataDecoder::Shutdown()
{ {
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch( mTaskQueue->Dispatch(
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown));
#ifdef DEBUG #ifdef DEBUG
if (NS_FAILED(rv)) { {
NS_WARNING("WMFMediaDataDecoder::Shutdown() dispatch of task failed!"); MonitorAutoLock mon(mMonitor);
// The MP4Reader should have flushed before calling Shutdown().
MOZ_ASSERT(!mIsDecodeTaskDispatched);
} }
#endif #endif
return NS_OK; return NS_OK;
@ -61,36 +64,73 @@ WMFMediaDataDecoder::Shutdown()
void void
WMFMediaDataDecoder::ProcessShutdown() WMFMediaDataDecoder::ProcessShutdown()
{ {
mMFTManager->Shutdown(); if (mMFTManager) {
mMFTManager = nullptr; mMFTManager->Shutdown();
mMFTManager = nullptr;
}
mDecoder = nullptr; mDecoder = nullptr;
} }
void
WMFMediaDataDecoder::EnsureDecodeTaskDispatched()
{
mMonitor.AssertCurrentThreadOwns();
if (!mIsDecodeTaskDispatched) {
mTaskQueue->Dispatch(
NS_NewRunnableMethod(this,
&WMFMediaDataDecoder::Decode));
mIsDecodeTaskDispatched = true;
}
}
// Inserts data into the decoder's pipeline. // Inserts data into the decoder's pipeline.
nsresult nsresult
WMFMediaDataDecoder::Input(MediaRawData* aSample) WMFMediaDataDecoder::Input(MediaRawData* aSample)
{ {
mTaskQueue->Dispatch( MonitorAutoLock mon(mMonitor);
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>( mInput.push(aSample);
this, EnsureDecodeTaskDispatched();
&WMFMediaDataDecoder::ProcessDecode,
nsRefPtr<MediaRawData>(aSample)));
return NS_OK; return NS_OK;
} }
void void
WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample) WMFMediaDataDecoder::Decode()
{ {
HRESULT hr = mMFTManager->Input(aSample); while (true) {
if (FAILED(hr)) { nsRefPtr<MediaRawData> input;
NS_WARNING("MFTManager rejected sample"); {
mCallback->Error(); MonitorAutoLock mon(mMonitor);
return; MOZ_ASSERT(mIsDecodeTaskDispatched);
if (mInput.empty()) {
if (mIsFlushing) {
if (mDecoder) {
mDecoder->Flush();
}
mIsFlushing = false;
}
mIsDecodeTaskDispatched = false;
mon.NotifyAll();
return;
}
input = mInput.front();
mInput.pop();
}
HRESULT hr = mMFTManager->Input(input);
if (FAILED(hr)) {
NS_WARNING("MFTManager rejected sample");
{
MonitorAutoLock mon(mMonitor);
PurgeInputQueue();
}
mCallback->Error();
return;
}
mLastStreamOffset = input->mOffset;
ProcessOutput();
} }
mLastStreamOffset = aSample->mOffset;
ProcessOutput();
} }
void void
@ -108,24 +148,33 @@ WMFMediaDataDecoder::ProcessOutput()
} }
} else if (FAILED(hr)) { } else if (FAILED(hr)) {
NS_WARNING("WMFMediaDataDecoder failed to output data"); NS_WARNING("WMFMediaDataDecoder failed to output data");
{
MonitorAutoLock mon(mMonitor);
PurgeInputQueue();
}
mCallback->Error(); mCallback->Error();
} }
} }
void
WMFMediaDataDecoder::PurgeInputQueue()
{
mMonitor.AssertCurrentThreadOwns();
while (!mInput.empty()) {
mInput.pop();
}
}
nsresult nsresult
WMFMediaDataDecoder::Flush() WMFMediaDataDecoder::Flush()
{ {
// Flush the input task queue. This cancels all pending Decode() calls. MonitorAutoLock mon(mMonitor);
// Note this blocks until the task queue finishes its current job, if PurgeInputQueue();
// it's executing at all. Note the MP4Reader ignores all output while mIsFlushing = true;
// flushing. EnsureDecodeTaskDispatched();
mTaskQueue->Flush(); while (mIsDecodeTaskDispatched || mIsFlushing) {
mon.Wait();
// Order the MFT to flush; drop all internal data. }
NS_ENSURE_TRUE(mDecoder, NS_ERROR_FAILURE);
HRESULT hr = mDecoder->Flush();
NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
return NS_OK; return NS_OK;
} }

View File

@ -74,9 +74,9 @@ public:
private: private:
// Called on the task queue. Inserts the sample into the decoder, and void Decode();
// extracts output if available. void EnsureDecodeTaskDispatched();
void ProcessDecode(MediaRawData* aSample); void PurgeInputQueue();
// Called on the task queue. Extracts output if available, and delivers // Called on the task queue. Extracts output if available, and delivers
// it to the reader. Called after ProcessDecode() and ProcessDrain(). // it to the reader. Called after ProcessDecode() and ProcessDrain().
@ -97,6 +97,11 @@ private:
// The last offset into the media resource that was passed into Input(). // The last offset into the media resource that was passed into Input().
// This is used to approximate the decoder's position in the media resource. // This is used to approximate the decoder's position in the media resource.
int64_t mLastStreamOffset; int64_t mLastStreamOffset;
Monitor mMonitor;
std::queue<nsRefPtr<MediaRawData>> mInput;
bool mIsDecodeTaskDispatched;
bool mIsFlushing;
}; };
} // namespace mozilla } // namespace mozilla