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/qgstbufferprovider_p.h>
12#include <common/qgstreamermediaplayer_p.h>
13#include <common/qgstreamervideosink_p.h>
14#include <mediacapture/qgstreamercamera_p.h>
15#include <mediacapture/qgstreamerimagecapture_p.h>
16#include <mediacapture/qgstreamermediacapturesession_p.h>
17#include <mediacapture/qgstreamermediarecorder_p.h>
18#include <uri_handler/qgstreamer_qiodevice_handler_p.h>
19#include <uri_handler/qgstreamer_qrc_handler_p.h>
21#if QT_CONFIG(gstreamer_qt_api)
22# include <QtMultimedia/spi/qgstreamervideosource.h>
24#include <QtCore/qloggingcategory.h>
25#include <QtMultimedia/private/qmediaplayer_p.h>
26#include <QtMultimedia/private/qmediacapturesession_p.h>
27#include <QtMultimedia/private/qcameradevice_p.h>
28#include <QtMultimedia/private/qvideoframe_p.h>
32static_assert(GST_CHECK_VERSION(1, 20, 0),
"Minimum required GStreamer version is 1.20");
34#if QT_CONFIG(gstreamer_qt_api)
38thread_local std::optional<GstElementOrDescription> customCameraContructionInput = { };
40QCamera *makeCustomGStreamerCameraImpl(QByteArray id, GstElementOrDescription elementOrDesc,
43 QCameraDevicePrivate *info =
new QCameraDevicePrivate;
44 info->id = std::move(id);
45 QCameraDevice device = info->create();
47 Q_ASSERT(!customCameraContructionInput);
48 customCameraContructionInput = std::move(elementOrDesc);
50 auto resetCustomCameraInput = qScopeGuard([] {
51 customCameraContructionInput.reset();
54 return new QCamera(device, parent);
57q23::expected<QPlatformCamera *, QString>
58createGStreamerVideoSourceImpl(QObject *videoSource,
const GstElementOrDescription &elementOrDesc)
60 using namespace Qt::Literals;
61 auto createImpl = [videoSource](
const auto &arg) -> q23::expected<QPlatformCamera *, QString> {
63 if constexpr (std::is_same_v<
decltype(arg),
const QString &>) {
65 return q23::unexpected{ u"GstBin description is empty"_s };
66 element = QGstBin::createFromPipelineDescription(arg.toUtf8(),
nullptr,
69 return q23::unexpected{ u"Failed to create GstBin from description"_s };
72 return q23::unexpected{ u"GstElement is null"_s };
74 element = QGstElement{ arg, QGstElement::NeedsRef };
77 return new QGstreamerCustomCamera(videoSource, std::move(element));
79 return std::visit(createImpl, elementOrDesc);
84QGStreamerInterfaceImplementation::~QGStreamerInterfaceImplementation() =
default;
86QAudioDevice QGStreamerInterfaceImplementation::makeCustomGStreamerAudioInput(
87 const QByteArray &gstreamerPipeline)
89 return qMakeCustomGStreamerAudioInput(gstreamerPipeline);
92QAudioDevice QGStreamerInterfaceImplementation::makeCustomGStreamerAudioOutput(
93 const QByteArray &gstreamerPipeline)
95 return qMakeCustomGStreamerAudioOutput(gstreamerPipeline);
99QGStreamerInterfaceImplementation::makeCustomGStreamerCamera(
const QByteArray &gstBinDescription,
102 return makeCustomGStreamerCameraImpl(gstBinDescription, QString::fromUtf8(gstBinDescription),
106QCamera *QGStreamerInterfaceImplementation::makeCustomGStreamerCamera(
107 GstElement *element, QObject *parent)
109 return makeCustomGStreamerCameraImpl(
"Custom Camera from GstElement", element, parent);
112GstPipeline *QGStreamerInterfaceImplementation::gstPipeline(QMediaPlayer *player)
114 auto *priv =
reinterpret_cast<QMediaPlayerPrivate *>(QMediaPlayerPrivate::get(player));
118 QGstreamerMediaPlayer *gstreamerPlayer =
dynamic_cast<QGstreamerMediaPlayer *>(priv->control);
119 return gstreamerPlayer ? gstreamerPlayer->pipeline().pipeline() :
nullptr;
123QGStreamerInterfaceImplementation::gstPipeline(QMediaCaptureSession *session)
125 auto *priv = QMediaCaptureSessionPrivate::get(session);
129 QGstreamerMediaCaptureSession *gstreamerCapture =
130 dynamic_cast<QGstreamerMediaCaptureSession *>(priv->captureSession.get());
131 return gstreamerCapture ? gstreamerCapture->pipeline().pipeline() :
nullptr;
134GstBuffer *QGStreamerInterfaceImplementation::gstBuffer(
const QVideoFrame &frame)
136 QHwVideoBuffer *hwBuffer = QVideoFramePrivate::hwBuffer(frame);
139 QGstBufferProvider *provider =
dynamic_cast<QGstBufferProvider *>(hwBuffer);
140 return provider ? provider->gstBuffer() :
nullptr;
143QVideoFrame QGStreamerInterfaceImplementation::createFrameFromGstBuffer(
144 GstBuffer *buffer,
const GstVideoInfo &videoInfo)
147 return QVideoFrame();
149 QGstVideoInfo qtVideoInfo{ videoInfo, std::nullopt };
151 return qCreateFrameFromGstBuffer(QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef },
155QVideoFrame QGStreamerInterfaceImplementation::createFrameFromGstBuffer(
156 GstBuffer *buffer,
const GstVideoInfoDmaDrm &videoInfoDmaDrm)
158#if !QT_GSTREAMER_SUPPORTS_GST_VIDEO_FORMAT_DMA_DRM
160 Q_UNUSED(videoInfoDmaDrm);
161 qWarning() << QStringLiteral(
"GstVideoInfoDmaDrm unsupported, minimum GStreamer version required: 1.24");
162 return QVideoFrame();
165 return QVideoFrame();
167 QGstVideoInfo qtVideoInfo{ { }, videoInfoDmaDrm.drm_modifier };
168 if (!gst_video_info_dma_drm_to_video_info(&videoInfoDmaDrm, &qtVideoInfo.gstVideoInfo))
169 qWarning() <<
"Failed to create QGstVideoInfo from GstVideoInfoDmaDrm";
171 return qCreateFrameFromGstBuffer(QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef },
182void rankDownPlugin(GstRegistry *reg,
const char *name)
184 QGstPluginFeatureHandle pluginFeature{
185 gst_registry_lookup_feature(reg, name),
186 QGstPluginFeatureHandle::HasRef,
189 gst_plugin_feature_set_rank(pluginFeature.get(), GST_RANK_PRIMARY - 1);
193constexpr auto vaapiPluginNames = {
194 "vaapidecodebin",
"vaapih264dec",
"vaapih264enc",
"vaapih265dec",
195 "vaapijpegdec",
"vaapijpegenc",
"vaapimpeg2dec",
"vaapipostproc",
196 "vaapisink",
"vaapivp8dec",
"vaapivp9dec",
200constexpr auto vaPluginNames = {
201 "vaav1dec",
"vacompositor",
"vadeinterlace",
"vah264dec",
"vah264enc",
"vah265dec",
202 "vajpegdec",
"vampeg2dec",
"vapostproc",
"vavp8dec",
"vavp9dec",
206constexpr auto nvcodecPluginNames = {
207 "cudaconvert",
"cudaconvertscale",
"cudadownload",
"cudaipcsink",
"cudaipcsrc",
208 "cudascale",
"cudaupload",
"nvautogpuh264enc",
"nvautogpuh265enc",
"nvav1dec",
209 "nvcudah264enc",
"nvcudah265enc",
"nvd3d11h264enc",
"nvd3d11h265enc",
"nvh264dec",
210 "nvh264enc",
"nvh265dec",
"nvh265enc",
"nvjpegdec",
"nvjpegenc",
211 "nvmpeg2videodec",
"nvmpeg4videodec",
"nvmpegvideodec",
"nvvp8dec",
"nvvp9dec",
219 gst_init(
nullptr,
nullptr);
221 const QGString version{ gst_version_string() };
222 qCInfo(lcGstreamer) <<
"Using Qt multimedia with GStreamer version:" << version.asStringView();
224 GstRegistry *reg = gst_registry_get();
226 if constexpr (!GST_CHECK_VERSION(1, 22, 0)) {
227 for (
const char *name : vaapiPluginNames)
228 rankDownPlugin(reg, name);
231 if (qEnvironmentVariableIsSet(
"QT_GSTREAMER_DISABLE_VA")) {
232 for (
const char *name : vaPluginNames)
233 rankDownPlugin(reg, name);
236 if (qEnvironmentVariableIsSet(
"QT_GSTREAMER_DISABLE_NVCODEC")) {
237 for (
const char *name : nvcodecPluginNames)
238 rankDownPlugin(reg, name);
250 if (qEnvironmentVariableIsSet(
"QT_GSTREAMER_DEINIT"))
261 return new QGstreamerVideoDevices(
this);
271 return QGstreamerAudioDecoder::create(decoder);
276 return QGstreamerMediaCaptureSession::create();
281 return QGstreamerMediaPlayer::create(player);
286#if QT_CONFIG(gstreamer_qt_api)
287 if (customCameraContructionInput)
288 return createGStreamerVideoSourceImpl(camera, *customCameraContructionInput);
291 return QGstreamerCamera::create(camera);
301 return QGstreamerImageCapture::create(imageCapture);
306 return QGstreamerAudioInput::create(q);
311 return QGstreamerAudioOutput::create(q);
316 const auto devices = videoDevices();
317 return devices ?
static_cast<QGstreamerVideoDevices *>(devices)->videoDevice(id) :
nullptr;
320#if QT_CONFIG(gstreamer_qt_api)
321q23::expected<QPlatformCamera *, QString>
322QGstreamerIntegration::createGStreamerVideoSource(QGStreamerVideoSource *videoSource,
323 const GstElementOrDescription &elementOrDesc)
325 return createGStreamerVideoSourceImpl(videoSource, elementOrDesc);
328QGStreamerInterface *QGstreamerIntegration::gstreamerInterface()
330 return &m_gstreamerInterface;
q23::expected< QPlatformCamera *, QString > createCamera(QCamera *) override
QPlatformVideoDevices * createVideoDevices() override
QPlatformMediaFormatInfo * createFormatInfo() override
q23::expected< QPlatformAudioOutput *, QString > createAudioOutput(QAudioOutput *) override
~QGstreamerIntegration() 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
Combined button and popup list for selecting options.
void qGstRegisterQIODeviceHandler(GstPlugin *plugin)
QT_BEGIN_NAMESPACE void qGstRegisterQRCHandler(GstPlugin *plugin)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)