1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "media/audio/media_child_ffmpeg_loader.h"
#include "core/crash_reports.h"
#include "core/file_location.h"
namespace Media {
ChildFFMpegLoader::ChildFFMpegLoader(
std::unique_ptr<ExternalSoundData> &&data)
: AbstractAudioFFMpegLoader(
Core::FileLocation(),
QByteArray(),
bytes::vector())
, _parentData(std::move(data)) {
Expects(_parentData->codec != nullptr);
}
bool ChildFFMpegLoader::open(crl::time positionMs) {
return initUsingContext(
_parentData->codec.get(),
_parentData->length,
_parentData->frequency);
}
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readFromInitialFrame() {
if (!_parentData->frame) {
return ReadError::Wait;
}
return replaceFrameAndRead(base::take(_parentData->frame));
}
auto ChildFFMpegLoader::readMore() -> ReadResult {
const auto initialFrameResult = readFromInitialFrame();
if (initialFrameResult != ReadError::Wait) {
return initialFrameResult;
}
const auto readResult = readFromReadyContext(
_parentData->codec.get());
if (readResult != ReadError::Wait) {
return readResult;
}
if (_queue.empty()) {
return _eofReached ? ReadError::EndOfFile : ReadError::Wait;
}
auto packet = std::move(_queue.front());
_queue.pop_front();
_eofReached = packet.empty();
if (_eofReached) {
avcodec_send_packet(_parentData->codec.get(), nullptr); // drain
return bytes::const_span();
}
auto res = avcodec_send_packet(
_parentData->codec.get(),
&packet.fields());
if (res < 0) {
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
LOG(("Audio Error: Unable to avcodec_send_packet() 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)));
// There is a sample voice message where skipping such packet
// results in a crash (read_access to nullptr) in swr_convert().
if (res == AVERROR_INVALIDDATA) {
return ReadError::NotYet; // try to skip bad packet
}
return ReadError::Other;
}
return bytes::const_span();
}
void ChildFFMpegLoader::enqueuePackets(
std::deque<FFmpeg::Packet> &&packets) {
if (_queue.empty()) {
_queue = std::move(packets);
} else {
_queue.insert(
end(_queue),
std::make_move_iterator(packets.begin()),
std::make_move_iterator(packets.end()));
}
packets.clear();
}
void ChildFFMpegLoader::setForceToBuffer(bool force) {
_forceToBuffer = force;
}
bool ChildFFMpegLoader::forceToBuffer() const {
return _forceToBuffer;
}
ChildFFMpegLoader::~ChildFFMpegLoader() = default;
} // namespace Media
|