diff options
Diffstat (limited to 'src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp')
-rw-r--r-- | src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp new file mode 100644 index 000000000..75886b7c2 --- /dev/null +++ b/src/plugins/multimedia/wasm/mediaplayer/qwasmmediaplayer.cpp @@ -0,0 +1,475 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qwasmmediaplayer_p.h" +#include <common/qwasmvideooutput_p.h> +#include <common/qwasmaudiooutput_p.h> +#include "qaudiooutput.h" + +#include <QtCore/qloggingcategory.h> +#include <QUuid> +#include <QtGlobal> +#include <QMimeDatabase> +#include <QFileInfo> + +QT_BEGIN_NAMESPACE + +static Q_LOGGING_CATEGORY(lcMediaPlayer, "qt.multimedia.wasm.mediaplayer"); + +QWasmMediaPlayer::QWasmMediaPlayer(QMediaPlayer *parent) + : QPlatformMediaPlayer(parent), + m_videoOutput(new QWasmVideoOutput), + m_State(QWasmMediaPlayer::Idle) +{ + qCDebug(lcMediaPlayer) << Q_FUNC_INFO << this; + +} + +QWasmMediaPlayer::~QWasmMediaPlayer() +{ + delete m_videoOutput; +} + +void QWasmMediaPlayer::initVideo() +{ + m_videoOutput->setVideoMode(QWasmVideoOutput::VideoOutput); + QUuid videoElementId = QUuid::createUuid(); + qCDebug(lcMediaPlayer) << Q_FUNC_INFO << "videoElementId"<< videoElementId << this; + + m_videoOutput->createVideoElement(videoElementId.toString(QUuid::WithoutBraces).toStdString()); + m_videoOutput->doElementCallbacks(); + m_videoOutput->createOffscreenElement(QSize(1280, 720)); + m_videoOutput->updateVideoElementGeometry(QRect(0, 0, 1280, 720)); // initial size 720p standard + + connect(m_videoOutput, &QWasmVideoOutput::bufferingChanged, this, + &QWasmMediaPlayer::bufferingChanged); + connect(m_videoOutput, &QWasmVideoOutput::errorOccured, this, + &QWasmMediaPlayer::errorOccured); + connect(m_videoOutput, &QWasmVideoOutput::stateChanged, this, + &QWasmMediaPlayer::mediaStateChanged); + connect(m_videoOutput, &QWasmVideoOutput::progressChanged, this, + &QWasmMediaPlayer::setPositionChanged); + connect(m_videoOutput, &QWasmVideoOutput::durationChanged, this, + &QWasmMediaPlayer::setDurationChanged); + connect(m_videoOutput, &QWasmVideoOutput::sizeChange, this, + &QWasmMediaPlayer::videoSizeChanged); + connect(m_videoOutput, &QWasmVideoOutput::readyChanged, this, + &QWasmMediaPlayer::videoOutputReady); + connect(m_videoOutput, &QWasmVideoOutput::statusChanged, this, + &QWasmMediaPlayer::onMediaStatusChanged); + connect(m_videoOutput, &QWasmVideoOutput::metaDataLoaded, this, + &QWasmMediaPlayer::videoMetaDataChanged); + + setVideoAvailable(true); +} + +void QWasmMediaPlayer::initAudio() +{ + connect(m_audioOutput->q, &QAudioOutput::deviceChanged, + this, &QWasmMediaPlayer::updateAudioDevice); + connect(m_audioOutput->q, &QAudioOutput::volumeChanged, + this, &QWasmMediaPlayer::volumeChanged); + connect(m_audioOutput->q, &QAudioOutput::mutedChanged, + this, &QWasmMediaPlayer::mutedChanged); + + connect(m_audioOutput, &QWasmAudioOutput::bufferingChanged, this, + &QWasmMediaPlayer::bufferingChanged); + connect(m_audioOutput, &QWasmAudioOutput::errorOccured, this, + &QWasmMediaPlayer::errorOccured); + connect(m_audioOutput, &QWasmAudioOutput::progressChanged, this, + &QWasmMediaPlayer::setPositionChanged); + connect(m_audioOutput, &QWasmAudioOutput::durationChanged, this, + &QWasmMediaPlayer::setDurationChanged); + connect(m_audioOutput, &QWasmAudioOutput::statusChanged, this, + &QWasmMediaPlayer::onMediaStatusChanged); + connect(m_audioOutput, &QWasmAudioOutput::stateChanged, this, + &QWasmMediaPlayer::mediaStateChanged); + setAudioAvailable(true); +} + +qint64 QWasmMediaPlayer::duration() const +{ + return m_videoOutput->getDuration(); +} + +qint64 QWasmMediaPlayer::position() const +{ + if (mediaStatus() == QMediaPlayer::EndOfMedia) + return duration(); + + if (m_videoAvailable) + return m_videoOutput->getCurrentPosition(); + + return 0; +} + +void QWasmMediaPlayer::setPosition(qint64 position) +{ + if (!isSeekable()) + return; + + const int seekPosition = (position > INT_MAX) ? INT_MAX : position; + + if (seekPosition == this->position()) + return; + + if (mediaStatus() == QMediaPlayer::EndOfMedia) + setMediaStatus(QMediaPlayer::LoadedMedia); + + if (m_videoAvailable) + return m_videoOutput->seekTo(position); + + emit positionChanged(seekPosition); +} + +void QWasmMediaPlayer::volumeChanged(float gain) +{ + if (m_State != QWasmMediaPlayer::Started) + return; + + if (m_videoAvailable) + m_videoOutput->setVolume(gain); +} + +void QWasmMediaPlayer::mutedChanged(bool muted) +{ + if (m_State != QWasmMediaPlayer::Started) + return; + + if (m_videoAvailable) + m_videoOutput->setMuted(muted); +} + +float QWasmMediaPlayer::bufferProgress() const +{ + return qBound(0.0, (m_bufferPercent * .01), 1.0); +} + +bool QWasmMediaPlayer::isAudioAvailable() const +{ + return m_audioAvailable; +} + +bool QWasmMediaPlayer::isVideoAvailable() const +{ + return m_videoAvailable; +} + +QMediaTimeRange QWasmMediaPlayer::availablePlaybackRanges() const +{ + return m_availablePlaybackRange; +} + +void QWasmMediaPlayer::updateAvailablePlaybackRanges() +{ + if (m_buffering) { + const qint64 pos = position(); + const qint64 end = (duration() / 100) * m_bufferPercent; + m_availablePlaybackRange.addInterval(pos, end); + } else if (isSeekable()) { + m_availablePlaybackRange = QMediaTimeRange(0, duration()); + } else { + m_availablePlaybackRange = QMediaTimeRange(); + } +} + +qreal QWasmMediaPlayer::playbackRate() const +{ + if (m_State != QWasmMediaPlayer::Started) + return 0; + + if (isVideoAvailable()) + return m_videoOutput->playbackRate(); + return 0; +} + +void QWasmMediaPlayer::setPlaybackRate(qreal rate) +{ + if (m_State != QWasmMediaPlayer::Started || !isVideoAvailable()) + return; + + m_videoOutput->setPlaybackRate(rate); + emit playbackRateChanged(rate); +} + +QUrl QWasmMediaPlayer::media() const +{ + return m_mediaContent; +} + +const QIODevice *QWasmMediaPlayer::mediaStream() const +{ + return m_mediaStream; +} + +void QWasmMediaPlayer::setMedia(const QUrl &mediaContent, QIODevice *stream) +{ + qCDebug(lcMediaPlayer) << Q_FUNC_INFO << mediaContent << stream; + QMimeDatabase db; + + if (mediaContent.isEmpty()) { + if (stream) { + m_mediaStream = stream; + qCDebug(lcMediaPlayer) << db.mimeTypeForData(stream).name(); + if (db.mimeTypeForData(stream).name().contains("audio")) { + setAudioAvailable(true); + m_audioOutput->setSource(m_mediaStream); + } else { // treat octet-stream as video + setVideoAvailable(true); + m_videoOutput->setSource(m_mediaStream); + } + } else { + + setMediaStatus(QMediaPlayer::NoMedia); + } + } else { + QString sourceFile = mediaContent.toLocalFile(); + qCDebug(lcMediaPlayer) << db.mimeTypeForFile(QFileInfo(sourceFile)).name(); + if (db.mimeTypeForFile(QFileInfo(sourceFile)).name().contains("audio")) { + setAudioAvailable(true); + m_audioOutput->setSource(mediaContent); + } else { // treat octet-stream as video + setVideoAvailable(true); + m_videoOutput->setSource(mediaContent); + } + } + + resetBufferingProgress(); +} + +void QWasmMediaPlayer::setVideoSink(QVideoSink *sink) +{ + if (m_videoSink == sink) + return; + + m_videoSink = sink; + + if (!m_videoSink) + return; + + initVideo(); + m_videoOutput->setSurface(sink); + setVideoAvailable(true); + if (isAudioAvailable() && m_audioOutput) + m_audioOutput->setVideoElement(m_videoOutput->currentVideoElement()); +} + +void QWasmMediaPlayer::setAudioOutput(QPlatformAudioOutput *output) +{ + if (m_audioOutput == output) + return; + + if (m_audioOutput) + m_audioOutput->q->disconnect(this); + m_audioOutput = static_cast<QWasmAudioOutput *>(output); + setAudioAvailable(true); +} + +void QWasmMediaPlayer::updateAudioDevice() +{ + if (m_audioOutput) { + m_audioOutput->setAudioDevice(m_audioOutput->q->device()); + } +} + +void QWasmMediaPlayer::play() +{ + resetCurrentLoop(); + + if (isVideoAvailable()) { + m_videoOutput->start(); + m_playWhenReady = true; + } else { + initAudio(); + if (isAudioAvailable()) { + m_audioOutput->start(); + } + } + +#ifdef DEBUG_AUDIOENGINE + QAudioEnginePrivate::checkNoError("play"); +#endif +} + +void QWasmMediaPlayer::pause() +{ + if ((m_State + & (QWasmMediaPlayer::Started | QWasmMediaPlayer::Paused + | QWasmMediaPlayer::PlaybackCompleted)) == 0) { + return; + } + if (isVideoAvailable()) { + m_videoOutput->pause(); + } else { + m_audioOutput->pause(); + stateChanged(QMediaPlayer::PausedState); + } +} + +void QWasmMediaPlayer::stop() +{ + m_playWhenReady = false; + + if (m_State == QWasmMediaPlayer::Idle || m_State == QWasmMediaPlayer::PlaybackCompleted + || m_State == QWasmMediaPlayer::Stopped) { + qWarning() << Q_FUNC_INFO << __LINE__; + return; + } + + if (isVideoAvailable()) { + m_videoOutput->stop(); + } else { + m_audioOutput->stop(); + } + +} + +bool QWasmMediaPlayer::isSeekable() const +{ + return isVideoAvailable() && m_videoOutput->isVideoSeekable(); +} + +void QWasmMediaPlayer::errorOccured(qint32 code, const QString &message) +{ + QString errorString; + QMediaPlayer::Error error = QMediaPlayer::ResourceError; + + switch (code) { + case QWasmMediaNetworkState::NetworkEmpty: // no data + break; + case QWasmMediaNetworkState::NetworkIdle: + break; + case QWasmMediaNetworkState::NetworkLoading: + break; + case QWasmMediaNetworkState::NetworkNoSource: // no source + error = QMediaPlayer::ResourceError; + errorString = message; + break; + }; + + emit QPlatformMediaPlayer::error(error, errorString); +} + +void QWasmMediaPlayer::bufferingChanged(qint32 percent) +{ + m_buffering = percent != 100; + m_bufferPercent = percent; + + updateAvailablePlaybackRanges(); + emit bufferProgressChanged(bufferProgress()); +} + +void QWasmMediaPlayer::videoSizeChanged(qint32 width, qint32 height) +{ + QSize newSize(width, height); + + if (width == 0 || height == 0 || newSize == m_videoSize) + return; + + m_videoSize = newSize; +} + +void QWasmMediaPlayer::mediaStateChanged(QWasmMediaPlayer::QWasmMediaPlayerState state) +{ + m_State = state; + QMediaPlayer::PlaybackState m_mediaPlayerState; + switch (m_State) { + case QWasmMediaPlayer::Started: + m_mediaPlayerState = QMediaPlayer::PlayingState; + break; + case QWasmMediaPlayer::Paused: + m_mediaPlayerState = QMediaPlayer::PausedState; + break; + case QWasmMediaPlayer::Stopped: + m_mediaPlayerState = QMediaPlayer::StoppedState; + break; + default: + m_mediaPlayerState = QMediaPlayer::StoppedState; + break; + }; + + QPlatformMediaPlayer::stateChanged(m_mediaPlayerState); +} + +int QWasmMediaPlayer::trackCount(TrackType trackType) +{ + Q_UNUSED(trackType) + // TODO QTBUG-108517 + return 0; // tracks.count(); +} + +void QWasmMediaPlayer::setPositionChanged(qint64 position) +{ + QPlatformMediaPlayer::positionChanged(position); +} + +void QWasmMediaPlayer::setDurationChanged(qint64 duration) +{ + QPlatformMediaPlayer::durationChanged(duration); +} + +void QWasmMediaPlayer::videoOutputReady(bool ready) +{ + setVideoAvailable(ready); + + if (m_playWhenReady && m_videoOutput->isReady()) + play(); +} + +void QWasmMediaPlayer::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + mediaStatusChanged(status); + + switch (status) { + case QMediaPlayer::NoMedia: + case QMediaPlayer::InvalidMedia: + emit durationChanged(0); + break; + case QMediaPlayer::EndOfMedia: + setPositionChanged(position()); + default: + break; + }; +} + +void QWasmMediaPlayer::setAudioAvailable(bool available) +{ + if (m_audioAvailable == available) + return; + + m_audioAvailable = available; + emit audioAvailableChanged(m_audioAvailable); +} + +void QWasmMediaPlayer::setVideoAvailable(bool available) +{ + if (m_videoAvailable == available) + return; + + if (!available) + m_videoSize = QSize(); + + m_videoAvailable = available; + emit videoAvailableChanged(m_videoAvailable); +} + +void QWasmMediaPlayer::resetBufferingProgress() +{ + m_buffering = false; + m_bufferPercent = 0; + m_availablePlaybackRange = QMediaTimeRange(); +} + +void QWasmMediaPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + setMediaStatus(status); +} + +void QWasmMediaPlayer::videoMetaDataChanged() +{ + metaDataChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qwasmmediaplayer_p.cpp" |