af_volume: support using replaygain frame side data
authorAnton Khirnov <anton@khirnov.net>
Wed, 19 Feb 2014 20:01:37 +0000 (21:01 +0100)
committerAnton Khirnov <anton@khirnov.net>
Mon, 24 Mar 2014 05:07:51 +0000 (06:07 +0100)
doc/filters.texi
libavfilter/af_volume.c
libavfilter/af_volume.h

index 8d46cd1fb4ced37f77f1a91f4d8c9b166084b046..93625c6c80e1e39660436ce7ab975241cd986f27 100644 (file)
@@ -616,6 +616,23 @@ precision of the volume scaling.
 @item double
 64-bit floating-point; limits input sample format to DBL.
 @end table
+
+@item replaygain
+Behaviour on encountering ReplayGain side data in input frames.
+
+@table @option
+@item drop
+Remove ReplayGain side data, ignoring its contents (the default).
+
+@item ignore
+Ignore ReplayGain side data, but leave it in the frame.
+
+@item track
+Prefer track gain, if present.
+
+@item album
+Prefer album gain, if present.
+@end table
 @end table
 
 @subsection Examples
index 59223e548be31e6cf5a41d474a8c871b88354aa0..165624e9dfd4544924c08dbe9695b5f5dcb8e72a 100644 (file)
 #include "libavutil/common.h"
 #include "libavutil/eval.h"
 #include "libavutil/float_dsp.h"
+#include "libavutil/intreadwrite.h"
 #include "libavutil/opt.h"
+#include "libavutil/replaygain.h"
+
 #include "audio.h"
 #include "avfilter.h"
 #include "formats.h"
@@ -50,6 +53,12 @@ static const AVOption options[] = {
         { "fixed",  "8-bit fixed-point.",     0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FIXED  }, INT_MIN, INT_MAX, A, "precision" },
         { "float",  "32-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FLOAT  }, INT_MIN, INT_MAX, A, "precision" },
         { "double", "64-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_DOUBLE }, INT_MIN, INT_MAX, A, "precision" },
+    { "replaygain", "Apply replaygain side data when present",
+            OFFSET(replaygain), AV_OPT_TYPE_INT, { .i64 = REPLAYGAIN_DROP }, REPLAYGAIN_DROP, REPLAYGAIN_ALBUM, A, "replaygain" },
+        { "drop",   "replaygain side data is dropped", 0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_DROP   }, 0, 0, A, "replaygain" },
+        { "ignore", "replaygain side data is ignored", 0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_IGNORE }, 0, 0, A, "replaygain" },
+        { "track",  "track gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_TRACK  }, 0, 0, A, "replaygain" },
+        { "album",  "album gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_ALBUM  }, 0, 0, A, "replaygain" },
     { NULL },
 };
 
@@ -229,8 +238,38 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     AVFilterLink *outlink = inlink->dst->outputs[0];
     int nb_samples        = buf->nb_samples;
     AVFrame *out_buf;
+    AVFrameSideData *sd = av_frame_get_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
     int ret;
 
+    if (sd && vol->replaygain != REPLAYGAIN_IGNORE) {
+        if (vol->replaygain != REPLAYGAIN_DROP) {
+            AVReplayGain *replaygain = (AVReplayGain*)sd->data;
+            int32_t gain;
+            float g;
+
+            if (vol->replaygain == REPLAYGAIN_TRACK &&
+                replaygain->track_gain != INT32_MIN)
+                gain = replaygain->track_gain;
+            else if (replaygain->album_gain != INT32_MIN)
+                gain = replaygain->album_gain;
+            else {
+                av_log(inlink->dst, AV_LOG_WARNING, "Both ReplayGain gain "
+                       "values are unknown.\n");
+                gain = 100000;
+            }
+            g = gain / 100000.0f;
+
+            av_log(inlink->dst, AV_LOG_VERBOSE,
+                   "Using gain %f dB from replaygain side data.\n", g);
+
+            vol->volume   = pow(10, g / 20);
+            vol->volume_i = (int)(vol->volume * 256 + 0.5);
+
+            volume_init(vol);
+        }
+        av_frame_remove_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
+    }
+
     if (vol->volume == 1.0 || vol->volume_i == 256)
         return ff_filter_frame(outlink, buf);
 
index a1883ed2b990550fece51c800064162bd916bbd0..ec13e80ae32d222c8fe2793d6a9b96c5373b0830 100644 (file)
@@ -35,10 +35,18 @@ enum PrecisionType {
     PRECISION_DOUBLE,
 };
 
+enum ReplayGainType {
+    REPLAYGAIN_DROP,
+    REPLAYGAIN_IGNORE,
+    REPLAYGAIN_TRACK,
+    REPLAYGAIN_ALBUM,
+};
+
 typedef struct VolumeContext {
     const AVClass *class;
     AVFloatDSPContext fdsp;
     enum PrecisionType precision;
+    enum ReplayGainType replaygain;
     double volume;
     int    volume_i;
     int    channels;