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
qwasmvideooutput_p.h
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
4//
5// W A R N I N G
6// -------------
7//
8// This file is not part of the Qt API. It exists purely as an
9// implementation detail. This header file may change from version to
10// version without notice, or even be removed.
11//
12// We mean it.
13//
14
15#ifndef QWASMVIDEOOUTPUT_H
16#define QWASMVIDEOOUTPUT_H
17
18#include <QObject>
19
20#include <emscripten/val.h>
21#include <emscripten/html5_webgl.h>
22#include <emscripten/html5.h>
23
24#include <QMediaPlayer>
25#include <QVideoFrame>
26#include <QtMultimedia/qtvideo.h>
27
29#include "private/qwasmmediadevices_p.h"
31
32#include <private/qwasmjs_p.h>
33
34#include <QtCore/qloggingcategory.h>
35
36#include <private/qstdweb_p.h>
37#include <private/qwasmsuspendresumecontrol_p.h>
38
40
41Q_DECLARE_LOGGING_CATEGORY(qWasmMediaVideoOutput)
42
43class QVideoSink;
44
46{
48public:
53
54 explicit QWasmVideoOutput(QObject *parent = nullptr);
56
57 void setVideoSize(const QSize &);
58 void start();
59 void stop();
60 void reset();
61 void pause();
62
63 void setSurface(QVideoSink *surface);
65
66 bool isReady() const;
67
68 void setSource(const QUrl &url);
69 void setSource(QIODevice *stream);
70 void setVolume(qreal volume);
71 void setMuted(bool muted);
72
74 void seekTo(qint64 position);
75 bool isVideoSeekable();
76 void setPlaybackRate(qreal rate);
78
80 void newFrame(const QVideoFrame &newFrame);
81
82 void createVideoElement(const std::string &id);
83 void createOffscreenElement(const QSize &offscreenSize);
84 void doElementCallbacks();
85 void updateVideoElementGeometry(const QRect &windowGeometry);
86 void updateVideoElementSource(const QString &src);
87 void addCameraSourceElement(const std::string &id);
90
91 void setHasAudio(bool needsAudio) { m_hasAudio = needsAudio; }
92
93 bool hasCapability(const QString &cap);
95 bool setDeviceSetting(const std::string &key, emscripten::val value);
96 bool isCameraReady() { return m_cameraIsReady; }
97 bool m_hasVideoFrame = false;
98
99 void videoFrameCallback(void *context);
101
102 void webglVideoFrameCallback(void *context);
103 void getWebGLContext();
104 bool m_hasWebGLContext = false;
105
106 // mediacapturesession has the videosink
108
110 m_video.isNull() || m_video.isUndefined() ? emscripten::val::null()
111 : m_video) ; }
112
114
115 static QVideoFrameFormat::PixelFormat fromJsPixelFormat(std::string_view videoFormat);
116
118
120 void readyChanged(bool);
121 void bufferingChanged(qint32 percent);
122 void errorOccured(qint32 code, const QString &message);
124 void progressChanged(qint32 position);
125 void durationChanged(qint64 duration);
126 void statusChanged(QMediaPlayer::MediaStatus status);
127 void sizeChange(qint32 width, qint32 height);
129 void seekableChanged(bool seekable);
130 void orientationChanged(int rotationIndex);
131
132private:
133 void checkNetworkState();
134 void videoComputeFrame(void *context);
135 void getDeviceSettings();
136 bool isPlatformiOs();
137
138 emscripten::val m_video = emscripten::val::undefined();
139 emscripten::val m_videoElementSource = emscripten::val::undefined();
140
141 QString m_source;
142 float m_requestedPosition = 0.0;
143 emscripten::val m_offscreen = emscripten::val::undefined();
144 WasmCameraMode m_cameraMode;
145 QtVideo::Rotation m_rotateBy = QtVideo::Rotation::None;
146
147
148 bool m_isStopped = false;
149 bool m_toBePaused = false;
150 bool m_isSeeking = false;
151 bool m_hasAudio = false;
152 bool m_cameraIsReady = false;
153 bool m_shouldBeStarted = false;
154 bool m_isSeekable = false;
155 bool m_useCameraRotation = false;
156
157 emscripten::val m_offscreenContext = emscripten::val::undefined();
158 QSize m_pendingVideoSize;
160 QMediaPlayer::MediaStatus m_currentMediaStatus;
161 qreal m_currentBufferedValue;
162 JsMediaInputStream *m_mediaInputStream = nullptr;
163
164 QScopedPointer<QWasmEventHandler> m_timeUpdateEvent;
165 QScopedPointer<QWasmEventHandler> m_playEvent;
166 QScopedPointer<QWasmEventHandler> m_endedEvent;
167 QScopedPointer<QWasmEventHandler> m_durationChangeEvent;
168 QScopedPointer<QWasmEventHandler> m_loadedDataEvent;
169 QScopedPointer<QWasmEventHandler> m_errorChangeEvent;
170 QScopedPointer<QWasmEventHandler> m_resizeChangeEvent;
171 QScopedPointer<QWasmEventHandler> m_loadedMetadataChangeEvent;
172 QScopedPointer<QWasmEventHandler> m_loadStartChangeEvent;
173 QScopedPointer<QWasmEventHandler> m_canPlayChangeEvent;
174 QScopedPointer<QWasmEventHandler> m_canPlayThroughChangeEvent;
175 QScopedPointer<QWasmEventHandler> m_seekingChangeEvent;
176 QScopedPointer<QWasmEventHandler> m_seekedChangeEvent;
177 QScopedPointer<QWasmEventHandler> m_emptiedChangeEvent;
178 QScopedPointer<QWasmEventHandler> m_stalledChangeEvent;
179 QScopedPointer<QWasmEventHandler> m_waitingChangeEvent;
180 QScopedPointer<QWasmEventHandler> m_playingChangeEvent;
181 QScopedPointer<QWasmEventHandler> m_progressChangeEvent;
182 QScopedPointer<QWasmEventHandler> m_pauseChangeEvent;
183 QScopedPointer<QWasmEventHandler> m_beforeUnloadEvent;
184
185 std::string m_cameraId;
186 QMetaObject::Connection m_connection;
187 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_glContextHandle = 0;
188 emscripten::val m_glCanvas = emscripten::val::undefined();
189 static bool orientationchangeCallback(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData);
190};
191
192QT_END_NAMESPACE
193#endif // QWASMVIDEOOUTPUT_H
void addCameraSourceElement(const std::string &id)
void updateVideoElementGeometry(const QRect &windowGeometry)
bool setDeviceSetting(const std::string &key, emscripten::val value)
void sizeChange(qint32 width, qint32 height)
void newFrame(const QVideoFrame &newFrame)
emscripten::val surfaceElement()
void seekableChanged(bool seekable)
void durationChanged(qint64 duration)
emscripten::val getDeviceCapabilities()
void videoFrameCallback(void *context)
void setVideoSize(const QSize &)
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 webglVideoFrameCallback(void *context)
void orientationChanged(int rotationIndex)
void setVolume(qreal volume)
void createVideoElement(const std::string &id)
void stateChanged(QWasmMediaPlayer::QWasmMediaPlayerState newState)
void setSurface(QVideoSink *surface)
bool hasCapability(const QString &cap)
void updateVideoElementSource(const QString &src)
void removeSourceElement()
std::string m_videoSurfaceId
void statusChanged(QMediaPlayer::MediaStatus status)
static QVideoFrameFormat::PixelFormat fromJsPixelFormat(std::string_view videoFormat)
void progressChanged(qint32 position)
void errorOccured(qint32 code, const QString &message)
void setSource(QIODevice *stream)
void setPlaybackRate(qreal rate)
void setHasAudio(bool needsAudio)
void createOffscreenElement(const QSize &offscreenSize)
Combined button and popup list for selecting options.
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
#define GL_CLAMP_TO_EDGE
Definition qopenglext.h:100
static bool checkForVideoFrame()
EM_JS(void, qt_st_sink_loadWorkletModule,(EM_VAL ctxHandle, int callbackId, int channels), { var ctx=Emval.toValue(ctxHandle);var code=[ 'class QtSink extends AudioWorkletProcessor {', ' constructor(opts) {', ' super(opts);', ' this._numChannels=opts.processorOptions.channels|0;', ' this._queue=[];', ' this._pos=0;', ' this.port.onmessage=(e)=> { this._queue.push(e.data);};', ' }', ' process(inputs, outputs) {', ' var out=outputs[0];', ' if(!out||!out.length) return true;', ' var samplesPerChannel=out[0].length;', ' for(var i=0;i< samplesPerChannel;i++) {', ' while(this._queue.length > 0 &&this._pos >=this._queue[0].samplesPerChannel) {', ' this._queue.shift();', ' this._pos=0;', ' }', ' if(this._queue.length===0) break;', ' var frame=this._queue[0];', ' for(var channel=0;channel< out.length &&channel< frame.numChannels;channel++)', ' out[channel][i]=frame.data[channel *frame.samplesPerChannel+this._pos];', ' this._pos++;', ' }', ' this.port.postMessage(null);', ' return true;', ' }', '}', 'registerProcessor("qt-audio-sink", QtSink);'].join('\n');var blob=new Blob([code], { type:'application/javascript' });var url=URL.createObjectURL(blob);ctx.audioWorklet.addModule(url).then(function() { URL.revokeObjectURL(url);Module._qt_sinkWorkletReady(callbackId);});})