Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwasmmediaplayer.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
7#include "qaudiooutput.h"
8
9#include <QtCore/qloggingcategory.h>
10#include <QUuid>
11#include <QtGlobal>
12#include <QMimeDatabase>
13#include <QFileInfo>
14
16
17static Q_LOGGING_CATEGORY(lcMediaPlayer, "qt.multimedia.wasm.mediaplayer");
18
20 : QPlatformMediaPlayer(parent),
21 m_videoOutput(new QWasmVideoOutput),
22 m_State(QWasmMediaPlayer::Idle)
23{
24 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << this;
25
26}
27
29{
30 delete m_videoOutput;
31}
32
33void QWasmMediaPlayer::initVideo()
34{
36 QUuid videoElementId = QUuid::createUuid();
37 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << "videoElementId"<< videoElementId << this;
38
39 m_videoOutput->createVideoElement(videoElementId.toString(QUuid::WithoutBraces).toStdString());
40 m_videoOutput->doElementCallbacks();
41 m_videoOutput->createOffscreenElement(QSize(1280, 720));
42 m_videoOutput->updateVideoElementGeometry(QRect(0, 0, 1280, 720)); // initial size 720p standard
43
44 connect(m_videoOutput, &QWasmVideoOutput::bufferingChanged, this,
45 &QWasmMediaPlayer::bufferingChanged);
46 connect(m_videoOutput, &QWasmVideoOutput::errorOccured, this,
47 &QWasmMediaPlayer::errorOccured);
48 connect(m_videoOutput, &QWasmVideoOutput::stateChanged, this,
49 &QWasmMediaPlayer::mediaStateChanged);
50 connect(m_videoOutput, &QWasmVideoOutput::progressChanged, this,
51 &QWasmMediaPlayer::setPositionChanged);
52 connect(m_videoOutput, &QWasmVideoOutput::durationChanged, this,
53 &QWasmMediaPlayer::setDurationChanged);
54 connect(m_videoOutput, &QWasmVideoOutput::sizeChange, this,
55 &QWasmMediaPlayer::videoSizeChanged);
56 connect(m_videoOutput, &QWasmVideoOutput::readyChanged, this,
57 &QWasmMediaPlayer::videoOutputReady);
58 connect(m_videoOutput, &QWasmVideoOutput::statusChanged, this,
59 &QWasmMediaPlayer::onMediaStatusChanged);
60 connect(m_videoOutput, &QWasmVideoOutput::metaDataLoaded, this,
61 &QWasmMediaPlayer::videoMetaDataChanged);
62
63 setVideoAvailable(true);
64}
65
66void QWasmMediaPlayer::initAudio()
67{
68 connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
70 connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
71 this, &QWasmMediaPlayer::volumeChanged);
72 connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
73 this, &QWasmMediaPlayer::mutedChanged);
74
75 connect(m_audioOutput, &QWasmAudioOutput::bufferingChanged, this,
76 &QWasmMediaPlayer::bufferingChanged);
77 connect(m_audioOutput, &QWasmAudioOutput::errorOccured, this,
78 &QWasmMediaPlayer::errorOccured);
79 connect(m_audioOutput, &QWasmAudioOutput::progressChanged, this,
80 &QWasmMediaPlayer::setPositionChanged);
81 connect(m_audioOutput, &QWasmAudioOutput::durationChanged, this,
82 &QWasmMediaPlayer::setDurationChanged);
83 connect(m_audioOutput, &QWasmAudioOutput::statusChanged, this,
84 &QWasmMediaPlayer::onMediaStatusChanged);
85 connect(m_audioOutput, &QWasmAudioOutput::stateChanged, this,
86 &QWasmMediaPlayer::mediaStateChanged);
87 setAudioAvailable(true);
88}
89
91{
92 return m_videoOutput->getDuration();
93}
94
96{
98 return duration();
99
100 if (m_videoAvailable)
101 return m_videoOutput->getCurrentPosition();
102
103 return 0;
104}
105
107{
108 if (!isSeekable())
109 return;
110
111 const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
112
113 if (seekPosition == this->position())
114 return;
115
117 setMediaStatus(QMediaPlayer::LoadedMedia);
118
119 if (m_videoAvailable)
120 return m_videoOutput->seekTo(position);
121
122 emit positionChanged(seekPosition);
123}
124
125void QWasmMediaPlayer::volumeChanged(float gain)
126{
127 if (m_State != QWasmMediaPlayer::Started)
128 return;
129
130 if (m_videoAvailable)
131 m_videoOutput->setVolume(gain);
132}
133
134void QWasmMediaPlayer::mutedChanged(bool muted)
135{
136 if (m_State != QWasmMediaPlayer::Started)
137 return;
138
139 if (m_videoAvailable)
140 m_videoOutput->setMuted(muted);
141}
142
144{
145 return qBound(0.0, (m_bufferPercent * .01), 1.0);
146}
147
149{
150 return m_audioAvailable;
151}
152
154{
155 return m_videoAvailable;
156}
157
159{
160 return m_availablePlaybackRange;
161}
162
163void QWasmMediaPlayer::updateAvailablePlaybackRanges()
164{
165 if (m_buffering) {
166 const qint64 pos = position();
167 const qint64 end = (duration() / 100) * m_bufferPercent;
168 m_availablePlaybackRange.addInterval(pos, end);
169 } else if (isSeekable()) {
170 m_availablePlaybackRange = QMediaTimeRange(0, duration());
171 } else {
172 m_availablePlaybackRange = QMediaTimeRange();
173 }
174}
175
177{
178 if (m_State != QWasmMediaPlayer::Started)
179 return 0;
180
181 if (isVideoAvailable())
182 return m_videoOutput->playbackRate();
183 return 0;
184}
185
187{
188 if (m_State != QWasmMediaPlayer::Started || !isVideoAvailable())
189 return;
190
191 m_videoOutput->setPlaybackRate(rate);
193}
194
196{
197 return m_mediaContent;
198}
199
201{
202 return m_mediaStream;
203}
204
206{
207 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << mediaContent << stream;
209
210 if (mediaContent.isEmpty()) {
211 if (stream) {
212 m_mediaStream = stream;
213 qCDebug(lcMediaPlayer) << db.mimeTypeForData(stream).name();
214 if (db.mimeTypeForData(stream).name().contains("audio")) {
215 setAudioAvailable(true);
216 m_audioOutput->setSource(m_mediaStream);
217 } else { // treat octet-stream as video
218 setVideoAvailable(true);
219 m_videoOutput->setSource(m_mediaStream);
220 }
221 } else {
222
223 setMediaStatus(QMediaPlayer::NoMedia);
224 }
225 } else {
226 QString sourceFile = mediaContent.toLocalFile();
227 qCDebug(lcMediaPlayer) << db.mimeTypeForFile(QFileInfo(sourceFile)).name();
228 if (db.mimeTypeForFile(QFileInfo(sourceFile)).name().contains("audio")) {
229 setAudioAvailable(true);
230 m_audioOutput->setSource(mediaContent);
231 } else { // treat octet-stream as video
232 setVideoAvailable(true);
233 m_videoOutput->setSource(mediaContent);
234 }
235 }
236
237 resetBufferingProgress();
238}
239
241{
242 if (m_videoSink == sink)
243 return;
244
245 m_videoSink = sink;
246
247 if (!m_videoSink)
248 return;
249
250 initVideo();
251 m_videoOutput->setSurface(sink);
252 setVideoAvailable(true);
253 if (isAudioAvailable() && m_audioOutput)
254 m_audioOutput->setVideoElement(m_videoOutput->currentVideoElement());
255}
256
258{
259 if (m_audioOutput == output)
260 return;
261
262 if (m_audioOutput)
263 m_audioOutput->q->disconnect(this);
264 m_audioOutput = static_cast<QWasmAudioOutput *>(output);
265 setAudioAvailable(true);
266}
267
269{
270 if (m_audioOutput) {
271 m_audioOutput->setAudioDevice(m_audioOutput->q->device());
272 }
273}
274
276{
278
279 if (isVideoAvailable()) {
280 m_videoOutput->start();
281 m_playWhenReady = true;
282 } else {
283 initAudio();
284 if (isAudioAvailable()) {
285 m_audioOutput->start();
286 }
287 }
288
289#ifdef DEBUG_AUDIOENGINE
290 QAudioEnginePrivate::checkNoError("play");
291#endif
292}
293
295{
296 if ((m_State
299 return;
300 }
301 if (isVideoAvailable()) {
302 m_videoOutput->pause();
303 } else {
304 m_audioOutput->pause();
306 }
307}
308
310{
311 m_playWhenReady = false;
312
314 || m_State == QWasmMediaPlayer::Stopped) {
315 qWarning() << Q_FUNC_INFO << __LINE__;
316 return;
317 }
318
319 if (isVideoAvailable()) {
320 m_videoOutput->stop();
321 } else {
322 m_audioOutput->stop();
323 }
324
325}
326
328{
329 return isVideoAvailable() && m_videoOutput->isVideoSeekable();
330}
331
332void QWasmMediaPlayer::errorOccured(qint32 code, const QString &message)
333{
334 QString errorString;
336
337 switch (code) {
339 break;
341 break;
343 break;
346 errorString = message;
347 break;
348 };
349
351}
352
353void QWasmMediaPlayer::bufferingChanged(qint32 percent)
354{
355 m_buffering = percent != 100;
356 m_bufferPercent = percent;
357
358 updateAvailablePlaybackRanges();
360}
361
362void QWasmMediaPlayer::videoSizeChanged(qint32 width, qint32 height)
363{
364 QSize newSize(width, height);
365
366 if (width == 0 || height == 0 || newSize == m_videoSize)
367 return;
368
369 m_videoSize = newSize;
370}
371
372void QWasmMediaPlayer::mediaStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state)
373{
374 m_State = state;
375 QMediaPlayer::PlaybackState m_mediaPlayerState;
376 switch (m_State) {
378 m_mediaPlayerState = QMediaPlayer::PlayingState;
379 break;
381 m_mediaPlayerState = QMediaPlayer::PausedState;
382 break;
384 m_mediaPlayerState = QMediaPlayer::StoppedState;
385 break;
386 default:
387 m_mediaPlayerState = QMediaPlayer::StoppedState;
388 break;
389 };
390
391 QPlatformMediaPlayer::stateChanged(m_mediaPlayerState);
392}
393
395{
396 Q_UNUSED(trackType)
397 // TODO QTBUG-108517
398 return 0; // tracks.count();
399}
400
401void QWasmMediaPlayer::setPositionChanged(qint64 position)
402{
404}
405
406void QWasmMediaPlayer::setDurationChanged(qint64 duration)
407{
409}
410
411void QWasmMediaPlayer::videoOutputReady(bool ready)
412{
413 setVideoAvailable(ready);
414
415 if (m_playWhenReady && m_videoOutput->isReady())
416 play();
417}
418
419void QWasmMediaPlayer::setMediaStatus(QMediaPlayer::MediaStatus status)
420{
421 mediaStatusChanged(status);
422
423 switch (status) {
427 break;
429 setPositionChanged(position());
430 default:
431 break;
432 };
433}
434
435void QWasmMediaPlayer::setAudioAvailable(bool available)
436{
437 if (m_audioAvailable == available)
438 return;
439
440 m_audioAvailable = available;
441 emit audioAvailableChanged(m_audioAvailable);
442}
443
444void QWasmMediaPlayer::setVideoAvailable(bool available)
445{
446 if (m_videoAvailable == available)
447 return;
448
449 if (!available)
450 m_videoSize = QSize();
451
452 m_videoAvailable = available;
453 emit videoAvailableChanged(m_videoAvailable);
454}
455
456void QWasmMediaPlayer::resetBufferingProgress()
457{
458 m_buffering = false;
459 m_bufferPercent = 0;
460 m_availablePlaybackRange = QMediaTimeRange();
461}
462
463void QWasmMediaPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
464{
465 setMediaStatus(status);
466}
467
468void QWasmMediaPlayer::videoMetaDataChanged()
469{
471}
472
474
475#include "moc_qwasmmediaplayer_p.cpp"
void deviceChanged()
void mutedChanged(bool muted)
QAudioDevice device
\qmlproperty AudioDevice QtMultimedia::AudioOutput::device
void volumeChanged(float volume)
\inmodule QtCore \reentrant
Definition qiodevice.h:34
The QMediaPlayer class allows the playing of a media files.
MediaStatus
\qmlproperty enumeration QtMultimedia::MediaPlayer::playbackState
PlaybackState
Defines the current state of a media player.
Error
\qmlproperty enumeration QtMultimedia::MediaPlayer::mediaStatus
The QMediaTimeRange class represents a set of zero or more disjoint time intervals.
void addInterval(qint64 start, qint64 end)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
QMimeType mimeTypeForData(const QByteArray &data) const
Returns a MIME type for data.
QMimeType mimeTypeForFile(const QString &fileName, MatchMode mode=MatchDefault) const
Returns a MIME type for the file named fileName using mode.
QString name
the name of the MIME type
Definition qmimetype.h:29
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
virtual QMediaPlayer::PlaybackState state() const
void positionChanged(qint64 position)
virtual QMediaPlayer::MediaStatus mediaStatus() const
void durationChanged(qint64 duration)
void playbackRateChanged(qreal rate)
void error(int error, const QString &errorString)
void audioAvailableChanged(bool audioAvailable)
void stateChanged(QMediaPlayer::PlaybackState newState)
void videoAvailableChanged(bool videoAvailable)
void mediaStatusChanged(QMediaPlayer::MediaStatus status)
void bufferProgressChanged(float progress)
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
\inmodule QtCore
Definition qurl.h:94
\inmodule QtCore
Definition quuid.h:31
static QUuid createUuid()
On any platform other than Windows, this function returns a new UUID with variant QUuid::DCE and vers...
Definition quuid.cpp:997
@ WithoutBraces
Definition quuid.h:54
The QVideoSink class represents a generic sink for video data.
Definition qvideosink.h:22
void progressChanged(qint32 position)
void bufferingChanged(qint32 percent)
void errorOccured(qint32 code, const QString &message)
void stateChanged(QWasmMediaPlayer::QWasmMediaPlayerState newState)
void statusChanged(QMediaPlayer::MediaStatus status)
void setVideoElement(emscripten::val videoElement)
void durationChanged(qint64 duration)
void setAudioDevice(const QAudioDevice &device) final
void setSource(const QUrl &url)
void setVideoSink(QVideoSink *surface) override
qint64 duration() const override
void pause() override
qint64 position() const override
void play() override
const QIODevice * mediaStream() const override
QMediaTimeRange availablePlaybackRanges() const override
qreal playbackRate() const override
float bufferProgress() const override
bool isVideoAvailable() const override
QWasmMediaPlayer(QMediaPlayer *parent=0)
~QWasmMediaPlayer() override
void setMedia(const QUrl &mediaContent, QIODevice *stream) override
void setPosition(qint64 position) override
void setPlaybackRate(qreal rate) override
void setAudioOutput(QPlatformAudioOutput *output) override
bool isSeekable() const override
bool isAudioAvailable() const override
int trackCount(TrackType trackType) override
void stop() override
QUrl media() const override
void readyChanged(bool)
void updateVideoElementGeometry(const QRect &windowGeometry)
void sizeChange(qint32 width, qint32 height)
void durationChanged(qint64 duration)
void setMuted(bool muted)
emscripten::val currentVideoElement()
void setSource(const QUrl &url)
void setVideoMode(QWasmVideoOutput::WasmVideoMode mode)
void bufferingChanged(qint32 percent)
void seekTo(qint64 position)
void setVolume(qreal volume)
void createVideoElement(const std::string &id)
void stateChanged(QWasmMediaPlayer::QWasmMediaPlayerState newState)
void setSurface(QVideoSink *surface)
void statusChanged(QMediaPlayer::MediaStatus status)
void progressChanged(qint32 position)
void errorOccured(qint32 code, const QString &message)
void setPlaybackRate(qreal rate)
void createOffscreenElement(const QSize &offscreenSize)
else opt state
[0]
Combined button and popup list for selecting options.
#define Q_FUNC_INFO
DBusConnection const char DBusError * error
EGLStreamKHR stream
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint GLsizei GLsizei height
GLuint GLuint end
GLint GLsizei width
GLuint GLsizei const GLchar * message
GLuint name
GLuint GLenum * rate
GLsizei GLenum GLboolean sink
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define emit
#define Q_UNUSED(x)
int qint32
Definition qtypes.h:49
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QT_BEGIN_NAMESPACE typedef uchar * output
QMimeDatabase db
[0]