QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstHwVideoBufferFactory.cc
Go to the documentation of this file.
3
4#include <QtCore/QMutex>
5#include <QtCore/QMutexLocker>
6#include <QtCore/QSet>
7#include <QtCore/QString>
8#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
9# include <QtGui/QGuiApplication>
10#endif
11
12#include <private/qhwvideobuffer_p.h>
13
14#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
15# include "GstDmaBufVideoBuffer.h"
16# include <gst/allocators/gstdmabuf.h>
17#endif
18#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
19# include "GstGlVideoBuffer.h"
20# include <gst/gl/gstglmemory.h>
21#endif
22#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
23# include "GstD3D11VideoBuffer.h"
24# include <gst/d3d11/gstd3d11.h>
25#endif
26#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
27# include "GstD3D12VideoBuffer.h"
28# include <gst/d3d12/gstd3d12.h>
29#endif
30#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
32#endif
33#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
35# include <gst/android/gstandroid.h>
36#endif
37
38QGC_LOGGING_CATEGORY(GstHwBufFactoryLog, "Video.GStreamer.HwBuffers.Factory")
39
40std::unique_ptr<QHwVideoBuffer> makeHwVideoBuffer(
41 GstSample *sample,
42 [[maybe_unused]] const GstVideoInfo &info,
43 [[maybe_unused]] QVideoFrameFormat format,
44 bool gpuEnabled,
45#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
46 EGLDisplay eglDisplay,
47#else
48 void * /*eglDisplay*/,
49#endif
50#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
51 EGLDisplay ahbEglDisplay,
52#else
53 void * /*ahbEglDisplay*/,
54#endif
55 HwVideoBufferPath &matchedPath)
56{
57 matchedPath = HwVideoBufferPath::None;
58 if (!gpuEnabled || !sample) {
59 return nullptr;
60 }
61
62 GstBuffer *buffer = gst_sample_get_buffer(sample);
63 if (!buffer) {
64 return nullptr;
65 }
66
67 // Plane 0's allocator type is the dispatch key; gst-video buffers from a single decoder use one allocator across all planes.
68 GstMemory *mem0 = gst_buffer_peek_memory(buffer, 0);
69 if (!mem0) {
70 return nullptr;
71 }
72
73 // Validate before commit — failure resets matchedPath so per-path counters don't double-count.
74 auto buildOrFallback = [&matchedPath](auto &&buf) -> std::unique_ptr<QHwVideoBuffer> {
75 if (!buf || !buf->validatePlaneHandles()) {
76 static std::atomic<quint64> s_validateFails{0};
77 const quint64 c = s_validateFails.fetch_add(1, std::memory_order_relaxed) + 1;
78 if ((c & 0x3F) == 1) {
79 qCWarning(GstHwBufFactoryLog)
80 << "validatePlaneHandles failed — CPU memcpy fallback (total:" << c << ")";
81 }
82 matchedPath = HwVideoBufferPath::None;
83 return nullptr;
84 }
85 return std::move(buf);
86 };
87
88#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
89 if (eglDisplay != EGL_NO_DISPLAY && gst_is_dmabuf_memory(mem0)) {
90 matchedPath = HwVideoBufferPath::DmaBuf;
91 // Pi/eglfs quirk: the EGL impl on RPi (Broadcom/Mesa V3D) does implicit YUV→RGB conversion
92 // when sampling YUYV/UYVY DMABuf via EGLImage, so the pixel data is already RGBA on the GPU
93 // texture. Declaring the format as RGBA8888 picks Qt's RGB sampler shader (otherwise Qt
94 // applies a YUV→RGB matrix in software, double-converting). Mirror's Qt's own backend
95 // (qtmultimedia/.../qgstvideorenderersink.cpp:render — eglfs UYVY/YUYV branch).
96 static const bool isEglfsQPA =
97 QGuiApplication::platformName() == QLatin1String("eglfs");
98 if (isEglfsQPA
99 && (format.pixelFormat() == QVideoFrameFormat::Format_UYVY
100 || format.pixelFormat() == QVideoFrameFormat::Format_YUYV)) {
101 QVideoFrameFormat spoofed(format.frameSize(), QVideoFrameFormat::Format_RGBA8888);
102 spoofed.setStreamFrameRate(format.streamFrameRate());
103 spoofed.setColorRange(format.colorRange());
104 spoofed.setColorSpace(format.colorSpace());
105 spoofed.setColorTransfer(format.colorTransfer());
106 spoofed.setViewport(format.viewport());
107 format = std::move(spoofed);
108 }
109 return buildOrFallback(std::make_unique<GstDmaBufVideoBuffer>(sample, info, format, eglDisplay));
110 }
111#endif
112
113#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
114 if (gst_is_gl_memory(mem0)) {
115 matchedPath = HwVideoBufferPath::GlMemory;
116 return buildOrFallback(std::make_unique<GstGlVideoBuffer>(sample, info, format));
117 }
118#endif
119
120#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
121 if (gst_is_d3d11_memory(mem0)) {
122 matchedPath = HwVideoBufferPath::D3D11;
123 return buildOrFallback(std::make_unique<GstD3D11VideoBuffer>(sample, info, format));
124 }
125#endif
126
127#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
128 if (gst_is_d3d12_memory(mem0)) {
129 matchedPath = HwVideoBufferPath::D3D12;
130 return buildOrFallback(std::make_unique<GstD3D12VideoBuffer>(sample, info, format));
131 }
132#endif
133
134#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
135 // String-compare the allocator name; gst-applemedia exports no public gst_is_apple_core_video_memory() predicate.
136 if (mem0->allocator && g_strcmp0(mem0->allocator->mem_type, "AppleCoreVideoMemory") == 0) {
137 matchedPath = HwVideoBufferPath::IOSurface;
138 return buildOrFallback(std::make_unique<GstIOSurfaceVideoBuffer>(sample, info, format));
139 }
140#endif
141
142#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
143 if (ahbEglDisplay != EGL_NO_DISPLAY && gst_is_ahardware_buffer_memory(mem0)) {
145 // GL_TEXTURE_EXTERNAL_OES requires the SamplerExternalOES pixel format for Qt's shader path.
146 format.setPixelFormat(QVideoFrameFormat::Format_SamplerExternalOES);
147 return buildOrFallback(std::make_unique<GstAHardwareBufferVideoBuffer>(sample, info, format, ahbEglDisplay));
148 }
149#endif
150
151 {
152 static QSet<QString> s_seen;
153 static QMutex s_mtx;
154 const QString memType = mem0->allocator
155 ? QString::fromUtf8(mem0->allocator->mem_type)
156 : QStringLiteral("<no-allocator>");
157 QMutexLocker lock(&s_mtx);
158 if (!s_seen.contains(memType)) {
159 s_seen.insert(memType);
160 qCDebug(GstHwBufFactoryLog) << "no zero-copy path for memory type"
161 << memType << "— falling back to CPU memcpy";
162 }
163 }
164 return nullptr;
165}
std::unique_ptr< QHwVideoBuffer > makeHwVideoBuffer(GstSample *sample, const GstVideoInfo &info, QVideoFrameFormat format, bool gpuEnabled, void *, void *, HwVideoBufferPath &matchedPath)
HwVideoBufferPath
Identifies which GPU path was chosen; used by the adapter to increment the right counter.
#define QGC_LOGGING_CATEGORY(name, categoryStr)