summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-11-04 22:30:50 +0100
committerMax Kellermann <max@musicpd.org>2018-11-04 22:30:50 +0100
commit6c602811df5f765cfc9ee92bf8cf97fca96b47d7 (patch)
tree873908ae58374d035b518284bf3491e0ce970609
parentbd115a40081ec6527e1e13231caec23f36768d73 (diff)
decoder/ffmepg: fill AudioFormat from AVCodecContext, not AVCodecParameters
`AVCodecParameters` contains values from the codec detected by avformat_find_stream_info(), but after avcodec_open2(), a different codec might be selected with a different `AVSampleFormat`. This leads to misinterpretation of data returned from FFmpeg, leading to random noise or silence. This was observed with FFmpeg 4.0.2 and a TS container file containing MP2. A mp3-float codec was detected returning `AV_SAMPLE_FMT_FLTP`, but finally the `mpegaudiodec_fixed.c` was used, returning `AV_SAMPLE_FMT_S16`. By using the audio format from `AVCodecContext`, we ensure that MPD and FFmpeg always agree on the actual audio format in the buffer. This removes the FFmpeg bug workaround from commit e1b032cbad5 which I assume is obsolete after 7 years. Fixes #380
-rw-r--r--NEWS1
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx23
2 files changed, 10 insertions, 14 deletions
diff --git a/NEWS b/NEWS
index 5eca473d4..f44fa5f23 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
ver 0.21.2 (not yet released)
* decoder
- ffmpeg: require FFmpeg 3.1 or later
+ - ffmpeg: fix broken sound with certain codecs
ver 0.21.1 (2018/11/04)
* protocol
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 0abd04841..2b9b39b52 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -556,27 +556,22 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
avcodec_parameters_to_context(codec_context, av_stream.codecpar);
+ const int open_result = avcodec_open2(codec_context, codec, nullptr);
+ if (open_result < 0) {
+ LogError(ffmpeg_domain, "Could not open codec");
+ return;
+ }
+
const SampleFormat sample_format =
- ffmpeg_sample_format(GetSampleFormat(codec_params));
+ ffmpeg_sample_format(codec_context->sample_fmt);
if (sample_format == SampleFormat::UNDEFINED) {
// (error message already done by ffmpeg_sample_format())
return;
}
- const auto audio_format = CheckAudioFormat(codec_params.sample_rate,
+ const auto audio_format = CheckAudioFormat(codec_context->sample_rate,
sample_format,
- codec_params.channels);
-
- /* the audio format must be read from AVCodecContext by now,
- because avcodec_open() has been demonstrated to fill bogus
- values into AVCodecContext.channels - a change that will be
- reverted later by avcodec_decode_audio3() */
-
- const int open_result = avcodec_open2(codec_context, codec, nullptr);
- if (open_result < 0) {
- LogError(ffmpeg_domain, "Could not open codec");
- return;
- }
+ codec_context->channels);
const SignedSongTime total_time =
av_stream.duration != (int64_t)AV_NOPTS_VALUE