Bug 1197319: P2. Parse raw data to identify single frames before decoding. r=kentuckyfriedtakahe

A VP9 or VP9 packet may contains alternate frames. They need to be fed separately to the ffmpeg decoder.
This commit is contained in:
Jean-Yves Avenard 2015-09-09 18:47:59 +10:00
parent bcf327201c
commit 13a129c06b
4 changed files with 64 additions and 4 deletions

View File

@ -42,12 +42,11 @@ protected:
AVCodecContext* mCodecContext;
AVFrame* mFrame;
nsRefPtr<MediaByteBuffer> mExtraData;
AVCodecID mCodecID;
private:
static bool sFFmpegInitDone;
static StaticMutex sMonitor;
AVCodecID mCodecID;
};
} // namespace mozilla

View File

@ -20,6 +20,9 @@ AV_FUNC(avcodec_get_edge_width, 0)
AV_FUNC(avcodec_open2, 0)
AV_FUNC(av_init_packet, 0)
AV_FUNC(av_dict_get, 0)
AV_FUNC(av_parser_init, 0)
AV_FUNC(av_parser_close, 0)
AV_FUNC(av_parser_parse2, 0)
/* libavutil */
AV_FUNC(av_image_fill_linesizes, 0)

View File

@ -33,6 +33,7 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
, mImageContainer(aImageContainer)
, mDisplayWidth(aConfig.mDisplay.width)
, mDisplayHeight(aConfig.mDisplay.height)
, mCodecParser(nullptr)
{
MOZ_COUNT_CTOR(FFmpegH264Decoder);
// Use a new MediaByteBuffer as the object will be modified during initialization.
@ -69,12 +70,63 @@ FFmpegH264Decoder<LIBAV_VER>::GetPts(const AVPacket& packet)
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample)
{
uint8_t* inputData = const_cast<uint8_t*>(aSample->Data());
size_t inputSize = aSample->Size();
if (inputSize && (mCodecID == AV_CODEC_ID_VP8
#if LIBAVCODEC_VERSION_MAJOR >= 55
|| mCodecID == AV_CODEC_ID_VP9
#endif
)) {
if (!mCodecParser) {
mCodecParser = av_parser_init(mCodecID);
if (!mCodecParser) {
mCallback->Error();
return DecodeResult::DECODE_ERROR;
}
mCodecParser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
}
bool gotFrame = false;
while (inputSize) {
uint8_t* data;
int size;
int len = av_parser_parse2(mCodecParser, mCodecContext, &data, &size,
inputData, inputSize,
aSample->mTime, aSample->mTimecode,
aSample->mOffset);
if (size_t(len) > inputSize) {
mCallback->Error();
return DecodeResult::DECODE_ERROR;
}
inputData += len;
inputSize -= len;
if (size) {
switch (DoDecodeFrame(aSample, data, size)) {
case DecodeResult::DECODE_ERROR:
return DecodeResult::DECODE_ERROR;
case DecodeResult::DECODE_FRAME:
gotFrame = true;
break;
default:
break;
}
}
}
return gotFrame ? DecodeResult::DECODE_FRAME : DecodeResult::DECODE_NO_FRAME;
}
return DoDecodeFrame(aSample, inputData, inputSize);
}
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
uint8_t* aData, int aSize)
{
AVPacket packet;
av_init_packet(&packet);
packet.data = const_cast<uint8_t*>(aSample->Data());
packet.size = aSample->Size();
packet.data = aData;
packet.size = aSize;
packet.dts = aSample->mTimecode;
packet.pts = aSample->mTime;
packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
@ -316,6 +368,10 @@ FFmpegH264Decoder<LIBAV_VER>::Flush()
FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
{
MOZ_COUNT_DTOR(FFmpegH264Decoder);
if (mCodecParser) {
av_parser_close(mCodecParser);
mCodecParser = nullptr;
}
}
AVCodecID

View File

@ -45,6 +45,7 @@ public:
private:
void DecodeFrame(MediaRawData* aSample);
DecodeResult DoDecodeFrame(MediaRawData* aSample);
DecodeResult DoDecodeFrame(MediaRawData* aSample, uint8_t* aData, int aSize);
void DoDrain();
void OutputDelayedFrames();
@ -65,6 +66,7 @@ private:
nsRefPtr<ImageContainer> mImageContainer;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
AVCodecParserContext* mCodecParser;
};
} // namespace mozilla