Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsgvivantevideomaterial.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Pelagicore AG
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <GLES2/gl2.h>
5#include <GLES2/gl2ext.h>
6
10#include "private/qsgvideotexture_p.h"
11
12#include <QOpenGLContext>
13#include <QThread>
14
15#include <unistd.h>
16
17#include <QtMultimedia/private/qtmultimediaglobal_p.h>
18#include "private/qgstvideobuffer_p.h"
19#if GST_CHECK_VERSION(1,14,0)
20#include <gst/allocators/gstphysmemory.h>
21#endif
22
23//#define QT_VIVANTE_VIDEO_DEBUG
24
26 mOpacity(1.0),
27 mWidth(0),
28 mHeight(0),
29 mFormat(QVideoFrameFormat::Format_Invalid),
30 mCurrentTexture(0),
31 mMappable(true),
32 mTexDirectTexture(0)
33{
34#ifdef QT_VIVANTE_VIDEO_DEBUG
36#endif
37
38 setFlag(Blending, false);
39
41}
42
47
49 static QSGMaterialType theType;
50 return &theType;
51}
52
56
58 if (this->type() == other->type()) {
59 const QSGVivanteVideoMaterial *m = static_cast<const QSGVivanteVideoMaterial *>(other);
60 if (this->mBitsToTextureMap == m->mBitsToTextureMap)
61 return 0;
62 else
63 return 1;
64 }
65 return 1;
66}
67
69 setFlag(Blending, qFuzzyCompare(mOpacity, qreal(1.0)) ? false : true);
70}
71
73{
74 QMutexLocker lock(&mFrameMutex);
75 mCurrentFrame = frame;
76 mMappable = mMapError == GL_NO_ERROR;
77
78#ifdef QT_VIVANTE_VIDEO_DEBUG
79 qDebug() << Q_FUNC_INFO << " new frame: " << frame;
80#endif
81}
82
84{
86 if (glcontext == 0) {
87 qWarning() << Q_FUNC_INFO << "no QOpenGLContext::currentContext() => return";
88 return;
89 }
90
91 QMutexLocker lock(&mFrameMutex);
92 if (mCurrentFrame.isValid())
93 mCurrentTexture = vivanteMapping(mCurrentFrame);
94 else
95 glBindTexture(GL_TEXTURE_2D, mCurrentTexture);
96}
97
98void QSGVivanteVideoMaterial::clearTextures()
99{
100 for (auto it = mBitsToTextureMap.cbegin(), end = mBitsToTextureMap.cend(); it != end; ++it) {
101 GLuint id = it.value();
102#ifdef QT_VIVANTE_VIDEO_DEBUG
103 qDebug() << "delete texture: " << id;
104#endif
105 glDeleteTextures(1, &id);
106 }
107 mBitsToTextureMap.clear();
108
109 if (mTexDirectTexture) {
110 glDeleteTextures(1, &mTexDirectTexture);
111 mTexDirectTexture = 0;
112 }
113}
114
116{
118 if (glcontext == 0) {
119 qWarning() << Q_FUNC_INFO << "no QOpenGLContext::currentContext() => return 0";
120 return 0;
121 }
122
123 static PFNGLTEXDIRECTVIVPROC glTexDirectVIV_LOCAL = 0;
124 static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap_LOCAL = 0;
125 static PFNGLTEXDIRECTINVALIDATEVIVPROC glTexDirectInvalidateVIV_LOCAL = 0;
126
127 if (glTexDirectVIV_LOCAL == 0 || glTexDirectVIVMap_LOCAL == 0 || glTexDirectInvalidateVIV_LOCAL == 0) {
128 glTexDirectVIV_LOCAL = reinterpret_cast<PFNGLTEXDIRECTVIVPROC>(glcontext->getProcAddress("glTexDirectVIV"));
129 glTexDirectVIVMap_LOCAL = reinterpret_cast<PFNGLTEXDIRECTVIVMAPPROC>(glcontext->getProcAddress("glTexDirectVIVMap"));
130 glTexDirectInvalidateVIV_LOCAL = reinterpret_cast<PFNGLTEXDIRECTINVALIDATEVIVPROC>(glcontext->getProcAddress("glTexDirectInvalidateVIV"));
131 }
132 if (glTexDirectVIV_LOCAL == 0 || glTexDirectVIVMap_LOCAL == 0 || glTexDirectInvalidateVIV_LOCAL == 0) {
133 qWarning() << Q_FUNC_INFO << "couldn't find \"glTexDirectVIVMap\" and/or \"glTexDirectInvalidateVIV\" => do nothing and return";
134 return 0;
135 }
136
137 if (mWidth != vF.width() || mHeight != vF.height() || mFormat != vF.pixelFormat()) {
138 mWidth = vF.width();
139 mHeight = vF.height();
140 mFormat = vF.pixelFormat();
141 mMapError = GL_NO_ERROR;
142 clearTextures();
143 }
144
145 if (vF.map(QVideoFrame::ReadOnly)) {
146
147 if (mMappable) {
148 if (!mBitsToTextureMap.contains(vF.bits())) {
149 // Haven't yet seen this logical address: map to texture.
150 GLuint tmpTexId;
151 glGenTextures(1, &tmpTexId);
152 mBitsToTextureMap.insert(vF.bits(), tmpTexId);
153
154 // Determine the full width & height. Full means: actual width/height plus extra padding pixels.
155 // The full width can be deduced from the bytesPerLine value. The full height is calculated
156 // by calculating the distance between the start of the first and second planes, and dividing
157 // it by the stride (= the bytesPerLine). If there is only one plane, we don't worry about
158 // extra padding rows, since there are no adjacent extra planes.
159 // XXX: This assumes the distance between bits(1) and bits(0) is exactly the size of the first
160 // plane (the Y plane in the case of YUV data). A better way would be to have a dedicated
161 // planeSize() or planeOffset() getter.
162 // Also, this assumes that planes are tightly packed, that is, there is no space between them.
163 // It is okay to assume this here though, because the Vivante direct textures also assume that.
164 // In other words, if the planes aren't tightly packed, then the direct textures won't be able
165 // to render the frame correctly anyway.
166 int fullWidth = vF.bytesPerLine() / QSGVivanteVideoNode::getBytesForPixelFormat(vF.pixelFormat());
167 int fullHeight = (vF.planeCount() > 1) ? ((vF.bits(1) - vF.bits(0)) / vF.bytesPerLine()) : vF.height();
168
169 // The uscale is the ratio of actual width to the full width (same for vscale and height).
170 // Since the vivante direct textures do not offer a way to explicitly specify the amount of padding
171 // columns and rows, we use a trick. We show the full frame - including the padding pixels - in the
172 // texture, but render only a subset of that texture. This subset goes from (0,0) to (uScale, vScale).
173 // In the shader, the texture coordinates (which go from (0.0, 0.0) to (1.0, 1.0)) are multiplied by
174 // the u/v scale values. Since 1.0 * x = x, this effectively limits the texture coordinates from
175 // (0.0, 0.0) - (1.0, 1.0) to (0.0, 0.0) - (uScale, vScale).
176 float uScale = float(vF.width()) / float(fullWidth);
177 float vScale = float(vF.height()) / float(fullHeight);
178 mShader->setUVScale(uScale, vScale);
179
180 const uchar *constBits = vF.bits();
181 void *bits = (void*)constBits;
182
183#ifdef QT_VIVANTE_VIDEO_DEBUG
185 << "new texture, texId: " << tmpTexId
186 << "; constBits: " << constBits
187 << "; actual/full width: " << vF.width() << "/" << fullWidth
188 << "; actual/full height: " << vF.height() << "/" << fullHeight
189 << "; UV scale: U " << uScale << " V " << vScale;
190#endif
191
192 GLuint physical = ~0U;
193#if GST_CHECK_VERSION(1,14,0)
194 auto buffer = reinterpret_cast<QGstVideoBuffer *>(vF.buffer());
195 auto mem = gst_buffer_peek_memory(buffer->buffer(), 0);
196 auto phys_addr = gst_is_phys_memory(mem) ? gst_phys_memory_get_phys_addr(mem) : 0;
197 if (phys_addr)
198 physical = phys_addr;
199#endif
200 glBindTexture(GL_TEXTURE_2D, tmpTexId);
201 glTexDirectVIVMap_LOCAL(GL_TEXTURE_2D,
202 fullWidth, fullHeight,
204 &bits, &physical);
205
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
210 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
211
212 mMapError = glGetError();
213 if (mMapError == GL_NO_ERROR)
214 return tmpTexId;
215
216 // Error occurred.
217 // Fallback to copying data.
218 } else {
219 // Fastest path: already seen this logical address. Just
220 // indicate that the data belonging to the texture has changed.
221 glBindTexture(GL_TEXTURE_2D, mBitsToTextureMap.value(vF.bits()));
222 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
223 return mBitsToTextureMap.value(vF.bits());
224 }
225 }
226
227 // Cannot map. So copy.
228 if (!mTexDirectTexture) {
229 glGenTextures(1, &mTexDirectTexture);
230 glBindTexture(GL_TEXTURE_2D, mTexDirectTexture);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
235 glTexDirectVIV_LOCAL(GL_TEXTURE_2D, mCurrentFrame.width(), mCurrentFrame.height(),
237 (GLvoid **) &mTexDirectPlanes);
238 } else {
239 glBindTexture(GL_TEXTURE_2D, mTexDirectTexture);
240 }
241 switch (mCurrentFrame.pixelFormat()) {
244 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0));
245 memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1));
246 memcpy(mTexDirectPlanes[2], mCurrentFrame.bits(2), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(2));
247 break;
250 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0));
251 memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1));
252 break;
253 default:
254 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(), mCurrentFrame.height() * mCurrentFrame.bytesPerLine());
255 break;
256 }
257 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
258 return mTexDirectTexture;
259 }
260 else {
261#ifdef QT_VIVANTE_VIDEO_DEBUG
262 qWarning() << " couldn't map the QVideoFrame vF: " << vF;
263#endif
264 return 0;
265 }
266
267 Q_ASSERT(false); // should never reach this line!;
268 return 0;
269}
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
bool contains(const Key &key) const
Definition qmap.h:341
const_iterator cend() const
Definition qmap.h:605
const_iterator cbegin() const
Definition qmap.h:601
void clear()
Definition qmap.h:289
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtGui
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
The QSGMaterialShader class represents a graphics API independent shader program.
The QSGMaterial class encapsulates rendering state for a shader program.
Definition qsgmaterial.h:15
virtual QSGMaterialType * type() const =0
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
void setFlag(Flags flags, bool on=true)
Sets the flags flags on this material if on is true; otherwise clears the attribute.
RenderMode
\value RenderMode2D Normal 2D rendering \value RenderMode2DNoDepthBuffer Normal 2D rendering with dep...
void setUVScale(float uScale, float vScale)
void setCurrentFrame(const QVideoFrame &frame, QSGVideoNode::FrameFlags flags)
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...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
GLuint vivanteMapping(QVideoFrame texIdVideoFramePair)
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
static int getBytesForPixelFormat(QVideoFrameFormat::PixelFormat pixelformat)
static const QMap< QVideoFrameFormat::PixelFormat, GLenum > & getVideoFormat2GLFormatMap()
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
int height() const
Returns the height of a video frame.
uchar * bits(int plane)
Returns a pointer to the start of the frame data buffer for a plane.
QVideoFrameFormat::PixelFormat pixelFormat() const
Returns the pixel format of this video frame.
bool isValid() const
Identifies whether a video frame is valid.
int width() const
Returns the width of a video frame.
int bytesPerLine(int plane) const
Returns the number of bytes in a scan line of a plane.
QSet< QString >::iterator it
#define Q_FUNC_INFO
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
const GLfloat * m
GLuint GLuint end
GLenum GLuint id
[7]
GLenum GLuint buffer
GLbitfield flags
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define GL_CLAMP_TO_EDGE
Definition qopenglext.h:100
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GLuint
unsigned char uchar
Definition qtypes.h:32
double qreal
Definition qtypes.h:187
QReadWriteLock lock
[0]
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.