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
qgstvideobuffer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 <common/qgstutils_p.h>
10
11#include <gst/video/video.h>
12#include <gst/video/video-frame.h>
13#include <gst/pbutils/gstpluginsbaseversion.h>
14
15
16#if QT_CONFIG(gstreamer_gl)
17# include <QtCore/qscopeguard.h>
18
19# include <QtGui/rhi/qrhi.h>
20# include <QtGui/qopenglcontext.h>
21# include <QtGui/qopenglfunctions.h>
22# include <QtGui/qopengl.h>
23
24# include <gst/gl/gstglconfig.h>
25# include <gst/gl/gstglmemory.h>
26# include <gst/gl/gstglsyncmeta.h>
27#endif
28
30
31Q_STATIC_LOGGING_CATEGORY(qLcGstVideoBuffer, "qt.multimedia.gstreamer.videobuffer")
32
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))
40{
41 if constexpr (QT_CONFIG(linux_dmabuf))
42 Q_ASSERT(m_memoryFormat != QGstCaps::DMABuf
43 && "DMABuf buffers should use QGstDmaBufVideoBuffer");
44}
45
46QGstVideoBuffer::~QGstVideoBuffer()
47{
48 Q_ASSERT(m_mode == QVideoFrame::NotMapped);
49}
50
51QAbstractVideoBuffer::MapData QGstVideoBuffer::map(QVideoFrame::MapMode mode)
52{
53 const GstMapFlags flags = GstMapFlags(((mode & QVideoFrame::ReadOnly) ? GST_MAP_READ : 0)
54 | ((mode & QVideoFrame::WriteOnly) ? GST_MAP_WRITE : 0));
55
56 MapData mapData;
57 if (mode == QVideoFrame::NotMapped || m_mode != QVideoFrame::NotMapped)
58 return mapData;
59
60 const GstVideoInfo &gstVideoInfo = m_videoInfo.gstVideoInfo;
61 if (!gstVideoInfo.finfo || gstVideoInfo.finfo->n_planes == 0) { // Encoded
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);
67
68 m_mode = mode;
69 }
70 } else if (gst_video_frame_map(&m_frame, &gstVideoInfo, m_buffer.get(), flags)) {
71 mapData.planeCount = GST_VIDEO_FRAME_N_PLANES(&m_frame);
72
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);
77 }
78
79 m_mode = mode;
80 }
81 return mapData;
82}
83
84void QGstVideoBuffer::unmap()
85{
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]);
89 else
90 gst_video_frame_unmap(&m_frame);
91 }
92 m_mode = QVideoFrame::NotMapped;
93}
94
95#if QT_CONFIG(gstreamer_gl)
96
97class QGstQVideoFrameTextures : public QVideoFrameTextures
98{
99public:
100 QGstQVideoFrameTextures(QRhi *rhi, QSize size, QVideoFrameFormat::PixelFormat format,
101 std::vector<guint32> textures)
102 : m_rhi(rhi), m_glTextures(std::move(textures))
103 {
104 QRhiTexture::Flags textureFlags = {};
105 if (QVideoTextureHelper::forceGlTextureExternalOesIsSet() && m_rhi
106 && rhi->backend() == QRhi::OpenGLES2)
107 textureFlags = {QRhiTexture::ExternalOES};
108
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 });
115 }
116 }
117
118 QRhiTexture *texture(uint plane) const override
119 {
120 return plane < m_glTextures.size() ? m_textures[plane].get() : nullptr;
121 }
122
123private:
124 QRhi *m_rhi = nullptr;
125 std::vector<guint32> m_glTextures;
126 std::unique_ptr<QRhiTexture> m_textures[QVideoTextureHelper::TextureDescription::maxPlanes];
127};
128
129static std::vector<guint32> mapFromGlTexture(const QGstBufferHandle &bufferHandle,
130 GstVideoFrame &frame, GstVideoInfo &videoInfo)
131{
132 qCDebug(qLcGstVideoBuffer) << "Mapping textures from GL memory";
133
134 GstBuffer *buffer = bufferHandle.get();
135 auto *mem = GST_GL_BASE_MEMORY_CAST(gst_buffer_peek_memory(buffer, 0));
136 if (!mem)
137 return {};
138
139 if (!gst_video_frame_map(&frame, &videoInfo, buffer, GstMapFlags(GST_MAP_READ|GST_MAP_GL))) {
140 qWarning() << "Could not map GL textures";
141 return {};
142 }
143
144 const auto unmapGuard = qScopeGuard([&] {
145 gst_video_frame_unmap(&frame);
146 });
147
148 // Set and wait on a GPU fence before accessing the texture.
149 {
150 auto *sync_meta = gst_buffer_get_gl_sync_meta(buffer);
151 QGstBufferHandle sync_buffer;
152 if (!sync_meta) {
153 sync_buffer.reset(gst_buffer_new(), QGstBufferHandle::HasRef);
154 sync_meta = gst_buffer_add_gl_sync_meta(mem->context, sync_buffer.get());
155 }
156 gst_gl_sync_meta_set_sync_point(sync_meta, mem->context);
157 gst_gl_sync_meta_wait(sync_meta, mem->context);
158 }
159
160 std::vector<guint32> textures;
161
162 for (uint i = 0; i < GST_VIDEO_FRAME_N_PLANES(&frame); ++i)
163 textures.push_back(*(guint32 *)frame.data[i]);
164
165 return textures;
166}
167
168#endif
169
170QVideoFrameTexturesUPtr QGstVideoBuffer::mapTextures([[maybe_unused]] QRhi &rhi)
171{
172 switch (m_memoryFormat) {
174#if QT_CONFIG(gstreamer_gl)
175 {
176 auto textures = mapFromGlTexture(m_buffer, m_frame, m_videoInfo.gstVideoInfo);
177 if (textures.size())
178 return std::make_unique<QGstQVideoFrameTextures>(
179 &rhi, QSize{ m_videoInfo.gstVideoInfo.width, m_videoInfo.gstVideoInfo.height },
180 m_frameFormat.pixelFormat(), std::move(textures));
181 [[fallthrough]];
182 }
183#endif
184 default:
185 return {};
186 }
187}
188
189QT_END_NAMESPACE
@ GLTexture
Definition qgst_p.h:394
~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.