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 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | static_assert(GST_CHECK_VERSION(1, 20, 0), "Minimum required GStreamer version is 1.20"); |
28 | |
29 | static thread_local bool inCustomCameraConstruction = false; |
30 | static thread_local QGstElement pendingCameraElement{}; |
31 | |
32 | QGStreamerPlatformSpecificInterfaceImplementation:: |
33 | ~QGStreamerPlatformSpecificInterfaceImplementation() = default; |
34 | |
35 | QAudioDevice QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerAudioInput( |
36 | const QByteArray &gstreamerPipeline) |
37 | { |
38 | return qMakeCustomGStreamerAudioInput(gstreamerPipeline); |
39 | } |
40 | |
41 | QAudioDevice QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerAudioOutput( |
42 | const QByteArray &gstreamerPipeline) |
43 | { |
44 | return qMakeCustomGStreamerAudioOutput(gstreamerPipeline); |
45 | } |
46 | |
47 | QCamera *QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerCamera( |
48 | const QByteArray &gstreamerPipeline, QObject *parent) |
49 | { |
50 | QCameraDevicePrivate *info = new QCameraDevicePrivate; |
51 | info->id = gstreamerPipeline; |
52 | QCameraDevice device = info->create(); |
53 | |
54 | inCustomCameraConstruction = true; |
55 | auto guard = qScopeGuard(f: [] { |
56 | inCustomCameraConstruction = false; |
57 | }); |
58 | |
59 | return new QCamera(device, parent); |
60 | } |
61 | |
62 | QCamera * |
63 | QGStreamerPlatformSpecificInterfaceImplementation::makeCustomGStreamerCamera(GstElement *element, |
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 | |
75 | inCustomCameraConstruction = true; |
76 | auto guard = qScopeGuard(f: [] { |
77 | inCustomCameraConstruction = false; |
78 | Q_ASSERT(!pendingCameraElement); |
79 | }); |
80 | |
81 | return new QCamera(device, parent); |
82 | } |
83 | |
84 | GstPipeline *QGStreamerPlatformSpecificInterfaceImplementation::gstPipeline(QMediaPlayer *player) |
85 | { |
86 | auto *priv = reinterpret_cast<QMediaPlayerPrivate *>(QMediaPlayerPrivate::get(session: 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 | |
94 | GstPipeline * |
95 | QGStreamerPlatformSpecificInterfaceImplementation::gstPipeline(QMediaCaptureSession *session) |
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 | |
106 | Q_LOGGING_CATEGORY(lcGstreamer, "qt.multimedia.gstreamer") |
107 | |
108 | namespace { |
109 | |
110 | void rankDownPlugin(GstRegistry *reg, const char *name) |
111 | { |
112 | QGstPluginFeatureHandle pluginFeature{ |
113 | gst_registry_lookup_feature(registry: reg, name), |
114 | QGstPluginFeatureHandle::HasRef, |
115 | }; |
116 | if (pluginFeature) |
117 | gst_plugin_feature_set_rank(feature: pluginFeature.get(), rank: GST_RANK_PRIMARY - 1); |
118 | } |
119 | |
120 | // https://gstreamer.freedesktop.org/documentation/vaapi/index.html |
121 | constexpr 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 |
128 | constexpr 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 |
134 | constexpr 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 | |
144 | QGstreamerIntegration::QGstreamerIntegration() |
145 | : QPlatformMediaIntegration(QLatin1String("gstreamer")) |
146 | { |
147 | gst_init(argc: nullptr, argv: nullptr); |
148 | qCDebug(lcGstreamer) << "Using gstreamer version: "<< gst_version_string(); |
149 | |
150 | GstRegistry *reg = gst_registry_get(); |
151 | |
152 | if constexpr (!GST_CHECK_VERSION(1, 22, 0)) { |
153 | GstRegistry* reg = gst_registry_get(); |
154 | for (const char *name : vaapiPluginNames) |
155 | rankDownPlugin(reg, name); |
156 | } |
157 | |
158 | if (qEnvironmentVariableIsSet(varName: "QT_GSTREAMER_DISABLE_VA")) { |
159 | for (const char *name : vaPluginNames) |
160 | rankDownPlugin(reg, name); |
161 | } |
162 | |
163 | if (qEnvironmentVariableIsSet(varName: "QT_GSTREAMER_DISABLE_NVCODEC")) { |
164 | for (const char *name : nvcodecPluginNames) |
165 | rankDownPlugin(reg, name); |
166 | } |
167 | |
168 | qGstRegisterQRCHandler(plugin: nullptr); |
169 | qGstRegisterQIODeviceHandler(plugin: nullptr); |
170 | } |
171 | |
172 | QPlatformMediaFormatInfo *QGstreamerIntegration::createFormatInfo() |
173 | { |
174 | return new QGstreamerFormatInfo(); |
175 | } |
176 | |
177 | QPlatformVideoDevices *QGstreamerIntegration::createVideoDevices() |
178 | { |
179 | return new QGstreamerVideoDevices(this); |
180 | } |
181 | |
182 | const QGstreamerFormatInfo *QGstreamerIntegration::gstFormatsInfo() |
183 | { |
184 | return static_cast<const QGstreamerFormatInfo *>(formatInfo()); |
185 | } |
186 | |
187 | QMaybe<QPlatformAudioDecoder *> QGstreamerIntegration::createAudioDecoder(QAudioDecoder *decoder) |
188 | { |
189 | return QGstreamerAudioDecoder::create(parent: decoder); |
190 | } |
191 | |
192 | QMaybe<QPlatformMediaCaptureSession *> QGstreamerIntegration::createCaptureSession() |
193 | { |
194 | return QGstreamerMediaCaptureSession::create(); |
195 | } |
196 | |
197 | QMaybe<QPlatformMediaPlayer *> QGstreamerIntegration::createPlayer(QMediaPlayer *player) |
198 | { |
199 | return QGstreamerMediaPlayer::create(parent: player); |
200 | } |
201 | |
202 | QMaybe<QPlatformCamera *> QGstreamerIntegration::createCamera(QCamera *camera) |
203 | { |
204 | if (inCustomCameraConstruction) { |
205 | QGstElement element = std::exchange(obj&: pendingCameraElement, new_val: {}); |
206 | return element ? new QGstreamerCustomCamera{ camera, std::move(element) } |
207 | : new QGstreamerCustomCamera{ camera }; |
208 | } |
209 | |
210 | return QGstreamerCamera::create(camera); |
211 | } |
212 | |
213 | QMaybe<QPlatformMediaRecorder *> QGstreamerIntegration::createRecorder(QMediaRecorder *recorder) |
214 | { |
215 | return new QGstreamerMediaRecorder(recorder); |
216 | } |
217 | |
218 | QMaybe<QPlatformImageCapture *> QGstreamerIntegration::createImageCapture(QImageCapture *imageCapture) |
219 | { |
220 | return QGstreamerImageCapture::create(parent: imageCapture); |
221 | } |
222 | |
223 | QMaybe<QPlatformVideoSink *> QGstreamerIntegration::createVideoSink(QVideoSink *sink) |
224 | { |
225 | return new QGstreamerVideoSink(sink); |
226 | } |
227 | |
228 | QMaybe<QPlatformAudioInput *> QGstreamerIntegration::createAudioInput(QAudioInput *q) |
229 | { |
230 | return QGstreamerAudioInput::create(parent: q); |
231 | } |
232 | |
233 | QMaybe<QPlatformAudioOutput *> QGstreamerIntegration::createAudioOutput(QAudioOutput *q) |
234 | { |
235 | return QGstreamerAudioOutput::create(parent: q); |
236 | } |
237 | |
238 | GstDevice *QGstreamerIntegration::videoDevice(const QByteArray &id) |
239 | { |
240 | const auto devices = videoDevices(); |
241 | return devices ? static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) : nullptr; |
242 | } |
243 | |
244 | QAbstractPlatformSpecificInterface *QGstreamerIntegration::platformSpecificInterface() |
245 | { |
246 | return &m_platformSpecificImplementation; |
247 | } |
248 | |
249 | QT_END_NAMESPACE |
250 |
Definitions
- inCustomCameraConstruction
- pendingCameraElement
- ~QGStreamerPlatformSpecificInterfaceImplementation
- makeCustomGStreamerAudioInput
- makeCustomGStreamerAudioOutput
- makeCustomGStreamerCamera
- makeCustomGStreamerCamera
- gstPipeline
- gstPipeline
- lcGstreamer
- rankDownPlugin
- vaapiPluginNames
- vaPluginNames
- nvcodecPluginNames
- QGstreamerIntegration
- createFormatInfo
- createVideoDevices
- gstFormatsInfo
- createAudioDecoder
- createCaptureSession
- createPlayer
- createCamera
- createRecorder
- createImageCapture
- createVideoSink
- createAudioInput
- createAudioOutput
- videoDevice
Start learning QML with our Intro Training
Find out more