Bug 1206568: P1. Ensure FFmpeg decoder is only accessed through the decoder's task queue. r=cpearce

Add strong assertion that it is indeed the case.
This commit is contained in:
Jean-Yves Avenard 2015-09-21 13:54:29 +10:00
Родитель d9647c7d7e
Коммит 8283012c2a
6 изменённых файлов: 89 добавлений и 41 удалений

Просмотреть файл

@ -18,8 +18,7 @@ namespace mozilla
FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
const AudioInfo& aConfig)
: FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mMimeType))
, mCallback(aCallback)
: FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
{
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
// Use a new MediaByteBuffer as the object will be modified during initialization.
@ -85,6 +84,7 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
void
FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
@ -160,12 +160,12 @@ FFmpegAudioDecoder<LIBAV_VER>::Input(MediaRawData* aSample)
return NS_OK;
}
nsresult
FFmpegAudioDecoder<LIBAV_VER>::Drain()
void
FFmpegAudioDecoder<LIBAV_VER>::ProcessDrain()
{
mTaskQueue->AwaitIdle();
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
ProcessFlush();
mCallback->DrainComplete();
return Flush();
}
AVCodecID

Просмотреть файл

@ -27,13 +27,11 @@ public:
virtual nsRefPtr<InitPromise> Init() override;
virtual nsresult Input(MediaRawData* aSample) override;
virtual nsresult Drain() override;
virtual void ProcessDrain() override;
static AVCodecID GetCodecId(const nsACString& aMimeType);
private:
void DecodePacket(MediaRawData* aSample);
MediaDataDecoderCallback* mCallback;
};
} // namespace mozilla

Просмотреть файл

