diff options
author | Max Kellermann <max@musicpd.org> | 2018-11-04 22:30:50 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2018-11-04 22:30:50 +0100 |
commit | 6c602811df5f765cfc9ee92bf8cf97fca96b47d7 (patch) | |
tree | 873908ae58374d035b518284bf3491e0ce970609 | |
parent | bd115a40081ec6527e1e13231caec23f36768d73 (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-- | NEWS | 1 | ||||
-rw-r--r-- | src/decoder/plugins/FfmpegDecoderPlugin.cxx | 23 |
2 files changed, 10 insertions, 14 deletions
@@ -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 |