4#include "playbackengine/qffmpegstreamdecoder_p.h"
5#include "playbackengine/qffmpegmediadataholder_p.h"
6#include <qloggingcategory.h>
14StreamDecoder::StreamDecoder(
const CodecContext &codecContext, TrackPosition absSeekPos)
15 : m_codecContext(codecContext),
16 m_absSeekPos(absSeekPos),
17 m_trackType(MediaDataHolder::trackTypeFromMediaType(codecContext.context()->codec_type))
19 qCDebug(qLcStreamDecoder) <<
"Create stream decoder, trackType" << m_trackType
20 <<
"absSeekPos:" << absSeekPos.get();
21 Q_ASSERT(m_trackType != QPlatformMediaPlayer::NTrackTypes);
26 avcodec_flush_buffers(m_codecContext.context());
36 m_packets.enqueue(packet);
43 auto packet = m_packets.dequeue();
45 auto decodePacket = [
this](Packet packet) {
46 if (trackType() == QPlatformMediaPlayer::SubtitleStream)
47 decodeSubtitle(packet);
52 if (packet.isValid() && packet.loopOffset().loopIndex != m_offset.loopIndex) {
55 qCDebug(qLcStreamDecoder) <<
"flush buffers due to new loop:"
56 << packet.loopOffset().loopIndex;
58 avcodec_flush_buffers(m_codecContext.context());
59 m_offset = packet.loopOffset();
64 setAtEnd(!packet.isValid());
67 emit packetProcessed(packet);
69 scheduleNextStep(
false);
94 if (frame.sourceId() != id())
97 --m_pendingFramesCount;
98 Q_ASSERT(m_pendingFramesCount >= 0);
105 const qint32 maxCount = maxQueueSize(m_trackType);
107 return !m_packets.empty() && m_pendingFramesCount < maxCount
108 && PlaybackEngineObject::canDoNextStep();
113 if (frame.isValid() && frame.absoluteEnd() < m_absSeekPos)
116 Q_ASSERT(m_pendingFramesCount >= 0);
117 ++m_pendingFramesCount;
118 emit requestHandleFrame(frame);
123 auto sendPacketResult = sendAVPacket(packet);
125 if (sendPacketResult == AVERROR(EAGAIN)) {
132 sendPacketResult = sendAVPacket(packet);
134 if (sendPacketResult != AVERROR(EAGAIN))
135 qWarning() <<
"Unexpected FFmpeg behavior";
138 if (sendPacketResult == 0)
139 receiveAVFrames(!packet.isValid());
144 return avcodec_send_packet(m_codecContext.context(), packet.isValid() ? packet.avPacket() :
nullptr);
150 auto avFrame = makeAVFrame();
152 const auto receiveFrameResult = avcodec_receive_frame(m_codecContext.context(), avFrame.get());
154 if (receiveFrameResult == AVERROR_EOF || receiveFrameResult == AVERROR(EAGAIN)) {
155 if (flushPacket && receiveFrameResult == AVERROR(EAGAIN)) {
163 qWarning() <<
"Unexpected FFmpeg behavior: EAGAIN state for avcodec_receive_frame "
164 <<
"at end of the stream";
171 if (receiveFrameResult < 0) {
172 emit error(QMediaPlayer::FormatError, err2str(receiveFrameResult));
178 if (m_trackType == QPlatformMediaPlayer::VideoStream)
179 avFrame = copyFromHwPool(
std::move(avFrame));
181 onFrameFound({ m_offset, std::move(avFrame), m_codecContext, id() });
187 if (!packet.isValid())
192 memset(&subtitle, 0,
sizeof(subtitle));
196 avcodec_decode_subtitle2(m_codecContext.context(), &subtitle, &gotSubtitle, packet.avPacket());
199 if (res < 0 || !gotSubtitle)
204 TrackPosition start = 0, end = 0;
205 if (subtitle.pts == AV_NOPTS_VALUE) {
206 start = m_codecContext.toTrackPosition(AVStreamPosition(packet.avPacket()->pts));
207 end = start + m_codecContext.toTrackDuration(AVStreamDuration(packet.avPacket()->duration));
209 auto pts = timeStampUs(subtitle.pts, AVRational{ 1, AV_TIME_BASE });
210 start = TrackPosition(*pts + qint64(subtitle.start_display_time) * 1000);
211 end = TrackPosition(*pts + qint64(subtitle.end_display_time) * 1000);
215 qWarning() <<
"Invalid subtitle time";
220 for (uint i = 0; i < subtitle.num_rects; ++i) {
221 const auto *r = subtitle.rects[i];
224 text += QLatin1Char(
'\n');
226 text += QString::fromUtf8(r->text);
228 const char *ass = r->ass;
237 text += QString::fromUtf8(ass);
240 text.replace(QLatin1String(
"\\N"), QLatin1String(
"\n"));
241 text.replace(QLatin1String(
"\\n"), QLatin1String(
"\n"));
242 text.replace(QLatin1String(
"\r\n"), QLatin1String(
"\n"));
243 if (text.endsWith(QLatin1Char(
'\n')))
246 onFrameFound({ m_offset, text, start, end - start, id() });
249 onFrameFound({ m_offset, QString(), end, TrackDuration(0), id() });
255#include "moc_qffmpegstreamdecoder_p.cpp"
bool canDoNextStep() const override
~StreamDecoder() override
void doNextStep() override
void onFrameProcessed(Frame frame)
void onFinalPacketReceived()
QPlatformMediaPlayer::TrackType trackType() const
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)