Bug 1039128 - Fix drain of video queue

This commit is contained in:
Anthony Jones 2014-07-25 14:57:25 +12:00
parent bc2513235c
commit 9b31f46826
9 changed files with 53 additions and 21 deletions

View File

@ -77,6 +77,7 @@ public:
}
virtual nsresult Drain() MOZ_OVERRIDE {
mCallback->DrainComplete();
return NS_OK;
}

View File

@ -349,41 +349,45 @@ MP4Reader::Decode(TrackType aTrack)
data.mMonitor.Unlock();
nsAutoPtr<MP4Sample> compressed(PopSample(aTrack));
if (!compressed) {
// EOS, or error. Let the state machine know there are no more
// frames coming.
// EOS, or error. Send the decoder a signal to drain.
LOG("Draining %s", TrackTypeToStr(aTrack));
data.mMonitor.Lock();
data.mDrainComplete = false;
data.mMonitor.Unlock();
data.mDecoder->Drain();
return false;
} else {
#ifdef LOG_SAMPLE_DECODE
LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack),
compressed->composition_timestamp, compressed->duration);
#endif
}
data.mMonitor.Lock();
data.mInputExhausted = false;
data.mNumSamplesInput++;
data.mMonitor.Unlock();
data.mMonitor.Lock();
data.mDrainComplete = false;
data.mInputExhausted = false;
data.mNumSamplesInput++;
data.mMonitor.Unlock();
if (NS_FAILED(data.mDecoder->Input(compressed))) {
return false;
if (NS_FAILED(data.mDecoder->Input(compressed))) {
return false;
}
// If Input() failed, we let the auto pointer delete |compressed|.
// Otherwise, we assume the decoder will delete it when it's finished
// with it.
compressed.forget();
}
// If Input() failed, we let the auto pointer delete |compressed|.
// Otherwise, we assume the decoder will delete it when it's finished
// with it.
compressed.forget();
data.mMonitor.Lock();
}
data.mMonitor.AssertCurrentThreadOwns();
while (!data.mError &&
prevNumFramesOutput == data.mNumSamplesOutput &&
!data.mInputExhausted ) {
!data.mInputExhausted &&
!data.mDrainComplete) {
data.mMonitor.Wait();
}
}
data.mMonitor.AssertCurrentThreadOwns();
bool drainComplete = data.mDrainComplete;
data.mMonitor.Unlock();
return true;
return !drainComplete;
}
void
@ -421,6 +425,15 @@ MP4Reader::Output(TrackType aTrack, MediaData* aSample)
mon.NotifyAll();
}
void
MP4Reader::DrainComplete(TrackType aTrack)
{
DecoderData& data = GetDecoderData(aTrack);
MonitorAutoLock mon(data.mMonitor);
data.mDrainComplete = true;
mon.NotifyAll();
}
void
MP4Reader::InputExhausted(TrackType aTrack)
{

View File

@ -74,6 +74,7 @@ private:
void Error(mp4_demuxer::TrackType aTrack);
bool Decode(mp4_demuxer::TrackType aTrack);
void Flush(mp4_demuxer::TrackType aTrack);
void DrainComplete(mp4_demuxer::TrackType aTrack);
nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
nsAutoPtr<PlatformDecoderModule> mPlatform;
@ -95,6 +96,9 @@ private:
virtual void Error() MOZ_OVERRIDE {
mReader->Error(mType);
}
virtual void DrainComplete() MOZ_OVERRIDE {
mReader->DrainComplete(mType);
}
private:
MP4Reader* mReader;
mp4_demuxer::TrackType mType;
@ -111,6 +115,7 @@ private:
, mInputExhausted(false)
, mError(false)
, mIsFlushing(false)
, mDrainComplete(false)
{
}
@ -132,6 +137,7 @@ private:
bool mInputExhausted;
bool mError;
bool mIsFlushing;
bool mDrainComplete;
};
DecoderData mAudio;
DecoderData mVideo;

View File

@ -129,6 +129,8 @@ public:
// Denotes that the last input sample has been inserted into the decoder,
// and no more output can be produced unless more input is sent.
virtual void InputExhausted() = 0;
virtual void DrainComplete() = 0;
};
// MediaDataDecoder is the interface exposed by decoders created by the
@ -173,14 +175,16 @@ public:
// The MP4Reader will not call Input() while it's calling Flush().
virtual nsresult Flush() = 0;
// Causes all complete samples in the pipeline that can be decoded to be
// output. If the decoder can't produce samples from the current output,
// it drops the input samples. The decoder may be holding onto samples
// that are required to decode samples that it expects to get in future.
// This is called when the demuxer reaches end of stream.
// The MP4Reader will not call Input() while it's calling Drain().
// This function is synchronous. Once it's returned, all samples to be
// output should have been returned via callback to the MP4Reader.
// This function is asynchronous. The MediaDataDecoder must call
// MediaDataDecoderCallback::DrainComplete() once all remaining
// samples have been output.
virtual nsresult Drain() = 0;
// Cancels all init/input/drain operations, and shuts down the

View File

@ -117,7 +117,7 @@ FFmpegAACDecoder<LIBAV_VER>::Input(MP4Sample* aSample)
nsresult
FFmpegAACDecoder<LIBAV_VER>::Drain()
{
// AAC is never delayed; nothing to do here.
mCallback->DrainComplete();
return NS_OK;
}

View File

@ -223,6 +223,12 @@ FFmpegH264Decoder<LIBAV_VER>::Input(mp4_demuxer::MP4Sample* aSample)
return NS_OK;
}
void
FFmpegH264Decoder<LIBAV_VER>::NotifyDrain()
{
mCallback->DrainComplete();
}
nsresult
FFmpegH264Decoder<LIBAV_VER>::Drain()
{
@ -236,6 +242,8 @@ FFmpegH264Decoder<LIBAV_VER>::Drain()
nsresult rv = Input(empty.forget());
NS_ENSURE_SUCCESS(rv, rv);
}
mTaskQueue->Dispatch(
NS_NewRunnableMethod(this, &FFmpegH264Decoder<LIBAV_VER>::NotifyDrain));
return NS_OK;
}

View File

@ -37,6 +37,7 @@ public:
private:
void DecodeFrame(mp4_demuxer::MP4Sample* aSample);
void NotifyDrain();
void OutputDelayedFrames();
/**

View File

@ -124,6 +124,7 @@ WMFMediaDataDecoder::ProcessDrain()
}
// Then extract all available output.
ProcessOutput();
mCallback->DrainComplete();
}
nsresult

View File

@ -216,8 +216,6 @@ MP4Sample::Update()
void
MP4Sample::Pad(size_t aPaddingBytes)
{
MOZ_ASSERT(data == mMediaBuffer->data());
size_t newSize = size + aPaddingBytes;
// If the existing MediaBuffer has enough space then we just recycle it. If