30 const AVPacket &avPacket = *packet.avPacket();
31 const AVStream &avStream = *context->streams[avPacket.stream_index];
32 const AVStreamDuration streamDuration(avStream.duration);
33 if (streamDuration.get() <= 0
34 || context->duration_estimation_method != AVFMT_DURATION_FROM_STREAM)
37 if (avPacket.pts == AV_NOPTS_VALUE) {
38 qWarning() <<
"QFFmpeg::Demuxer received AVPacket with pts == AV_NOPTS_VALUE";
42 if (avStream.start_time != AV_NOPTS_VALUE)
43 return AVStreamDuration(avPacket.pts - avStream.start_time) <= streamDuration;
45 const TrackPosition trackPos = toTrackPosition(AVStreamPosition(avPacket.pts), &avStream, context);
46 const TrackPosition trackPosOfStreamEnd = toTrackDuration(streamDuration, &avStream).asTimePoint();
47 return trackPos <= trackPosOfStreamEnd;
53Demuxer::Demuxer(
const PlaybackEngineObjectID &id, AVFormatContext *context,
54 TrackPosition initialPosUs,
bool seekPending,
const LoopOffset &loopOffset,
55 const StreamIndexes &streamIndexes,
int loops)
56 : PlaybackEngineObject(id),
59 && initialPosUs == TrackPosition{ 0 }),
60 m_posInLoopUs{ initialPosUs },
61 m_loopOffset(loopOffset),
64 qCDebug(qLcDemuxer) <<
"Create demuxer."
65 <<
"pos:" << m_posInLoopUs.get()
66 <<
"loop offset:" << m_loopOffset.loopStartTimeUs.get()
67 <<
"loop index:" << m_loopOffset.loopIndex <<
"loops:" << loops;
71 for (
auto i = 0; i < QPlatformMediaPlayer::NTrackTypes; ++i) {
72 if (streamIndexes[i] >= 0) {
73 const auto trackType =
static_cast<QPlatformMediaPlayer::TrackType>(i);
74 qCDebug(qLcDemuxer) <<
"Activate demuxing stream" << i <<
", trackType:" << trackType;
75 m_streams[streamIndexes[i]] = { trackType };
84 Packet packet(m_loopOffset, AVPacketUPtr{ av_packet_alloc() }, id());
85 AVPacket &avPacket = *packet.avPacket();
87 const int demuxStatus = av_read_frame(m_context, &avPacket);
88 if (demuxStatus == AVERROR_EXIT)
91 const int streamIndex = avPacket.stream_index;
92 auto streamIterator = m_streams.find(streamIndex);
93 const bool streamIsRelevant = streamIterator != m_streams.end();
95 if (demuxStatus == AVERROR_EOF
96 || (streamIsRelevant && !isPacketWithinStreamDuration(m_context, packet))) {
97 ++m_loopOffset.loopIndex;
99 const auto loops = m_loops.loadAcquire();
100 if (loops >= 0 && m_loopOffset.loopIndex >= loops) {
101 qCDebug(qLcDemuxer) <<
"finish demuxing";
103 if (!std::exchange(m_buffered,
true))
104 emit packetsBuffered();
110 m_posInLoopUs = TrackPosition(0);
111 m_loopOffset.loopStartTimeUs = m_maxPacketsEndPos;
112 m_maxPacketsEndPos = TrackPosition(0);
116 qCDebug(qLcDemuxer) <<
"Demuxer loops changed. Index:" << m_loopOffset.loopIndex
117 <<
"Offset:" << m_loopOffset.loopStartTimeUs.get();
125 if (demuxStatus < 0) {
126 qCWarning(qLcDemuxer) <<
"Demuxing failed" << demuxStatus << AVError(demuxStatus);
128 if (demuxStatus == AVERROR(EAGAIN) && m_demuxerRetryCount != s_maxDemuxerRetries) {
134 m_failTimePoint = std::chrono::steady_clock::now();
135 ++m_demuxerRetryCount;
137 qCDebug(qLcDemuxer) <<
"Retrying";
144 emit error(QMediaPlayer::ResourceError,
145 QLatin1StringView(
"Demuxing failed"));
151 m_demuxerRetryCount = 0;
152 m_failTimePoint.reset();
154 if (streamIsRelevant) {
155 auto &streamData = streamIterator->second;
156 const AVStream *stream = m_context->streams[streamIndex];
158 const TrackPosition endPos = packetEndPos(packet, stream, m_context);
159 m_maxPacketsEndPos = qMax(m_maxPacketsEndPos, endPos);
163 streamData.bufferedDuration += toTrackDuration(AVStreamDuration(avPacket.duration), stream);
164 streamData.bufferedSize += avPacket.size;
165 streamData.maxSentPacketsPos = qMax(streamData.maxSentPacketsPos, endPos);
166 updateStreamDataLimitFlag(streamData);
168 if (!m_buffered && streamData.isDataLimitReached) {
170 emit packetsBuffered();
173 if (!m_firstPacketFound) {
174 m_firstPacketFound =
true;
175 emit firstPacketFound(id(), m_posInLoopUs + m_loopOffset.loopStartTimeUs.asDuration());
178 auto signal = signalByTrackType(streamData.trackType);
179 emit (
this->*signal)(
std::move(packet));
187 Q_ASSERT(packet.isValid());
189 if (!checkID(packet.sourceID()))
192 auto &avPacket = *packet.avPacket();
194 const auto streamIndex = avPacket.stream_index;
195 const auto stream = m_context->streams[streamIndex];
196 auto it = m_streams.find(streamIndex);
198 if (it != m_streams.end()) {
199 auto &streamData = it->second;
203 streamData.bufferedDuration -= toTrackDuration(AVStreamDuration(avPacket.duration), stream);
204 streamData.bufferedSize -= avPacket.size;
205 streamData.maxProcessedPacketPos =
206 qMax(streamData.maxProcessedPacketPos, packetEndPos(packet, stream, m_context));
208 Q_ASSERT(it->second.bufferedDuration >= TrackDuration(0));
209 Q_ASSERT(it->second.bufferedSize >= 0);
211 updateStreamDataLimitFlag(streamData);
259 auto err = av_seek_frame(m_context, -1, seekPos.get(), AVSEEK_FLAG_BACKWARD);
278 case QPlatformMediaPlayer::TrackType::VideoStream:
279 return &Demuxer::requestProcessVideoPacket;
280 case QPlatformMediaPlayer::TrackType::AudioStream:
281 return &Demuxer::requestProcessAudioPacket;
282 case QPlatformMediaPlayer::TrackType::SubtitleStream:
283 return &Demuxer::requestProcessSubtitlePacket;
285 Q_ASSERT(!
"Unknown track type");