summaryrefslogtreecommitdiff
path: root/libavcodec/hevcdec.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2021-09-29 01:06:02 +0200
committerJames Almer <jamrial@gmail.com>2021-10-15 11:55:45 -0300
commit3cc3f5de2afda5b8f880c0817e9d67c2dafbfe1e (patch)
treeb6b31494a972106f66ebb8219bfce5fbed40ceb9 /libavcodec/hevcdec.c
parent5d16660598dd9409c1028204cac3a966a939b719 (diff)
avcodec/hevcdec: apply H.274 film grain
Similar in spirit and design to 66845cffc3bbb, but slightly simpler due to the lack of interlaced frames in HEVC. See that commit for more details. For the seed value, since no specification for this appears to exist, I semi-arbitrarily decided to base it off the POC id alone, since there's no analog of the idr_pic_id in HEVC's I-frames. This design is stable across remuxes and seeks, but changes for adjacent frames with a period that's typically long enough not to be noticeable, which makes it satisfy all of the requirements that a film grain seed should have. Tested with and without threading, using a patch to insert film grain metadata artificially (for lack of real files containing film grain).
Diffstat (limited to 'libavcodec/hevcdec.c')
-rw-r--r--libavcodec/hevcdec.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index b4edb3b3cc..246ffd7d80 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2884,14 +2884,14 @@ static int set_side_data(HEVCContext *s)
s->sei.timecode.num_clock_ts = 0;
}
- if (s->sei.film_grain_characteristics.present &&
- (s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) {
+ if (s->sei.film_grain_characteristics.present) {
HEVCSEIFilmGrainCharacteristics *fgc = &s->sei.film_grain_characteristics;
AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out);
if (!fgp)
return AVERROR(ENOMEM);
fgp->type = AV_FILM_GRAIN_PARAMS_H274;
+ fgp->seed = s->ref->poc; /* no poc_offset in HEVC */
fgp->codec.h274.model_id = fgc->model_id;
if (fgc->separate_colour_description_present_flag) {
@@ -2986,6 +2986,18 @@ static int hevc_frame_start(HEVCContext *s)
s->ref->frame->key_frame = IS_IRAP(s);
+ s->ref->needs_fg = s->sei.film_grain_characteristics.present &&
+ !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) &&
+ !s->avctx->hwaccel;
+
+ if (s->ref->needs_fg) {
+ s->ref->frame_grain->format = s->ref->frame->format;
+ s->ref->frame_grain->width = s->ref->frame->width;
+ s->ref->frame_grain->height = s->ref->frame->height;
+ if ((ret = ff_thread_get_buffer(s->avctx, &s->ref->tf_grain, 0)) < 0)
+ goto fail;
+ }
+
ret = set_side_data(s);
if (ret < 0)
goto fail;
@@ -3012,6 +3024,28 @@ fail:
return ret;
}
+static int hevc_frame_end(HEVCContext *s)
+{
+ HEVCFrame *out = s->ref;
+ const AVFrameSideData *sd;
+ int ret;
+
+ if (out->needs_fg) {
+ sd = av_frame_get_side_data(out->frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
+ av_assert0(out->frame_grain->buf[0] && sd);
+ ret = ff_h274_apply_film_grain(out->frame_grain, out->frame, &s->h274db,
+ (AVFilmGrainParams *) sd->data);
+
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_WARNING, "Failed synthesizing film "
+ "grain, ignoring: %s\n", av_err2str(ret));
+ out->needs_fg = 0;
+ }
+ }
+
+ return 0;
+}
+
static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
{
HEVCLocalContext *lc = s->HEVClc;
@@ -3170,6 +3204,9 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
else
ctb_addr_ts = hls_slice_data(s);
if (ctb_addr_ts >= (s->ps.sps->ctb_width * s->ps.sps->ctb_height)) {
+ ret = hevc_frame_end(s);
+ if (ret < 0)
+ goto fail;
s->is_decoded = 1;
}
@@ -3429,6 +3466,13 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
if (ret < 0)
return ret;
+ if (src->needs_fg) {
+ ret = ff_thread_ref_frame(&dst->tf_grain, &src->tf_grain);
+ if (ret < 0)
+ return ret;
+ dst->needs_fg = 1;
+ }
+
dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf);
if (!dst->tab_mvf_buf)
goto fail;
@@ -3481,6 +3525,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
ff_hevc_unref_frame(s, &s->DPB[i], ~0);
av_frame_free(&s->DPB[i].frame);
+ av_frame_free(&s->DPB[i].frame_grain);
}
ff_hevc_ps_uninit(&s->ps);
@@ -3534,6 +3579,11 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
if (!s->DPB[i].frame)
goto fail;
s->DPB[i].tf.f = s->DPB[i].frame;
+
+ s->DPB[i].frame_grain = av_frame_alloc();
+ if (!s->DPB[i].frame_grain)
+ goto fail;
+ s->DPB[i].tf_grain.f = s->DPB[i].frame_grain;
}
s->max_ra = INT_MAX;