summaryrefslogtreecommitdiffstats
path: root/dom/media
diff options
context:
space:
mode:
authortrav90 <travawine@protonmail.ch>2018-12-27 11:11:35 -0600
committertrav90 <travawine@palemoon.org>2018-12-28 17:51:55 -0600
commit515e0794f832e6557c0315e0f397be90fd6395af (patch)
treec7c6d5320d779cbcca83b6c76bae3d5d7c401fb7 /dom/media
parent83cd9661c27e943e84d6f299a1b3e6323a330d04 (diff)
downloadUXP-515e0794f832e6557c0315e0f397be90fd6395af.tar
UXP-515e0794f832e6557c0315e0f397be90fd6395af.tar.gz
UXP-515e0794f832e6557c0315e0f397be90fd6395af.tar.lz
UXP-515e0794f832e6557c0315e0f397be90fd6395af.tar.xz
UXP-515e0794f832e6557c0315e0f397be90fd6395af.zip
[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.
Diffstat (limited to 'dom/media')
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp2
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegLibWrapper.h4
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp66
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h1
4 files changed, 66 insertions, 7 deletions
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
index e1c326818..426e9f74b 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -145,6 +145,8 @@ FFmpegLibWrapper::Link()
AV_FUNC(avcodec_alloc_frame, (AV_FUNC_53 | AV_FUNC_54))
AV_FUNC(avcodec_get_frame_defaults, (AV_FUNC_53 | AV_FUNC_54))
AV_FUNC(avcodec_free_frame, AV_FUNC_54)
+ AV_FUNC(avcodec_send_packet, AV_FUNC_58)
+ AV_FUNC(avcodec_receive_frame, AV_FUNC_58)
AV_FUNC(av_log_set_level, AV_FUNC_AVUTIL_ALL)
AV_FUNC(av_malloc, AV_FUNC_AVUTIL_ALL)
AV_FUNC(av_freep, AV_FUNC_AVUTIL_ALL)
diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
index c6c43a4ae..b968edd32 100644
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
@@ -71,6 +71,10 @@ struct FFmpegLibWrapper
// libavcodec v54 only
void (*avcodec_free_frame)(AVFrame** frame);
+ // libavcodec v58 and later only
+ int (*avcodec_send_packet)(AVCodecContext* avctx, const AVPacket* avpkt);
+ int (*avcodec_receive_frame)(AVCodecContext* avctx, AVFrame* frame);
+
// libavutil
void (*av_log_set_level)(int level);
void* (*av_malloc)(size_t size);
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<LIBAV_VER>::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<LIBAV_VER>::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<LIBAV_VER>::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<LIBAV_VER>::DoDecode(MediaRawData* aSample,
RefPtr<VideoData> v =
VideoData::CreateAndCopyData(mInfo,
mImageContainer,
- aSample->mOffset,
- pts,
- duration,
+ aOffset,
+ aPts,
+ aDuration,
b,
!!mFrame->key_frame,
-1,
@@ -331,9 +386,6 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
RESULT_DETAIL("image allocation error"));
}
mCallback->Output(v);
- if (aGotFrame) {
- *aGotFrame = true;
- }
return NS_OK;
}
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
index 786df0da1..49a55e8a6 100644
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
@@ -49,6 +49,7 @@ private:
MediaResult DoDecode(MediaRawData* aSample) override;
MediaResult DoDecode(MediaRawData* aSample, bool* aGotFrame);
MediaResult DoDecode(MediaRawData* aSample, uint8_t* aData, int aSize, bool* aGotFrame);
+ MediaResult CreateImage(int64_t aOffset, int64_t aPts, int64_t aDuration);
void ProcessDrain() override;
void ProcessFlush() override;
void OutputDelayedFrames();