mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Fail resampling audio with inconsistent frames.
This commit is contained in:
parent
001be82566
commit
2161858088
@ -20,10 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "media/media_audio_ffmpeg_loader.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libswresample/swresample_internal.h>
|
||||
}
|
||||
|
||||
constexpr AVSampleFormat AudioToFormat = AV_SAMPLE_FMT_S16;
|
||||
constexpr int64_t AudioToChannelLayout = AV_CH_LAYOUT_STEREO;
|
||||
constexpr int32 AudioToChannels = 2;
|
||||
@ -212,11 +208,13 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||
|
||||
auto layout = codecParams->channel_layout;
|
||||
if (!layout) {
|
||||
auto channelsCount = codecParams->channels;
|
||||
switch (channelsCount) {
|
||||
switch (codecParams->channels) {
|
||||
case 1: layout = AV_CH_LAYOUT_MONO; break;
|
||||
case 2: layout = AV_CH_LAYOUT_STEREO; break;
|
||||
default: LOG(("Audio Error: Unknown channel layout for %1 channels.").arg(channelsCount)); break;
|
||||
default:
|
||||
LOG(("Audio Error: Unknown channel layout for %1 channels.").arg(codecParams->channels));
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
inputFormat = codecContext->sample_fmt;
|
||||
@ -245,6 +243,15 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||
sampleSize = -1; // convert needed
|
||||
break;
|
||||
}
|
||||
|
||||
if (av_popcount64(layout) != codecParams->channels) {
|
||||
LOG(("Audio Error: Bad channel layout %1 for %2 channels."
|
||||
).arg(codecParams->channel_layout
|
||||
).arg(codecParams->channels
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_samplesFrequency != 44100 && _samplesFrequency != 48000) {
|
||||
sampleSize = -1; // convert needed
|
||||
}
|
||||
@ -355,21 +362,40 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readFromReadyFrame(QByteArray &resul
|
||||
return ReadResult::Error;
|
||||
}
|
||||
}
|
||||
if (swrContext->in.ch_count == 2 && frame->extended_data[1] == nullptr) {
|
||||
|
||||
// There are crash reports of some files with swrContext->in.ch_count
|
||||
// equal to 2 and frame with only one channel data provided.
|
||||
// I'm not sure what to do with those files, could not get one for testing.
|
||||
// Currently just abort the reading because it crashes in swr_convert.
|
||||
//
|
||||
// Samples included:
|
||||
//
|
||||
// codecpar->channel_layout = 3
|
||||
// codecpar->channels = 1 (but it is 2 by the channel_layout!)
|
||||
// frame->channel_layout = 4
|
||||
// frame->channels = 1
|
||||
//
|
||||
// So it looks like codecpar->channel_layout was wrong and frame
|
||||
// really had only one channel, but swresample expected data for two channels.
|
||||
//
|
||||
// codecpar->channel_layout = 3
|
||||
// codecpar->channels = 2
|
||||
// frame->channel_layout = 4
|
||||
// frame->channels = 1
|
||||
//
|
||||
// So the frame just wasn't consistent with the codec params.
|
||||
if (fmtContext->streams[streamId]->codecpar->channels > 1
|
||||
&& frame->extended_data[1] == nullptr) {
|
||||
auto params = fmtContext->streams[streamId]->codecpar;
|
||||
SignalHandlers::setCrashAnnotation("MediaCrash",
|
||||
QString("layout:%1,channels:%2,rate:%3,format:%4,framelayout:%5,framechannels:%6,framerate:%7,stream:%8"
|
||||
LOG(("Audio Error: Inconsistent frame layout/channels in file, codec: (%1;%2), frame: (%3, %4)"
|
||||
).arg(params->channel_layout
|
||||
).arg(params->channels
|
||||
).arg(params->sample_rate
|
||||
).arg(codecContext->sample_fmt
|
||||
).arg(frame->channel_layout
|
||||
).arg(frame->channels
|
||||
).arg(frame->sample_rate
|
||||
).arg(streamId
|
||||
));
|
||||
Unexpected("Bad frame while reading audio!");
|
||||
return ReadResult::Error;
|
||||
}
|
||||
|
||||
if ((res = swr_convert(swrContext, dstSamplesData, dstSamples, (const uint8_t**)frame->extended_data, frame->nb_samples)) < 0) {
|
||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||
|
Loading…
Reference in New Issue
Block a user