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

Jonathan Campbell jonathan at impactstudiopro.com
Sun Sep 4 01:45:17 EEST 2016


On 09/03/2016 07:07 AM, James Almer wrote:
> On 9/3/2016 7:50 AM, Jonathan Campbell wrote:
>> +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length) {
>> +    unsigned int beg, end, segm;
>> +    const AVCRC *avcrc;
>> +    uint32_t crc = 1;
>> +
>> +    c->index = 0;
> 
> The AVLFG struct should IMO remain untouched if init is guaranteed to fail,
> as it would be the case with an out or range length value, so move this after
> that check.
> 
>> +    avcrc = av_crc_get_table(AV_CRC_32_IEEE); /* This can't fail. It's a well-defined table in crc.c */
> 
> You could also move this one below.
> 
>> +
>> +    /* avoid integer overflow in the loop below. */
>> +    if (length > (UINT_MAX / 128U)) return AVERROR(EINVAL);
>> +
>> +    /* across 64 segments 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 segment 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);
> 
> The thing about speed made me wonder, wouldn't using adler32 be faster?
> If so, this feature could maybe even be enabled by default with it.
> 
>> +        c->state[segm] = (unsigned int)crc;
>> +        beg = end;
>> +    }
>> +
>> +    return 0;
>> +}
>> diff --git a/libavutil/lfg.h b/libavutil/lfg.h
>> index ec90562..72eb673 100644
>> --- a/libavutil/lfg.h
>> +++ b/libavutil/lfg.h
>> @@ -22,6 +22,8 @@
>>  #ifndef AVUTIL_LFG_H
>>  #define AVUTIL_LFG_H
>>  
>> +#include <stdint.h> /* uint8_t type */
>> +
>>  typedef struct AVLFG {
>>      unsigned int state[64];
>>      int index;
>> @@ -29,6 +31,13 @@ typedef struct AVLFG {
>>  
>>  void av_lfg_init(AVLFG *c, unsigned int seed);
>>  
>> +/*
> 
> This is meant for doxygen, so /** like in every other function.
> 
>> + * Seed the state of the ALFG using binary data.
>> + *
>> + * Return value: 0 on success, negative value (AVERROR) on failure.
>> + */
>> +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length);
>> +
>>  /**
>>   * Get the next random unsigned 32-bit number using an ALFG.
>>   *
> 
> No more comments for me.
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
Here you go.

Jonathan Campbell
-------------- next part --------------
From 5de30d309fb48b26acd8d95f14ef4d4064450ddc Mon Sep 17 00:00:00 2001
From: Jonathan Campbell <jonathan at castus.tv>
Date: Sat, 3 Sep 2016 03:20:41 -0700
Subject: [PATCH 1/4] libavutil version bump, av_lfg_init_from_data() incoming

---
 libavutil/version.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavutil/version.h b/libavutil/version.h
index 7d32c7b..60b58eb 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  55
-#define LIBAVUTIL_VERSION_MINOR  29
+#define LIBAVUTIL_VERSION_MINOR  30
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
2.2.2

-------------- next part --------------
From 3cc9a0e4a8bae127ca9254f31cd8b7f00d107395 Mon Sep 17 00:00:00 2001
From: Jonathan Campbell <jonathan at castus.tv>
Date: Sat, 3 Sep 2016 03:29:29 -0700
Subject: [PATCH 2/4] libavutil av_lfg_init_from_data() function

seeds an AVLFG from binary data.
---
 libavutil/lfg.c | 27 +++++++++++++++++++++++++++
 libavutil/lfg.h |  9 +++++++++
 2 files changed, 36 insertions(+)

diff --git a/libavutil/lfg.c b/libavutil/lfg.c
index 08a4f67..0ef456a 100644
--- a/libavutil/lfg.c
+++ b/libavutil/lfg.c
@@ -23,7 +23,9 @@
 #include <limits.h>
 #include <math.h>
 #include "lfg.h"
+#include "crc.h"
 #include "md5.h"
+#include "error.h"
 #include "intreadwrite.h"
 #include "attributes.h"
 
@@ -58,3 +60,28 @@ void av_bmg_get(AVLFG *lfg, double out[2])
     out[0] = x1 * w;
     out[1] = x2 * w;
 }
+
+int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length) {
+    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 */
+
+    /* avoid integer overflow in the loop below. */
+    if (length > (UINT_MAX / 128U)) return AVERROR(EINVAL);
+
+    /* across 64 segments 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 segment 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;
+}
diff --git a/libavutil/lfg.h b/libavutil/lfg.h
index ec90562..72eb673 100644
--- a/libavutil/lfg.h
+++ b/libavutil/lfg.h
@@ -22,6 +22,8 @@
 #ifndef AVUTIL_LFG_H
 #define AVUTIL_LFG_H
 
+#include <stdint.h> /* uint8_t type */
+
 typedef struct AVLFG {
     unsigned int state[64];
     int index;
@@ -29,6 +31,13 @@ typedef struct AVLFG {
 
 void av_lfg_init(AVLFG *c, unsigned int seed);
 
+/*
+ * Seed the state of the ALFG using binary data.
+ *
+ * Return value: 0 on success, negative value (AVERROR) on failure.
+ */
+int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length);
+
 /**
  * Get the next random unsigned 32-bit number using an ALFG.
  *
-- 
2.2.2

-------------- next part --------------
From eb8b354c5edf9c876f3e4a209ec617500776fcf2 Mon Sep 17 00:00:00 2001
From: Jonathan Campbell <jonathan at castus.tv>
Date: Sat, 3 Sep 2016 03:34:01 -0700
Subject: [PATCH 3/4] ac3dec consistent noise generation option.

use av_lfg_init_from_data() to seed AC-3 dithering from the AC-3 frame
data to make it consistent given the same AC-3 frame, if option is set.
---
 libavcodec/ac3dec.c       | 7 +++++++
 libavcodec/ac3dec.h       | 4 ++++
 libavcodec/ac3dec_fixed.c | 1 +
 libavcodec/ac3dec_float.c | 1 +
 4 files changed, 13 insertions(+)

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 },
-- 
2.2.2

-------------- next part --------------
From 0ea7866d26746ce50ce7fe98fea3b82d1052b5a8 Mon Sep 17 00:00:00 2001
From: Jonathan Campbell <jonathan at castus.tv>
Date: Sat, 3 Sep 2016 15:35:48 -0700
Subject: [PATCH 4/4] don't modify AVLFG state until committed to carrying out
 the init.

---
 libavutil/lfg.c | 6 +++---
 libavutil/lfg.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libavutil/lfg.c b/libavutil/lfg.c
index 0ef456a..46b04d2 100644
--- a/libavutil/lfg.c
+++ b/libavutil/lfg.c
@@ -66,12 +66,12 @@ int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length) {
     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 */
-
     /* avoid integer overflow in the loop below. */
     if (length > (UINT_MAX / 128U)) return AVERROR(EINVAL);
 
+    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 */
+
     /* across 64 segments 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 segment is 0 bytes. */
diff --git a/libavutil/lfg.h b/libavutil/lfg.h
index 72eb673..1eaa7ba 100644
--- a/libavutil/lfg.h
+++ b/libavutil/lfg.h
@@ -22,7 +22,7 @@
 #ifndef AVUTIL_LFG_H
 #define AVUTIL_LFG_H
 
-#include <stdint.h> /* uint8_t type */
+#include <stdint.h>
 
 typedef struct AVLFG {
     unsigned int state[64];
-- 
2.2.2



More information about the ffmpeg-devel mailing list