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
Combined button and popup list for selecting options.