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 e1b032cbad
which I
assume is obsolete after 7 years.
Fixes #380
This commit is contained in:
parent
bd115a4008
commit
6c602811df
1
NEWS
1
NEWS
|
@ -1,6 +1,7 @@
|
||||||
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,28 +556,23 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
||||||
|
|
||||||
avcodec_parameters_to_context(codec_context, av_stream.codecpar);
|
avcodec_parameters_to_context(codec_context, av_stream.codecpar);
|
||||||
|
|
||||||
const SampleFormat sample_format =
|
|
||||||
ffmpeg_sample_format(GetSampleFormat(codec_params));
|
|
||||||
if (sample_format == SampleFormat::UNDEFINED) {
|
|
||||||
// (error message already done by ffmpeg_sample_format())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto audio_format = CheckAudioFormat(codec_params.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);
|
const int open_result = avcodec_open2(codec_context, codec, nullptr);
|
||||||
if (open_result < 0) {
|
if (open_result < 0) {
|
||||||
LogError(ffmpeg_domain, "Could not open codec");
|
LogError(ffmpeg_domain, "Could not open codec");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SampleFormat sample_format =
|
||||||
|
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_context->sample_rate,
|
||||||
|
sample_format,
|
||||||
|
codec_context->channels);
|
||||||
|
|
||||||
const SignedSongTime total_time =
|
const SignedSongTime total_time =
|
||||||
av_stream.duration != (int64_t)AV_NOPTS_VALUE
|
av_stream.duration != (int64_t)AV_NOPTS_VALUE
|
||||||
? FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base)
|
? FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base)
|
||||||
|
|
Loading…
Reference in New Issue