From 2161858088032660d82942781beae84d6a69df19 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 2 Dec 2017 12:58:50 +0400 Subject: [PATCH] Fail resampling audio with inconsistent frames. --- .../media/media_audio_ffmpeg_loader.cpp | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/Telegram/SourceFiles/media/media_audio_ffmpeg_loader.cpp b/Telegram/SourceFiles/media/media_audio_ffmpeg_loader.cpp index b33a8baa92..038e385c20 100644 --- a/Telegram/SourceFiles/media/media_audio_ffmpeg_loader.cpp +++ b/Telegram/SourceFiles/media/media_audio_ffmpeg_loader.cpp @@ -20,10 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "media/media_audio_ffmpeg_loader.h" -extern "C" { -#include -} - 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)));