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
qgstreamerintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
4#include <qgstreamerintegration_p.h>
5#include <qgstreamerformatinfo_p.h>
6#include <qgstreamervideodevices_p.h>
7#include <audio/qgstreameraudiodevice_p.h>
8#include <audio/qgstreameraudiodecoder_p.h>
9#include <common/qgstreameraudioinput_p.h>
10#include <common/qgstreameraudiooutput_p.h>
11#include <common/qgstreamermediaplayer_p.h>
12#include <common/qgstreamervideosink_p.h>
13#include <mediacapture/qgstreamercamera_p.h>
14#include <mediacapture/qgstreamerimagecapture_p.h>
15#include <mediacapture/qgstreamermediacapturesession_p.h>
16#include <mediacapture/qgstreamermediarecorder_p.h>
17#include <uri_handler/qgstreamer_qiodevice_handler_p.h>
18#include <uri_handler/qgstreamer_qrc_handler_p.h>
19
20#include <QtCore/qloggingcategory.h>
21#include <QtMultimedia/private/qmediaplayer_p.h>
22#include <QtMultimedia/private/qmediacapturesession_p.h>
23#include <QtMultimedia/private/qcameradevice_p.h>
24#include <QtMultimedia/private/qvideoframe_p.h>
25
27
28static_assert(GST_CHECK_VERSION(1, 20, 0), "Minimum required GStreamer version is 1.20");
29
30static thread_local bool inCustomCameraConstruction = false;
31static thread_local QGstElement pendingCameraElement{};
32
35
37 const QByteArray &gstreamerPipeline)
38{
39 return qMakeCustomGStreamerAudioInput(gstreamerPipeline);
40}
41
43 const QByteArray &gstreamerPipeline)
44{
45 return qMakeCustomGStreamerAudioOutput(gstreamerPipeline);
46}
47
49 const QByteArray &gstreamerPipeline, QObject *parent)
50{
51 QCameraDevicePrivate *info = new QCameraDevicePrivate;
52 info->id = gstreamerPipeline;
53 QCameraDevice device = info->create();
54
56 auto guard = qScopeGuard([] {
58 });
59
60 return new QCamera(device, parent);
61}
62
63QCamera *
65 QObject *parent)
66{
67 QCameraDevicePrivate *info = new QCameraDevicePrivate;
68 info->id = "Custom Camera from GstElement";
69 QCameraDevice device = info->create();
70
71 pendingCameraElement = QGstElement{
72 element,
73 QGstElement::NeedsRef,
74 };
75
77 auto guard = qScopeGuard([] {
79 Q_ASSERT(!pendingCameraElement);
80 });
81
82 return new QCamera(device, parent);
83}
84
86{
87 auto *priv = reinterpret_cast<QMediaPlayerPrivate *>(QMediaPlayerPrivate::get(player));
88 if (!priv)
89 return nullptr;
90
91 QGstreamerMediaPlayer *gstreamerPlayer = dynamic_cast<QGstreamerMediaPlayer *>(priv->control);
92 return gstreamerPlayer ? gstreamerPlayer->pipeline().pipeline() : nullptr;
93}
94
97{
98 auto *priv = QMediaCaptureSessionPrivate::get(session);
99 if (!priv)
100 return nullptr;
101
102 QGstreamerMediaCaptureSession *gstreamerCapture =
103 dynamic_cast<QGstreamerMediaCaptureSession *>(priv->captureSession.get());
104 return gstreamerCapture ? gstreamerCapture->pipeline().pipeline() : nullptr;
105}
106
108{
109 QHwVideoBuffer *hwBuffer = QVideoFramePrivate::hwBuffer(frame);
110 if (!hwBuffer)
111 return nullptr;
112 QGstVideoBuffer *gstBuffer = dynamic_cast<QGstVideoBuffer *>(hwBuffer);
113 return gstBuffer ? gstBuffer->gstBuffer() : nullptr;
114}
115
117 GstBuffer *buffer, const GstVideoInfo &videoInfo)
118{
119 if (!buffer)
120 return QVideoFrame();
121
122 QGstVideoInfo qtVideoInfo{ videoInfo, std::nullopt };
123
124 return qCreateFrameFromGstBuffer(QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef },
125 qtVideoInfo);
126}
127
129 GstBuffer *buffer, const GstVideoInfoDmaDrm &videoInfoDmaDrm)
130{
132 Q_UNUSED(buffer);
133 Q_UNUSED(videoInfoDmaDrm);
134 qWarning() << QStringLiteral("GstVideoInfoDmaDrm unsupported, minimum GStreamer version required: 1.24");
135 return QVideoFrame();
136#else
137 if (!buffer)
138 return QVideoFrame();
139
140 QGstVideoInfo qtVideoInfo{ { }, videoInfoDmaDrm.drm_modifier };
141 if (!gst_video_info_dma_drm_to_video_info(&videoInfoDmaDrm, &qtVideoInfo.gstVideoInfo))
142 qWarning() << "Failed to create QGstVideoInfo from GstVideoInfoDmaDrm";
143
144 return qCreateFrameFromGstBuffer(QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef },
145 qtVideoInfo);
146#endif
147}
148
149Q_STATIC_LOGGING_CATEGORY(lcGstreamer, "qt.multimedia.gstreamer")
150
151namespace {
152
153void rankDownPlugin(GstRegistry *reg, const char *name)
154{
155 QGstPluginFeatureHandle pluginFeature{
156 gst_registry_lookup_feature(reg, name),
157 QGstPluginFeatureHandle::HasRef,
158 };
159 if (pluginFeature)
160 gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
161}
162
163// https://gstreamer.freedesktop.org/documentation/vaapi/index.html
164constexpr auto vaapiPluginNames = {
165 "vaapidecodebin", "vaapih264dec", "vaapih264enc", "vaapih265dec",
166 "vaapijpegdec", "vaapijpegenc", "vaapimpeg2dec", "vaapipostproc",
167 "vaapisink", "vaapivp8dec", "vaapivp9dec",
168};
169
170// https://gstreamer.freedesktop.org/documentation/va/index.html
171constexpr auto vaPluginNames = {
172 "vaav1dec", "vacompositor", "vadeinterlace", "vah264dec", "vah264enc", "vah265dec",
173 "vajpegdec", "vampeg2dec", "vapostproc", "vavp8dec", "vavp9dec",
174};
175
176// https://gstreamer.freedesktop.org/documentation/nvcodec/index.html
177constexpr auto nvcodecPluginNames = {
178 "cudaconvert", "cudaconvertscale", "cudadownload", "cudaipcsink", "cudaipcsrc",
179 "cudascale", "cudaupload", "nvautogpuh264enc", "nvautogpuh265enc", "nvav1dec",
180 "nvcudah264enc", "nvcudah265enc", "nvd3d11h264enc", "nvd3d11h265enc", "nvh264dec",
181 "nvh264enc", "nvh265dec", "nvh265enc", "nvjpegdec", "nvjpegenc",
182 "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec",
183};
184
185} // namespace
186
189{
190 gst_init(nullptr, nullptr);
191
192 const QGString version{ gst_version_string() };
193 qCInfo(lcGstreamer) << "Using Qt multimedia with GStreamer version:" << version.asStringView();
194
195 GstRegistry *reg = gst_registry_get();
196
197 if constexpr (!GST_CHECK_VERSION(1, 22, 0)) {
198 for (const char *name : vaapiPluginNames)
199 rankDownPlugin(reg, name);
200 }
201
202 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_VA")) {
203 for (const char *name : vaPluginNames)
204 rankDownPlugin(reg, name);
205 }
206
207 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_NVCODEC")) {
208 for (const char *name : nvcodecPluginNames)
209 rankDownPlugin(reg, name);
210 }
211
214}
215
217{
218 // by default we don't deinit, as the application may have initialized gstreamer
219 // (gst_init/deinit is not refcounted).
220 // however it's useful to force deinitialization for leak detection in qt's unit tests.
221 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DEINIT"))
222 gst_deinit();
223}
224
229
231{
232 return new QGstreamerVideoDevices(this);
233}
234
236{
237 return static_cast<const QGstreamerFormatInfo *>(formatInfo());
238}
239
241{
242 return QGstreamerAudioDecoder::create(decoder);
243}
244
246{
247 return QGstreamerMediaCaptureSession::create();
248}
249
251{
252 return QGstreamerMediaPlayer::create(player);
253}
254
256{
258 QGstElement element = std::exchange(pendingCameraElement, {});
259 return element ? new QGstreamerCustomCamera{ camera, std::move(element) }
260 : new QGstreamerCustomCamera{ camera };
261 }
262
263 return QGstreamerCamera::create(camera);
264}
265
267{
268 return new QGstreamerMediaRecorder(recorder);
269}
270
272{
273 return QGstreamerImageCapture::create(imageCapture);
274}
275
280
282{
283 return QGstreamerAudioInput::create(q);
284}
285
287{
288 return QGstreamerAudioOutput::create(q);
289}
290
292{
293 const auto devices = videoDevices();
294 return devices ? static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) : nullptr;
295}
296
301
302QT_END_NAMESPACE
QCamera * makeCustomGStreamerCamera(GstElement *, QObject *parent) override
GstPipeline * gstPipeline(QMediaPlayer *) override
QAudioDevice makeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline) override
QCamera * makeCustomGStreamerCamera(const QByteArray &gstreamerPipeline, QObject *parent) override
QAudioDevice makeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline) override
QVideoFrame createFrameFromGstBuffer(GstBuffer *buffer, const GstVideoInfo &videoInfo) override
q23::expected< QPlatformCamera *, QString > createCamera(QCamera *) override
QPlatformVideoDevices * createVideoDevices() override
QPlatformMediaFormatInfo * createFormatInfo() override
q23::expected< QPlatformAudioOutput *, QString > createAudioOutput(QAudioOutput *) override
q23::expected< QPlatformVideoSink *, QString > createVideoSink(QVideoSink *sink) override
QGStreamerPlatformSpecificInterfaceImplementation m_platformSpecificImplementation
QAbstractPlatformSpecificInterface * platformSpecificInterface() override
q23::expected< QPlatformMediaCaptureSession *, QString > createCaptureSession() override
q23::expected< QPlatformMediaPlayer *, QString > createPlayer(QMediaPlayer *player) override
q23::expected< QPlatformMediaRecorder *, QString > createRecorder(QMediaRecorder *) override
const QGstreamerFormatInfo * gstFormatsInfo()
q23::expected< QPlatformAudioDecoder *, QString > createAudioDecoder(QAudioDecoder *decoder) override
q23::expected< QPlatformImageCapture *, QString > createImageCapture(QImageCapture *) override
GstDevice * videoDevice(const QByteArray &id)
q23::expected< QPlatformAudioInput *, QString > createAudioInput(QAudioInput *) override
const QGstPipeline & pipeline() const
Combined button and popup list for selecting options.
#define QT_GSTREAMER_SUPPORTS_GST_VIDEO_FORMAT_DMA_DRM
Definition qgst_p.h:38
void qGstRegisterQIODeviceHandler(GstPlugin *plugin)
QT_BEGIN_NAMESPACE void qGstRegisterQRCHandler(GstPlugin *plugin)
static bool inCustomCameraConstruction
static QGstElement pendingCameraElement
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)