From 515e0794f832e6557c0315e0f397be90fd6395af Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 27 Dec 2018 11:11:35 -0600 Subject: [FFmpeg] Use new decode API with recent FFmpeg version. In libavcodec 58 and later, the old avcodec_decode_video2 is broken and only return the first visible frame found after a VP9 super-frame. --- dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp | 66 ++++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) (limited to 'dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp') diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index aec1e9136..d71a86b3c 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -224,6 +224,48 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; packet.pos = aSample->mOffset; +#if LIBAVCODEC_VERSION_MAJOR >= 58 + packet.duration = aSample->mDuration; + int res = mLib->avcodec_send_packet(mCodecContext, &packet); + if (res < 0) { + // In theory, avcodec_send_packet could sent -EAGAIN should its internal + // buffers be full. In practice this can't happen as we only feed one frame + // at a time, and we immediately call avcodec_receive_frame right after. + FFMPEG_LOG("avcodec_send_packet error: %d", res); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("avcodec_send_packet error: %d", res)); + } + + if (aGotFrame) { + *aGotFrame = false; + } + do { + if (!PrepareFrame()) { + NS_WARNING("FFmpeg h264 decoder failed to allocate frame."); + return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); + } + res = mLib->avcodec_receive_frame(mCodecContext, mFrame); + if (res == int(AVERROR_EOF)) { + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; + } + if (res == AVERROR(EAGAIN)) { + return NS_OK; + } + if (res < 0) { + FFMPEG_LOG("avcodec_receive_frame error: %d", res); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("avcodec_receive_frame error: %d", res)); + } + MediaResult rv = CreateImage(mFrame->pkt_pos, mFrame->pkt_pts, + mFrame->pkt_duration); + if (NS_FAILED(rv)) { + return rv; + } + if (aGotFrame) { + *aGotFrame = true; + } + } while (true); +#else // LibAV provides no API to retrieve the decoded sample's duration. // (FFmpeg >= 1.0 provides av_frame_get_pkt_duration) // As such we instead use a map using the dts as key that we will retrieve @@ -276,8 +318,21 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, // against the map becoming extremely big. mDurationMap.Clear(); } + + MediaResult rv = CreateImage(aSample->mOffset, pts, duration); + if (NS_SUCCEEDED(rv) && aGotFrame) { + *aGotFrame = true; + } + return rv; +#endif +} + +MediaResult +FFmpegVideoDecoder::CreateImage(int64_t aOffset, int64_t aPts, + int64_t aDuration) +{ FFMPEG_LOG("Got one frame output with pts=%lld dts=%lld duration=%lld opaque=%lld", - pts, mFrame->pkt_dts, duration, mCodecContext->reordered_opaque); + aPts, mFrame->pkt_dts, aDuration, mCodecContext->reordered_opaque); VideoData::YCbCrBuffer b; b.mPlanes[0].mData = mFrame->data[0]; @@ -317,9 +372,9 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, RefPtr v = VideoData::CreateAndCopyData(mInfo, mImageContainer, - aSample->mOffset, - pts, - duration, + aOffset, + aPts, + aDuration, b, !!mFrame->key_frame, -1, @@ -331,9 +386,6 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, RESULT_DETAIL("image allocation error")); } mCallback->Output(v); - if (aGotFrame) { - *aGotFrame = true; - } return NS_OK; } -- cgit v1.2.3