Commit 6c602811 authored by Max Kellermann's avatar Max Kellermann

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 e1b032cb which I assume is obsolete after 7 years. Fixes #380
parent bd115a40
ver 0.21.2 (not yet released) ver 0.21.2 (not yet released)
* decoder * decoder
- ffmpeg: require FFmpeg 3.1 or later - ffmpeg: require FFmpeg 3.1 or later
- ffmpeg: fix broken sound with certain codecs
ver 0.21.1 (2018/11/04) ver 0.21.1 (2018/11/04)
* protocol * protocol
......
...@@ -556,27 +556,22 @@ FfmpegDecode(DecoderClient &client, InputStream &input, ...@@ -556,27 +556,22 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
avcodec_parameters_to_context(codec_context, av_stream.codecpar); 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 = const SampleFormat sample_format =
ffmpeg_sample_format(GetSampleFormat(codec_params)); ffmpeg_sample_format(codec_context->sample_fmt);
if (sample_format == SampleFormat::UNDEFINED) { if (sample_format == SampleFormat::UNDEFINED) {
// (error message already done by ffmpeg_sample_format()) // (error message already done by ffmpeg_sample_format())
return; return;
} }
const auto audio_format = CheckAudioFormat(codec_params.sample_rate, const auto audio_format = CheckAudioFormat(codec_context->sample_rate,
sample_format, sample_format,
codec_params.channels); codec_context->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;
}
const SignedSongTime total_time = const SignedSongTime total_time =
av_stream.duration != (int64_t)AV_NOPTS_VALUE av_stream.duration != (int64_t)AV_NOPTS_VALUE
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment