[FFmpeg-devel] CNG (consistent noise generation) patch for AC-3 decoder

James Almer jamrial at gmail.com
Sat Sep 3 03:34:29 EEST 2016


On 9/2/2016 8:49 PM, Jonathan Campbell wrote:
> diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
> index fac189b..18a674b 100644
> --- a/libavcodec/ac3dec.c
> +++ b/libavcodec/ac3dec.c
> @@ -1419,6 +1419,13 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
>                              (const uint16_t *) buf, cnt);
>      } else
>          memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
> +
> +    /* if consistent noise generation is enabled, seed the linear feedback generator
> +     * with the contents of the AC-3 frame so that the noise is identical across
> +     * decodes given the same AC-3 frame data, for use with non-linear edititing software. */
> +    if (s->consistent_noise_generation)
> +        av_lfg_init_from_data(&s->dith_state, s->input_buffer, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
> +
>      buf = s->input_buffer;
>      /* initialize the GetBitContext with the start of valid AC-3 Frame */
>      if ((ret = init_get_bits8(&s->gbc, buf, buf_size)) < 0)
> diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
> index c2b867e..98184e9 100644
> --- a/libavcodec/ac3dec.h
> +++ b/libavcodec/ac3dec.h
> @@ -177,6 +177,10 @@ typedef struct AC3DecodeContext {
>      int end_freq[AC3_MAX_CHANNELS];         ///< end frequency bin                      (endmant)
>  ///@}
>  
> +///@name Consistent noise generation
> +    int consistent_noise_generation;        ///< seed noise generation with AC-3 frame on decode
> +///@}
> +
>  ///@name Rematrixing
>      int num_rematrixing_bands;              ///< number of rematrixing bands            (nrematbnd)
>      int rematrixing_flags[4];               ///< rematrixing flags                      (rematflg)
> diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c
> index 6416da4..1f79ade 100644
> --- a/libavcodec/ac3dec_fixed.c
> +++ b/libavcodec/ac3dec_fixed.c
> @@ -168,6 +168,7 @@ static void ac3_downmix_c_fixed16(int16_t **samples, int16_t (*matrix)[2],
>  #include "ac3dec.c"
>  
>  static const AVOption options[] = {
> +    { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR },
>      { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
>      { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR },
>      { NULL},
> diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c
> index 0a5319a..b85a4ce 100644
> --- a/libavcodec/ac3dec_float.c
> +++ b/libavcodec/ac3dec_float.c
> @@ -32,6 +32,7 @@
>  #include "ac3dec.c"
>  
>  static const AVOption options[] = {
> +    { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR },
>      { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
>      { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR },
>      { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR },

Bump libavcodec micro version by 1 in its own patch as Michael requested.

> diff --git a/libavutil/lfg.c b/libavutil/lfg.c
> index 08a4f67..178d27e 100644
> --- a/libavutil/lfg.c
> +++ b/libavutil/lfg.c
> @@ -23,6 +23,7 @@
>  #include <limits.h>
>  #include <math.h>
>  #include "lfg.h"
> +#include "crc.h"
>  #include "md5.h"
>  #include "intreadwrite.h"
>  #include "attributes.h"
> @@ -58,3 +59,29 @@ void av_bmg_get(AVLFG *lfg, double out[2])
>      out[0] = x1 * w;
>      out[1] = x2 * w;
>  }
> +
> +void av_lfg_init_from_data(AVLFG *c, const unsigned char *data, unsigned int length) {

Don't return void if one of the arguments can be invalid. The user needs to know
if init failed in some way. Return int.
Also, crc (and every other hash function) expect const uint8_t*, so use that for data.

> +    unsigned int beg, end, segm;
> +    const AVCRC *avcrc;
> +    uint32_t crc = 1;
> +
> +    c->index = 0;
> +
> +    avcrc = av_crc_get_table(AV_CRC_32_IEEE);

This can't fail. It's a well defined table in crc.c, so just remove the check below.

> +    if (avcrc == NULL) return;
> +
> +    /* try to avoid integer overflow during the segmented crc loop below.
> +     * the code below would break if "end" went backwards before "beg". */
> +    if (length > (UINT_MAX / 128U)) return;

return AVERROR(EINVAL).

> +
> +    /* across 64 pieces of the incoming data,
> +     * do a running crc of each segment and store the crc as the state for that slot.
> +     * this works even if the length of the piece is 0 bytes. */
> +    beg = 0;
> +    for (segm = 0;segm < 64;segm++) {
> +        end = (((segm + 1) * length) / 64);
> +        crc = av_crc(avcrc, crc, data + beg, end - beg);
> +        c->state[segm] = (unsigned int)crc;
> +        beg = end;
> +    }

return 0 on success, of course.

> +}
> diff --git a/libavutil/lfg.h b/libavutil/lfg.h
> index ec90562..f3c08ec 100644
> --- a/libavutil/lfg.h
> +++ b/libavutil/lfg.h
> @@ -29,6 +29,11 @@ typedef struct AVLFG {
>  
>  void av_lfg_init(AVLFG *c, unsigned int seed);
>  
> +/*
> + * Seed the state of the ALFG using binary data
> + */

Make sure to mention possible return values are 0 on success, negative value on
failure after the above changes.

> +void av_lfg_init_from_data(AVLFG *c, const unsigned char *data, unsigned int length);
> +
>  /**
>   * Get the next random unsigned 32-bit number using an ALFG.
>   *

You should add a line in doc/APIChanges about the new function, and bump
minor version for libavutil as Michael requested.



More information about the ffmpeg-devel mailing list