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
26
27static_assert(GST_CHECK_VERSION(1, 20, 0), "Minimum required GStreamer version is 1.20");
28
29static thread_local bool inCustomCameraConstruction = false;
30static thread_local QGstElement pendingCameraElement{};
31
34
36 const QByteArray &gstreamerPipeline)
37{
38 return qMakeCustomGStreamerAudioInput(gstreamerPipeline);
39}
40
42 const QByteArray &gstreamerPipeline)
43{
44 return qMakeCustomGStreamerAudioOutput(gstreamerPipeline);
45}
46
48 const QByteArray &gstreamerPipeline, QObject *parent)
49{
50 QCameraDevicePrivate *info = new QCameraDevicePrivate;
51 info->id = gstreamerPipeline;
52 QCameraDevice device = info->create();
53
55 auto guard = qScopeGuard([] {
57 });
58
59 return new QCamera(device, parent);
60}
61
62QCamera *
64 QObject *parent)
65{
66 QCameraDevicePrivate *info = new QCameraDevicePrivate;
67 info->id = "Custom Camera from GstElement";
68 QCameraDevice device = info->create();
69
70 pendingCameraElement = QGstElement{
71 element,
72 QGstElement::NeedsRef,
73 };
74
76 auto guard = qScopeGuard([] {
78 Q_ASSERT(!pendingCameraElement);
79 });
80
81 return new QCamera(device, parent);
82}
83
85{
86 auto *priv = reinterpret_cast<QMediaPlayerPrivate *>(QMediaPlayerPrivate::get(player));
87 if (!priv)
88 return nullptr;
89
90 QGstreamerMediaPlayer *gstreamerPlayer = dynamic_cast<QGstreamerMediaPlayer *>(priv->control);
91 return gstreamerPlayer ? gstreamerPlayer->pipeline().pipeline() : nullptr;
92}
93
96{
97 auto *priv = QMediaCaptureSessionPrivate::get(session);
98 if (!priv)
99 return nullptr;
100
101 QGstreamerMediaCaptureSession *gstreamerCapture =
102 dynamic_cast<QGstreamerMediaCaptureSession *>(priv->captureSession.get());
103 return gstreamerCapture ? gstreamerCapture->pipeline().pipeline() : nullptr;
104}
105
106Q_STATIC_LOGGING_CATEGORY(lcGstreamer, "qt.multimedia.gstreamer")
107
108namespace {
109
110void rankDownPlugin(GstRegistry *reg, const char *name)
111{
112 QGstPluginFeatureHandle pluginFeature{
113 gst_registry_lookup_feature(reg, name),
114 QGstPluginFeatureHandle::HasRef,
115 };
116 if (pluginFeature)
117 gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
118}
119
120// https://gstreamer.freedesktop.org/documentation/vaapi/index.html
121constexpr auto vaapiPluginNames = {
122 "vaapidecodebin", "vaapih264dec", "vaapih264enc", "vaapih265dec",
123 "vaapijpegdec", "vaapijpegenc", "vaapimpeg2dec", "vaapipostproc",
124 "vaapisink", "vaapivp8dec", "vaapivp9dec",
125};
126
127// https://gstreamer.freedesktop.org/documentation/va/index.html
128constexpr auto vaPluginNames = {
129 "vaav1dec", "vacompositor", "vadeinterlace", "vah264dec", "vah264enc", "vah265dec",
130 "vajpegdec", "vampeg2dec", "vapostproc", "vavp8dec", "vavp9dec",
131};
132
133// https://gstreamer.freedesktop.org/documentation/nvcodec/index.html
134constexpr auto nvcodecPluginNames = {
135 "cudaconvert", "cudaconvertscale", "cudadownload", "cudaipcsink", "cudaipcsrc",
136 "cudascale", "cudaupload", "nvautogpuh264enc", "nvautogpuh265enc", "nvav1dec",
137 "nvcudah264enc", "nvcudah265enc", "nvd3d11h264enc", "nvd3d11h265enc", "nvh264dec",
138 "nvh264enc", "nvh265dec", "nvh265enc", "nvjpegdec", "nvjpegenc",
139 "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec",
140};
141
142} // namespace
143
146{
147 gst_init(nullptr, nullptr);
148
149 const QGString version{ gst_version_string() };
150 qCInfo(lcGstreamer) << "Using Qt multimedia with GStreamer version:" << version.asStringView();
151
152 GstRegistry *reg = gst_registry_get();
153
154 if constexpr (!GST_CHECK_VERSION(1, 22, 0)) {
155 for (const char *name : vaapiPluginNames)
156 rankDownPlugin(reg, name);
157 }
158
159 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_VA")) {
160 for (const char *name : vaPluginNames)
161 rankDownPlugin(reg, name);
162 }
163
164 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_NVCODEC")) {
165 for (const char *name : nvcodecPluginNames)
166 rankDownPlugin(reg, name);
167 }
168
171}
172
174{
175 // by default we don't deinit, as the application may have initialized gstreamer
176 // (gst_init/deinit is not refcounted).
177 // however it's useful to force deinitialization for leak detection in qt's unit tests.
178 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DEINIT"))
179 gst_deinit();
180}
181
186
188{
189 return new QGstreamerVideoDevices(this);
190}
191
193{
194 return static_cast<const QGstreamerFormatInfo *>(formatInfo());
195}
196
198{
199 return QGstreamerAudioDecoder::create(decoder);
200}
201
203{
204 return QGstreamerMediaCaptureSession::create();
205}
206
208{
209 return QGstreamerMediaPlayer::create(player);
210}
211
213{
215 QGstElement element = std::exchange(pendingCameraElement, {});
216 return element ? new QGstreamerCustomCamera{ camera, std::move(element) }
217 : new QGstreamerCustomCamera{ camera };
218 }
219
220 return QGstreamerCamera::create(camera);
221}
222
224{
225 return new QGstreamerMediaRecorder(recorder);
226}
227
229{
230 return QGstreamerImageCapture::create(imageCapture);
231}
232
237
239{
240 return QGstreamerAudioInput::create(q);
241}
242
244{
245 return QGstreamerAudioOutput::create(q);
246}
247
249{
250 const auto devices = videoDevices();
251 return devices ? static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) : nullptr;
252}
253
258
259QT_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
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
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
void qGstRegisterQIODeviceHandler(GstPlugin *plugin)
void qGstRegisterQRCHandler(GstPlugin *plugin)
static thread_local bool inCustomCameraConstruction
static thread_local QGstElement pendingCameraElement