9#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
11#include <QtCore/QLoggingCategory>
12#include <QtCore/QSize>
14#include <gst/gl/gstglbasememory.h>
15#include <gst/gl/gstglmemory.h>
16#include <gst/gl/gstglsyncmeta.h>
17#include <gst/video/video.h>
18#include <private/qvideotexturehelper_p.h>
24#include <QtGui/qopengl.h>
43 bool matches(QRhi* rhi, QSize size, QVideoFrameFormat::PixelFormat pixelFormat,
44 const std::array<GLuint, kMaxPlanes>& names,
int count)
const
46 if (_rhi != rhi || _size != size || _pixelFormat != pixelFormat || _count != count) {
49 for (
int i = 0; i <
_count; ++i) {
50 if (_names[i] == 0 || _names[i] != names[i] || !_textures[i]) {
64 std::array<GLuint, kMaxPlanes> names{};
67 bool operator==(
const GlTexKey& o)
const noexcept {
return count == o.count && names == o.names; }
72 std::size_t operator()(
const GlTexKey& k)
const noexcept
74 std::size_t h = std::hash<int>{}(k.count);
75 for (
int i = 0; i < k.count; ++i) {
76 h ^= std::hash<GLuint>{}(k.names[i]) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
84constexpr std::size_t kGlRingCapacity = 8;
89GstGlVideoBuffer::GstGlVideoBuffer(GstSample* sample,
const GstVideoInfo& videoInfo,
const QVideoFrameFormat& format)
93bool GstGlVideoBuffer::validatePlaneHandles()
const
96 return validatePlanes([](GstMemory* mem) {
return mem && gst_is_gl_memory(mem); });
99QVideoFrameTexturesUPtr GstGlVideoBuffer::mapTextures(QRhi& rhi, QVideoFrameTexturesUPtr& old)
103 GstBuffer* buffer =
nullptr;
104 if (!checkMapPreconditions(rhi,
static_cast<int>(QRhi::OpenGLES2), GstGlBufLog(), s_diag, buffer)) {
109 rhi.makeThreadLocalNativeContextCurrent();
111 GstMemory* mem0 = gst_buffer_peek_memory(buffer, 0);
112 if (!mem0 || !gst_is_gl_memory(mem0)) {
116 GstVideoFrame frame = {};
118 if (!gst_video_frame_map(&frame, &_videoInfo, buffer,
static_cast<GstMapFlags
>(GST_MAP_READ | GST_MAP_GL))) {
119 qCWarning(GstGlBufLog) <<
"gst_video_frame_map(GST_MAP_READ | GST_MAP_GL) failed";
126 GstGLContext* glCtx = GST_GL_BASE_MEMORY_CAST(mem0)->context;
128 GstGLSyncMeta* syncMeta = gst_buffer_get_gl_sync_meta(buffer);
129 GstBuffer* throwaway =
nullptr;
131 throwaway = gst_buffer_new();
133 qCWarning(GstGlBufLog) <<
"gst_buffer_new() failed while creating GL sync meta holder";
136 gst_video_frame_unmap(&frame);
139 syncMeta = gst_buffer_add_gl_sync_meta(glCtx, throwaway);
142 gst_gl_sync_meta_set_sync_point(syncMeta, glCtx);
143 gst_gl_sync_meta_wait(syncMeta, glCtx);
147 gst_buffer_unref(throwaway);
151 const int planeCount = std::clamp(
int(GST_VIDEO_FRAME_N_PLANES(&frame)), 1, kMaxPlanes);
152 std::array<GLuint, kMaxPlanes> names{};
153 for (
int i = 0; i < planeCount; ++i) {
155 const GLuint* texIdPtr =
static_cast<const GLuint*
>(GST_VIDEO_FRAME_PLANE_DATA(&frame, i));
156 names[i] = texIdPtr ? *texIdPtr : 0;
159 gst_video_frame_unmap(&frame);
162 if (prev->matches(&rhi, _format.frameSize(), _format.pixelFormat(), names, planeCount)) {
164 prev->setSourceSample(takeSample());
165 QVideoFrameTexturesUPtr reused = std::move(old);
173 const GlTexKey ringKey{names, planeCount};
174 const bool ringHit = (s_glRingCache.find(ringKey) !=
nullptr);
179 _format.frameSize())) {
184 std::make_unique<FrameTextures>(&rhi, _format.frameSize(), _format.pixelFormat(), names, planeCount);
186 for (
int i = 0; i < planeCount; ++i) {
187 if (!textures->texture(
static_cast<uint
>(i))) {
188 qCWarning(GstGlBufLog) <<
"createFrom failed for plane" << i <<
"format=" << _format.pixelFormat();
197 s_glRingCache.insert(ringKey,
char{});
198 textures->setSourceSample(takeSample());
HwVideoBufferPath
Identifies which GPU path was chosen; used by the adapter to increment the right counter.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Shared base for GL-texture-backed QVideoFrameTextures wrappers (GLMemory and DMABuf-via-EGLImage).
GstGlFrameTextures(QRhi *rhi, QSize size, QVideoFrameFormat::PixelFormat pixelFormat, std::array< GLuint, GstHw::kMaxPlanes > names, int count, FallbackPolicy fallback=FallbackPolicy::Enable)
virtual HwVideoBufferPath sourcePath() const
GPU path that produced this bundle; used after a type-safe downcast to decide path-local reuse.
RAII timer: records mapTextures() wall time into the path's EWMA on scope exit.
Common base for GStreamer-backed QHwVideoBuffer subclasses.
void recordSyncWait(HwVideoBufferPath path, bool gpuSide) noexcept
GL fence sync wait; split CPU-blocking vs GPU-side.
void recordFallbackReason(HwVideoBufferPath attemptedPath, HwFallbackReason reason) noexcept
Per-(path,reason) fallback accounting; lets a bug report show why a path demoted to CPU.
void recordTextureReuse(HwVideoBufferPath path) noexcept
Prior frame's QRhiTexture wrappers reused (decoder pool returned same native handle).
constexpr int kMaxPlanes
Matches GST_VIDEO_MAX_PLANES (gst-video pins it at 4); single source of truth for every per-platform ...
One-shot warning flags per failure cause; paths with extra causes (D3D, IOSurface) derive and add mem...