From 7f71ef378405e3366944dcc264bb415b92c91138 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 18 Dec 2016 12:12:42 +0300 Subject: [PATCH] Fixed bug in ffmpeg animation reader. --- .../SourceFiles/media/media_clip_ffmpeg.cpp | 22 ++++++++++++++----- .../SourceFiles/media/media_clip_ffmpeg.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp index bd3abc4e0..cec2dff1e 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp @@ -27,6 +27,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Media { namespace Clip { namespace internal { +namespace { + +constexpr int kSkipInvalidDataPackets = 10; + +} // namespace FFMpegReaderImplementation::FFMpegReaderImplementation(FileLocation *location, QByteArray *data, uint64 playId) : ReaderImplementation(location, data) , _playId(playId) { @@ -54,6 +59,10 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() { if (_mode == Mode::Normal) { return ReadResult::EndOfFile; } + if (!_hadFrame) { + LOG(("Gif Error: Got EOF before a single frame was read!")); + return ReadResult::Error; + } if ((res = avformat_seek_file(_fmtContext, _streamId, std::numeric_limits::min(), 0, std::numeric_limits::max(), 0)) < 0) { if ((res = av_seek_frame(_fmtContext, _streamId, 0, AVSEEK_FLAG_BYTE)) < 0) { @@ -70,11 +79,12 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() { _hadFrame = false; _frameMs = 0; _lastReadVideoMs = _lastReadAudioMs = 0; + _skippedInvalidDataPackets = 0; continue; } else if (res != AVERROR(EAGAIN)) { char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; - LOG(("Audio Error: Unable to avcodec_receive_frame() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + LOG(("Gif Error: Unable to avcodec_receive_frame() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return ReadResult::Error; } @@ -100,9 +110,11 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() { finishPacket(); char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; - LOG(("Audio Error: Unable to avcodec_send_packet() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + LOG(("Gif Error: Unable to avcodec_send_packet() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); if (res == AVERROR_INVALIDDATA) { - continue; // try to skip bad packet + if (++_skippedInvalidDataPackets < kSkipInvalidDataPackets) { + continue; // try to skip bad packet + } } return ReadResult::Error; } @@ -319,11 +331,11 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) { _codecContext = avcodec_alloc_context3(nullptr); if (!_codecContext) { - LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData())); + LOG(("Gif Error: Unable to avcodec_alloc_context3 %1").arg(logData())); return false; } if ((res = avcodec_parameters_to_context(_codecContext, _fmtContext->streams[_streamId]->codecpar)) < 0) { - LOG(("Audio Error: Unable to avcodec_parameters_to_context %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + LOG(("Gif Error: Unable to avcodec_parameters_to_context %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } av_codec_set_pkt_timebase(_codecContext, _fmtContext->streams[_streamId]->time_base); diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.h b/Telegram/SourceFiles/media/media_clip_ffmpeg.h index 2810e7e7f..3860c766d 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.h +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.h @@ -103,6 +103,7 @@ private: bool _opened = false; bool _hadFrame = false; bool _frameRead = false; + int _skippedInvalidDataPackets = 0; int _audioStreamId = -1; uint64 _playId = 0;