Browse code

af_volume: support using replaygain frame side data

Anton Khirnov authored on 2014/02/20 05:01:37
Showing 3 changed files
... ...
@@ -616,6 +616,23 @@ precision of the volume scaling.
616 616
 @item double
617 617
 64-bit floating-point; limits input sample format to DBL.
618 618
 @end table
619
+
620
+@item replaygain
621
+Behaviour on encountering ReplayGain side data in input frames.
622
+
623
+@table @option
624
+@item drop
625
+Remove ReplayGain side data, ignoring its contents (the default).
626
+
627
+@item ignore
628
+Ignore ReplayGain side data, but leave it in the frame.
629
+
630
+@item track
631
+Prefer track gain, if present.
632
+
633
+@item album
634
+Prefer album gain, if present.
635
+@end table
619 636
 @end table
620 637
 
621 638
 @subsection Examples
... ...
@@ -28,7 +28,10 @@
28 28
 #include "libavutil/common.h"
29 29
 #include "libavutil/eval.h"
30 30
 #include "libavutil/float_dsp.h"
31
+#include "libavutil/intreadwrite.h"
31 32
 #include "libavutil/opt.h"
33
+#include "libavutil/replaygain.h"
34
+
32 35
 #include "audio.h"
33 36
 #include "avfilter.h"
34 37
 #include "formats.h"
... ...
@@ -50,6 +53,12 @@ static const AVOption options[] = {
50 50
         { "fixed",  "8-bit fixed-point.",     0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FIXED  }, INT_MIN, INT_MAX, A, "precision" },
51 51
         { "float",  "32-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FLOAT  }, INT_MIN, INT_MAX, A, "precision" },
52 52
         { "double", "64-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_DOUBLE }, INT_MIN, INT_MAX, A, "precision" },
53
+    { "replaygain", "Apply replaygain side data when present",
54
+            OFFSET(replaygain), AV_OPT_TYPE_INT, { .i64 = REPLAYGAIN_DROP }, REPLAYGAIN_DROP, REPLAYGAIN_ALBUM, A, "replaygain" },
55
+        { "drop",   "replaygain side data is dropped", 0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_DROP   }, 0, 0, A, "replaygain" },
56
+        { "ignore", "replaygain side data is ignored", 0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_IGNORE }, 0, 0, A, "replaygain" },
57
+        { "track",  "track gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_TRACK  }, 0, 0, A, "replaygain" },
58
+        { "album",  "album gain is preferred",         0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_ALBUM  }, 0, 0, A, "replaygain" },
53 59
     { NULL },
54 60
 };
55 61
 
... ...
@@ -229,8 +238,38 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
229 229
     AVFilterLink *outlink = inlink->dst->outputs[0];
230 230
     int nb_samples        = buf->nb_samples;
231 231
     AVFrame *out_buf;
232
+    AVFrameSideData *sd = av_frame_get_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
232 233
     int ret;
233 234
 
235
+    if (sd && vol->replaygain != REPLAYGAIN_IGNORE) {
236
+        if (vol->replaygain != REPLAYGAIN_DROP) {
237
+            AVReplayGain *replaygain = (AVReplayGain*)sd->data;
238
+            int32_t gain;
239
+            float g;
240
+
241
+            if (vol->replaygain == REPLAYGAIN_TRACK &&
242
+                replaygain->track_gain != INT32_MIN)
243
+                gain = replaygain->track_gain;
244
+            else if (replaygain->album_gain != INT32_MIN)
245
+                gain = replaygain->album_gain;
246
+            else {
247
+                av_log(inlink->dst, AV_LOG_WARNING, "Both ReplayGain gain "
248
+                       "values are unknown.\n");
249
+                gain = 100000;
250
+            }
251
+            g = gain / 100000.0f;
252
+
253
+            av_log(inlink->dst, AV_LOG_VERBOSE,
254
+                   "Using gain %f dB from replaygain side data.\n", g);
255
+
256
+            vol->volume   = pow(10, g / 20);
257
+            vol->volume_i = (int)(vol->volume * 256 + 0.5);
258
+
259
+            volume_init(vol);
260
+        }
261
+        av_frame_remove_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
262
+    }
263
+
234 264
     if (vol->volume == 1.0 || vol->volume_i == 256)
235 265
         return ff_filter_frame(outlink, buf);
236 266
 
... ...
@@ -35,10 +35,18 @@ enum PrecisionType {
35 35
     PRECISION_DOUBLE,
36 36
 };
37 37
 
38
+enum ReplayGainType {
39
+    REPLAYGAIN_DROP,
40
+    REPLAYGAIN_IGNORE,
41
+    REPLAYGAIN_TRACK,
42
+    REPLAYGAIN_ALBUM,
43
+};
44
+
38 45
 typedef struct VolumeContext {
39 46
     const AVClass *class;
40 47
     AVFloatDSPContext fdsp;
41 48
     enum PrecisionType precision;
49
+    enum ReplayGainType replaygain;
42 50
     double volume;
43 51
     int    volume_i;
44 52
     int    channels;