6#include <QtMultimedia/private/qvideotexturehelper_p.h>
7#include <QtCore/qloggingcategory.h>
9#include <common/qgstutils_p.h>
11#include <gst/video/video.h>
12#include <gst/video/video-frame.h>
13#include <gst/pbutils/gstpluginsbaseversion.h>
16#if QT_CONFIG(gstreamer_gl)
17# include <QtCore/qscopeguard.h>
19# include <QtGui/rhi/qrhi.h>
20# include <QtGui/qopenglcontext.h>
21# include <QtGui/qopenglfunctions.h>
22# include <QtGui/qopengl.h>
24# include <gst/gl/gstglconfig.h>
25# include <gst/gl/gstglmemory.h>
26# include <gst/gl/gstglsyncmeta.h>
31Q_STATIC_LOGGING_CATEGORY(qLcGstVideoBuffer,
"qt.multimedia.gstreamer.videobuffer")
33QGstVideoBuffer::QGstVideoBuffer(QGstBufferHandle buffer,
const QGstVideoInfo &videoInfo,
34 const QVideoFrameFormat &frameFormat)
35 : m_memoryFormat(buffer.isValid() ? qMemoryFormatFromGstBuffer(buffer.get())
36 : QGstCaps::CpuMemory),
37 m_frameFormat(frameFormat),
38 m_videoInfo(videoInfo),
39 m_buffer(std::move(buffer))
41 if constexpr (QT_CONFIG(linux_dmabuf))
42 Q_ASSERT(m_memoryFormat != QGstCaps::DMABuf
43 &&
"DMABuf buffers should use QGstDmaBufVideoBuffer");
48 Q_ASSERT(m_mode == QVideoFrame::NotMapped);
53 const GstMapFlags flags = GstMapFlags(((mode & QVideoFrame::ReadOnly) ? GST_MAP_READ : 0)
54 | ((mode & QVideoFrame::WriteOnly) ? GST_MAP_WRITE : 0));
57 if (mode == QVideoFrame::NotMapped || m_mode != QVideoFrame::NotMapped)
60 const GstVideoInfo &gstVideoInfo = m_videoInfo.gstVideoInfo;
61 if (!gstVideoInfo.finfo || gstVideoInfo.finfo->n_planes == 0) {
62 if (gst_buffer_map(m_buffer.get(), &m_frame.map[0], flags)) {
63 mapData.planeCount = 1;
64 mapData.bytesPerLine[0] = -1;
65 mapData.dataSize[0] = m_frame.map[0].size;
66 mapData.data[0] =
static_cast<uchar *>(m_frame.map[0].data);
70 }
else if (gst_video_frame_map(&m_frame, &gstVideoInfo, m_buffer.get(), flags)) {
71 mapData.planeCount = GST_VIDEO_FRAME_N_PLANES(&m_frame);
73 for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES(&m_frame); ++i) {
74 mapData.bytesPerLine[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&m_frame, i);
75 mapData.data[i] =
static_cast<uchar *>(GST_VIDEO_FRAME_PLANE_DATA(&m_frame, i));
76 mapData.dataSize[i] = mapData.bytesPerLine[i]*GST_VIDEO_FRAME_COMP_HEIGHT(&m_frame, i);
86 if (m_mode != QVideoFrame::NotMapped) {
87 if (!m_videoInfo.gstVideoInfo.finfo || m_videoInfo.gstVideoInfo.finfo->n_planes == 0)
88 gst_buffer_unmap(m_buffer.get(), &m_frame.map[0]);
90 gst_video_frame_unmap(&m_frame);
92 m_mode = QVideoFrame::NotMapped;
95#if QT_CONFIG(gstreamer_gl)
97class QGstQVideoFrameTextures :
public QVideoFrameTextures
100 QGstQVideoFrameTextures(QRhi *rhi, QSize size, QVideoFrameFormat::PixelFormat format,
101 std::vector<guint32> textures)
102 : m_rhi(rhi), m_glTextures(std::move(textures))
104 QRhiTexture::Flags textureFlags = {};
105 if (QVideoTextureHelper::forceGlTextureExternalOesIsSet() && m_rhi
106 && rhi->backend() == QRhi::OpenGLES2)
107 textureFlags = {QRhiTexture::ExternalOES};
109 auto desc = QVideoTextureHelper::textureDescription(format);
110 for (uint i = 0; i < textures.size(); ++i) {
111 QSize planeSize = desc->rhiPlaneSize(size, i, m_rhi);
112 QRhiTexture::Format format = desc->rhiTextureFormat(i, m_rhi);
113 m_textures[i].reset(rhi->newTexture(format, planeSize, 1, textureFlags));
114 m_textures[i]->createFrom({ textures[i], 0 });
118 QRhiTexture *texture(uint plane)
const override
120 return plane < m_glTextures.size() ? m_textures[plane].get() :
nullptr;
124 QRhi *m_rhi =
nullptr;
125 std::vector<guint32> m_glTextures;
126 std::unique_ptr<QRhiTexture> m_textures[QVideoTextureHelper::TextureDescription::maxPlanes];
129static std::vector<guint32> mapFromGlTexture(
const QGstBufferHandle &bufferHandle,
130 GstVideoFrame &frame, GstVideoInfo &videoInfo)
132 qCDebug(qLcGstVideoBuffer) <<
"Mapping textures from GL memory";
134 GstBuffer *buffer = bufferHandle.get();
135 auto *mem = GST_GL_BASE_MEMORY_CAST(gst_buffer_peek_memory(buffer, 0));
139 if (!gst_video_frame_map(&frame, &videoInfo, buffer, GstMapFlags(GST_MAP_READ|GST_MAP_GL))) {
140 qWarning() <<
"Could not map GL textures";
144 const auto unmapGuard = qScopeGuard([&] {
145 gst_video_frame_unmap(&frame);
150 auto *sync_meta = gst_buffer_get_gl_sync_meta(buffer);
151 QGstBufferHandle sync_buffer;
153 sync_buffer.reset(gst_buffer_new(), QGstBufferHandle::HasRef);
154 sync_meta = gst_buffer_add_gl_sync_meta(mem->context, sync_buffer.get());
156 gst_gl_sync_meta_set_sync_point(sync_meta, mem->context);
157 gst_gl_sync_meta_wait(sync_meta, mem->context);
160 std::vector<guint32> textures;
162 for (uint i = 0; i < GST_VIDEO_FRAME_N_PLANES(&frame); ++i)
163 textures.push_back(*(guint32 *)frame.data[i]);
172 switch (m_memoryFormat) {
174#if QT_CONFIG(gstreamer_gl)
176 auto textures = mapFromGlTexture(m_buffer, m_frame, m_videoInfo.gstVideoInfo);
178 return std::make_unique<QGstQVideoFrameTextures>(
179 &rhi, QSize{ m_videoInfo.gstVideoInfo.width, m_videoInfo.gstVideoInfo.height },
180 m_frameFormat.pixelFormat(), std::move(textures));
~QGstVideoBuffer() 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.
QVideoFrameTexturesUPtr mapTextures(QRhi &) override
Combined button and popup list for selecting options.