aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx56
2 files changed, 58 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 78403121e..f26a818d1 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ ver 0.20 (not yet released)
- report song duration with milliseconds precision
* tags
- ape: drop support for non-standard tag "album artist"
+* decoder
+ - ffmpeg: support ReplayGain
* output
- pulse: set channel map to WAVE-EX
* mixer
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 7adbb5899..9010b7402 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -26,6 +26,8 @@
#include "../DecoderAPI.hxx"
#include "FfmpegMetaData.hxx"
#include "tag/TagHandler.hxx"
+#include "tag/ReplayGain.hxx"
+#include "tag/MixRamp.hxx"
#include "input/InputStream.hxx"
#include "CheckAudioFormat.hxx"
#include "util/Error.hxx"
@@ -438,6 +440,58 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
}
static void
+FfmpegParseMetaData(AVDictionary &dict, ReplayGainInfo &rg, MixRampInfo &mr)
+{
+ AVDictionaryEntry *i = nullptr;
+
+ while ((i = av_dict_get(&dict, "", i,
+ AV_DICT_IGNORE_SUFFIX)) != nullptr) {
+ const char *name = i->key;
+ const char *value = i->value;
+
+ if (!ParseReplayGainTag(rg, name, value))
+ ParseMixRampTag(mr, name, value);
+ }
+}
+
+static void
+FfmpegParseMetaData(const AVStream &stream,
+ ReplayGainInfo &rg, MixRampInfo &mr)
+{
+ FfmpegParseMetaData(*stream.metadata, rg, mr);
+}
+
+static void
+FfmpegParseMetaData(const AVFormatContext &format_context, int audio_stream,
+ ReplayGainInfo &rg, MixRampInfo &mr)
+{
+ FfmpegParseMetaData(*format_context.metadata, rg, mr);
+
+ if (audio_stream >= 0)
+ FfmpegParseMetaData(*format_context.streams[audio_stream],
+ rg, mr);
+}
+
+static void
+FfmpegParseMetaData(Decoder &decoder,
+ const AVFormatContext &format_context, int audio_stream)
+{
+ ReplayGainInfo rg;
+ rg.Clear();
+
+ MixRampInfo mr;
+ mr.Clear();
+
+ FfmpegParseMetaData(format_context, audio_stream, rg, mr);
+
+ if (rg.IsDefined())
+ decoder_replay_gain(decoder, &rg);
+
+ if (mr.IsDefined())
+ decoder_mixramp(decoder, std::move(mr));
+}
+
+static void
ffmpeg_decode(Decoder &decoder, InputStream &input)
{
AVInputFormat *input_format = ffmpeg_probe(&decoder, input);
@@ -541,6 +595,8 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
decoder_initialized(decoder, audio_format,
input.IsSeekable(), total_time);
+ FfmpegParseMetaData(decoder, *format_context, audio_stream);
+
#if LIBAVUTIL_VERSION_MAJOR >= 53
AVFrame *frame = av_frame_alloc();
#else