5#include <QtQuick/qsgmaterial.h>
7#include <QtMultimedia/private/qvideotexturehelper_p.h>
8#include <private/qsginternaltextnode_p.h>
9#include <private/qquickitem_p.h>
10#include <private/qquickvideooutput_p.h>
11#include <private/qhwvideobuffer_p.h>
12#include <private/qvideoframetexturepool_p.h>
14#if QT_CONFIG(opengles2)
15#include <private/qshaderdescription_p.h>
21static inline void qSetGeom(QSGGeometry::TexturedPoint2D *v,
const QPointF &p)
27static inline void qSetTex(QSGGeometry::TexturedPoint2D *v,
const QPointF &p)
33static inline void qSwapTex(QSGGeometry::TexturedPoint2D *v0, QSGGeometry::TexturedPoint2D *v1)
49 const QRhiSwapChain::Format surfaceFormat,
50 const QRhiSwapChainHdrInfo &hdrInfo,
56 setShaderFileName(VertexStage, QVideoTextureHelper::vertexShaderFileName(m_videoFormat));
57 if (QVideoTextureHelper::forceGlTextureExternalOesIsSet()
58 && rhi && rhi->backend() == QRhi::OpenGLES2)
61 setShaderFileName(FragmentStage, QVideoTextureHelper::fragmentShaderFileName(
62 m_videoFormat, rhi, m_surfaceFormat));
68 QSGMaterial *oldMaterial)
override;
71 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
override;
81#if QT_CONFIG(opengles2)
82 qDebug() <<
"QSGVideoMaterialRhiShader: Setting up external OES shader for OpenGLES2";
84 using namespace Qt::Literals::StringLiterals;
85 QByteArray fragmentShader = R"(
86 #extension GL_OES_EGL_image_external : require
87 precision highp float;
88 varying vec2 texCoord;
89 uniform samplerExternalOES tex0;
90 void main()
91 {
92 gl_FragColor = texture2D(tex0, texCoord);
93 }
94 )"_ba;
96 QShaderDescription desc;
97 QShaderDescriptionPrivate *descData = QShaderDescriptionPrivate::get(&desc);
99 QShaderDescription::InOutVariable texCoordInput;
100 texCoordInput.name =
"texCoord";
101 texCoordInput.type = QShaderDescription::Vec2;
102 texCoordInput.location = 0;
104 descData->inVars = { texCoordInput };
106 QShaderDescription::InOutVariable fragColorOutput;
107 fragColorOutput.name =
"gl_FragColor";
108 fragColorOutput.type = QShaderDescription::Vec4;
109 fragColorOutput.location = 0;
111 descData->outVars = { fragColorOutput };
113 QShaderDescription::InOutVariable samplerTex0;
114 samplerTex0.name =
"tex0";
115 samplerTex0.type = QShaderDescription::SamplerExternalOES;
116 samplerTex0.binding = 1;
118 descData->combinedImageSamplers = { samplerTex0 };
121 shaderPack.setStage(QShader::FragmentStage);
122 shaderPack.setDescription(desc);
123 shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)),
124 QShaderCode(fragmentShader));
126 setShader(FragmentStage, shaderPack);
136 static constexpr int NFormats = QRhiSwapChain::HDRExtendedDisplayP3Linear + 1;
137 static QSGMaterialType type[QVideoFrameFormat::NPixelFormats][NFormats];
138 return &type[m_videoFormat.pixelFormat()][m_surfaceFormat];
142 return new QSGVideoMaterialRhiShader(m_videoFormat, m_surfaceFormat, m_hdrInfo, m_rhi);
145 int compare(
const QSGMaterial *other)
const override {
148 qint64 diff = m_textures[0].comparisonKey() - m->m_textures[0].comparisonKey();
150 diff = m_textures[1].comparisonKey() - m->m_textures[1].comparisonKey();
152 diff = m_textures[2].comparisonKey() - m->m_textures[2].comparisonKey();
154 return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
159 setFlag(Blending, !qFuzzyCompare(m_opacity,
float(1.0)));
164 m_surfaceFormat = surfaceFormat;
187 if (!m_texturePool->texturesDirty())
190 QVideoFrameTextures *textures = m_texturePool->updateTextures(*rhi, *resourceUpdates);
194 for (
int plane = 0; plane < 3; ++plane)
195 m_textures[plane].setRhiTexture(textures->texture(plane));
200 QSGMaterial *oldMaterial)
202 Q_UNUSED(oldMaterial);
206 if (!state.isMatrixDirty() && !state.isOpacityDirty())
209 if (state.isOpacityDirty()) {
210 m->m_opacity = state.opacity();
217 m->updateTextures(state.rhi(), state.resourceUpdateBatch());
220 if (m_surfaceFormat == QRhiSwapChain::HDRExtendedSrgbLinear) {
221 if (m_hdrInfo.limitsType == QRhiSwapChainHdrInfo::ColorComponentValue)
222 maxNits = 100 * m_hdrInfo.limits.colorComponentValue.maxColorComponentValue;
224 maxNits = m_hdrInfo.limits.luminanceInNits.maxLuminance;
227 QVideoTextureHelper::updateUniformData(state.uniformData(), m->m_rhi, m_videoFormat,
228 m->m_texturePool->currentFrame(), state.combinedMatrix(),
229 state.opacity(), maxNits);
235 QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
238 Q_UNUSED(oldMaterial);
239 if (binding < 1 || binding > 3)
243 *texture = &m->m_textures[binding - 1];
250 setFlag(Blending,
false);
257 setFlag(QSGNode::OwnsMaterial);
258 setFlag(QSGNode::OwnsGeometry);
260 setMaterial(m_material);
265 delete m_subtitleTextNode;
270 texturePool()->setCurrentFrame(frame);
271 markDirty(DirtyMaterial);
272 updateSubtitle(frame);
277 m_material->setSurfaceFormat(surfaceFormat);
278 markDirty(DirtyMaterial);
283 m_material->setHdrInfo(hdrInfo);
284 markDirty(DirtyMaterial);
287void QSGVideoNode::updateSubtitle(
const QVideoFrame &frame)
289 QSize subtitleFrameSize = m_rect.size().toSize();
290 if (subtitleFrameSize.isEmpty())
293 subtitleFrameSize = qRotatedFrameSize(subtitleFrameSize, m_videoOutputTransformation.rotation);
295 if (!m_subtitleLayout.update(subtitleFrameSize, frame.subtitleText()))
298 delete m_subtitleTextNode;
299 m_subtitleTextNode =
nullptr;
300 if (frame.subtitleText().isEmpty())
303 QQuickItemPrivate *parent_d = QQuickItemPrivate::get(m_parent);
305 m_subtitleTextNode = parent_d->sceneGraphContext()->createInternalTextNode(parent_d->sceneGraphRenderContext());
306 m_subtitleTextNode->setColor(Qt::white);
307 QColor bgColor = Qt::black;
308 bgColor.setAlpha(128);
309 m_subtitleTextNode->addRectangleNode(m_subtitleLayout.bounds, bgColor);
310 m_subtitleTextNode->addTextLayout(m_subtitleLayout.layout.position(), &m_subtitleLayout.layout);
311 appendChildNode(m_subtitleTextNode);
312 setSubtitleGeometry();
317 if (!m_subtitleTextNode)
321 updateSubtitle(texturePool()->currentFrame());
323 float rotate = -1.f * qToUnderlying(m_videoOutputTransformation.rotation);
324 float yTranslate = 0;
325 float xTranslate = 0;
326 if (m_videoOutputTransformation.rotation == QtVideo::Rotation::Clockwise90) {
327 yTranslate = m_rect.height();
328 }
else if (m_videoOutputTransformation.rotation == QtVideo::Rotation::Clockwise180) {
329 yTranslate = m_rect.height();
330 xTranslate = m_rect.width();
331 }
else if (m_videoOutputTransformation.rotation == QtVideo::Rotation::Clockwise270) {
332 xTranslate = m_rect.width();
335 QMatrix4x4 transform;
336 transform.translate(m_rect.x() + xTranslate, m_rect.y() + yTranslate);
337 transform.rotate(rotate, 0, 0, 1);
342 m_subtitleTextNode->setMatrix(transform);
343 m_subtitleTextNode->markDirty(DirtyGeometry);
348 VideoTransformation videoOutputTransformation)
350 const VideoTransformation currentFrameTransformation = qNormalizedFrameTransformation(
351 m_material ? texturePool()->currentFrame() : QVideoFrame{}, videoOutputTransformation);
353 if (rect == m_rect && textureRect == m_textureRect
354 && videoOutputTransformation == m_videoOutputTransformation
355 && currentFrameTransformation == m_frameTransformation)
359 m_textureRect = textureRect;
360 m_videoOutputTransformation = videoOutputTransformation;
361 m_frameTransformation = currentFrameTransformation;
363 QSGGeometry *g = geometry();
366 g =
new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
368 QSGGeometry::TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
376 qSetGeom(v + 0, rect.topLeft());
377 qSetGeom(v + 1, rect.bottomLeft());
378 qSetGeom(v + 2, rect.topRight());
379 qSetGeom(v + 3, rect.bottomRight());
382 switch (currentFrameTransformation.rotation) {
385 qSetTex(v + 0, textureRect.topLeft());
386 qSetTex(v + 1, textureRect.bottomLeft());
387 qSetTex(v + 2, textureRect.topRight());
388 qSetTex(v + 3, textureRect.bottomRight());
391 case QtVideo::Rotation::Clockwise90:
393 qSetTex(v + 0, textureRect.bottomLeft());
394 qSetTex(v + 1, textureRect.bottomRight());
395 qSetTex(v + 2, textureRect.topLeft());
396 qSetTex(v + 3, textureRect.topRight());
399 case QtVideo::Rotation::Clockwise180:
401 qSetTex(v + 0, textureRect.bottomRight());
402 qSetTex(v + 1, textureRect.topRight());
403 qSetTex(v + 2, textureRect.bottomLeft());
404 qSetTex(v + 3, textureRect.topLeft());
407 case QtVideo::Rotation::Clockwise270:
409 qSetTex(v + 0, textureRect.topRight());
410 qSetTex(v + 1, textureRect.topLeft());
411 qSetTex(v + 2, textureRect.bottomRight());
412 qSetTex(v + 3, textureRect.bottomLeft());
416 if (m_frameTransformation.mirroredHorizontallyAfterRotation) {
417 qSwapTex(v + 0, v + 2);
418 qSwapTex(v + 1, v + 3);
424 markDirty(DirtyGeometry);
426 setSubtitleGeometry();
431 return m_material->m_texturePool;
QVideoFrameFormat m_videoFormat
QRhiSwapChainHdrInfo m_hdrInfo
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QSGVideoMaterialRhiShader(const QVideoFrameFormat &videoFormat, const QRhiSwapChain::Format surfaceFormat, const QRhiSwapChainHdrInfo &hdrInfo, QRhi *rhi)
QRhiSwapChain::Format m_surfaceFormat
void setupExternalOESShader()
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to prepare use of sampled images in the shader,...
QVideoFrameTexturePoolPtr m_texturePool
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
void updateTextures(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
void setHdrInfo(const QRhiSwapChainHdrInfo &hdrInfo)
int compare(const QSGMaterial *other) const override
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
QRhiSwapChainHdrInfo m_hdrInfo
std::array< QSGVideoTexture, 3 > m_textures
void setSurfaceFormat(const QRhiSwapChain::Format surfaceFormat)
QSGVideoMaterial(const QVideoFrameFormat &videoFormat, QRhi *rhi)
QRhiSwapChain::Format m_surfaceFormat
QVideoFrameFormat m_videoFormat
const QVideoFrameTexturePoolPtr & texturePool() const
void setHdrInfo(const QRhiSwapChainHdrInfo &hdrInfo)
void setSurfaceFormat(const QRhiSwapChain::Format surfaceFormat)
QSGVideoNode(QQuickVideoOutput *parent, const QVideoFrameFormat &videoFormat, QRhi *rhi)
void setCurrentFrame(const QVideoFrame &frame)
void setTexturedRectGeometry(const QRectF &boundingRect, const QRectF &textureRect, VideoTransformation videoOutputTransformation)
static void qSetTex(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
static QT_BEGIN_NAMESPACE void qSetGeom(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
static void qSwapTex(QSGGeometry::TexturedPoint2D *v0, QSGGeometry::TexturedPoint2D *v1)