[FFmpeg-devel] [PATCH 1/2] libavutil: introduce AVFilmGrainParams side data

James Almer jamrial at gmail.com
Thu Nov 12 15:40:44 EET 2020


On 11/12/2020 8:58 AM, Lynne wrote:
> This patch introduces a new frame side data type AVFilmGrainParams for use
> with video codecs able to offload film grain application during presentation.
> 
> It is generalized rather than being AV1 specific as AV2 is expected to carry
> the same data, as well as the fact it was based on general research of
> film grain synthesis.
> 
> This patch also introduces an option to export this side data from compatible
> decoders. It will be used in the next patch.
> 
> Patch attached.

> From 2600c67e3c6e5ff33351be6522be9e55d996ba74 Mon Sep 17 00:00:00 2001
> From: Lynne <dev at lynne.ee>
> Date: Thu, 12 Nov 2020 12:44:30 +0100
> Subject: [PATCH 1/2] libavutil: introduce AVFilmGrainParams side data
> 
> This patch introduces a new frame side data type AVFilmGrainParams for use
> with video codecs able to offload film grain application during presentation.
> 
> It is generalized rather than being AV1 specific as AV2 is expected to carry
> the same data, as well as the fact it was based on general research of
> film grain synthesis.
> 
> This patch also introduces an option to export this side data from compatible
> decoders. It will be used in the next patch.
> ---
>  libavcodec/avcodec.h          |   5 ++
>  libavcodec/options_table.h    |   1 +
>  libavutil/Makefile            |   2 +
>  libavutil/film_grain_params.c |  37 +++++++++
>  libavutil/film_grain_params.h | 144 ++++++++++++++++++++++++++++++++++
>  libavutil/frame.c             |   1 +
>  libavutil/frame.h             |   6 ++
>  7 files changed, 196 insertions(+)
>  create mode 100644 libavutil/film_grain_params.c
>  create mode 100644 libavutil/film_grain_params.h

Missing APIChanges entry, version bumps, and the lavu and lavc changes 
should be in separate patches.

