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
|
/*
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 {
namespace {
using FFmpeg::AvErrorWrap;
} // namespace
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, float64 speed) {
const auto sample = (positionMs * samplesFrequency()) / 1000LL;
overrideDuration(sample, _parentData->duration);
return initUsingContext(_parentData->codec.get(), speed);
}
auto ChildFFMpegLoader::readFromInitialFrame() -> ReadResult {
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 ReadError::Retry;
}
AvErrorWrap error = avcodec_send_packet(
_parentData->codec.get(),
&packet.fields());
if (error) {
LogError(u"avcodec_send_packet"_q, error);
// There is a sample voice message where skipping such packet
// results in a crash (read_access to nullptr) in swr_convert().
if (error.code() == AVERROR_INVALIDDATA) {
return ReadError::Retry; // try to skip bad packet
}
return ReadError::Other;
}
return ReadError::Retry;
}
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
|