Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qffmpegmediaplayer.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "private/qplatformaudiooutput_p.h"
6#include "qvideosink.h"
7#include "qaudiooutput.h"
8
10#include <qiodevice.h>
11#include <qvideosink.h>
12#include <qtimer.h>
13
14#include <qloggingcategory.h>
15
17
18using namespace QFFmpeg;
19
22{
23 m_positionUpdateTimer.setInterval(50);
24 m_positionUpdateTimer.setTimerType(Qt::PreciseTimer);
25 connect(&m_positionUpdateTimer, &QTimer::timeout, this, &QFFmpegMediaPlayer::updatePosition);
26}
27
29
31{
32 return m_playbackEngine ? m_playbackEngine->duration() / 1000 : 0;
33}
34
36{
37 if (m_playbackEngine) {
38 m_playbackEngine->seek(position * 1000);
39 updatePosition();
40 }
43}
44
45void QFFmpegMediaPlayer::updatePosition()
46{
47 positionChanged(m_playbackEngine ? m_playbackEngine->currentPosition() / 1000 : 0);
48}
49
50void QFFmpegMediaPlayer::endOfStream()
51{
52 // start update timer and report end position anyway
53 m_positionUpdateTimer.stop();
55
58}
59
60void QFFmpegMediaPlayer::onLoopChanged()
61{
62 // report about finish and start
63 // reporting both signals is a bit contraversial
64 // but it eshures the idea of notifications about
65 // imporatant position points.
66 // Also, it ensures more predictable flow for testing.
69 m_positionUpdateTimer.stop();
70 m_positionUpdateTimer.start();
71}
72
74{
75 return 1.;
76}
77
79{
80 return {};
81}
82
84{
85 return m_playbackRate;
86}
87
89{
90 if (m_playbackRate == rate)
91 return;
92 m_playbackRate = rate;
93 if (m_playbackEngine)
94 m_playbackEngine->setPlaybackRate(rate);
95}
96
98{
99 return m_url;
100}
101
103{
104 return m_device;
105}
106
108{
109 m_url = media;
110 m_device = stream;
111 m_playbackEngine = nullptr;
112
114
115 auto handleIncorrectMedia = [this](QMediaPlayer::MediaStatus status) {
116 seekableChanged(false);
120 mediaStatusChanged(status);
121 };
122
123 if (media.isEmpty() && !stream) {
124 handleIncorrectMedia(QMediaPlayer::NoMedia);
125 return;
126 }
127
129 m_playbackEngine = std::make_unique<PlaybackEngine>();
130
131 connect(m_playbackEngine.get(), &PlaybackEngine::endOfStream, this,
132 &QFFmpegMediaPlayer::endOfStream);
133 connect(m_playbackEngine.get(), &PlaybackEngine::errorOccured, this,
134 &QFFmpegMediaPlayer::error);
135 connect(m_playbackEngine.get(), &PlaybackEngine::loopChanged, this,
136 &QFFmpegMediaPlayer::onLoopChanged);
137
138 if (!m_playbackEngine->setMedia(media, stream)) {
139 m_playbackEngine.reset();
140 handleIncorrectMedia(QMediaPlayer::InvalidMedia);
141 return;
142 }
143
144 m_playbackEngine->setAudioSink(m_audioOutput);
145 m_playbackEngine->setVideoSink(m_videoSink);
146 m_playbackEngine->setLoops(loops());
147 m_playbackEngine->setPlaybackRate(m_playbackRate);
148
152 seekableChanged(m_playbackEngine->isSeekable());
153
155 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::AudioStream).isEmpty());
157 !m_playbackEngine->streamInfo(QPlatformMediaPlayer::VideoStream).isEmpty());
158
159 // TODO: get rid of the delayed update
160 QMetaObject::invokeMethod(this, "delayedLoadedStatus", Qt::QueuedConnection);
161}
162
164{
165 if (!m_playbackEngine)
166 return;
167
169 m_playbackEngine->seek(0);
171 }
172
173 runPlayback();
174}
175
176void QFFmpegMediaPlayer::runPlayback()
177{
178 m_playbackEngine->play();
179 m_positionUpdateTimer.start();
182}
183
185{
186 if (!m_playbackEngine)
187 return;
189 m_playbackEngine->seek(0);
191 }
192 m_playbackEngine->pause();
193 m_positionUpdateTimer.stop();
196}
197
199{
200 if (!m_playbackEngine)
201 return;
202 m_playbackEngine->stop();
203 m_positionUpdateTimer.stop();
207}
208
210{
211 if (m_audioOutput == output)
212 return;
213
214 m_audioOutput = output;
215 if (m_playbackEngine)
216 m_playbackEngine->setAudioSink(output);
217}
218
220{
221 return m_playbackEngine ? m_playbackEngine->metaData() : QMediaMetaData{};
222}
223
225{
226 if (m_videoSink == sink)
227 return;
228
229 m_videoSink = sink;
230 if (m_playbackEngine)
231 m_playbackEngine->setVideoSink(sink);
232}
233
235{
236 return m_videoSink;
237}
238
240{
241 return m_playbackEngine ? m_playbackEngine->streamInfo(type).count() : 0;
242}
243
245{
246 if (!m_playbackEngine || streamNumber < 0
247 || streamNumber >= m_playbackEngine->streamInfo(type).count())
248 return {};
249 return m_playbackEngine->streamInfo(type).at(streamNumber).metaData;
250}
251
253{
254 return m_playbackEngine ? m_playbackEngine->activeTrack(type) : -1;
255}
256
258{
259 if (m_playbackEngine)
260 m_playbackEngine->setActiveTrack(type, streamNumber);
261 else
262 qWarning() << "Cannot set active track without open source";
263}
264
266{
267 if (m_playbackEngine)
268 m_playbackEngine->setLoops(loops);
269
271}
272
274
275#include "moc_qffmpegmediaplayer_p.cpp"
QMediaPlayer player
Definition audio.cpp:205
void setActiveTrack(TrackType, int streamNumber) override
void setVideoSink(QVideoSink *sink) override
QMediaMetaData trackMetaData(TrackType type, int streamNumber) override
void setLoops(int loops) override
QVideoSink * videoSink() const
void setAudioOutput(QPlatformAudioOutput *) override
qint64 duration() const override
float bufferProgress() const override
const QIODevice * mediaStream() const override
void setPosition(qint64 position) override
void setPlaybackRate(qreal rate) override
int activeTrack(TrackType) override
QUrl media() const override
QMediaTimeRange availablePlaybackRanges() const override
qreal playbackRate() const override
QFFmpegMediaPlayer(QMediaPlayer *player)
QMediaMetaData metaData() const override
void setMedia(const QUrl &media, QIODevice *stream) override
int trackCount(TrackType) override
void errorOccured(int, const QString &)
\inmodule QtCore \reentrant
Definition qiodevice.h:34
\inmodule QtMultimedia
The QMediaPlayer class allows the playing of a media files.
MediaStatus
\qmlproperty enumeration QtMultimedia::MediaPlayer::playbackState
The QMediaTimeRange class represents a set of zero or more disjoint time intervals.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
virtual QMediaPlayer::PlaybackState state() const
void positionChanged(qint64 position)
virtual QMediaPlayer::MediaStatus mediaStatus() const
void seekableChanged(bool seekable)
void durationChanged(qint64 duration)
void audioAvailableChanged(bool audioAvailable)
void stateChanged(QMediaPlayer::PlaybackState newState)
void videoAvailableChanged(bool videoAvailable)
virtual qint64 position() const
virtual void setLoops(int loops)
void mediaStatusChanged(QMediaPlayer::MediaStatus status)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:208
void setInterval(int msec)
Definition qtimer.cpp:607
void stop()
Stops the timer.
Definition qtimer.cpp:226
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
void setTimerType(Qt::TimerType atype)
Definition qtimer.cpp:661
\inmodule QtCore
Definition qurl.h:94
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1888
The QVideoSink class represents a generic sink for video data.
Definition qvideosink.h:22
Combined button and popup list for selecting options.
@ PreciseTimer
@ QueuedConnection
EGLStreamKHR stream
#define qWarning
Definition qlogging.h:162
GLenum type
GLuint GLenum * rate
GLsizei GLenum GLboolean sink
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
QT_BEGIN_NAMESPACE typedef uchar * output
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...