Fail resampling audio with inconsistent frames.

This commit is contained in:
John Preston 2017-12-02 12:58:50 +04:00
parent 001be82566
commit 2161858088
1 changed files with 41 additions and 15 deletions

View File

@ -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)));