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#include "private/qvideoframe_p.h"
12
13#include <QOpenGLContext>
14#include <QThread>
15
16#include <unistd.h>
17
18#include <QtMultimedia/private/qtmultimediaglobal_p.h>
19#include "private/qgstvideobuffer_p.h"
20#if GST_CHECK_VERSION(1,14,0)
21#include <gst/allocators/gstphysmemory.h>
22#endif
23
24//#define QT_VIVANTE_VIDEO_DEBUG
25
27 mOpacity(1.0),
28 mWidth(0),
29 mHeight(0),
30 mFormat(QVideoFrameFormat::Format_Invalid),
31 mCurrentTexture(0),
32 mMappable(true),
33 mTexDirectTexture(0)
34{
35#ifdef QT_VIVANTE_VIDEO_DEBUG
37#endif
38
39 setFlag(Blending, false);
40
42}
43
48
50 static QSGMaterialType theType;
51 return &theType;
52}
53
57
59 if (this->type() == other->type()) {
60 const QSGVivanteVideoMaterial *m = static_cast<const QSGVivanteVideoMaterial *>(other);
61 if (this->mBitsToTextureMap == m->mBitsToTextureMap)
62 return 0;
63 else
64 return 1;
65 }
66 return 1;
67}
68
70 setFlag(Blending, qFuzzyCompare(mOpacity, qreal(1.0)) ? false : true);
71}
72
74{
75 QMutexLocker lock(&mFrameMutex);
76 mCurrentFrame = frame;
77 mMappable = mMapError == GL_NO_ERROR;
78
79#ifdef QT_VIVANTE_VIDEO_DEBUG
80 qDebug() << Q_FUNC_INFO << " new frame: " << frame;
81#endif
82}
83
85{
87 if (glcontext == 0) {
88 qWarning() << Q_FUNC_INFO << "no QOpenGLContext::currentContext() => return";
89 return;
90 }
91
92 QMutexLocker lock(&mFrameMutex);
93 if (mCurrentFrame.isValid())
94 mCurrentTexture = vivanteMapping(mCurrentFrame);
95 else
96 glBindTexture(GL_TEXTURE_2D, mCurrentTexture);
97}
98
99void QSGVivanteVideoMaterial::clearTextures()
100{
101 for (auto it = mBitsToTextureMap.cbegin(), end = mBitsToTextureMap.cend(); it != end; ++it) {
102 GLuint id = it.value();
103#ifdef QT_VIVANTE_VIDEO_DEBUG
104 qDebug() << "delete texture: " << id;
105#endif
106 glDeleteTextures(1, &id);
107 }
108 mBitsToTextureMap.clear();
109
110 if (mTexDirectTexture) {
111 glDeleteTextures(1, &mTexDirectTexture);
112 mTexDirectTexture = 0;
113 }
114}
115
117{
119 if (glcontext == 0) {
120 qWarning() << Q_FUNC_INFO << "no QOpenGLContext::currentContext() => return 0";
121 return 0;
122 }
123
124 static PFNGLTEXDIRECTVIVPROC glTexDirectVIV_LOCAL = 0;
125 static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap_LOCAL = 0;
126 static PFNGLTEXDIRECTINVALIDATEVIVPROC glTexDirectInvalidateVIV_LOCAL = 0;
127
128 if (glTexDirectVIV_LOCAL == 0 || glTexDirectVIVMap_LOCAL == 0 || glTexDirectInvalidateVIV_LOCAL == 0) {
129 glTexDirectVIV_LOCAL = reinterpret_cast<PFNGLTEXDIRECTVIVPROC>(glcontext->getProcAddress("glTexDirectVIV"));
130 glTexDirectVIVMap_LOCAL = reinterpret_cast<PFNGLTEXDIRECTVIVMAPPROC>(glcontext->getProcAddress("glTexDirectVIVMap"));
131 glTexDirectInvalidateVIV_LOCAL = reinterpret_cast<PFNGLTEXDIRECTINVALIDATEVIVPROC>(glcontext->getProcAddress("glTexDirectInvalidateVIV"));
132 }
133 if (glTexDirectVIV_LOCAL == 0 || glTexDirectVIVMap_LOCAL == 0 || glTexDirectInvalidateVIV_LOCAL == 0) {
134 qWarning() << Q_FUNC_INFO << "couldn't find \"glTexDirectVIVMap\" and/or \"glTexDirectInvalidateVIV\" => do nothing and return";
135 return 0;
136 }
137
138 if (mWidth != vF.width() || mHeight != vF.height() || mFormat != vF.pixelFormat()) {
139 mWidth = vF.width();
140 mHeight = vF.height();
141 mFormat = vF.pixelFormat();
142 mMapError = GL_NO_ERROR;
143 clearTextures();
144 }
145
146 if (vF.map(QtVideo::MapMode::ReadOnly)) {
147
148 if (mMappable) {
149 if (!mBitsToTextureMap.contains(vF.bits())) {
150 // Haven't yet seen this logical address: map to texture.
151 GLuint tmpTexId;
152 glGenTextures(1, &tmpTexId);
153 mBitsToTextureMap.insert(vF.bits(), tmpTexId);
154
155 // Determine the full width & height. Full means: actual width/height plus extra padding pixels.
156 // The full width can be deduced from the bytesPerLine value. The full height is calculated
157 // by calculating the distance between the start of the first and second planes, and dividing
158 // it by the stride (= the bytesPerLine). If there is only one plane, we don't worry about
159 // extra padding rows, since there are no adjacent extra planes.
160 // XXX: This assumes the distance between bits(1) and bits(0) is exactly the size of the first
161 // plane (the Y plane in the case of YUV data). A better way would be to have a dedicated
162 // planeSize() or planeOffset() getter.
163 // Also, this assumes that planes are tightly packed, that is, there is no space between them.
164 // It is okay to assume this here though, because the Vivante direct textures also assume that.
165 // In other words, if the planes aren't tightly packed, then the direct textures won't be able
166 // to render the frame correctly anyway.
167 int fullWidth = vF.bytesPerLine() / QSGVivanteVideoNode::getBytesForPixelFormat(vF.pixelFormat());
168 int fullHeight = (vF.planeCount() > 1) ? ((vF.bits(1) - vF.bits(0)) / vF.bytesPerLine()) : vF.height();
169
170 // The uscale is the ratio of actual width to the full width (same for vscale and height).
171 // Since the vivante direct textures do not offer a way to explicitly specify the amount of padding
172 // columns and rows, we use a trick. We show the full frame - including the padding pixels - in the
173 // texture, but render only a subset of that texture. This subset goes from (0,0) to (uScale, vScale).
174 // In the shader, the texture coordinates (which go from (0.0, 0.0) to (1.0, 1.0)) are multiplied by
175 // the u/v scale values. Since 1.0 * x = x, this effectively limits the texture coordinates from
176 // (0.0, 0.0) - (1.0, 1.0) to (0.0, 0.0) - (uScale, vScale).
177 float uScale = float(vF.width()) / float(fullWidth);
178 float vScale = float(vF.height()) / float(fullHeight);
179 mShader->setUVScale(uScale, vScale);
180
181 const uchar *constBits = vF.bits();
182 void *bits = (void*)constBits;
183
184#ifdef QT_VIVANTE_VIDEO_DEBUG
186 << "new texture, texId: " << tmpTexId
187 << "; constBits: " << constBits
188 << "; actual/full width: " << vF.width() << "/" << fullWidth
189 << "; actual/full height: " << vF.height() << "/" << fullHeight
190 << "; UV scale: U " << uScale << " V " << vScale;
191#endif
192
193 GLuint physical = ~0U;
194#if GST_CHECK_VERSION(1,14,0)
195 auto buffer = reinterpret_cast<QGstVideoBuffer *>(QVideoFramePrivate::buffer(vF));
196 auto mem = gst_buffer_peek_memory(buffer->buffer(), 0);
197 auto phys_addr = gst_is_phys_memory(mem) ? gst_phys_memory_get_phys_addr(mem) : 0;
198 if (phys_addr)
199 physical = phys_addr;
200#endif
201 glBindTexture(GL_TEXTURE_2D, tmpTexId);
202 glTexDirectVIVMap_LOCAL(GL_TEXTURE_2D,
203 fullWidth, fullHeight,
205 &bits, &physical);
206
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
211 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
212
213 mMapError = glGetError();
214 if (mMapError == GL_NO_ERROR)
215 return tmpTexId;
216
217 // Error occurred.
218 // Fallback to copying data.
219 } else {
220 // Fastest path: already seen this logical address. Just
221 // indicate that the data belonging to the texture has changed.
222 glBindTexture(GL_TEXTURE_2D, mBitsToTextureMap.value(vF.bits()));
223 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
224 return mBitsToTextureMap.value(vF.bits());
225 }
226 }
227
228 // Cannot map. So copy.
229 if (!mTexDirectTexture) {
230 glGenTextures(1, &mTexDirectTexture);
231 glBindTexture(GL_TEXTURE_2D, mTexDirectTexture);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
236 glTexDirectVIV_LOCAL(GL_TEXTURE_2D, mCurrentFrame.width(), mCurrentFrame.height(),
238 (GLvoid **) &mTexDirectPlanes);
239 } else {
240 glBindTexture(GL_TEXTURE_2D, mTexDirectTexture);
241 }
242 switch (mCurrentFrame.pixelFormat()) {
245 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0));
246 memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1));
247 memcpy(mTexDirectPlanes[2], mCurrentFrame.bits(2), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(2));
248 break;
251 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0));
252 memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1));
253 break;
254 default:
255 memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(), mCurrentFrame.height() * mCurrentFrame.bytesPerLine());
256 break;
257 }
258 glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D);
259 return mTexDirectTexture;
260 }
261 else {
262#ifdef QT_VIVANTE_VIDEO_DEBUG
263 qWarning() << " couldn't map the QVideoFrame vF: " << vF;
264#endif
265 return 0;
266 }
267
268 Q_ASSERT(false); // should never reach this line!;
269 return 0;
270}
iterator insert(const Key &key, const T &value)
Definition qmap.h:689
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:358
bool contains(const Key &key) const
Definition qmap.h:342
const_iterator cend() const
Definition qmap.h:606
const_iterator cbegin() const
Definition qmap.h:602
void clear()
Definition qmap.h:290
\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.
static QAbstractVideoBuffer * buffer(const QVideoFrame &frame)
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:165
#define qWarning
Definition qlogging.h:167
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.