@ -21,12 +21,16 @@ bool FFmpegDataDecoder<LIBAV_VER>::sFFmpegInitDone = false;
StaticMutex FFmpegDataDecoder<LIBAV_VER>::sMonitor;
FFmpegDataDecoder<LIBAV_VER>::FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
AVCodecID aCodecID)
: mTaskQueue(aTaskQueue)
, mCallback(aCallback)
, mCodecContext(nullptr)
, mFrame(NULL)
, mExtraData(nullptr)
, mCodecID(aCodecID)
, mMonitor("FFMpegaDataDecoder")
, mIsFlushing(false)
{
MOZ_COUNT_CTOR(FFmpegDataDecoder);
}
@ -128,15 +132,58 @@ FFmpegDataDecoder<LIBAV_VER>::InitDecoder()
}
nsresult
FFmpegDataDecoder<LIBAV_VER>::Flush()
FFmpegDataDecoder<LIBAV_VER>::Shutdown()
{
mTaskQueue->Flush();
avcodec_flush_buffers(mCodecContext);
if (mTaskQueue) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown);
mTaskQueue->Dispatch(runnable.forget());
} else {
ProcessShutdown();
}
return NS_OK;
}
nsresult
FFmpegDataDecoder<LIBAV_VER>::Shutdown()
FFmpegDataDecoder<LIBAV_VER>::Flush()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
mIsFlushing = true;
mTaskQueue->Flush();
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessFlush);
MonitorAutoLock mon(mMonitor);
mTaskQueue->Dispatch(runnable.forget());
while (mIsFlushing) {
mon.Wait();
}
return NS_OK;
}
nsresult
FFmpegDataDecoder<LIBAV_VER>::Drain()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &FFmpegDataDecoder<LIBAV_VER>::ProcessDrain);
mTaskQueue->Dispatch(runnable.forget());
return NS_OK;
}
void
FFmpegDataDecoder<LIBAV_VER>::ProcessFlush()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mCodecContext) {
avcodec_flush_buffers(mCodecContext);
}
MonitorAutoLock mon(mMonitor);
mIsFlushing = false;
mon.NotifyAll();
}
void
FFmpegDataDecoder<LIBAV_VER>::ProcessShutdown()
{
StaticMutexAutoLock mon(sMonitor);
@ -152,12 +199,12 @@ FFmpegDataDecoder<LIBAV_VER>::Shutdown()
mFrame = nullptr;
#endif
}
return NS_OK;
}
AVFrame*
FFmpegDataDecoder<LIBAV_VER>::PrepareFrame()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
#if LIBAVCODEC_VERSION_MAJOR >= 55
if (mFrame) {
av_frame_unref(mFrame);

Просмотреть файл

@ -23,7 +23,9 @@ template <>
class FFmpegDataDecoder<LIBAV_VER> : public MediaDataDecoder
{
public:
FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue, AVCodecID aCodecID);
FFmpegDataDecoder(FlushableTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
AVCodecID aCodecID);
virtual ~FFmpegDataDecoder();
static bool Link();
@ -31,19 +33,33 @@ public:
virtual nsRefPtr<InitPromise> Init() override = 0;
virtual nsresult Input(MediaRawData* aSample) override = 0;
virtual nsresult Flush() override;
virtual nsresult Drain() override = 0;
virtual nsresult Drain() override;
virtual nsresult Shutdown() override;
protected:
// Flush and Drain operation, always run
virtual void ProcessFlush();
virtual void ProcessDrain() = 0;
virtual void ProcessShutdown();
AVFrame* PrepareFrame();
nsresult InitDecoder();
FlushableTaskQueue* mTaskQueue;
nsRefPtr<FlushableTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
AVCodecContext* mCodecContext;
AVFrame* mFrame;
nsRefPtr<MediaByteBuffer> mExtraData;
AVCodecID mCodecID;
// For wait on mIsFlushing during Shutdown() process.
// Protects mReorderQueue.
Monitor mMonitor;
// Set on reader/decode thread calling Flush() to indicate that output is
// not required and so input samples on mTaskQueue need not be processed.
// Cleared on mTaskQueue in ProcessDrain().
Atomic<bool> mIsFlushing;
private:
static bool sFFmpegInitDone;
static StaticMutex sMonitor;

Просмотреть файл

@ -28,8 +28,7 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
const VideoInfo& aConfig,
ImageContainer* aImageContainer)
: FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mMimeType))
, mCallback(aCallback)
: FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType))
, mImageContainer(aImageContainer)
, mDisplayWidth(aConfig.mDisplay.width)
, mDisplayHeight(aConfig.mDisplay.height)
@ -57,6 +56,7 @@ FFmpegH264Decoder<LIBAV_VER>::Init()
int64_t
FFmpegH264Decoder<LIBAV_VER>::GetPts(const AVPacket& packet)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
#if LIBAVCODEC_VERSION_MAJOR == 53
if (mFrame->pkt_pts == 0) {
return mFrame->pkt_dts;
@ -71,6 +71,8 @@ FFmpegH264Decoder<LIBAV_VER>::GetPts(const AVPacket& packet)
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
uint8_t* inputData = const_cast<uint8_t*>(aSample->Data());
size_t inputSize = aSample->Size();
@ -122,6 +124,8 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
uint8_t* aData, int aSize)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
AVPacket packet;
av_init_packet(&packet);
@ -208,6 +212,8 @@ FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
void
FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (DoDecodeFrame(aSample) != DecodeResult::DECODE_ERROR &&
mTaskQueue->IsEmpty()) {
mCallback->InputExhausted();
@ -339,32 +345,15 @@ FFmpegH264Decoder<LIBAV_VER>::Input(MediaRawData* aSample)
}
void
FFmpegH264Decoder<LIBAV_VER>::DoDrain()
FFmpegH264Decoder<LIBAV_VER>::ProcessDrain()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
nsRefPtr<MediaRawData> empty(new MediaRawData());
while (DoDecodeFrame(empty) == DecodeResult::DECODE_FRAME) {
}
mCallback->DrainComplete();
}
nsresult
FFmpegH264Decoder<LIBAV_VER>::Drain()
{
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableMethod(this, &FFmpegH264Decoder<LIBAV_VER>::DoDrain));
mTaskQueue->Dispatch(runnable.forget());
return NS_OK;
}
nsresult
FFmpegH264Decoder<LIBAV_VER>::Flush()
{
nsresult rv = FFmpegDataDecoder::Flush();
// Even if the above fails we may as well clear our frame queue.
return rv;
}
FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
{
MOZ_COUNT_DTOR(FFmpegH264Decoder);

Просмотреть файл

@ -38,8 +38,7 @@ public:
virtual nsRefPtr<InitPromise> Init() override;
virtual nsresult Input(MediaRawData* aSample) override;
virtual nsresult Drain() override;
virtual nsresult Flush() override;
virtual void ProcessDrain() override;
static AVCodecID GetCodecId(const nsACString& aMimeType);
private:
@ -62,7 +61,6 @@ private:
static void ReleaseBufferCb(AVCodecContext* aCodecContext, AVFrame* aFrame);
int64_t GetPts(const AVPacket& packet);
MediaDataDecoderCallback* mCallback;
nsRefPtr<ImageContainer> mImageContainer;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;