Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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
5#include <common/qwasmvideooutput_p.h>
6#include <common/qwasmaudiooutput_p.h>
7#include "qaudiooutput.h"
8
9#include <QtCore/qloggingcategory.h>
10#include <QUuid>
11#include <QtGlobal>
12#include <QMimeDatabase>
13#include <QFileInfo>
14
16
17Q_STATIC_LOGGING_CATEGORY(lcMediaPlayer, "qt.multimedia.wasm.mediaplayer");
18
19using namespace Qt::Literals;
20
21QWasmMediaPlayer::QWasmMediaPlayer(QMediaPlayer *parent)
22 : QPlatformMediaPlayer(parent),
23 m_videoOutput(new QWasmVideoOutput),
25{
26 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << this;
27
28}
29
31{
32 delete m_videoOutput;
33}
34
35void QWasmMediaPlayer::initVideo()
36{
37 m_videoOutput->setVideoMode(QWasmVideoOutput::VideoDisplay);
38 QUuid videoElementId = QUuid::createUuid();
39 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << "videoElementId"<< videoElementId << this;
40
41 m_videoOutput->createVideoElement(videoElementId.toString(QUuid::WithoutBraces).toStdString());
42 m_videoOutput->doElementCallbacks();
43 m_videoOutput->createOffscreenElement(QSize(1280, 720));
44 m_videoOutput->updateVideoElementGeometry(QRect(0, 0, 1280, 720)); // initial size 720p standard
45
46 connect(m_videoOutput, &QWasmVideoOutput::bufferingChanged, this,
47 &QWasmMediaPlayer::bufferingChanged);
48 connect(m_videoOutput, &QWasmVideoOutput::errorOccured, this,
49 &QWasmMediaPlayer::errorOccured);
50 connect(m_videoOutput, &QWasmVideoOutput::stateChanged, this,
51 &QWasmMediaPlayer::mediaStateChanged);
52 connect(m_videoOutput, &QWasmVideoOutput::progressChanged, this,
53 &QWasmMediaPlayer::setPositionChanged);
54 connect(m_videoOutput, &QWasmVideoOutput::durationChanged, this,
55 &QWasmMediaPlayer::setDurationChanged);
56 connect(m_videoOutput, &QWasmVideoOutput::sizeChange, this,
57 &QWasmMediaPlayer::videoSizeChanged);
58 connect(m_videoOutput, &QWasmVideoOutput::readyChanged, this,
59 &QWasmMediaPlayer::videoOutputReady);
60 connect(m_videoOutput, &QWasmVideoOutput::statusChanged, this,
61 &QWasmMediaPlayer::onMediaStatusChanged);
62 connect(m_videoOutput, &QWasmVideoOutput::metaDataLoaded, this,
63 &QWasmMediaPlayer::videoMetaDataChanged);
64 connect(m_videoOutput, &QWasmVideoOutput::seekableChanged, this,
65 &QWasmMediaPlayer::seekableMediaChanged);
66
67 setVideoAvailable(true);
68}
69
70void QWasmMediaPlayer::initAudio()
71{
72 connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
73 this, &QWasmMediaPlayer::updateAudioDevice);
74 connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
75 this, &QWasmMediaPlayer::volumeChanged);
76 connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
77 this, &QWasmMediaPlayer::mutedChanged);
78
79 connect(m_audioOutput, &QWasmAudioOutput::bufferingChanged, this,
80 &QWasmMediaPlayer::bufferingChanged);
81 connect(m_audioOutput, &QWasmAudioOutput::errorOccured, this,
82 &QWasmMediaPlayer::errorOccured);
83 connect(m_audioOutput, &QWasmAudioOutput::progressChanged, this,
84 &QWasmMediaPlayer::setPositionChanged);
85 connect(m_audioOutput, &QWasmAudioOutput::durationChanged, this,
86 &QWasmMediaPlayer::setDurationChanged);
87 connect(m_audioOutput, &QWasmAudioOutput::statusChanged, this,
88 &QWasmMediaPlayer::onMediaStatusChanged);
89 connect(m_audioOutput, &QWasmAudioOutput::stateChanged, this,
90 &QWasmMediaPlayer::mediaStateChanged);
91 setAudioAvailable(true);
92}
93
94qint64 QWasmMediaPlayer::duration() const
95{
96 return m_videoOutput->getDuration();
97}
98
100{
101 if (mediaStatus() == QMediaPlayer::EndOfMedia)
102 return duration();
103
104 if (m_videoAvailable)
105 return m_videoOutput->getCurrentPosition();
106
107 return 0;
108}
109
110void QWasmMediaPlayer::setPosition(qint64 position)
111{
112 if (!isSeekable())
113 return;
114
115 const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
116
117 if (seekPosition == this->position())
118 return;
119
120 if (mediaStatus() == QMediaPlayer::EndOfMedia)
121 setMediaStatus(QMediaPlayer::LoadedMedia);
122
123 if (m_videoAvailable)
124 return m_videoOutput->seekTo(position);
125
126 emit positionChanged(seekPosition);
127}
128
129void QWasmMediaPlayer::volumeChanged(float gain)
130{
131 if (m_State != QWasmMediaPlayer::Started)
132 return;
133
134 if (m_videoAvailable)
135 m_videoOutput->setVolume(gain);
136}
137
138void QWasmMediaPlayer::mutedChanged(bool muted)
139{
140 if (m_State != QWasmMediaPlayer::Started)
141 return;
142
143 if (m_videoAvailable)
144 m_videoOutput->setMuted(muted);
145}
146
148{
149 return qBound(0.0, (m_bufferPercent * .01), 1.0);
150}
151
153{
154 return m_audioAvailable;
155}
156
158{
159 return m_videoAvailable;
160}
161
163{
164 return m_availablePlaybackRange;
165}
166
167void QWasmMediaPlayer::updateAvailablePlaybackRanges()
168{
169 if (m_buffering) {
170 const qint64 pos = position();
171 const qint64 end = (duration() / 100) * m_bufferPercent;
172 m_availablePlaybackRange.addInterval(pos, end);
173 } else if (isSeekable()) {
174 m_availablePlaybackRange = QMediaTimeRange(0, duration());
175 } else {
176 m_availablePlaybackRange = QMediaTimeRange();
177 }
178}
179
181{
182 if (m_State != QWasmMediaPlayer::Started)
183 return 0;
184
185 if (isVideoAvailable())
186 return m_videoOutput->playbackRate();
187 return 0;
188}
189
191{
193 return;
194
195 m_videoOutput->setPlaybackRate(rate);
196 emit playbackRateChanged(rate);
197}
198
200{
201 return m_mediaContent;
202}
203
205{
206 return m_mediaStream;
207}
208
209void QWasmMediaPlayer::setMedia(const QUrl &mediaContent, QIODevice *stream)
210{
211 qCDebug(lcMediaPlayer) << Q_FUNC_INFO << mediaContent << stream;
212 QMimeDatabase db;
213
214 if (mediaContent.isEmpty()) {
215 if (stream) {
216 m_mediaStream = stream;
217 qCDebug(lcMediaPlayer) << db.mimeTypeForData(stream).name();
218 if (db.mimeTypeForData(stream).name().contains(u"audio"_s)) {
219 setAudioAvailable(true);
220 m_audioOutput->setSource(m_mediaStream);
221 } else { // treat octet-stream as video
222 setVideoAvailable(true);
223 m_videoOutput->setSource(m_mediaStream);
224 }
225 } else {
226
227 setMediaStatus(QMediaPlayer::NoMedia);
228 }
229 } else {
230 if (mediaContent.isLocalFile()) {
231 QString sourceFile = mediaContent.toLocalFile();
232 if (db.mimeTypeForFile(QFileInfo(sourceFile)).name().contains(u"audio"_s)) {
233 setAudioAvailable(true);
234 m_audioOutput->setSource(mediaContent);
235 } else { // treat octet-stream as video
236 setVideoAvailable(true);
237 m_videoOutput->setSource(mediaContent);
238 }
239 } else {
240 // web url
241 if (!m_videoOutput->currentVideoElement().isNull()) {
242 m_videoOutput->setSource(mediaContent);
243 setVideoAvailable(true);
244 } else {
245 m_audioOutput->setSource(mediaContent);
246 setAudioAvailable(true);
247 }
248 }
249 }
250
251 resetBufferingProgress();
252}
253
254void QWasmMediaPlayer::setVideoSink(QVideoSink *sink)
255{
256 if (m_videoSink == sink)
257 return;
258
259 m_videoSink = sink;
260
261 if (!m_videoSink)
262 return;
263
264 initVideo();
265 m_videoOutput->setSurface(sink);
266 setVideoAvailable(true);
267 if (isAudioAvailable() && m_audioOutput)
268 m_audioOutput->setVideoElement(m_videoOutput->currentVideoElement());
269}
270
271void QWasmMediaPlayer::setAudioOutput(QPlatformAudioOutput *output)
272{
273 if (m_audioOutput == output)
274 return;
275
276 if (m_audioOutput)
277 m_audioOutput->q->disconnect(this);
278 m_audioOutput = static_cast<QWasmAudioOutput *>(output);
279 setAudioAvailable(true);
280}
281
283{
284 if (m_audioOutput) {
285 m_audioOutput->setAudioDevice(m_audioOutput->q->device());
286 }
287}
288
290{
291 resetCurrentLoop();
292
293 if (isVideoAvailable()) {
294 m_videoOutput->start();
295 m_playWhenReady = true;
296 } else {
297 initAudio();
298 if (isAudioAvailable()) {
299 m_audioOutput->start();
300 }
301 }
302
303#ifdef DEBUG_AUDIOENGINE
304 QAudioEnginePrivate::checkNoError("play");
305#endif
306}
307
309{
310 if ((m_State
313 return;
314 }
315 if (isVideoAvailable()) {
316 m_videoOutput->pause();
317 } else {
318 m_audioOutput->pause();
319 stateChanged(QMediaPlayer::PausedState);
320 }
321}
322
324{
325 m_playWhenReady = false;
326
328 || m_State == QWasmMediaPlayer::Stopped) {
329 qWarning() << Q_FUNC_INFO << __LINE__;
330 return;
331 }
332
333 if (isVideoAvailable()) {
334 m_videoOutput->stop();
335 } else {
336 m_audioOutput->stop();
337 }
338
339}
340
342{
343 return isVideoAvailable() && m_videoOutput->isVideoSeekable();
344}
345
346void QWasmMediaPlayer::errorOccured(qint32 code, const QString &message)
347{
348 QString errorString;
349 QMediaPlayer::Error error = QMediaPlayer::ResourceError;
350
351 switch (code) {
352 case QWasmMediaNetworkState::NetworkEmpty: // no data
353 break;
354 case QWasmMediaNetworkState::NetworkIdle:
355 break;
356 case QWasmMediaNetworkState::NetworkLoading:
357 break;
358 case QWasmMediaNetworkState::NetworkNoSource: // no source
359 error = QMediaPlayer::ResourceError;
360 errorString = message;
361 break;
362 };
363
364 emit QPlatformMediaPlayer::error(error, errorString);
365}
366
367void QWasmMediaPlayer::bufferingChanged(qint32 percent)
368{
369 m_buffering = percent != 100;
370 m_bufferPercent = percent;
371
372 updateAvailablePlaybackRanges();
373 emit bufferProgressChanged(bufferProgress());
374}
375
376void QWasmMediaPlayer::videoSizeChanged(qint32 width, qint32 height)
377{
378 QSize newSize(width, height);
379
380 if (width == 0 || height == 0 || newSize == m_videoSize)
381 return;
382
383 m_videoSize = newSize;
384}
385
386void QWasmMediaPlayer::mediaStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state)
387{
388 m_State = state;
389 QMediaPlayer::PlaybackState m_mediaPlayerState;
390 switch (m_State) {
391 case QWasmMediaPlayer::Started:
392 m_mediaPlayerState = QMediaPlayer::PlayingState;
393 break;
394 case QWasmMediaPlayer::Paused:
395 m_mediaPlayerState = QMediaPlayer::PausedState;
396 break;
397 case QWasmMediaPlayer::Stopped:
398 m_mediaPlayerState = QMediaPlayer::StoppedState;
399 break;
400 default:
401 m_mediaPlayerState = QMediaPlayer::StoppedState;
402 break;
403 };
404
405 QPlatformMediaPlayer::stateChanged(m_mediaPlayerState);
406}
407
408int QWasmMediaPlayer::trackCount(TrackType trackType)
409{
410 Q_UNUSED(trackType)
411 // TODO QTBUG-108517
412 return 0; // tracks.count();
413}
414
415void QWasmMediaPlayer::setPositionChanged(qint64 position)
416{
417 QPlatformMediaPlayer::positionChanged(position);
418}
419
420void QWasmMediaPlayer::setDurationChanged(qint64 duration)
421{
422 QPlatformMediaPlayer::durationChanged(duration);
423}
424
425void QWasmMediaPlayer::videoOutputReady(bool ready)
426{
427 setVideoAvailable(ready);
428
429 if (m_playWhenReady && m_videoOutput->isReady())
430 play();
431}
432
433void QWasmMediaPlayer::setMediaStatus(QMediaPlayer::MediaStatus status)
434{
435 mediaStatusChanged(status);
436
437 switch (status) {
438 case QMediaPlayer::NoMedia:
439 case QMediaPlayer::InvalidMedia:
440 emit durationChanged(0);
441 break;
442 case QMediaPlayer::EndOfMedia:
443 setPositionChanged(position());
444 default:
445 break;
446 };
447}
448
449void QWasmMediaPlayer::setAudioAvailable(bool available)
450{
451 if (m_audioAvailable == available)
452 return;
453
454 m_audioAvailable = available;
455 emit audioAvailableChanged(m_audioAvailable);
456}
457
458void QWasmMediaPlayer::setVideoAvailable(bool available)
459{
460 if (m_videoAvailable == available)
461 return;
462
463 if (!available)
464 m_videoSize = QSize();
465
466 m_videoAvailable = available;
467 emit videoAvailableChanged(m_videoAvailable);
468}
469
470void QWasmMediaPlayer::resetBufferingProgress()
471{
472 m_buffering = false;
473 m_bufferPercent = 0;
474 m_availablePlaybackRange = QMediaTimeRange();
475}
476
477void QWasmMediaPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
478{
479 setMediaStatus(status);
480}
481
482void QWasmMediaPlayer::videoMetaDataChanged()
483{
484 metaDataChanged();
485}
486
487void QWasmMediaPlayer::seekableMediaChanged(bool seekable)
488{
489 seekableChanged(seekable);
490}
491
492QT_END_NAMESPACE
493
494#include "moc_qwasmmediaplayer_p.cpp"
\inmodule QtCore
Definition qsize.h:26
void setVideoSink(QVideoSink *surface) 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() override
void setMedia(const QUrl &mediaContent, QIODevice *stream) override
void setPosition(qint64 position) override
void setPlaybackRate(qreal rate) override
bool isSeekable() const override
bool isAudioAvailable() const override
int trackCount(TrackType trackType) override
void stop() override
QUrl media() const override