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
116Q_STATIC_LOGGING_CATEGORY(lcGstreamer, "qt.multimedia.gstreamer")
117
118namespace {
119
120void rankDownPlugin(GstRegistry *reg, const char *name)
121{
122 QGstPluginFeatureHandle pluginFeature{
123 gst_registry_lookup_feature(reg, name),
124 QGstPluginFeatureHandle::HasRef,
125 };
126 if (pluginFeature)
127 gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
128}
129
130// https://gstreamer.freedesktop.org/documentation/vaapi/index.html
131constexpr auto vaapiPluginNames = {
132 "vaapidecodebin", "vaapih264dec", "vaapih264enc", "vaapih265dec",
133 "vaapijpegdec", "vaapijpegenc", "vaapimpeg2dec", "vaapipostproc",
134 "vaapisink", "vaapivp8dec", "vaapivp9dec",
135};
136
137// https://gstreamer.freedesktop.org/documentation/va/index.html
138constexpr auto vaPluginNames = {
139 "vaav1dec", "vacompositor", "vadeinterlace", "vah264dec", "vah264enc", "vah265dec",
140 "vajpegdec", "vampeg2dec", "vapostproc", "vavp8dec", "vavp9dec",
141};
142
143// https://gstreamer.freedesktop.org/documentation/nvcodec/index.html
144constexpr auto nvcodecPluginNames = {
145 "cudaconvert", "cudaconvertscale", "cudadownload", "cudaipcsink", "cudaipcsrc",
146 "cudascale", "cudaupload", "nvautogpuh264enc", "nvautogpuh265enc", "nvav1dec",
147 "nvcudah264enc", "nvcudah265enc", "nvd3d11h264enc", "nvd3d11h265enc", "nvh264dec",
148 "nvh264enc", "nvh265dec", "nvh265enc", "nvjpegdec", "nvjpegenc",
149 "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec",
150};
151
152} // namespace
153
156{
157 gst_init(nullptr, nullptr);
158
159 const QGString version{ gst_version_string() };
160 qCInfo(lcGstreamer) << "Using Qt multimedia with GStreamer version:" << version.asStringView();
161
162 GstRegistry *reg = gst_registry_get();
163
164 if constexpr (!GST_CHECK_VERSION(1, 22, 0)) {
165 for (const char *name : vaapiPluginNames)
166 rankDownPlugin(reg, name);
167 }
168
169 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_VA")) {
170 for (const char *name : vaPluginNames)
171 rankDownPlugin(reg, name);
172 }
173
174 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DISABLE_NVCODEC")) {
175 for (const char *name : nvcodecPluginNames)
176 rankDownPlugin(reg, name);
177 }
178
181}
182
184{
185 // by default we don't deinit, as the application may have initialized gstreamer
186 // (gst_init/deinit is not refcounted).
187 // however it's useful to force deinitialization for leak detection in qt's unit tests.
188 if (qEnvironmentVariableIsSet("QT_GSTREAMER_DEINIT"))
189 gst_deinit();
190}
191
196
198{
199 return new QGstreamerVideoDevices(this);
200}
201
203{
204 return static_cast<const QGstreamerFormatInfo *>(formatInfo());
205}
206
208{
209 return QGstreamerAudioDecoder::create(decoder);
210}
211
213{
214 return QGstreamerMediaCaptureSession::create();
215}
216
218{
219 return QGstreamerMediaPlayer::create(player);
220}
221
223{
225 QGstElement element = std::exchange(pendingCameraElement, {});
226 return element ? new QGstreamerCustomCamera{ camera, std::move(element) }
227 : new QGstreamerCustomCamera{ camera };
228 }
229
230 return QGstreamerCamera::create(camera);
231}
232
234{
235 return new QGstreamerMediaRecorder(recorder);
236}
237
239{
240 return QGstreamerImageCapture::create(imageCapture);
241}
242
247
249{
250 return QGstreamerAudioInput::create(q);
251}
252
254{
255 return QGstreamerAudioOutput::create(q);
256}
257
259{
260 const auto devices = videoDevices();
261 return devices ? static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) : nullptr;
262}
263
268
269QT_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
Combined button and popup list for selecting options.
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)