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
qgstvideobuffer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
5#include <private/qvideotexturehelper_p.h>
6#include <QtCore/qloggingcategory.h>
7
8#include <gst/video/video.h>
9#include <gst/video/video-frame.h>
10#include <gst/video/gstvideometa.h>
11#include <gst/pbutils/gstpluginsbaseversion.h>
12
13#include <common/qgstutils_p.h>
14
15#if QT_CONFIG(gstreamer_gl)
16# include <QtGui/rhi/qrhi.h>
17# include <QtGui/qopenglcontext.h>
18# include <QtGui/qopenglfunctions.h>
19# include <QtGui/qopengl.h>
20
21# include <gst/gl/gstglconfig.h>
22# include <gst/gl/gstglmemory.h>
23# include <gst/gl/gstglsyncmeta.h>
24
25# if QT_CONFIG(gstreamer_gl_egl)
26# include <EGL/egl.h>
27# include <EGL/eglext.h>
28# endif
29
30# if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
31# include <common/qgstreameregldisplay_p.h>
32# include <gst/allocators/gstdmabuf.h>
33# endif
34#endif
35
37
38Q_STATIC_LOGGING_CATEGORY(qLcGstVideoBuffer, "qt.multimedia.gstreamer.videobuffer");
39
40// keep things building without drm_fourcc.h
41#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) |
42 ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
43#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
44#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */
45#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
46#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
47#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */
48#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */
49#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */
50#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
51#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
52#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
53#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
54#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
55#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
56#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
57#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
58#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
59#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
60#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */
61#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
62#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */
63#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */
64#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
65#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */
66#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */
67#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
68
69QGstVideoBuffer::QGstVideoBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo,
70 const QVideoFrameFormat &frameFormat)
77{
78 m_type = m_memoryFormat != QGstCaps::CpuMemory ? QVideoFrame::RhiTextureHandle
79 : QVideoFrame::NoHandle;
80}
81
82QGstVideoBuffer::~QGstVideoBuffer()
83{
84 Q_ASSERT(m_mode == QVideoFrame::NotMapped);
85}
86
87QAbstractVideoBuffer::MapData QGstVideoBuffer::map(QVideoFrame::MapMode mode)
88{
89 const GstMapFlags flags = GstMapFlags(((mode & QVideoFrame::ReadOnly) ? GST_MAP_READ : 0)
90 | ((mode & QVideoFrame::WriteOnly) ? GST_MAP_WRITE : 0));
91
92 MapData mapData;
93 if (mode == QVideoFrame::NotMapped || m_mode != QVideoFrame::NotMapped)
94 return mapData;
95
96 const GstVideoInfo &gstVideoInfo = m_videoInfo.gstVideoInfo;
97 if (!gstVideoInfo.finfo || gstVideoInfo.finfo->n_planes == 0) { // Encoded
98 if (gst_buffer_map(m_buffer.get(), &m_frame.map[0], flags)) {
99 mapData.planeCount = 1;
100 mapData.bytesPerLine[0] = -1;
101 mapData.dataSize[0] = m_frame.map[0].size;
102 mapData.data[0] = static_cast<uchar *>(m_frame.map[0].data);
103
104 m_mode = mode;
105 }
106 } else if (gst_video_frame_map(&m_frame, &gstVideoInfo, m_buffer.get(), flags)) {
107 mapData.planeCount = GST_VIDEO_FRAME_N_PLANES(&m_frame);
108
109 for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES(&m_frame); ++i) {
110 mapData.bytesPerLine[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&m_frame, i);
111 mapData.data[i] = static_cast<uchar *>(GST_VIDEO_FRAME_PLANE_DATA(&m_frame, i));
112 mapData.dataSize[i] = mapData.bytesPerLine[i]*GST_VIDEO_FRAME_COMP_HEIGHT(&m_frame, i);
113 }
114
115 m_mode = mode;
116 }
117 return mapData;
118}
119
120void QGstVideoBuffer::unmap()
121{
122 if (m_mode != QVideoFrame::NotMapped) {
123 if (!m_videoInfo.gstVideoInfo.finfo || m_videoInfo.gstVideoInfo.finfo->n_planes == 0)
124 gst_buffer_unmap(m_buffer.get(), &m_frame.map[0]);
125 else
126 gst_video_frame_unmap(&m_frame);
127 }
128 m_mode = QVideoFrame::NotMapped;
129}
130
131bool QGstVideoBuffer::isDmaBuf() const
132{
133 return m_memoryFormat == QGstCaps::DMABuf;
134}
135
136#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
137
138static int
139fourccFromGstVideoFormat(const GstVideoFormat format, int plane, bool singleEGLImage)
140{
141#if G_BYTE_ORDER == G_LITTLE_ENDIAN
142 const gint argb_fourcc = DRM_FORMAT_ARGB8888;
143 const gint rgba_fourcc = DRM_FORMAT_ABGR8888;
144 const gint rgb_fourcc = DRM_FORMAT_BGR888;
145 const gint rg_fourcc = DRM_FORMAT_GR88;
146#else
147 const gint argb_fourcc = DRM_FORMAT_BGRA8888;
148 const gint rgba_fourcc = DRM_FORMAT_RGBA8888;
149 const gint rgb_fourcc = DRM_FORMAT_RGB888;
150 const gint rg_fourcc = DRM_FORMAT_RG88;
151#endif
152
153 switch (format) {
154 case GST_VIDEO_FORMAT_RGB16:
155 case GST_VIDEO_FORMAT_BGR16:
156 return DRM_FORMAT_RGB565;
157
158 case GST_VIDEO_FORMAT_RGB:
159 case GST_VIDEO_FORMAT_BGR:
160 return rgb_fourcc;
161
162 case GST_VIDEO_FORMAT_BGRx:
163 case GST_VIDEO_FORMAT_BGRA:
164 return argb_fourcc;
165
166 case GST_VIDEO_FORMAT_AYUV:
167 if (singleEGLImage) return DRM_FORMAT_AYUV;
168 [[fallthrough]];
169 case GST_VIDEO_FORMAT_RGBx:
170 case GST_VIDEO_FORMAT_RGBA:
171 case GST_VIDEO_FORMAT_ARGB:
172 case GST_VIDEO_FORMAT_xRGB:
173 case GST_VIDEO_FORMAT_ABGR:
174 case GST_VIDEO_FORMAT_xBGR:
175 return rgba_fourcc;
176
177 case GST_VIDEO_FORMAT_GRAY8:
178 return DRM_FORMAT_R8;
179
180 case GST_VIDEO_FORMAT_YUY2:
181 return DRM_FORMAT_YUYV;
182
183 case GST_VIDEO_FORMAT_UYVY:
184 return DRM_FORMAT_UYVY;
185
186 case GST_VIDEO_FORMAT_GRAY16_LE:
187 case GST_VIDEO_FORMAT_GRAY16_BE:
188 if (singleEGLImage) return DRM_FORMAT_R16;
189 return rg_fourcc;
190
191 case GST_VIDEO_FORMAT_NV12:
192 if (singleEGLImage) return DRM_FORMAT_NV12;
193 [[fallthrough]];
194 case GST_VIDEO_FORMAT_NV21:
195 if (singleEGLImage) return DRM_FORMAT_NV21;
196 return plane == 0 ? DRM_FORMAT_R8 : rg_fourcc;
197
198 case GST_VIDEO_FORMAT_I420:
199 if (singleEGLImage) return DRM_FORMAT_YUV420;
200 [[fallthrough]];
201 case GST_VIDEO_FORMAT_YV12:
202 if (singleEGLImage) return DRM_FORMAT_YVU420;
203 [[fallthrough]];
204 case GST_VIDEO_FORMAT_Y41B:
205 if (singleEGLImage) return DRM_FORMAT_YUV411;
206 [[fallthrough]];
207 case GST_VIDEO_FORMAT_Y42B:
208 if (singleEGLImage) return DRM_FORMAT_YUV422;
209 [[fallthrough]];
210 case GST_VIDEO_FORMAT_Y444:
211 if (singleEGLImage) return DRM_FORMAT_YUV444;
212 return DRM_FORMAT_R8;
213
214 case GST_VIDEO_FORMAT_BGR10A2_LE:
215 return DRM_FORMAT_BGRA1010102;
216
217 case GST_VIDEO_FORMAT_P010_10LE:
218 case GST_VIDEO_FORMAT_P010_10BE:
219 if (singleEGLImage) return DRM_FORMAT_P010;
220 return plane == 0 ? DRM_FORMAT_R16 : DRM_FORMAT_RG1616;
221
222 default:
223 return -1;
224 }
225}
226
227static void logGlAndEglErrors(const char *context)
228{
229 if (!qLcGstVideoBuffer().isDebugEnabled())
230 return;
231
232 const GLenum glError = glGetError();
233 const EGLint eglError = eglGetError();
234 if (glError == GL_NO_ERROR && eglError == EGL_SUCCESS)
235 return;
236
237 qCDebug(qLcGstVideoBuffer).nospace()
238 << context << ": GL error 0x" << Qt::hex << glError
239 << ", EGL error 0x" << eglError;
240}
241#endif
242
243#if QT_CONFIG(gstreamer_gl)
244struct GlTextures
245{
246 uint count = 0;
247 bool owned = false;
248 std::array<guint32, QVideoTextureHelper::TextureDescription::maxPlanes> names{};
249};
250
251class QGstQVideoFrameTextures : public QVideoFrameTextures
252{
253public:
254 QGstQVideoFrameTextures(QRhi *rhi,
255 QSize size,
256 QVideoFrameFormat::PixelFormat format,
257 GlTextures &textures,
258 QGstCaps::MemoryFormat memoryFormat)
259 : m_rhi(rhi)
260 , m_glTextures(textures)
261 {
262 QRhiTexture::Flags textureFlags = {};
263 if (QVideoTextureHelper::forceGlTextureExternalOesIsSet()
264 && m_rhi && rhi->backend() == QRhi::OpenGLES2)
265 textureFlags = {QRhiTexture::ExternalOES};
266
267 bool isDmaBuf = memoryFormat == QGstCaps::DMABuf;
268 auto fallbackPolicy = isDmaBuf
269 ? QVideoTextureHelper::TextureDescription::FallbackPolicy::Disable
270 : QVideoTextureHelper::TextureDescription::FallbackPolicy::Enable;
271
272 auto desc = QVideoTextureHelper::textureDescription(format);
273 for (uint i = 0; i < textures.count; ++i) {
274 // Pass nullptr to rhiPlaneSize to disable fallback in its call to rhiTextureFormat
275 QSize planeSize = desc->rhiPlaneSize(size, i, isDmaBuf ? nullptr : m_rhi);
276 QRhiTexture::Format format = desc->rhiTextureFormat(i, m_rhi, fallbackPolicy);
277 m_textures[i].reset(rhi->newTexture(format, planeSize, 1, textureFlags));
278 m_textures[i]->createFrom({textures.names[i], 0});
279 }
280 }
281
282 ~QGstQVideoFrameTextures() override
283 {
284 m_rhi->makeThreadLocalNativeContextCurrent();
285 auto ctx = QOpenGLContext::currentContext();
286 if (m_glTextures.owned && ctx)
287 ctx->functions()->glDeleteTextures(int(m_glTextures.count), m_glTextures.names.data());
288 }
289
290 QRhiTexture *texture(uint plane) const override
291 {
292 return plane < m_glTextures.count ? m_textures[plane].get() : nullptr;
293 }
294
295private:
296 QRhi *m_rhi = nullptr;
297 GlTextures m_glTextures;
298 std::unique_ptr<QRhiTexture> m_textures[QVideoTextureHelper::TextureDescription::maxPlanes];
299};
300
301static GlTextures mapFromGlTexture(const QGstBufferHandle &bufferHandle, GstVideoFrame &frame,
302 GstVideoInfo &videoInfo)
303{
304 qCDebug(qLcGstVideoBuffer) << "Mapping textures from GL memory";
305
306 GstBuffer *buffer = bufferHandle.get();
307 auto *mem = GST_GL_BASE_MEMORY_CAST(gst_buffer_peek_memory(buffer, 0));
308 if (!mem)
309 return {};
310
311 if (!gst_video_frame_map(&frame, &videoInfo, buffer, GstMapFlags(GST_MAP_READ|GST_MAP_GL))) {
312 qWarning() << "Could not map GL textures";
313 return {};
314 }
315
316 auto *sync_meta = gst_buffer_get_gl_sync_meta(buffer);
317 GstBuffer *sync_buffer = nullptr;
318 if (!sync_meta) {
319 sync_buffer = gst_buffer_new();
320 sync_meta = gst_buffer_add_gl_sync_meta(mem->context, sync_buffer);
321 }
322 gst_gl_sync_meta_set_sync_point (sync_meta, mem->context);
323 gst_gl_sync_meta_wait (sync_meta, mem->context);
324 if (sync_buffer)
325 gst_buffer_unref(sync_buffer);
326
327 GlTextures textures;
328 textures.count = frame.info.finfo->n_planes;
329
330 for (uint i = 0; i < textures.count; ++i)
331 textures.names[i] = *(guint32 *)frame.data[i];
332
333 gst_video_frame_unmap(&frame);
334
335 return textures;
336}
337
338# if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
339static GlTextures mapFromDmaBuffer(QRhi *rhi, const QGstBufferHandle &bufferHandle,
340 const QGstVideoInfo &videoInfo, Qt::HANDLE eglDisplay,
341 QFunctionPointer eglImageTargetTexture2D)
342{
343 qCDebug(qLcGstVideoBuffer) << "Importing textures from DMA buffer";
344 logGlAndEglErrors("mapFromDmaBuffer");
345
346 GstBuffer *buffer = bufferHandle.get();
347
348 Q_ASSERT(gst_is_dmabuf_memory(gst_buffer_peek_memory(buffer, 0)));
349 Q_ASSERT(eglDisplay);
350 Q_ASSERT(eglImageTargetTexture2D);
351 Q_ASSERT(rhi);
352 Q_ASSERT(rhi->backend() == QRhi::OpenGLES2);
353
354 auto *nativeHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
355 auto glContext = nativeHandles->context;
356 if (!glContext) {
357 qCWarning(qLcGstVideoBuffer) << "no GL context";
358 return {};
359 }
360
361 const GstVideoInfo &gstVideoInfo = videoInfo.gstVideoInfo;
362 if (!gstVideoInfo.finfo) {
363 qCWarning(qLcGstVideoBuffer) << "Missing valid GstVideoInfo for DMABuf GstBuffer";
364 return {};
365 }
366
367 if (videoInfo.dmaDrmModifier && *videoInfo.dmaDrmModifier != 0) {
368 qCWarning(qLcGstVideoBuffer) << "Unsupported non-linear DMABuf modifier:"
369 << Qt::hex << *videoInfo.dmaDrmModifier;
370 return {};
371 }
372
373 const GstVideoMeta *videoMeta = gst_buffer_get_video_meta(buffer);
374 const GstVideoFormat videoInfoFormat = GST_VIDEO_INFO_FORMAT(&gstVideoInfo);
375 GstVideoFormat format = videoMeta ? videoMeta->format : videoInfoFormat;
376 if (format == GST_VIDEO_FORMAT_UNKNOWN)
377 format = videoInfoFormat;
378
379 const int nPlanes = videoMeta ? videoMeta->n_planes : GST_VIDEO_INFO_N_PLANES(&gstVideoInfo);
380 const int nMemoryBlocks = gst_buffer_n_memory(buffer);
381 static const bool externalOes = QVideoTextureHelper::forceGlTextureExternalOesIsSet();
382 static const bool singleEGLImage =
383 externalOes || qEnvironmentVariableIntValue("QT_GSTREAMER_FORCE_SINGLE_EGLIMAGE") != 0;
384
385 qCDebug(qLcGstVideoBuffer) << "format:" << gst_video_format_to_string(format)
386 << "nPlanes:" << nPlanes
387 << "nMemoryBlocks:" << nMemoryBlocks
388 << "externalOes:" << externalOes
389 << "singleEGLImage:" << singleEGLImage;
390
391 constexpr int maxPlanes = 4;
392 Q_ASSERT(nPlanes >= 1
393 && nPlanes <= maxPlanes
394 && (nMemoryBlocks == 1 || nMemoryBlocks == nPlanes));
395
396 const int nEGLImages = singleEGLImage ? 1 : nPlanes;
397 std::array<EGLAttrib, maxPlanes> planeFourcc{};
398 for (int plane = 0; plane < nEGLImages; ++plane) {
399 const int fourcc = fourccFromGstVideoFormat(format, plane, singleEGLImage);
400 if (fourcc < 0) {
401 qCWarning(qLcGstVideoBuffer) << "Unsupported format for DMABuf:"
402 << gst_video_format_to_string(format) << "plane:" << plane
403 << "singleEGLImage" << singleEGLImage;
404 return {};
405 }
406 planeFourcc[plane] = EGLAttrib(fourcc);
407 }
408
409 GlTextures textures = {};
410 textures.owned = true;
411 textures.count = nEGLImages;
412
413 QOpenGLFunctions functions(glContext);
414 functions.glGenTextures(int(textures.count), textures.names.data());
415 logGlAndEglErrors("glGenTextures");
416
417 std::array<int, maxPlanes> fds{-1, -1, -1, -1};
418 for (int i = 0; i < nMemoryBlocks && i < maxPlanes; ++i) {
419 fds[i] = gst_dmabuf_memory_get_fd(gst_buffer_peek_memory(buffer, i));
420 }
421
422 auto fdForPlane = [&](int plane) -> EGLAttrib {
423 if (plane < 0 || plane >= maxPlanes || plane >= nMemoryBlocks)
424 return fds[0];
425 return (fds[plane] >= 0) ? fds[plane] : fds[0];
426 };
427
428 auto compWidth = [&](int plane) -> EGLAttrib {
429 return singleEGLImage ? GST_VIDEO_INFO_WIDTH(&gstVideoInfo)
430 : GST_VIDEO_INFO_COMP_WIDTH(&gstVideoInfo, plane);
431 };
432
433 auto compHeight = [&](int plane) -> EGLAttrib {
434 return singleEGLImage ? GST_VIDEO_INFO_HEIGHT(&gstVideoInfo)
435 : GST_VIDEO_INFO_COMP_HEIGHT(&gstVideoInfo, plane);
436 };
437
438 auto planeOffset = [&](int plane) -> EGLAttrib {
439 // videoMeta/videoInfo offset can be incorrect when each plane has a separate memory black.
440 if (nPlanes == nMemoryBlocks)
441 return 0;
442 if (videoMeta)
443 return videoMeta->offset[plane];
444 return GST_VIDEO_INFO_PLANE_OFFSET(&gstVideoInfo, plane);
445 };
446
447 auto planeStride = [&](int plane) -> EGLAttrib {
448 if (videoMeta)
449 return videoMeta->stride[plane];
450 return GST_VIDEO_INFO_PLANE_STRIDE(&gstVideoInfo, plane);
451 };
452
453 for (int plane = 0; plane < nEGLImages; ++plane) {
454 constexpr int maxAttrCount = 31;
455 std::array<EGLAttrib, maxAttrCount> attr;
456 int i = 0;
457
458 const int width = compWidth(plane);
459 const int height = compHeight(plane);
460
461 attr[i++] = EGL_WIDTH;
462 attr[i++] = width;
463 attr[i++] = EGL_HEIGHT;
464 attr[i++] = height;
465 attr[i++] = EGL_LINUX_DRM_FOURCC_EXT;
466 attr[i++] = planeFourcc[plane];
467
468 attr[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
469 attr[i++] = fdForPlane(plane);
470 attr[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
471 attr[i++] = planeOffset(plane);
472 attr[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
473 attr[i++] = planeStride(plane);
474
475 if (singleEGLImage && nPlanes > 1) {
476 attr[i++] = EGL_DMA_BUF_PLANE1_FD_EXT;
477 attr[i++] = fdForPlane(1);
478 attr[i++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
479 attr[i++] = planeOffset(1);
480 attr[i++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
481 attr[i++] = planeStride(1);
482 }
483
484 if (singleEGLImage && nPlanes > 2) {
485 attr[i++] = EGL_DMA_BUF_PLANE2_FD_EXT;
486 attr[i++] = fdForPlane(2);
487 attr[i++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
488 attr[i++] = planeOffset(2);
489 attr[i++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
490 attr[i++] = planeStride(2);
491 }
492
493 if (singleEGLImage && nPlanes > 3) {
494 attr[i++] = EGL_DMA_BUF_PLANE3_FD_EXT;
495 attr[i++] = fdForPlane(3);
496 attr[i++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
497 attr[i++] = planeOffset(3);
498 attr[i++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
499 attr[i++] = planeStride(3);
500 }
501
502 attr[i++] = EGL_NONE;
503 Q_ASSERT(i <= maxAttrCount);
504
505 EGLImage image = eglCreateImage(eglDisplay,
506 EGL_NO_CONTEXT,
507 EGL_LINUX_DMA_BUF_EXT,
508 nullptr,
509 attr.data());
510 if (image == EGL_NO_IMAGE_KHR) {
511 qCWarning(qLcGstVideoBuffer) << "could not create EGL image for plane" << plane
512 << ", EGL error 0x" << Qt::hex << eglGetError();
513 continue;
514 }
515 logGlAndEglErrors("eglCreateImage");
516
517 #ifdef GL_OES_EGL_image_external
518 GLenum target = externalOes ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
519 #else
520 GLenum target = GL_TEXTURE_2D;
521 #endif
522 functions.glBindTexture(target, textures.names[plane]);
523
524 auto EGLImageTargetTexture2D = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglImageTargetTexture2D;
525 EGLImageTargetTexture2D(target, image);
526 logGlAndEglErrors("glEGLImageTargetTexture2DOES");
527
528 eglDestroyImage(eglDisplay, image);
529 }
530
531 return textures;
532}
533#endif
534#endif
535
536QVideoFrameTexturesUPtr QGstVideoBuffer::mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr& /*oldTextures*/)
537{
538#if QT_CONFIG(gstreamer_gl)
539 GlTextures textures = {};
540 if (m_memoryFormat == QGstCaps::GLTexture)
541 textures = mapFromGlTexture(m_buffer, m_frame, m_videoInfo.gstVideoInfo);
542
543# if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
544 else if (m_memoryFormat == QGstCaps::DMABuf && qGstEglCanMapDmaBuf()
545 && rhi.backend() == QRhi::OpenGLES2)
546 textures = mapFromDmaBuffer(&rhi, m_buffer, m_videoInfo, qGstEglDisplay(),
547 qGstEglImageTargetTexture2D());
548
549# endif
550 if (textures.count > 0)
551 return std::make_unique<QGstQVideoFrameTextures>(
552 &rhi, QSize{ m_videoInfo.gstVideoInfo.width, m_videoInfo.gstVideoInfo.height },
553 m_frameFormat.pixelFormat(), textures, m_memoryFormat);
554#endif
555 return {};
556}
557
558QT_END_NAMESPACE
@ DMABuf
Definition qgst_p.h:394
QGstVideoBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo, const QVideoFrameFormat &frameFormat)
~QGstVideoBuffer() override
bool isDmaBuf() const override
QVideoFrameTexturesUPtr mapTextures(QRhi &, QVideoFrameTexturesUPtr &) override
void unmap() override
Releases the memory mapped by the map() function.
MapData map(QVideoFrame::MapMode mode) override
Maps the planes of a video buffer to memory.
Combined button and popup list for selecting options.
#define fourcc_code(a, b, c, d)