16 m_absSeekPos(absSeekPos),
19 qCDebug(qLcStreamDecoder) <<
"Create stream decoder, trackType" << m_trackType
20 <<
"absSeekPos:" << absSeekPos;
26 avcodec_flush_buffers(m_codec.
context());
36 m_packets.enqueue(packet);
43 auto packet = m_packets.dequeue();
45 auto decodePacket = [
this](
Packet packet) {
47 decodeSubtitle(packet);
52 if (packet.isValid() && packet.loopOffset().index != m_offset.
index) {
55 qCDebug(qLcStreamDecoder) <<
"flush buffers due to new loop:" << packet.loopOffset().index;
57 avcodec_flush_buffers(m_codec.
context());
58 m_offset = packet.loopOffset();
78 if (
frame.sourceId() !=
id())
81 --m_pendingFramesCount;
89 constexpr qint32 maxPendingFramesCount = 3;
90 constexpr qint32 maxPendingAudioFramesCount = 9;
93 ? maxPendingAudioFramesCount
95 ? maxPendingFramesCount * 2
96 : maxPendingFramesCount;
98 return !m_packets.empty() && m_pendingFramesCount <
maxCount
104 if (
frame.isValid() &&
frame.absoluteEnd() < m_absSeekPos)
107 Q_ASSERT(m_pendingFramesCount >= 0);
108 ++m_pendingFramesCount;
112void StreamDecoder::decodeMedia(Packet packet)
114 auto sendPacketResult = sendAVPacket(packet);
116 if (sendPacketResult == AVERROR(EAGAIN)) {
123 sendPacketResult = sendAVPacket(packet);
125 if (sendPacketResult != AVERROR(EAGAIN))
126 qWarning() <<
"Unexpected ffmpeg behavior";
129 if (sendPacketResult == 0)
133int StreamDecoder::sendAVPacket(Packet packet)
135 return avcodec_send_packet(m_codec.
context(), packet.isValid() ? packet.avPacket() :
nullptr);
138void StreamDecoder::receiveAVFrames()
143 const auto receiveFrameResult = avcodec_receive_frame(m_codec.
context(), avFrame.get());
145 if (receiveFrameResult == AVERROR_EOF || receiveFrameResult == AVERROR(EAGAIN))
148 if (receiveFrameResult < 0) {
153 onFrameFound({ m_offset, std::move(avFrame), m_codec, 0,
id() });
157void StreamDecoder::decodeSubtitle(Packet packet)
159 if (!packet.isValid())
164 memset(&subtitle, 0,
sizeof(subtitle));
168 avcodec_decode_subtitle2(m_codec.
context(), &subtitle, &gotSubtitle, packet.avPacket());
171 if (
res < 0 || !gotSubtitle)
177 if (subtitle.pts == AV_NOPTS_VALUE) {
178 start = m_codec.
toUs(packet.avPacket()->pts);
179 end =
start + m_codec.
toUs(packet.avPacket()->duration);
181 auto pts =
timeStampUs(subtitle.pts, AVRational{ 1, AV_TIME_BASE });
182 start = *pts +
qint64(subtitle.start_display_time) * 1000;
183 end = *pts +
qint64(subtitle.end_display_time) * 1000;
187 qWarning() <<
"Invalid subtitle time";
192 for (
uint i = 0;
i < subtitle.num_rects; ++
i) {
193 const auto *
r = subtitle.rects[
i];
200 const char *ass =
r->ass;
227#include "moc_qffmpegstreamdecoder_p.cpp"
AVCodecContext * context() const
qint64 toUs(qint64 ts) const
virtual bool canDoNextStep() const
void error(int code, const QString &errorString)
void setAtEnd(bool isAtEnd)
void scheduleNextStep(bool allowDoImmediatelly=true)
StreamDecoder(const Codec &codec, qint64 absSeekPos)
bool canDoNextStep() const override
void doNextStep() override
void onFrameProcessed(Frame frame)
void packetProcessed(Packet)
void onFinalPacketReceived()
void requestHandleFrame(Frame frame)
QPlatformMediaPlayer::TrackType trackType() const
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString & replace(qsizetype i, qsizetype len, QChar after)
void chop(qsizetype n)
Removes n characters from the end of the string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
AVFrameUPtr makeAVFrame()
QString err2str(int errnum)
std::optional< qint64 > timeStampUs(qint64 ts, AVRational base)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
QLatin1StringView QLatin1String
\inmodule QtCore \reentrant