[v7,6/7] af_volume: implement replaygain clipping prevention

Message ID 1396794308-5489-1-git-send-email-alessandro@ghedini.me
State New
Headers show

Commit Message

Alessandro Ghedini April 6, 2014, 2:25 p.m.
This adds a new "replaygain_noclip" option to the filter, and, if enabled,
limits the gain applied for tracks where clipping would occur.
---
Restored the fallback mechanism, if track gain is selected but undefined.

 doc/filters.texi        |  5 +++++
 libavfilter/af_volume.c | 25 ++++++++++++++++++-------
 libavfilter/af_volume.h |  1 +
 3 files changed, 24 insertions(+), 7 deletions(-)

Comments

Alessandro Ghedini April 12, 2014, 4:31 p.m. | #1
On dom, apr 06, 2014 at 04:25:08 +0200, Alessandro Ghedini wrote:
> This adds a new "replaygain_noclip" option to the filter, and, if enabled,
> limits the gain applied for tracks where clipping would occur.
> ---
> Restored the fallback mechanism, if track gain is selected but undefined.
> 
>  doc/filters.texi        |  5 +++++
>  libavfilter/af_volume.c | 25 ++++++++++++++++++-------
>  libavfilter/af_volume.h |  1 +
>  3 files changed, 24 insertions(+), 7 deletions(-)
> 
> diff --git a/doc/filters.texi b/doc/filters.texi
> index f986623..1ed57dd 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -639,6 +639,11 @@ Pre-amplification gain in dB to apply to the selected replaygain gain.
>  
>  Default value for @var{replaygain_preamp} is 0.0.
>  
> +@item replaygain_noclip
> +Prevent clipping by limiting the gain applied.
> +
> +Default value for @var{replaygain_noclip} is 1.
> +
>  @end table
>  
>  @subsection Examples
> diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
> index 823fa15..81fb281 100644
> --- a/libavfilter/af_volume.c
> +++ b/libavfilter/af_volume.c
> @@ -61,6 +61,8 @@ static const AVOption options[] = {
>          { "album",  "album gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_ALBUM  }, 0, 0, A, "replaygain" },
>      { "replaygain_preamp", "Apply replaygain pre-amplification",
>              OFFSET(replaygain_preamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, -15.0, 15.0, A },
> +    { "replaygain_noclip", "Apply replaygain clipping prevention",
> +            OFFSET(replaygain_noclip), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, A },
>      { NULL },
>  };
>  
> @@ -246,25 +248,34 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
>      if (sd && vol->replaygain != REPLAYGAIN_IGNORE) {
>          if (vol->replaygain != REPLAYGAIN_DROP) {
>              AVReplayGain *replaygain = (AVReplayGain*)sd->data;
> -            int32_t gain;
> -            float g;
> +            int32_t gain  = 100000;
> +            uint32_t peak = 100000;
> +            float g, p;
>  
> -            if (vol->replaygain == REPLAYGAIN_TRACK &&
> -                replaygain->track_gain != INT32_MIN)
> +            if ((vol->replaygain == REPLAYGAIN_TRACK) &&
> +                (replaygain->track_gain != INT32_MIN)) {
>                  gain = replaygain->track_gain;
> -            else if (replaygain->album_gain != INT32_MIN)
> +
> +                if (replaygain->track_peak != 0)
> +                    peak = replaygain->track_peak;
> +            } else if (replaygain->album_gain != INT32_MIN) {
>                  gain = replaygain->album_gain;
> -            else {
> +
> +                if (replaygain->album_peak != 0)
> +                    peak = replaygain->album_peak;
> +            } else {
>                  av_log(inlink->dst, AV_LOG_WARNING, "Both ReplayGain gain "
>                         "values are unknown.\n");
> -                gain = 100000;
>              }
>              g = gain / 100000.0f;
> +            p = peak / 100000.0f;
>  
>              av_log(inlink->dst, AV_LOG_VERBOSE,
>                     "Using gain %f dB from replaygain side data.\n", g);
>  
>              vol->volume   = pow(10, (g + vol->replaygain_preamp) / 20);
> +            if (vol->replaygain_noclip)
> +                vol->volume = FFMIN(vol->volume, 1.0 / p);
>              vol->volume_i = (int)(vol->volume * 256 + 0.5);
>  
>              volume_init(vol);
> diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h
> index d831ec4..6bd89ac 100644
> --- a/libavfilter/af_volume.h
> +++ b/libavfilter/af_volume.h
> @@ -48,6 +48,7 @@ typedef struct VolumeContext {
>      enum PrecisionType precision;
>      enum ReplayGainType replaygain;
>      double replaygain_preamp;
> +    int    replaygain_noclip;
>      double volume;
>      int    volume_i;
>      int    channels;
> -- 
> 1.9.1

Ping?
Justin Ruggles April 12, 2014, 5:21 p.m. | #2
On 04/06/2014 10:25 AM, Alessandro Ghedini wrote:
> -            if (vol->replaygain == REPLAYGAIN_TRACK &&
> -                replaygain->track_gain != INT32_MIN)
> +            if ((vol->replaygain == REPLAYGAIN_TRACK) &&
> +                (replaygain->track_gain != INT32_MIN)) {
>                  gain = replaygain->track_gain;

Unnecessary extra parentheses.

Otherwise LGTM.

-Justin
Anton Khirnov April 13, 2014, 9:26 a.m. | #3
On Sun,  6 Apr 2014 16:25:08 +0200, Alessandro Ghedini <alessandro@ghedini.me> wrote:
> This adds a new "replaygain_noclip" option to the filter, and, if enabled,
> limits the gain applied for tracks where clipping would occur.
> ---
> Restored the fallback mechanism, if track gain is selected but undefined.
> 

Pushed.
Thanks

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index f986623..1ed57dd 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -639,6 +639,11 @@  Pre-amplification gain in dB to apply to the selected replaygain gain.
 
 Default value for @var{replaygain_preamp} is 0.0.
 
+@item replaygain_noclip
+Prevent clipping by limiting the gain applied.
+
+Default value for @var{replaygain_noclip} is 1.
+
 @end table
 
 @subsection Examples
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index 823fa15..81fb281 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -61,6 +61,8 @@  static const AVOption options[] = {
         { "album",  "album gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_ALBUM  }, 0, 0, A, "replaygain" },
     { "replaygain_preamp", "Apply replaygain pre-amplification",
             OFFSET(replaygain_preamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, -15.0, 15.0, A },
+    { "replaygain_noclip", "Apply replaygain clipping prevention",
+            OFFSET(replaygain_noclip), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, A },
     { NULL },
 };
 
@@ -246,25 +248,34 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     if (sd && vol->replaygain != REPLAYGAIN_IGNORE) {
         if (vol->replaygain != REPLAYGAIN_DROP) {
             AVReplayGain *replaygain = (AVReplayGain*)sd->data;
-            int32_t gain;
-            float g;
+            int32_t gain  = 100000;
+            uint32_t peak = 100000;
+            float g, p;
 
-            if (vol->replaygain == REPLAYGAIN_TRACK &&
-                replaygain->track_gain != INT32_MIN)
+            if ((vol->replaygain == REPLAYGAIN_TRACK) &&
+                (replaygain->track_gain != INT32_MIN)) {
                 gain = replaygain->track_gain;
-            else if (replaygain->album_gain != INT32_MIN)
+
+                if (replaygain->track_peak != 0)
+                    peak = replaygain->track_peak;
+            } else if (replaygain->album_gain != INT32_MIN) {
                 gain = replaygain->album_gain;
-            else {
+
+                if (replaygain->album_peak != 0)
+                    peak = replaygain->album_peak;
+            } else {
                 av_log(inlink->dst, AV_LOG_WARNING, "Both ReplayGain gain "
                        "values are unknown.\n");
-                gain = 100000;
             }
             g = gain / 100000.0f;
+            p = peak / 100000.0f;
 
             av_log(inlink->dst, AV_LOG_VERBOSE,
                    "Using gain %f dB from replaygain side data.\n", g);
 
             vol->volume   = pow(10, (g + vol->replaygain_preamp) / 20);
+            if (vol->replaygain_noclip)
+                vol->volume = FFMIN(vol->volume, 1.0 / p);
             vol->volume_i = (int)(vol->volume * 256 + 0.5);
 
             volume_init(vol);
diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h
index d831ec4..6bd89ac 100644
--- a/libavfilter/af_volume.h
+++ b/libavfilter/af_volume.h
@@ -48,6 +48,7 @@  typedef struct VolumeContext {
     enum PrecisionType precision;
     enum ReplayGainType replaygain;
     double replaygain_preamp;
+    int    replaygain_noclip;
     double volume;
     int    volume_i;
     int    channels;