210std::unique_ptr<QHwVideoBuffer>
makeHwVideoBuffer(GstSample* sample, [[maybe_unused]]
const GstVideoInfo& info,
211 [[maybe_unused]] QVideoFrameFormat format,
220 GstBuffer* buffer = gst_sample_get_buffer(sample);
227 GstMemory* mem0 = gst_buffer_peek_memory(buffer, 0);
233 auto buildOrFallback = [&matchedPath, &info, cache](
auto&& buf) -> std::unique_ptr<QHwVideoBuffer> {
234 if (!buf || !buf->validatePlaneHandles()) {
236 static std::atomic<quint64> s_validateFails{0};
237 const quint64 c = s_validateFails.fetch_add(1, std::memory_order_relaxed) + 1;
238 if ((c & 0x3F) == 1) {
239 qCWarning(GstHwBufFactoryLog)
240 <<
"validatePlaneHandles failed — CPU memcpy fallback (total:" << c <<
")";
249 qCDebug(GstHwBufFactoryLog).noquote()
250 <<
"zero-copy path selected:" << pathName(matchedPath)
251 <<
"format=" << gst_video_format_to_string(GST_VIDEO_INFO_FORMAT(&info))
252 << GST_VIDEO_INFO_WIDTH(&info) <<
"x" << GST_VIDEO_INFO_HEIGHT(&info);
255 cache->
path = matchedPath;
264 if (memoryMatchesPath(cache->
path, mem0, context)) {
265 matchedPath = cache->
path;
266 if (
auto buf = constructForPath(cache->
path, sample, info, format, context)) {
267 return buildOrFallback(std::move(buf));
274#if defined(QGC_HAS_GST_CUDA_GPU_PATH)
277 if (gst_is_cuda_memory(mem0)) {
280 static std::atomic<bool> s_cudaExportUnsupported{
false};
281 if (s_cudaExportUnsupported.load(std::memory_order_relaxed)) {
285 if (
auto buf = buildOrFallback(GstCudaVideoBuffer::exportToDmaBuf(sample, info, format, context))) {
288 if (!s_cudaExportUnsupported.exchange(
true, std::memory_order_relaxed)) {
291 qCWarning(GstHwBufFactoryLog) <<
"CUDA->DMABuf export unsupported on this driver — CPU fallback for the"
292 <<
"remainder of the process";
299#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
300 if (context.dmaBufEglDisplay != EGL_NO_DISPLAY && gst_is_dmabuf_memory(mem0)) {
302 return buildOrFallback(std::make_unique<GstDmaBufVideoBuffer>(sample, info, format, context.dmaBufEglDisplay));
306#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
307 if (gst_is_gl_memory(mem0)) {
308 if (!glMemoryConsumable()) {
309 static std::atomic<bool> s_warned{
false};
310 if (!s_warned.exchange(
true, std::memory_order_relaxed)) {
311 qCWarning(GstHwBufFactoryLog) <<
"GLMemory frame but QRhi backend is not OpenGL — routing to CPU pool";
318 return buildOrFallback(std::make_unique<GstGlVideoBuffer>(sample, info, format));
322#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
323 if (gst_is_d3d11_memory(mem0)) {
325 return buildOrFallback(std::make_unique<GstD3D11VideoBuffer>(sample, info, format));
329#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
330 if (gst_is_d3d12_memory(mem0)) {
332 return buildOrFallback(std::make_unique<GstD3D12VideoBuffer>(sample, info, format));
336#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
337 if (gst_is_vulkan_image_memory(mem0)) {
339 return buildOrFallback(std::make_unique<GstVulkanVideoBuffer>(sample, info, format));
343#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
345 if (mem0->allocator && g_strcmp0(mem0->allocator->mem_type,
"AppleCoreVideoMemory") == 0) {
347 return buildOrFallback(std::make_unique<GstIOSurfaceVideoBuffer>(sample, info, format));
351#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
352 if (context.ahbEglDisplay != EGL_NO_DISPLAY && gst_is_ahardware_buffer_memory(mem0)) {
355 format.setPixelFormat(QVideoFrameFormat::Format_SamplerExternalOES);
356 return buildOrFallback(
357 std::make_unique<GstAHardwareBufferVideoBuffer>(sample, info, format, context.ahbEglDisplay));
362 static QSet<QString> s_seen;
364 const QString memType =
365 mem0->allocator ? QString::fromUtf8(mem0->allocator->mem_type) : QStringLiteral(
"<no-allocator>");
366 QMutexLocker lock(&s_mtx);
367 if (!s_seen.contains(memType)) {
368 s_seen.insert(memType);
369 qCDebug(GstHwBufFactoryLog) <<
"no zero-copy path for memory type" << memType
370 <<
"— falling back to CPU memcpy";
Platform context for the factory; encapsulates EGL handles so callers don't need path-specific ifdefs...