avcodec/hevcdec: apply H.274 film grain

Similar in spirit and design to 66845cffc3, 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).
pull/370/head
Niklas Haas 3 years ago committed by James Almer
parent 5d16660598
commit 3cc3f5de2a
  1. 10
      libavcodec/hevc_refs.c
  2. 54
      libavcodec/hevcdec.c
  3. 5
      libavcodec/hevcdec.h

@ -38,6 +38,8 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
frame->flags &= ~flags; frame->flags &= ~flags;
if (!frame->flags) { if (!frame->flags) {
ff_thread_release_buffer(s->avctx, &frame->tf); ff_thread_release_buffer(s->avctx, &frame->tf);
ff_thread_release_buffer(s->avctx, &frame->tf_grain);
frame->needs_fg = 0;
av_buffer_unref(&frame->tab_mvf_buf); av_buffer_unref(&frame->tab_mvf_buf);
frame->tab_mvf = NULL; frame->tab_mvf = NULL;
@ -208,7 +210,7 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
if (nb_output) { if (nb_output) {
HEVCFrame *frame = &s->DPB[min_idx]; HEVCFrame *frame = &s->DPB[min_idx];
ret = av_frame_ref(out, frame->frame); ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame);
if (frame->flags & HEVC_FRAME_FLAG_BUMPING) if (frame->flags & HEVC_FRAME_FLAG_BUMPING)
ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING); ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING);
else else
@ -216,6 +218,12 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (frame->needs_fg && (ret = av_frame_copy_props(out, frame->frame)) < 0)
return ret;
if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
av_log(s->avctx, AV_LOG_DEBUG, av_log(s->avctx, AV_LOG_DEBUG,
"Output frame with POC %d.\n", frame->poc); "Output frame with POC %d.\n", frame->poc);
return 1; return 1;

@ -2884,14 +2884,14 @@ static int set_side_data(HEVCContext *s)
s->sei.timecode.num_clock_ts = 0; s->sei.timecode.num_clock_ts = 0;
} }
if (s->sei.film_grain_characteristics.present && if (s->sei.film_grain_characteristics.present) {
(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) {
HEVCSEIFilmGrainCharacteristics *fgc = &s->sei.film_grain_characteristics; HEVCSEIFilmGrainCharacteristics *fgc = &s->sei.film_grain_characteristics;
AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out); AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out);
if (!fgp) if (!fgp)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
fgp->type = AV_FILM_GRAIN_PARAMS_H274; 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; fgp->codec.h274.model_id = fgc->model_id;
if (fgc->separate_colour_description_present_flag) { 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->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); ret = set_side_data(s);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
@ -3012,6 +3024,28 @@ fail:
return ret; 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) static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
{ {
HEVCLocalContext *lc = s->HEVClc; HEVCLocalContext *lc = s->HEVClc;
@ -3170,6 +3204,9 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal)
else else
ctb_addr_ts = hls_slice_data(s); ctb_addr_ts = hls_slice_data(s);
if (ctb_addr_ts >= (s->ps.sps->ctb_width * s->ps.sps->ctb_height)) { 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; s->is_decoded = 1;
} }
@ -3429,6 +3466,13 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
if (ret < 0) if (ret < 0)
return ret; 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); dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf);
if (!dst->tab_mvf_buf) if (!dst->tab_mvf_buf)
goto fail; 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++) { for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
ff_hevc_unref_frame(s, &s->DPB[i], ~0); ff_hevc_unref_frame(s, &s->DPB[i], ~0);
av_frame_free(&s->DPB[i].frame); av_frame_free(&s->DPB[i].frame);
av_frame_free(&s->DPB[i].frame_grain);
} }
ff_hevc_ps_uninit(&s->ps); ff_hevc_ps_uninit(&s->ps);
@ -3534,6 +3579,11 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
if (!s->DPB[i].frame) if (!s->DPB[i].frame)
goto fail; goto fail;
s->DPB[i].tf.f = s->DPB[i].frame; 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; s->max_ra = INT_MAX;

@ -39,6 +39,7 @@
#include "hevc_ps.h" #include "hevc_ps.h"
#include "hevc_sei.h" #include "hevc_sei.h"
#include "hevcdsp.h" #include "hevcdsp.h"
#include "h274.h"
#include "internal.h" #include "internal.h"
#include "thread.h" #include "thread.h"
#include "videodsp.h" #include "videodsp.h"
@ -395,7 +396,10 @@ typedef struct DBParams {
typedef struct HEVCFrame { typedef struct HEVCFrame {
AVFrame *frame; AVFrame *frame;
AVFrame *frame_grain;
ThreadFrame tf; ThreadFrame tf;
ThreadFrame tf_grain;
int needs_fg; /* 1 if grain needs to be applied by the decoder */
MvField *tab_mvf; MvField *tab_mvf;
RefPicList *refPicList; RefPicList *refPicList;
RefPicListTab **rpl_tab; RefPicListTab **rpl_tab;
@ -525,6 +529,7 @@ typedef struct HEVCContext {
HEVCDSPContext hevcdsp; HEVCDSPContext hevcdsp;
VideoDSPContext vdsp; VideoDSPContext vdsp;
BswapDSPContext bdsp; BswapDSPContext bdsp;
H274FilmGrainDatabase h274db;
int8_t *qp_y_tab; int8_t *qp_y_tab;
uint8_t *horizontal_bs; uint8_t *horizontal_bs;
uint8_t *vertical_bs; uint8_t *vertical_bs;

Loading…
Cancel
Save