> 
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 20af3ef00d..5047da0f6a 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -410,6 +410,11 @@ typedef struct RcOverride{
>   * Export the AVVideoEncParams structure through frame side data.
>   */
>  #define AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS (1 << 2)
> +/**
> + * Decoding only.
> + * Do not apply film grain, export it instead.
> + */
> +#define AV_CODEC_EXPORT_DATA_FILM_GRAIN (1 << 3)
>  
>  /**
>   * Pan Scan area.
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index 66bda42663..77e1211ae0 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -83,6 +83,7 @@ static const AVOption avcodec_options[] = {
>  {"mvs", "export motion vectors through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_MVS}, INT_MIN, INT_MAX, V|D, "export_side_data"},
>  {"prft", "export Producer Reference Time through packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_PRFT}, INT_MIN, INT_MAX, A|V|S|E, "export_side_data"},
>  {"venc_params", "export video encoding parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS}, INT_MIN, INT_MAX, V|D, "export_side_data"},
> +{"export_film_grain", "export film grain parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_FILM_GRAIN}, INT_MIN, INT_MAX, V|D, "export_side_data"},
>  {"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT_MAX},
>  {"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E},
>  {"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E},
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 9b08372eb2..27bafe9e12 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -84,6 +84,7 @@ HEADERS = adler32.h                                                     \
>            xtea.h                                                        \
>            tea.h                                                         \
>            tx.h                                                          \
> +          film_grain_params.h                                           \
>  
>  HEADERS-$(CONFIG_LZO)                   += lzo.h
>  
> @@ -170,6 +171,7 @@ OBJS = adler32.o                                                        \
>         tx_double.o                                                      \
>         tx_int32.o                                                       \
>         video_enc_params.o                                               \
> +       film_grain_params.o                                              \
>  
>  
>  OBJS-$(CONFIG_CUDA)                     += hwcontext_cuda.o
> diff --git a/libavutil/film_grain_params.c b/libavutil/film_grain_params.c
> new file mode 100644
> index 0000000000..79c2c37960
> --- /dev/null
> +++ b/libavutil/film_grain_params.c
> @@ -0,0 +1,37 @@
> +/**
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "film_grain_params.h"
> +
> +AVBufferRef *av_film_grain_params_buffer_alloc(void)
> +{
> +    return av_buffer_allocz(sizeof(AVFilmGrainParams));
> +}
> +
> +AVFilmGrainParams *av_film_grain_params_create_side_data(AVFrame *frame)
> +{
> +    AVFrameSideData *side_data = av_frame_new_side_data(frame,
> +                                                        AV_FRAME_DATA_FILM_GRAIN_PARAMS,
> +                                                        sizeof(AVFilmGrainParams));
> +    if (!side_data)
> +        return NULL;
> +
> +    memset(side_data->data, 0, sizeof(AVFilmGrainParams));
> +
> +    return (AVFilmGrainParams *)side_data->data;
> +}
> diff --git a/libavutil/film_grain_params.h b/libavutil/film_grain_params.h
> new file mode 100644
> index 0000000000..485b7ba228
> --- /dev/null
> +++ b/libavutil/film_grain_params.h
> @@ -0,0 +1,144 @@
> +/*
> + * Copyright (c) 2016 Neil Birkbeck <neil.birkbeck at gmail.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVUTIL_FILM_GRAIN_PARAMS_H
> +#define AVUTIL_FILM_GRAIN_PARAMS_H
> +
> +#include "frame.h"
> +
> +enum AVFilmGrainParamsType {
> +    AV_FILM_GRAM_PARAMS_NONE = -1,
> +
> +    /**
> +     * For AV1 all parameters up to and including clip_to_limited_range
> +     * are used.

Maybe instead of this you could use a union in AVFilmGrainParams. 
There's no guarantee any future non AOMedia FG implementation will match 
the AV1 FG one even partially. All you need is one existing field having 
different semantics in a future codec and then you'll start having to 
duplicate or replace fields.

Something like

typedef struct AVFilmGrainParams {
     uint64_t seed;
     int clip_to_limited_range;
     union {
         AVFilmGrainAV1Params av1;
         AVFilmGrainXXXParams xxx;
     } codec;
} AVFilmGrainParams;

Where the true generic fields are outside would be the safest and most 
future proof approach, all while not bloating the struct size (Most 
fields below could be safely made into uint8_t, int16_t and so, 
following the AV1 spec).

> +     */
> +    AV_FILM_GRAM_PARAMS_AV1,
> +};
> +
> +typedef struct AVFilmGrainParams {
> +    enum AVFilmGrainParamsType type;
> +
> +    /**
> +     * Seed to use for the synthesis process.
> +     */
> +    uint32_t seed;
> +
> +    /**
> +     * Number of points for the piecewise linear scaling function of the
> +     * luma plane.
> +     */
> +    int num_y_points;
> +
> +    /**
> +     * Piecewise scaling function values and scale for each point.
> +     */
> +    uint8_t y_points[14][2 /* value, scaling */];
> +
> +    /**
> +     * Signals whether to derive the chroma scaling function from the luma.
> +     * Not equivalent to copying the luma values and scales.
> +     */
> +    int chroma_scaling_from_luma;
> +
> +    /**
> +     * If chroma_scaling_from_luma is set to 0, signals the chroma scaling
> +     * function parameters.
> +     */
> +    int num_uv_points[2];
> +    uint8_t uv_points[2][10][2 /* value, scaling */];
> +
> +    /**
> +     * Specifies the shift applied to the chroma components. For AV1, its within
> +     * [8; 11] and determines the range and quantization of the film grain.
> +     */
> +    int scaling_shift;
> +
> +    /**
> +     * Specifies the auto-regression coefficients for both luma and chroma.
> +     */
> +    int ar_coeff_lag;
> +
> +    /**
> +     * Luma auto-regression coefficients.
> +     */
> +    int8_t ar_coeffs_y[24];
> +
> +    /**
> +     * Chroma auto-regression coefficients. Padded to help with SIMD, last
> +     * 3 values of each chroma coeff are not used.
> +     */
> +    int8_t ar_coeffs_uv[2][25 + 3 /* padding for alignment purposes */];
> +
> +    /**
> +     * Specifies the range of the auto-regressive coefficients. Values of 6,
> +     * 7, 8 and so on represent a range of [-2, 2), [-1, 1), [-0.5, 0.5) and
> +     * so on. For AV1 must be between 6 and 9.
> +     */
> +    uint64_t ar_coeff_shift;
> +
> +    /**
> +     * Signals the down shift applied to the generated gaussian numbers during
> +     * synthesis.
> +     */
> +    int grain_scale_shift;
> +
> +    /**
> +     * Specifies the luma/chroma multipliers for the index to the component
> +     * scaling function.
> +     */
> +    int uv_mult[2];
> +    int uv_mult_luma[2];
> +
> +    /**
> +     * Offset used for component scaling function. For AV1 its a 9-bit value
> +     * with a range [-256, 255] */
> +    int uv_offset[2];
> +
> +    /**
> +     * Signals whether to overlap film grain blocks.
> +     */
> +    int overlap_flag;
> +
> +    /**
> +     * Specifies to clip to limited color levels after film grain application.
> +     */
> +    int clip_to_limited_range;
> +} AVFilmGrainParams;
> +
> +/**
> + * Allocate an AVBufferRef containing an AVFilmGrainParams structure and
> + * set it to default values.
> + *
> + * @return An AVBufferRef containing an AVFilmGrainParams filled with
> + *         default values or NULL on failure.
> + */
> +AVBufferRef *av_film_grain_params_buffer_alloc(void);

