2016-07-05 17:44:02 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2016-07-05 17:44:02 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2016-07-05 17:44:02 +00:00
|
|
|
*/
|
2019-02-13 12:36:59 +00:00
|
|
|
#include "media/audio/media_child_ffmpeg_loader.h"
|
2016-07-05 17:44:02 +00:00
|
|
|
|
2017-12-12 12:03:51 +00:00
|
|
|
#include "core/crash_reports.h"
|
2020-10-13 16:43:18 +00:00
|
|
|
#include "core/file_location.h"
|
2017-12-12 12:03:51 +00:00
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
namespace Media {
|
2023-03-08 09:31:58 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
using FFmpeg::AvErrorWrap;
|
|
|
|
|
|
|
|
} // namespace
|
2017-12-12 12:03:51 +00:00
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
ChildFFMpegLoader::ChildFFMpegLoader(
|
|
|
|
std::unique_ptr<ExternalSoundData> &&data)
|
2018-01-02 17:22:13 +00:00
|
|
|
: AbstractAudioFFMpegLoader(
|
2020-10-13 16:43:18 +00:00
|
|
|
Core::FileLocation(),
|
2018-01-02 17:22:13 +00:00
|
|
|
QByteArray(),
|
2018-03-27 12:16:00 +00:00
|
|
|
bytes::vector())
|
2017-02-21 13:45:56 +00:00
|
|
|
, _parentData(std::move(data)) {
|
2019-02-28 21:03:25 +00:00
|
|
|
Expects(_parentData->codec != nullptr);
|
2016-07-05 17:44:02 +00:00
|
|
|
}
|
|
|
|
|
2023-03-08 09:31:58 +00:00
|
|
|
bool ChildFFMpegLoader::open(crl::time positionMs, float64 speed) {
|
|
|
|
const auto sample = (positionMs * samplesFrequency()) / 1000LL;
|
|
|
|
overrideDuration(sample, _parentData->duration);
|
|
|
|
return initUsingContext(_parentData->codec.get(), speed);
|
2016-07-05 17:44:02 +00:00
|
|
|
}
|
|
|
|
|
2023-03-08 09:31:58 +00:00
|
|
|
auto ChildFFMpegLoader::readFromInitialFrame() -> ReadResult {
|
2019-02-17 11:08:29 +00:00
|
|
|
if (!_parentData->frame) {
|
2023-03-06 09:51:37 +00:00
|
|
|
return ReadError::Wait;
|
2019-02-17 11:08:29 +00:00
|
|
|
}
|
2023-03-06 09:51:37 +00:00
|
|
|
return replaceFrameAndRead(base::take(_parentData->frame));
|
2019-02-17 11:08:29 +00:00
|
|
|
}
|
|
|
|
|
2023-03-06 09:51:37 +00:00
|
|
|
auto ChildFFMpegLoader::readMore() -> ReadResult {
|
2023-03-12 03:24:53 +00:00
|
|
|
if (_readTillEnd) {
|
|
|
|
return ReadError::EndOfFile;
|
|
|
|
}
|
2023-03-06 09:51:37 +00:00
|
|
|
const auto initialFrameResult = readFromInitialFrame();
|
|
|
|
if (initialFrameResult != ReadError::Wait) {
|
2019-02-17 11:08:29 +00:00
|
|
|
return initialFrameResult;
|
|
|
|
}
|
|
|
|
|
2018-01-02 17:22:13 +00:00
|
|
|
const auto readResult = readFromReadyContext(
|
2023-03-06 09:51:37 +00:00
|
|
|
_parentData->codec.get());
|
|
|
|
if (readResult != ReadError::Wait) {
|
2018-01-02 17:22:13 +00:00
|
|
|
return readResult;
|
2016-07-22 15:01:24 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
if (_queue.empty()) {
|
2023-03-12 03:24:53 +00:00
|
|
|
if (!_eofReached) {
|
|
|
|
return ReadError::Wait;
|
|
|
|
}
|
|
|
|
_readTillEnd = true;
|
|
|
|
return ReadError::EndOfFile;
|
2016-07-05 17:44:02 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
auto packet = std::move(_queue.front());
|
|
|
|
_queue.pop_front();
|
2016-07-19 16:02:39 +00:00
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
_eofReached = packet.empty();
|
2016-07-05 17:44:22 +00:00
|
|
|
if (_eofReached) {
|
2019-02-28 21:03:25 +00:00
|
|
|
avcodec_send_packet(_parentData->codec.get(), nullptr); // drain
|
2023-03-08 09:31:58 +00:00
|
|
|
return ReadError::Retry;
|
2016-07-05 17:44:22 +00:00
|
|
|
}
|
|
|
|
|
2023-03-08 09:31:58 +00:00
|
|
|
AvErrorWrap error = avcodec_send_packet(
|
2019-02-28 21:03:25 +00:00
|
|
|
_parentData->codec.get(),
|
|
|
|
&packet.fields());
|
2023-03-08 09:31:58 +00:00
|
|
|
if (error) {
|
|
|
|
LogError(u"avcodec_send_packet"_q, error);
|
2016-08-14 18:57:23 +00:00
|
|
|
// There is a sample voice message where skipping such packet
|
|
|
|
// results in a crash (read_access to nullptr) in swr_convert().
|
2023-03-08 09:31:58 +00:00
|
|
|
if (error.code() == AVERROR_INVALIDDATA) {
|
|
|
|
return ReadError::Retry; // try to skip bad packet
|
2017-05-26 14:18:58 +00:00
|
|
|
}
|
2023-03-06 09:51:37 +00:00
|
|
|
return ReadError::Other;
|
2016-07-05 17:44:02 +00:00
|
|
|
}
|
2023-03-08 09:31:58 +00:00
|
|
|
return ReadError::Retry;
|
2016-07-22 15:01:24 +00:00
|
|
|
}
|
2016-07-05 17:44:02 +00:00
|
|
|
|
2019-02-21 13:40:09 +00:00
|
|
|
void ChildFFMpegLoader::enqueuePackets(
|
2019-06-26 15:04:38 +00:00
|
|
|
std::deque<FFmpeg::Packet> &&packets) {
|
2019-02-21 13:40:09 +00:00
|
|
|
if (_queue.empty()) {
|
|
|
|
_queue = std::move(packets);
|
|
|
|
} else {
|
2019-02-28 21:03:25 +00:00
|
|
|
_queue.insert(
|
|
|
|
end(_queue),
|
|
|
|
std::make_move_iterator(packets.begin()),
|
|
|
|
std::make_move_iterator(packets.end()));
|
2019-02-21 13:40:09 +00:00
|
|
|
}
|
2016-07-05 17:44:02 +00:00
|
|
|
packets.clear();
|
|
|
|
}
|
|
|
|
|
2019-02-21 13:40:09 +00:00
|
|
|
void ChildFFMpegLoader::setForceToBuffer(bool force) {
|
|
|
|
_forceToBuffer = force;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ChildFFMpegLoader::forceToBuffer() const {
|
|
|
|
return _forceToBuffer;
|
|
|
|
}
|
|
|
|
|
2019-02-28 21:03:25 +00:00
|
|
|
ChildFFMpegLoader::~ChildFFMpegLoader() = default;
|
|
|
|
|
|
|
|
} // namespace Media
|