summaryrefslogtreecommitdiff
path: root/libavcodec/h264dec.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2021-08-17 21:54:56 +0200
committerJames Almer <jamrial@gmail.com>2021-08-24 09:58:52 -0300
commit66845cffc3bbb17f91294d15cd6f57f3df3bce97 (patch)
tree413847a6a899872e940d88fd1ad1c34e91631794 /libavcodec/h264dec.c
parent6bc29a6b571c83058d04dc7b8b0f827dfee31b2c (diff)
avcodec/h264dec: apply H.274 film grain
Because we need access to ref frames without film grain applied, we have to add an extra AVFrame to H264Picture to avoid messing with the original. This requires some amount of overhead to make the reference moves work out, but it allows us to benefit from frame multithreading for film grain application "for free". Unfortunately, this approach requires twice as much RAM to be constantly allocated for ref frames, due to the need for an extra buffer per H264Picture. In theory, we could get away with freeing up this memory as soon as it's no longer needed (since ref frames do not need film grain buffers any longer), but trying to call ff_thread_release_buffer() from output_frame() conflicts with possible later accesses to that same frame and I'm not sure how to synchronize that well. Tested on all three cases of (no fg), (fg present but exported) and (fg present and not exported), with and without threading. Co-authored-by: James Almer <jamrial@gmail.com> Signed-off-by: Niklas Haas <git@haasn.dev> Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavcodec/h264dec.c')
-rw-r--r--libavcodec/h264dec.c55
1 files changed, 37 insertions, 18 deletions
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index f46d29baa6..5e5b1c1d69 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -275,9 +275,22 @@ int ff_h264_slice_context_init(H264Context *h, H264SliceContext *sl)
return 0;
}
+static int h264_init_pic(H264Picture *pic)
+{
+ pic->f = av_frame_alloc();
+ if (!pic->f)
+ return AVERROR(ENOMEM);
+
+ pic->f_grain = av_frame_alloc();
+ if (!pic->f_grain)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
static int h264_init_context(AVCodecContext *avctx, H264Context *h)
{
- int i;
+ int i, ret;
h->avctx = avctx;
h->cur_chroma_format_idc = -1;
@@ -308,18 +321,15 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
}
for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
- h->DPB[i].f = av_frame_alloc();
- if (!h->DPB[i].f)
- return AVERROR(ENOMEM);
+ if ((ret = h264_init_pic(&h->DPB[i])) < 0)
+ return ret;
}
- h->cur_pic.f = av_frame_alloc();
- if (!h->cur_pic.f)
- return AVERROR(ENOMEM);
+ if ((ret = h264_init_pic(&h->cur_pic)) < 0)
+ return ret;
- h->last_pic_for_ec.f = av_frame_alloc();
- if (!h->last_pic_for_ec.f)
- return AVERROR(ENOMEM);
+ if ((ret = h264_init_pic(&h->last_pic_for_ec)) < 0)
+ return ret;
for (i = 0; i < h->nb_slice_ctx; i++)
h->slice_ctx[i].h264 = h;
@@ -327,6 +337,13 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
return 0;
}
+static void h264_free_pic(H264Context *h, H264Picture *pic)
+{
+ ff_h264_unref_picture(h, pic);
+ av_frame_free(&pic->f);
+ av_frame_free(&pic->f_grain);
+}
+
static av_cold int h264_decode_end(AVCodecContext *avctx)
{
H264Context *h = avctx->priv_data;
@@ -336,8 +353,7 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
ff_h264_free_tables(h);
for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) {
- ff_h264_unref_picture(h, &h->DPB[i]);
- av_frame_free(&h->DPB[i].f);
+ h264_free_pic(h, &h->DPB[i]);
}
memset(h->delayed_pic, 0, sizeof(h->delayed_pic));
@@ -351,10 +367,8 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
ff_h2645_packet_uninit(&h->pkt);
- ff_h264_unref_picture(h, &h->cur_pic);
- av_frame_free(&h->cur_pic.f);
- ff_h264_unref_picture(h, &h->last_pic_for_ec);
- av_frame_free(&h->last_pic_for_ec.f);
+ h264_free_pic(h, &h->cur_pic);
+ h264_free_pic(h, &h->last_pic_for_ec);
return 0;
}
@@ -837,13 +851,15 @@ static int h264_export_enc_params(AVFrame *f, H264Picture *p)
static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
{
- AVFrame *src = srcp->f;
int ret;
- ret = av_frame_ref(dst, src);
+ ret = av_frame_ref(dst, srcp->needs_fg ? srcp->f_grain : srcp->f);
if (ret < 0)
return ret;
+ if (srcp->needs_fg && (ret = av_frame_copy_props(dst, srcp->f)) < 0)
+ return ret;
+
av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(&h->sei.frame_packing), 0);
if (srcp->sei_recovery_frame_cnt == 0)
@@ -855,6 +871,9 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
goto fail;
}
+ if (!(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
+ av_frame_remove_side_data(dst, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
+
return 0;
fail:
av_frame_unref(dst);