5#include "private/qplatformaudiooutput_p.h"
11#include <qvideosink.h>
12#include <QtMultimedia/qplaybackoptions.h>
14#include <QtConcurrent/QtConcurrent>
16#include <qloggingcategory.h>
28 void cancel() { m_cancelled.store(
true, std::memory_order_release); }
31 std::atomic_bool m_cancelled =
false;
39 : QPlatformMediaPlayer(player)
41 m_positionUpdateTimer.setInterval(50);
42 m_positionUpdateTimer.setTimerType(Qt::PreciseTimer);
43 connect(&m_positionUpdateTimer, &QTimer::timeout,
this, &QFFmpegMediaPlayer::updatePosition);
49 m_cancelToken->cancel();
51 m_loadMedia.waitForFinished();
56 return m_playbackEngine ? toUserDuration(m_playbackEngine->duration()).get() : 0;
61 if (mediaStatus() == QMediaPlayer::LoadingMedia)
64 if (m_playbackEngine) {
65 m_playbackEngine->seek(toTrackPosition(UserTrackPosition(position)));
69 mediaStatusChanged(QMediaPlayer::LoadedMedia);
74 positionChanged(m_playbackEngine ? toUserPosition(m_playbackEngine->currentPosition()).get()
81 m_positionUpdateTimer.stop();
82 QPointer currentPlaybackEngine(m_playbackEngine.get());
83 positionChanged(duration());
87 if (currentPlaybackEngine)
88 stateChanged(QMediaPlayer::StoppedState);
89 if (currentPlaybackEngine)
90 mediaStatusChanged(QMediaPlayer::EndOfMedia);
100 positionChanged(duration());
102 m_positionUpdateTimer.stop();
103 m_positionUpdateTimer.start();
108 if (mediaStatus() == QMediaPlayer::BufferingMedia)
109 mediaStatusChanged(QMediaPlayer::BufferedMedia);
114 return m_bufferProgress;
119 if (mediaStatus() == status)
122 const auto newBufferProgress = status == QMediaPlayer::BufferingMedia ? 0.25f
123 : status == QMediaPlayer::BufferedMedia ? 1.f
126 if (!qFuzzyCompare(newBufferProgress, m_bufferProgress)) {
127 m_bufferProgress = newBufferProgress;
128 bufferProgressChanged(newBufferProgress);
131 QPlatformMediaPlayer::mediaStatusChanged(status);
141 return m_playbackRate;
146 const float effectiveRate =
std::max(
static_cast<
float>(rate), 0.0f);
148 if (qFuzzyCompare(m_playbackRate, effectiveRate))
151 m_playbackRate = effectiveRate;
153 if (m_playbackEngine)
154 m_playbackEngine->setPlaybackRate(effectiveRate);
156 playbackRateChanged(effectiveRate);
171 seekableChanged(
false);
172 audioAvailableChanged(
false);
173 videoAvailableChanged(
false);
175 mediaStatusChanged(status);
176 m_playbackEngine =
nullptr;
183 m_cancelToken->cancel();
185 m_loadMedia.waitForFinished();
189 m_playbackEngine =
nullptr;
191 if (media.isEmpty() && !stream) {
192 handleIncorrectMedia(QMediaPlayer::NoMedia);
196 mediaStatusChanged(QMediaPlayer::LoadingMedia);
198 m_requestedStatus = QMediaPlayer::StoppedState;
200 m_cancelToken = std::make_shared<CancelToken>();
203 m_loadMedia = QtConcurrent::run([
this, media, stream, cancelToken = m_cancelToken] {
205 const MediaDataHolder::Maybe mediaHolder =
206 MediaDataHolder::create(media, stream, playbackOptions(), cancelToken);
210 QMetaObject::invokeMethod(
this, [
this, mediaHolder, cancelToken] {
211 setMediaAsync(mediaHolder, cancelToken);
216void QFFmpegMediaPlayer::setMediaAsync(QFFmpeg::MediaDataHolder::Maybe mediaDataHolder,
225 if (cancelToken->isCancelled()) {
229 Q_ASSERT(mediaStatus() == QMediaPlayer::LoadingMedia);
231 if (!mediaDataHolder) {
232 const auto [code, description] = mediaDataHolder.error();
233 error(code, description);
234 handleIncorrectMedia(QMediaPlayer::MediaStatus::InvalidMedia);
238 m_playbackEngine = std::make_unique<PlaybackEngine>(playbackOptions());
240 connect(m_playbackEngine.get(), &PlaybackEngine::endOfStream,
this,
241 &QFFmpegMediaPlayer::endOfStream);
242 connect(m_playbackEngine.get(), &PlaybackEngine::errorOccured,
this,
243 &QFFmpegMediaPlayer::error);
244 connect(m_playbackEngine.get(), &PlaybackEngine::loopChanged,
this,
245 &QFFmpegMediaPlayer::onLoopChanged);
246 connect(m_playbackEngine.get(), &PlaybackEngine::buffered,
this,
247 &QFFmpegMediaPlayer::onBuffered);
249 m_playbackEngine->setMedia(std::move(*mediaDataHolder.value()));
251 m_playbackEngine->setAudioBufferOutput(m_audioBufferOutput);
252 m_playbackEngine->setAudioSink(m_audioOutput);
253 m_playbackEngine->setVideoSink(m_videoSink);
255 m_playbackEngine->setLoops(loops());
256 m_playbackEngine->setPlaybackRate(m_playbackRate);
257 m_playbackEngine->setPitchCompensation(m_pitchCompensation);
259 durationChanged(duration());
262 seekableChanged(m_playbackEngine->isSeekable());
264 audioAvailableChanged(
265 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::AudioStream).isEmpty());
266 videoAvailableChanged(
267 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::VideoStream).isEmpty());
269 mediaStatusChanged(QMediaPlayer::LoadedMedia);
271 if (m_requestedStatus != QMediaPlayer::StoppedState) {
272 if (m_requestedStatus == QMediaPlayer::PlayingState)
274 else if (m_requestedStatus == QMediaPlayer::PausedState)
281 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
282 m_requestedStatus = QMediaPlayer::PlayingState;
286 if (!m_playbackEngine)
289 if (mediaStatus() == QMediaPlayer::EndOfMedia && state() == QMediaPlayer::StoppedState) {
290 m_playbackEngine->seek(TrackPosition(0));
299 m_playbackEngine->play();
300 m_positionUpdateTimer.start();
301 stateChanged(QMediaPlayer::PlayingState);
303 if (mediaStatus() == QMediaPlayer::LoadedMedia || mediaStatus() == QMediaPlayer::EndOfMedia)
304 mediaStatusChanged(QMediaPlayer::BufferingMedia);
309 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
310 m_requestedStatus = QMediaPlayer::PausedState;
314 if (!m_playbackEngine)
317 if (mediaStatus() == QMediaPlayer::EndOfMedia && state() == QMediaPlayer::StoppedState) {
318 m_playbackEngine->seek(TrackPosition(0));
321 m_playbackEngine->pause();
322 m_positionUpdateTimer.stop();
323 stateChanged(QMediaPlayer::PausedState);
325 if (mediaStatus() == QMediaPlayer::LoadedMedia || mediaStatus() == QMediaPlayer::EndOfMedia)
326 mediaStatusChanged(QMediaPlayer::BufferingMedia);
331 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
332 m_requestedStatus = QMediaPlayer::StoppedState;
336 if (!m_playbackEngine)
339 m_playbackEngine->stop();
340 m_positionUpdateTimer.stop();
341 m_playbackEngine->seek(TrackPosition(0));
343 stateChanged(QMediaPlayer::StoppedState);
344 mediaStatusChanged(QMediaPlayer::LoadedMedia);
349 m_audioOutput = output;
350 if (m_playbackEngine)
351 m_playbackEngine->setAudioSink(output);
355 m_audioBufferOutput = output;
356 if (m_playbackEngine)
357 m_playbackEngine->setAudioBufferOutput(output);
362 return m_playbackEngine ? m_playbackEngine->metaData() : QMediaMetaData{};
368 if (m_playbackEngine)
369 m_playbackEngine->setVideoSink(sink);
379 return m_playbackEngine ? m_playbackEngine->streamInfo(type).count() : 0;
384 if (!m_playbackEngine || streamNumber < 0
385 || streamNumber >= m_playbackEngine->streamInfo(type).count())
387 return m_playbackEngine->streamInfo(type).at(streamNumber).metaData;
392 return m_playbackEngine ? m_playbackEngine->activeTrack(type) : -1;
397 if (m_playbackEngine)
398 m_playbackEngine->setActiveTrack(type, streamNumber);
400 qWarning() <<
"Cannot set active track without open source";
405 if (m_playbackEngine)
406 m_playbackEngine->setLoops(loops);
408 QPlatformMediaPlayer::setLoops(loops);
413 if (enabled == m_pitchCompensation)
416 m_pitchCompensation = enabled;
417 if (m_playbackEngine)
418 m_playbackEngine->setPitchCompensation(enabled);
419 QPlatformMediaPlayer::pitchCompensationChanged(enabled);
424 return m_pitchCompensation;
430 return PitchCompensationAvailability::Available;
435#include "moc_qffmpegmediaplayer_p.cpp"
bool isCancelled() const override
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType