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_demuxerBuffered =
false;
66 m_playbackEngine->seek(toTrackPosition(UserTrackPosition(position)));
70 mediaStatusChanged(QMediaPlayer::LoadedMedia);
75 positionChanged(m_playbackEngine ? toUserPosition(m_playbackEngine->currentPosition()).get()
82 m_positionUpdateTimer.stop();
83 QPointer currentPlaybackEngine(m_playbackEngine.get());
84 positionChanged(duration());
88 if (currentPlaybackEngine)
89 stateChanged(QMediaPlayer::StoppedState);
90 if (currentPlaybackEngine)
91 mediaStatusChanged(QMediaPlayer::EndOfMedia);
101 positionChanged(duration());
103 m_positionUpdateTimer.stop();
104 m_positionUpdateTimer.start();
109 m_demuxerBuffered =
true;
110 if (mediaStatus() == QMediaPlayer::BufferingMedia)
111 mediaStatusChanged(QMediaPlayer::BufferedMedia);
116 return m_bufferProgress;
121 if (mediaStatus() == status)
124 const auto newBufferProgress = status == QMediaPlayer::BufferingMedia ? 0.25f
125 : status == QMediaPlayer::BufferedMedia ? 1.f
128 if (!QtPrivate::fuzzyCompare(newBufferProgress, m_bufferProgress)) {
129 m_bufferProgress = newBufferProgress;
130 bufferProgressChanged(newBufferProgress);
133 QPlatformMediaPlayer::mediaStatusChanged(status);
143 return m_playbackRate;
148 const float effectiveRate =
std::max(
static_cast<
float>(rate), 0.0f);
150 if (QtPrivate::fuzzyCompare(m_playbackRate, effectiveRate))
153 m_playbackRate = effectiveRate;
155 if (m_playbackEngine)
156 m_playbackEngine->setPlaybackRate(effectiveRate);
158 playbackRateChanged(effectiveRate);
173 seekableChanged(
false);
174 audioAvailableChanged(
false);
175 videoAvailableChanged(
false);
177 mediaStatusChanged(status);
178 m_playbackEngine =
nullptr;
185 m_cancelToken->cancel();
187 m_loadMedia.waitForFinished();
191 m_playbackEngine =
nullptr;
192 m_demuxerBuffered =
false;
194 if (media.isEmpty() && !stream) {
195 handleIncorrectMedia(QMediaPlayer::NoMedia);
199 mediaStatusChanged(QMediaPlayer::LoadingMedia);
201 m_requestedStatus = QMediaPlayer::StoppedState;
203 m_cancelToken = std::make_shared<CancelToken>();
206 m_loadMedia = QtConcurrent::run([
this, media, stream, cancelToken = m_cancelToken] {
208 const MediaDataHolder::Maybe mediaHolder =
209 MediaDataHolder::create(media, stream, playbackOptions(), cancelToken);
213 QMetaObject::invokeMethod(
this, [
this, mediaHolder, cancelToken] {
214 setMediaAsync(mediaHolder, cancelToken);
219void QFFmpegMediaPlayer::setMediaAsync(QFFmpeg::MediaDataHolder::Maybe mediaDataHolder,
228 if (cancelToken->isCancelled()) {
232 Q_ASSERT(mediaStatus() == QMediaPlayer::LoadingMedia);
234 if (!mediaDataHolder) {
235 const auto [code, description] = mediaDataHolder.error();
236 error(code, description);
237 handleIncorrectMedia(QMediaPlayer::MediaStatus::InvalidMedia);
241 m_playbackEngine = std::make_unique<PlaybackEngine>(playbackOptions());
243 connect(m_playbackEngine.get(), &PlaybackEngine::endOfStream,
this,
245 connect(m_playbackEngine.get(), &PlaybackEngine::errorOccured,
this,
246 &QFFmpegMediaPlayer::error);
247 connect(m_playbackEngine.get(), &PlaybackEngine
::loopChanged,
this,
249 connect(m_playbackEngine.get(), &PlaybackEngine
::buffered,
this,
252 m_playbackEngine->setMedia(std::move(*mediaDataHolder.value()));
254 m_playbackEngine->setAudioBufferOutput(m_audioBufferOutput);
255 m_playbackEngine->setAudioSink(m_audioOutput);
256 m_playbackEngine->setVideoSink(m_videoSink);
258 m_playbackEngine->setLoops(loops());
259 m_playbackEngine->setPlaybackRate(m_playbackRate);
260 m_playbackEngine->setPitchCompensation(m_pitchCompensation);
262 durationChanged(duration());
265 seekableChanged(m_playbackEngine->isSeekable());
267 audioAvailableChanged(
268 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::AudioStream).isEmpty());
269 videoAvailableChanged(
270 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::VideoStream).isEmpty());
272 mediaStatusChanged(QMediaPlayer::LoadedMedia);
274 if (m_requestedStatus != QMediaPlayer::StoppedState) {
275 if (m_requestedStatus == QMediaPlayer::PlayingState)
277 else if (m_requestedStatus == QMediaPlayer::PausedState)
284 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
285 m_requestedStatus = QMediaPlayer::PlayingState;
289 if (!m_playbackEngine)
292 if (mediaStatus() == QMediaPlayer::EndOfMedia && state() == QMediaPlayer::StoppedState) {
293 m_playbackEngine->seek(TrackPosition(0));
302 m_playbackEngine->play();
303 m_positionUpdateTimer.start();
304 stateChanged(QMediaPlayer::PlayingState);
306 if (mediaStatus() == QMediaPlayer::LoadedMedia || mediaStatus() == QMediaPlayer::EndOfMedia) {
307 mediaStatusChanged(m_demuxerBuffered ? QMediaPlayer::BufferedMedia
308 : QMediaPlayer::BufferingMedia);
314 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
315 m_requestedStatus = QMediaPlayer::PausedState;
319 if (!m_playbackEngine)
322 if (mediaStatus() == QMediaPlayer::EndOfMedia && state() == QMediaPlayer::StoppedState) {
323 m_playbackEngine->seek(TrackPosition(0));
326 m_playbackEngine->pause();
327 m_positionUpdateTimer.stop();
328 stateChanged(QMediaPlayer::PausedState);
330 if (mediaStatus() == QMediaPlayer::LoadedMedia || mediaStatus() == QMediaPlayer::EndOfMedia) {
331 mediaStatusChanged(m_demuxerBuffered ? QMediaPlayer::BufferedMedia
332 : QMediaPlayer::BufferingMedia);
338 if (mediaStatus() == QMediaPlayer::LoadingMedia) {
339 m_requestedStatus = QMediaPlayer::StoppedState;
343 if (!m_playbackEngine)
346 m_demuxerBuffered =
false;
347 m_playbackEngine->stop();
348 m_positionUpdateTimer.stop();
349 m_playbackEngine->seek(TrackPosition(0));
351 stateChanged(QMediaPlayer::StoppedState);
352 mediaStatusChanged(QMediaPlayer::LoadedMedia);
357 m_audioOutput = output;
358 if (m_playbackEngine)
359 m_playbackEngine->setAudioSink(output);
363 m_audioBufferOutput = output;
364 if (m_playbackEngine)
365 m_playbackEngine->setAudioBufferOutput(output);
370 return m_playbackEngine ? m_playbackEngine->metaData() : QMediaMetaData{};
376 if (m_playbackEngine)
377 m_playbackEngine->setVideoSink(sink);
387 return m_playbackEngine ? m_playbackEngine->streamInfo(type).count() : 0;
392 if (!m_playbackEngine || streamNumber < 0
393 || streamNumber >= m_playbackEngine->streamInfo(type).count())
395 return m_playbackEngine->streamInfo(type).at(streamNumber).metaData;
400 return m_playbackEngine ? m_playbackEngine->activeTrack(type) : -1;
405 if (m_playbackEngine)
406 m_playbackEngine->setActiveTrack(type, streamNumber);
408 qWarning() <<
"Cannot set active track without open source";
413 if (m_playbackEngine)
414 m_playbackEngine->setLoops(loops);
416 QPlatformMediaPlayer::setLoops(loops);
421 if (enabled == m_pitchCompensation)
424 m_pitchCompensation = enabled;
425 if (m_playbackEngine)
426 m_playbackEngine->setPitchCompensation(enabled);
427 QPlatformMediaPlayer::pitchCompensationChanged(enabled);
432 return m_pitchCompensation;
438 return PitchCompensationAvailability::Available;
443#include "moc_qffmpegmediaplayer_p.cpp"
bool isCancelled() const override
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
Combined button and popup list for selecting options.