Don't allocate or return an AVBufferRef here, just the raw struct. 
There's nothing to gain doing this (If you want to attach it to a frame, 
you should use the other function below), and we should aim to keep 
alloc functions consistent across lavu modules (mastering display, 
content light, spherical, video_enc_params, etc).

That includes adding a size_t *size output parameter, too.

> +
> +/**
> + * Allocate a complete AVFilmGrainParams and add it to the frame.
> + *
> + * @param frame The frame which side data is added to.
> + *
> + * @return The AVFilmGrainParams structure to be filled by caller.
> + */
> +AVFilmGrainParams *av_film_grain_params_create_side_data(AVFrame *frame);
> +
> +#endif /* AVUTIL_FILM_GRAIN_PARAMS_H */
> diff --git a/libavutil/frame.c b/libavutil/frame.c
> index 3ab1aa3242..668a0e9e3c 100644
> --- a/libavutil/frame.c
> +++ b/libavutil/frame.c
> @@ -864,6 +864,7 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type)
>      case AV_FRAME_DATA_REGIONS_OF_INTEREST: return "Regions Of Interest";
>      case AV_FRAME_DATA_VIDEO_ENC_PARAMS:            return "Video encoding parameters";
>      case AV_FRAME_DATA_SEI_UNREGISTERED:            return "H.26[45] User Data Unregistered SEI message";
> +    case AV_FRAME_DATA_FILM_GRAIN_PARAMS:           return "Film grain parameters";
>      }
>      return NULL;
>  }
> diff --git a/libavutil/frame.h b/libavutil/frame.h
> index 3bd240fc97..392315f40f 100644
> --- a/libavutil/frame.h
> +++ b/libavutil/frame.h
> @@ -192,6 +192,12 @@ enum AVFrameSideDataType {
>       * uuid_iso_iec_11578 followed by AVFrameSideData.size - 16 bytes of user_data_payload_byte.
>       */
>      AV_FRAME_DATA_SEI_UNREGISTERED,
> +
> +    /**
> +     * Film grain parameters for a frame, described by AVFilmGrainParameters.
> +     * Must be present for every frame which should have film grain applied.
> +     */
> +    AV_FRAME_DATA_FILM_GRAIN_PARAMS,
>  };
>  
>  enum AVActiveFormatDescription {
> -- 
> 2.29.2
> 


More information about the ffmpeg-devel mailing list