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
qgstdmabufvideobuffer.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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
6#include <QtMultimedia/private/qvideotexturehelper_p.h>
7#include <QtCore/qloggingcategory.h>
8
9#include <gst/allocators/gstdmabuf.h>
10#include <gst/video/gstvideometa.h>
11
12#include <array>
13#include <optional>
14
16
17Q_STATIC_LOGGING_CATEGORY(qLcGstDmaBufVideoBuffer, "qt.multimedia.gstreamer.dmabufvideobuffer")
18
19using QtMultimediaPrivate::DmaBufImportMode;
20using QtMultimediaPrivate::DmaBufPlane;
21using QtMultimediaPrivate::DRMFormat;
22
23static std::optional<DRMFormat> fourccFromGstVideoFormat(const GstVideoFormat format, int plane,
24 bool singleEGLImage)
25{
26#if G_BYTE_ORDER == G_LITTLE_ENDIAN
27 constexpr DRMFormat argb_fourcc = DRMFormat::ARGB8888;
28 constexpr DRMFormat rgba_fourcc = DRMFormat::ABGR8888;
29 constexpr DRMFormat rgb_fourcc = DRMFormat::BGR888;
30 constexpr DRMFormat rg_fourcc = DRMFormat::GR88;
31#else
32 constexpr DRMFormat argb_fourcc = DRMFormat::BGRA8888;
33 constexpr DRMFormat rgba_fourcc = DRMFormat::RGBA8888;
34 constexpr DRMFormat rgb_fourcc = DRMFormat::RGB888;
35 constexpr DRMFormat rg_fourcc = DRMFormat::RG88;
36#endif
37
38 switch (format) {
39 case GST_VIDEO_FORMAT_RGB16:
40 case GST_VIDEO_FORMAT_BGR16:
41 return DRMFormat::RGB565;
42
43 case GST_VIDEO_FORMAT_RGB:
44 case GST_VIDEO_FORMAT_BGR:
45 return rgb_fourcc;
46
47 case GST_VIDEO_FORMAT_BGRx:
48 case GST_VIDEO_FORMAT_BGRA:
49 return argb_fourcc;
50
51 case GST_VIDEO_FORMAT_AYUV:
52 if (singleEGLImage)
53 return DRMFormat::AYUV;
54 [[fallthrough]];
55 case GST_VIDEO_FORMAT_RGBx:
56 case GST_VIDEO_FORMAT_RGBA:
57 case GST_VIDEO_FORMAT_ARGB:
58 case GST_VIDEO_FORMAT_xRGB:
59 case GST_VIDEO_FORMAT_ABGR:
60 case GST_VIDEO_FORMAT_xBGR:
61 return rgba_fourcc;
62
63 case GST_VIDEO_FORMAT_GRAY8:
64 return DRMFormat::R8;
65
66 case GST_VIDEO_FORMAT_YUY2:
67 return DRMFormat::YUYV;
68
69 case GST_VIDEO_FORMAT_UYVY:
70 return DRMFormat::UYVY;
71
72 case GST_VIDEO_FORMAT_GRAY16_LE:
73 case GST_VIDEO_FORMAT_GRAY16_BE:
74 if (singleEGLImage)
75 return DRMFormat::R16;
76 return rg_fourcc;
77
78 case GST_VIDEO_FORMAT_NV12:
79 if (singleEGLImage)
80 return DRMFormat::NV12;
81 [[fallthrough]];
82 case GST_VIDEO_FORMAT_NV21:
83 if (singleEGLImage)
84 return DRMFormat::NV21;
85 return plane == 0 ? DRMFormat::R8 : rg_fourcc;
86
87 case GST_VIDEO_FORMAT_I420:
88 if (singleEGLImage)
89 return DRMFormat::YUV420;
90 [[fallthrough]];
91 case GST_VIDEO_FORMAT_YV12:
92 if (singleEGLImage)
93 return DRMFormat::YVU420;
94 [[fallthrough]];
95 case GST_VIDEO_FORMAT_Y41B:
96 if (singleEGLImage)
97 return DRMFormat::YUV411;
98 [[fallthrough]];
99 case GST_VIDEO_FORMAT_Y42B:
100 if (singleEGLImage)
101 return DRMFormat::YUV422;
102 [[fallthrough]];
103 case GST_VIDEO_FORMAT_Y444:
104 if (singleEGLImage)
105 return DRMFormat::YUV444;
106 return DRMFormat::R8;
107
108 case GST_VIDEO_FORMAT_BGR10A2_LE:
109 return DRMFormat::BGRA1010102;
110
111 case GST_VIDEO_FORMAT_P010_10LE:
112 case GST_VIDEO_FORMAT_P010_10BE:
113 if (singleEGLImage)
114 return DRMFormat::P010;
115 return plane == 0 ? DRMFormat::R16 : DRMFormat::RG1616;
116
117 default:
118 return std::nullopt;
119 }
120}
121
122QGstDmaBufVideoBuffer::QGstDmaBufVideoBuffer(QSpan<const DmaBufPlane> planes,
123 DmaBufImportMode importMode, QGstBufferHandle buffer,
124 QVideoFrameFormat::PixelFormat format, QSize size)
125 : QDmaBufVideoBuffer(format, size, planes, std::make_shared<QGstBufferHandle>(buffer),
126 importMode),
127 m_buffer(std::move(buffer))
128{
129}
130
131QGstDmaBufVideoBuffer::~QGstDmaBufVideoBuffer() = default;
132
133std::unique_ptr<QGstDmaBufVideoBuffer>
134QGstDmaBufVideoBuffer::create(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo,
135 const QVideoFrameFormat &frameFormat)
136{
137 using namespace QtMultimediaPrivate;
138
139 if (!buffer.isValid())
140 return nullptr;
141
142 GstBuffer *gstBuffer = buffer.get();
143 if (!gst_is_dmabuf_memory(gst_buffer_peek_memory(gstBuffer, 0)))
144 return nullptr;
145
146 const GstVideoInfo &gstVideoInfo = videoInfo.gstVideoInfo;
147 if (!gstVideoInfo.finfo)
148 return nullptr;
149
150 const GstVideoMeta *videoMeta = gst_buffer_get_video_meta(gstBuffer);
151 GstVideoFormat format = videoMeta ? videoMeta->format : GST_VIDEO_INFO_FORMAT(&gstVideoInfo);
152 if (format == GST_VIDEO_FORMAT_UNKNOWN)
153 format = GST_VIDEO_INFO_FORMAT(&gstVideoInfo);
154
155 const int nPlanes = videoMeta ? videoMeta->n_planes : GST_VIDEO_INFO_N_PLANES(&gstVideoInfo);
156 const int nMemoryBlocks = gst_buffer_n_memory(gstBuffer);
157 if (nPlanes < 1 || nPlanes > 4 || (nMemoryBlocks != 1 && nMemoryBlocks != nPlanes))
158 return nullptr;
159
160 const QVideoFrameFormat::PixelFormat pixelFormat = frameFormat.pixelFormat();
161 const auto *desc = QVideoTextureHelper::textureDescription(pixelFormat);
162 if (!desc || desc->nplanes != nPlanes)
163 return nullptr;
164
165 static const bool singleEGLImageEnv =
166 qEnvironmentVariableIntValue("QT_GSTREAMER_FORCE_SINGLE_EGLIMAGE") != 0;
167 const bool singleEGLImage =
168 QVideoTextureHelper::forceGlTextureExternalOesIsSet() || singleEGLImageEnv;
169
170 std::array<DmaBufPlane, 4> planes;
171 std::array<int, 4> fds{ -1, -1, -1, -1 };
172 for (int i = 0; i < nMemoryBlocks && i < 4; ++i)
173 fds[i] = gst_dmabuf_memory_get_fd(gst_buffer_peek_memory(gstBuffer, i));
174
175 const DRMModifier modifier = videoInfo.dmaDrmModifier ? DRMModifier{ *videoInfo.dmaDrmModifier }
176 : DmaBufFormatModifierInvalid;
177
178 for (int plane = 0; plane < nPlanes; ++plane) {
179 const std::optional<DRMFormat> fourcc =
180 fourccFromGstVideoFormat(format, plane, singleEGLImage);
181 if (!fourcc) {
182 qCWarning(qLcGstDmaBufVideoBuffer)
183 << "Unsupported format for DMABuf:" << gst_video_format_to_string(format)
184 << "plane:" << plane << "singleEGLImage:" << singleEGLImage;
185 return nullptr;
186 }
187
188 const int fd = (plane < nMemoryBlocks && fds[plane] >= 0) ? fds[plane] : fds[0];
189 if (fd < 0)
190 return nullptr;
191
192 planes[plane].fd = fd;
193 // videoMeta/videoInfo offset can be incorrect when each plane has a separate memory block
194 if (nPlanes == nMemoryBlocks) {
195 planes[plane].offset = 0;
196 } else if (videoMeta) {
197 planes[plane].offset = videoMeta->offset[plane];
198 } else {
199 planes[plane].offset = GST_VIDEO_INFO_PLANE_OFFSET(&gstVideoInfo, plane);
200 }
201 if (videoMeta)
202 planes[plane].pitch = videoMeta->stride[plane];
203 else
204 planes[plane].pitch = GST_VIDEO_INFO_PLANE_STRIDE(&gstVideoInfo, plane);
205 planes[plane].drmFormat = *fourcc;
206 planes[plane].modifier = modifier;
207 }
208
209 const DmaBufImportMode importMode =
210 singleEGLImage ? DmaBufImportMode::SingleImage : DmaBufImportMode::PerPlane;
211 return std::unique_ptr<QGstDmaBufVideoBuffer>(
212 new QGstDmaBufVideoBuffer(QSpan<const DmaBufPlane>(planes.data(), nPlanes), importMode,
213 std::move(buffer), pixelFormat, frameFormat.frameSize()));
214}
215
216QT_END_NAMESPACE
typedefQT_BEGIN_NAMESPACE struct _GstBuffer GstBuffer
static std::optional< DRMFormat > fourccFromGstVideoFormat(const GstVideoFormat format, int plane, bool singleEGLImage)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)