QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GStreamer.cc
Go to the documentation of this file.
1#include "GStreamer.h"
2#include "GStreamerHelpers.h"
3#include "AppSettings.h"
4#include "GstVideoReceiver.h"
6#include "SettingsManager.h"
7#include "VideoSettings.h"
8
9#include <QtCore/QCoreApplication>
10#include <QtCore/QSettings>
11#include <QtCore/QStringList>
12#include <QtQuick/QQuickItem>
13
14#include <gst/gst.h>
15
16QGC_LOGGING_CATEGORY(GStreamerLog, "Video.GStreamer")
17QGC_LOGGING_CATEGORY(GStreamerDecoderRanksLog, "Video.GStreamerDecoderRanks")
18QGC_LOGGING_CATEGORY_ON(GStreamerAPILog, "Video.GStreamerAPI")
19
20// TODO: Clean These up with Macros or CMake
21G_BEGIN_DECLS
46GST_PLUGIN_STATIC_DECLARE(typefindfunctions);
52
55
56namespace GStreamer
57{
58
60{
61#ifdef QGC_GST_STATIC_BUILD
62 #ifdef GST_PLUGIN_androidmedia_FOUND
63 GST_PLUGIN_STATIC_REGISTER(androidmedia);
64 #endif
65 #ifdef GST_PLUGIN_applemedia_FOUND
66 GST_PLUGIN_STATIC_REGISTER(applemedia);
67 #endif
68 GST_PLUGIN_STATIC_REGISTER(coreelements);
69 #ifdef GST_PLUGIN_d3d_FOUND
70 GST_PLUGIN_STATIC_REGISTER(d3d);
71 #endif
72 #ifdef GST_PLUGIN_d3d11_FOUND
73 GST_PLUGIN_STATIC_REGISTER(d3d11);
74 #endif
75 #ifdef GST_PLUGIN_d3d12_FOUND
76 GST_PLUGIN_STATIC_REGISTER(d3d12);
77 #endif
78 #ifdef GST_PLUGIN_dav1d_FOUND
79 GST_PLUGIN_STATIC_REGISTER(dav1d);
80 #endif
81 #ifdef GST_PLUGIN_dxva_FOUND
82 GST_PLUGIN_STATIC_REGISTER(dxva);
83 #endif
84 GST_PLUGIN_STATIC_REGISTER(isomp4);
85 GST_PLUGIN_STATIC_REGISTER(libav);
86 GST_PLUGIN_STATIC_REGISTER(matroska);
87 GST_PLUGIN_STATIC_REGISTER(mpegtsdemux);
88 #ifdef GST_PLUGIN_msdk_FOUND
89 GST_PLUGIN_STATIC_REGISTER(msdk);
90 #endif
91 #ifdef GST_PLUGIN_nvcodec_FOUND
92 GST_PLUGIN_STATIC_REGISTER(nvcodec);
93 #endif
94 GST_PLUGIN_STATIC_REGISTER(opengl);
95 GST_PLUGIN_STATIC_REGISTER(openh264);
96 GST_PLUGIN_STATIC_REGISTER(playback);
97 #ifdef GST_PLUGIN_qsv_FOUND
98 GST_PLUGIN_STATIC_REGISTER(qsv);
99 #endif
100 GST_PLUGIN_STATIC_REGISTER(rtp);
101 GST_PLUGIN_STATIC_REGISTER(rtpmanager);
102 GST_PLUGIN_STATIC_REGISTER(rtsp);
103 GST_PLUGIN_STATIC_REGISTER(sdpelem);
104 GST_PLUGIN_STATIC_REGISTER(tcp);
105 GST_PLUGIN_STATIC_REGISTER(typefindfunctions);
106 GST_PLUGIN_STATIC_REGISTER(udp);
107 #ifdef GST_PLUGIN_va_FOUND
108 GST_PLUGIN_STATIC_REGISTER(va);
109 #endif
110 GST_PLUGIN_STATIC_REGISTER(videoparsersbad);
111 GST_PLUGIN_STATIC_REGISTER(vpx);
112 #ifdef GST_PLUGIN_vulkan_FOUND
113 GST_PLUGIN_STATIC_REGISTER(vulkan);
114 #endif
115#endif
116
117// #if !defined(GST_PLUGIN_qml6_FOUND) && defined(QGC_GST_STATIC_BUILD)
118 GST_PLUGIN_STATIC_REGISTER(qml6);
119// #endif
120
121 GST_PLUGIN_STATIC_REGISTER(qgc);
122}
123
124void _qtGstLog(GstDebugCategory *category,
125 GstDebugLevel level,
126 const gchar *file,
127 const gchar *function,
128 gint line,
129 GObject *object,
130 GstDebugMessage *message,
131 gpointer data)
132{
133 Q_UNUSED(data);
134
135 if (level > gst_debug_category_get_threshold(category)) {
136 return;
137 }
138
139 QMessageLogger log(file, line, function);
140
141 char *object_info = gst_info_strdup_printf("%" GST_PTR_FORMAT, static_cast<void*>(object));
142
143 switch (level) {
144 case GST_LEVEL_ERROR:
145 log.critical(GStreamerAPILog, "%s %s", object_info, gst_debug_message_get(message));
146 break;
147 case GST_LEVEL_WARNING:
148 log.warning(GStreamerAPILog, "%s %s", object_info, gst_debug_message_get(message));
149 break;
150 case GST_LEVEL_FIXME:
151 case GST_LEVEL_INFO:
152 log.info(GStreamerAPILog, "%s %s", object_info, gst_debug_message_get(message));
153 break;
154 case GST_LEVEL_DEBUG:
155#ifdef QT_DEBUG
156 case GST_LEVEL_LOG:
157 case GST_LEVEL_TRACE:
158 case GST_LEVEL_MEMDUMP:
159#endif
160 log.debug(GStreamerAPILog, "%s %s", object_info, gst_debug_message_get(message));
161 break;
162 default:
163 break;
164 }
165
166 g_clear_pointer(&object_info, g_free);
167}
168
170{
171 const QString appDir = QCoreApplication::applicationDirPath();
172 qCDebug(GStreamerLog) << "App Directory:" << appDir;
173
174#if defined(Q_OS_MACOS) && defined(QGC_GST_MACOS_FRAMEWORK)
175 const QString frameworkDir = QDir(appDir).filePath("../Frameworks/GStreamer.framework");
176 const QString rootDir = QDir(frameworkDir).filePath("Versions/1.0");
177 const QString libDir = QDir(rootDir).filePath("../lib");
178 const QString pluginDir = QDir(libDir).filePath("gstreamer-1.0");
179 const QString gioMod = QDir(libDir).filePath("gio/modules");
180 const QString libexecDir = QDir(appDir).filePath("../libexec");
181 const QString scanner = QDir(libexecDir).filePath("gstreamer-1.0/gst-plugin-scanner");
182 const QString ptp = QDir(libexecDir).filePath("gstreamer-1.0/gst-ptp-helper");
183
184 if (QFileInfo::exists(frameworkDir)) {
185 qputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no");
186 qputenv("GIO_EXTRA_MODULES", gioMod.toUtf8().constData());
187 qputenv("GST_PTP_HELPER_1_0", ptp.toUtf8().constData());
188 qputenv("GST_PTP_HELPER", ptp.toUtf8().constData());
189 qputenv("GST_PLUGIN_SCANNER_1_0", scanner.toUtf8().constData());
190 qputenv("GST_PLUGIN_SCANNER", scanner.toUtf8().constData());
191 qputenv("GST_PLUGIN_SYSTEM_PATH_1_0", pluginDir.toUtf8().constData());
192 qputenv("GST_PLUGIN_SYSTEM_PATH", pluginDir.toUtf8().constData());
193 qputenv("GST_PLUGIN_PATH_1_0", pluginDir.toUtf8().constData());
194 qputenv("GST_PLUGIN_PATH", pluginDir.toUtf8().constData());
195 qputenv("GTK_PATH", rootDir.toUtf8().constData());
196 }
197#elif defined(Q_OS_WIN)
198 const QString binDir = appDir;
199 const QString libDir = QDir(binDir).filePath("../lib");
200 const QString pluginDir = QDir(libDir).filePath("gstreamer-1.0");
201 const QString gioMod = QDir(libDir).filePath("gio/modules");
202 const QString libexecDir = QDir(binDir).filePath("../libexec");
203 const QString scanner = QDir(libexecDir).filePath("gstreamer-1.0/gst-plugin-scanner");
204 const QString ptp = QDir(libexecDir).filePath("gstreamer-1.0/gst-ptp-helper");
205
206 if (QFileInfo::exists(pluginDir)) {
207 qputenv("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no");
208 qputenv("GIO_EXTRA_MODULES", gioMod.toUtf8().constData());
209 qputenv("GST_PTP_HELPER_1_0", ptp.toUtf8().constData());
210 qputenv("GST_PTP_HELPER", ptp.toUtf8().constData());
211 qputenv("GST_PLUGIN_SCANNER_1_0", scanner.toUtf8().constData());
212 qputenv("GST_PLUGIN_SCANNER", scanner.toUtf8().constData());
213 qputenv("GST_PLUGIN_SYSTEM_PATH_1_0", pluginDir.toUtf8().constData());
214 qputenv("GST_PLUGIN_SYSTEM_PATH", pluginDir.toUtf8().constData());
215 qputenv("GST_PLUGIN_PATH_1_0", pluginDir.toUtf8().constData());
216 qputenv("GST_PLUGIN_PATH", pluginDir.toUtf8().constData());
217 }
218#endif
219}
220
221void _logPlugin(gpointer data, gpointer /*user_data*/)
222{
223 GstPlugin *plugin = static_cast<GstPlugin*>(data);
224 if (!plugin) {
225 return;
226 }
227
228 const gchar *name = gst_plugin_get_name(plugin);
229 const gchar *version = gst_plugin_get_version(plugin);
230 qCDebug(GStreamerLog) << " " << name << "-" << version;
231}
232
234{
235 bool result = true;
236
237 GstRegistry *registry = gst_registry_get();
238
239 qCDebug(GStreamerLog) << "Installed GStreamer Plugins:";
240 GList *plugins = gst_registry_get_plugin_list(registry);
241 g_list_foreach(plugins, _logPlugin, NULL);
242 g_list_free(plugins);
243
244 static constexpr const char *pluginNames[2] = {"qml6", "qgc"};
245 for (const char *name : pluginNames) {
246 GstPlugin *plugin = gst_registry_find_plugin(registry, name);
247 if (!plugin) {
248 qCCritical(GStreamerLog) << name << "plugin NOT found.";
249 result = false;
250 continue;
251 }
252 gst_clear_object(&plugin);
253 }
254
255 if (!result) {
256 QString pluginPath;
257 if (qEnvironmentVariableIsSet("GST_PLUGIN_PATH_1_0")) {
258 pluginPath = qgetenv("GST_PLUGIN_PATH_1_0");
259 } else if (qEnvironmentVariableIsSet("GST_PLUGIN_PATH")) {
260 pluginPath = qgetenv("GST_PLUGIN_PATH");
261 }
262
263#ifdef QGC_GST_STATIC_BUILD
264 qCCritical(GStreamerLog) << "Please update the list of static plugins in GStreamer.cc";
265#else
266 if (!pluginPath.isEmpty()) {
267 qCCritical(GStreamerLog) << "Please check in GST_PLUGIN_PATH=" << pluginPath;
268 } else {
269 qCCritical(GStreamerLog) << "Please set GST_PLUGIN_PATH to the path of your plugin";
270 }
271#endif
272 }
273
274 return result;
275}
276
278{
279 GList *decoderFactories = gst_element_factory_list_get_elements(
280 static_cast<GstElementFactoryListType>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
281 GST_RANK_NONE);
282
283 if (!decoderFactories) {
284 qCDebug(GStreamerDecoderRanksLog) << "No video decoder factories found.";
285 return;
286 }
287
288 decoderFactories = g_list_sort(decoderFactories, [](gconstpointer lhs, gconstpointer rhs) -> gint {
289 GstElementFactory *lhsFactory = GST_ELEMENT_FACTORY(lhs);
290 GstElementFactory *rhsFactory = GST_ELEMENT_FACTORY(rhs);
291
292 if (!lhsFactory && !rhsFactory) {
293 return 0;
294 }
295 if (!lhsFactory) {
296 return 1;
297 }
298 if (!rhsFactory) {
299 return -1;
300 }
301
302 const guint lhsRank = gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(lhsFactory));
303 const guint rhsRank = gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(rhsFactory));
304 if (lhsRank == rhsRank) {
305 const gchar *lhsName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(lhsFactory));
306 const gchar *rhsName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(rhsFactory));
307 return g_strcmp0(lhsName, rhsName);
308 }
309
310 return lhsRank > rhsRank ? -1 : 1;
311 });
312
313 qCDebug(GStreamerDecoderRanksLog) << "Video decoder plugin ranks:";
314 for (GList *node = decoderFactories; node != nullptr; node = node->next) {
315 GstElementFactory *factory = GST_ELEMENT_FACTORY(node->data);
316 if (!factory) {
317 continue;
318 }
319
320 const gchar *decoderKlass = gst_element_factory_get_klass(factory);
321 GstPluginFeature *feature = GST_PLUGIN_FEATURE(factory);
322 const gchar *featureName = gst_plugin_feature_get_name(feature);
323 const guint rank = gst_plugin_feature_get_rank(feature);
324
325 GstPlugin *plugin = gst_plugin_feature_get_plugin(feature);
326 if (plugin) {
327 qCDebug(GStreamerDecoderRanksLog) << " " << gst_plugin_get_name(plugin) << "/" << featureName << "-" << decoderKlass << ":" << rank;
328 gst_object_unref(plugin);
329 } else {
330 qCDebug(GStreamerDecoderRanksLog) << " " << featureName << "-" << decoderKlass << ":" << rank;
331 }
332 }
333
334 gst_plugin_feature_list_free(decoderFactories);
335}
336
337void _lowerSoftwareDecoderRanks(GstRegistry *registry)
338{
339 static constexpr uint16_t NewRank = GST_RANK_NONE;
340 if (!registry) {
341 qCCritical(GStreamerLog) << "Invalid registry!";
342 return;
343 }
344
345 const char* softDecoders[] = {"avdec_h264", "avdec_h265", "avdec_mjpeg", "avdec_mpeg2video", "avdec_mpeg4",
346 "avdec_vp8", "avdec_vp9", "dav1ddec", "vp8dec", "vp9dec"};
347
348 for (const char *name : softDecoders) {
349 GstPluginFeature *feature = gst_registry_lookup_feature(registry, name);
350 if (feature) {
351 qCDebug(GStreamerLog) << "Setting software decoder rank low:" << name << " rank:" << NewRank;
352 gst_plugin_feature_set_rank(feature, NewRank);
353 gst_object_unref(feature);
354 } else {
355 qCDebug(GStreamerLog) << "Software decoder not found:" << name;
356 }
357 }
358}
359
360void _changeFeatureRank(GstRegistry *registry, const char *featureName, uint16_t rank)
361{
362 if (!registry || !featureName) {
363 return;
364 }
365
366 GstPluginFeature *feature = gst_registry_lookup_feature(registry, featureName);
367 if (!feature) {
368 qCDebug(GStreamerLog) << "Failed to change ranking of feature. Feature does not exist:" << featureName;
369 return;
370 }
371
372 qCDebug(GStreamerLog) << " Changing feature (" << featureName << ") to use rank:" << rank;
373 gst_plugin_feature_set_rank(feature, rank);
374 gst_clear_object(&feature);
375}
376
377void _prioritizeByHardwareClass(GstRegistry *registry, uint16_t prioritizedRank, bool requireHardware)
378{
379 if (!registry) {
380 qCCritical(GStreamerLog) << "Failed to get gstreamer registry.";
381 return;
382 }
383
384 GList *decoderFactories = gst_element_factory_list_get_elements(
385 static_cast<GstElementFactoryListType>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
386 GST_RANK_NONE);
387
388 if (!decoderFactories) {
389 qCDebug(GStreamerLog) << "No decoder factories available while prioritizing"
390 << (requireHardware ? "hardware" : "software") << "decoders";
391 return;
392 }
393
394 qCDebug(GStreamerLog) << "Prioritizing" << (requireHardware ? "hardware" : "software")
395 << "video decoders with rank:" << prioritizedRank;
396 int matchedFactories = 0;
397 for (GList *node = decoderFactories; node != nullptr; node = node->next) {
398 GstElementFactory *factory = GST_ELEMENT_FACTORY(node->data);
399 if (!factory) {
400 continue;
401 }
402
403 if (GStreamer::is_hardware_decoder_factory(factory) != requireHardware) {
404 continue;
405 }
406
407 const gchar *featureName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
408 if (!featureName) {
409 continue;
410 }
411
412 _changeFeatureRank(registry, featureName, prioritizedRank);
413 ++matchedFactories;
414 }
415
416 if (matchedFactories == 0) {
417 qCWarning(GStreamerLog) << "No" << (requireHardware ? "hardware" : "software")
418 << "video decoder factories found to reprioritize.";
419 }
420
421 // Lower software decoder rank when using hardware decoders
422 if(requireHardware) {
423 qCCritical(GstVideoReceiverLog) << "Set the software decoder rank low.";
425 }
426
427 gst_plugin_feature_list_free(decoderFactories);
428}
429
431{
432 GstRegistry *registry = gst_registry_get();
433
434 if (!registry) {
435 qCCritical(GStreamerLog) << "Failed to get gstreamer registry.";
436 return;
437 }
438
439 static constexpr uint16_t PrioritizedRank = GST_RANK_PRIMARY + 1;
440
441 // TODO: ForceVideoDecoderCustom in VideoSettings with textbox in QML
442
443 switch (option) {
445 break;
447 _prioritizeByHardwareClass(registry, PrioritizedRank, false);
448 break;
450 _prioritizeByHardwareClass(registry, PrioritizedRank, true);
451 break;
453 for (const char *name : {"vaav1dec", "vah264dec", "vah265dec", "vajpegdec", "vampeg2dec", "vavp8dec", "vavp9dec"}) {
454 _changeFeatureRank(registry, name, PrioritizedRank);
455 }
456 break;
458 for (const char *name : {"nvav1dec", "nvh264dec", "nvh265dec", "nvjpegdec", "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec"}) {
459 _changeFeatureRank(registry, name, PrioritizedRank);
460 }
461 break;
463 for (const char *name : {"d3d11av1dec", "d3d11h264dec", "d3d11h265dec", "d3d11mpeg2dec", "d3d11vp8dec", "d3d11vp9dec",
464 "d3d12av1dec", "d3d12h264dec", "d3d12h265dec", "d3d12mpeg2dec", "d3d12vp8dec", "d3d12vp9dec",
465 "dxvaav1decoder", "dxvah264decoder", "dxvah265decoder", "dxvampeg2decoder", "dxvavp8decoder", "dxvavp9decoder" }) {
466 _changeFeatureRank(registry, name, PrioritizedRank);
467 }
468 break;
470 for (const char *name : {"vtdec_hw", "vtdec"}) {
471 _changeFeatureRank(registry, name, PrioritizedRank);
472 }
473 break;
475 for (const char *name : {"qsvh264dec", "qsvh265dec", "qsvjpegdec", "qsvvp9dec", "msdkav1dec", "msdkh264dec", "msdkh265dec", "msdkmjpegdec", "msdkmpeg2dec", "msdkvc1dec", "msdkvp8dec", "msdkvp9dec"}) {
476 _changeFeatureRank(registry, name, PrioritizedRank);
477 }
478 break;
480 for (const char *name : {"vulkanh264dec", "vulkanh265dec"}) {
481 _changeFeatureRank(registry, name, PrioritizedRank);
482 }
483 break;
484 default:
485 qCWarning(GStreamerLog) << "Can't handle decode option:" << option;
486 break;
487 }
488}
489
490bool initialize()
491{
493
494 if (qEnvironmentVariableIsEmpty("GST_DEBUG")) {
495 int gstDebugLevel = 0;
496 QSettings settings;
497 if (settings.contains(AppSettings::gstDebugLevelName)) {
498 gstDebugLevel = settings.value(AppSettings::gstDebugLevelName).toInt();
499 }
500 gst_debug_set_default_threshold(static_cast<GstDebugLevel>(gstDebugLevel));
501 }
502
503 gst_debug_remove_log_function(gst_debug_log_default);
504 gst_debug_add_log_function(_qtGstLog, nullptr, nullptr);
505
506 const QStringList args = QCoreApplication::arguments();
507 int gstArgc = args.size();
508
509 QByteArrayList argData;
510 argData.reserve(gstArgc);
511
512 QVarLengthArray<char*, 16> rawArgv;
513 rawArgv.reserve(gstArgc);
514
515 for (const QString &arg : args) {
516 argData.append(arg.toUtf8());
517 rawArgv.append(argData.last().data());
518 }
519
520 char **argvPtr = rawArgv.data();
521 GError *error = nullptr;
522 const gboolean ok = gst_init_check(&gstArgc, &argvPtr, &error);
523 if (!ok) {
524 qCritical(GStreamerLog) << "Failed to initialize GStreamer:" << error->message;
525 g_clear_error(&error);
526 return false;
527 }
528
529 const gchar *version = gst_version_string();
530 qCDebug(GStreamerLog) << QString("GStreamer Initialized (Version: %1)").arg(version);
531
533
534 if (!_verifyPlugins()) {
535 qCCritical(GStreamerLog) << "Failed to verify plugins - Check your GStreamer setup";
536 return false;
537 }
538
540 _setCodecPriorities(static_cast<GStreamer::VideoDecoderOptions>(SettingsManager::instance()->videoSettings()->forceVideoDecoder()->rawValue().toInt()));
541
542 GstElement *sink = gst_element_factory_make("qml6glsink", nullptr);
543 if (!sink) {
544 qCCritical(GStreamerLog) << "failed to init qml6glsink";
545 return false;
546 }
547
548 gst_clear_object(&sink);
549 return true;
550}
551
552void *createVideoSink(QQuickItem *widget, QObject * /*parent*/)
553{
554 GstElement *videoSinkBin = gst_element_factory_make("qgcvideosinkbin", NULL);
555 if (videoSinkBin) {
556 if (widget) {
557 g_object_set(videoSinkBin, "widget", widget, NULL);
558 }
559 } else {
560 qCCritical(GStreamerLog) << "gst_element_factory_make('qgcvideosinkbin') failed";
561 }
562
563 return videoSinkBin;
564}
565
566void releaseVideoSink(void *sink)
567{
568 GstElement *videoSink = GST_ELEMENT(sink);
569 gst_clear_object(&videoSink);
570}
571
573{
574 return new GstVideoReceiver(parent);
575}
576
577} // namespace GStreamer
G_BEGIN_DECLS GST_PLUGIN_STATIC_DECLARE(androidmedia)
struct _GstElement GstElement
Error error
#define QGC_LOGGING_CATEGORY_ON(name, categoryStr)
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static const char * gstDebugLevelName
Definition AppSettings.h:45
G_END_DECLS
void _changeFeatureRank(GstRegistry *registry, const char *featureName, uint16_t rank)
Definition GStreamer.cc:360
void _lowerSoftwareDecoderRanks(GstRegistry *registry)
Definition GStreamer.cc:337
VideoReceiver * createVideoReceiver(QObject *parent)
Definition GStreamer.cc:572
void _setCodecPriorities(GStreamer::VideoDecoderOptions option)
Definition GStreamer.cc:430
void releaseVideoSink(void *sink)
Definition GStreamer.cc:566
void * createVideoSink(QQuickItem *widget, QObject *)
Definition GStreamer.cc:552
bool _verifyPlugins()
Definition GStreamer.cc:233
bool is_hardware_decoder_factory(GstElementFactory *factory)
void _qtGstLog(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer data)
Definition GStreamer.cc:124
void _setGstEnvVars()
Definition GStreamer.cc:169
VideoDecoderOptions
Definition GStreamer.h:14
@ ForceVideoDecoderDefault
Definition GStreamer.h:15
@ ForceVideoDecoderIntel
Definition GStreamer.h:21
@ ForceVideoDecoderVulkan
Definition GStreamer.h:22
@ ForceVideoDecoderSoftware
Definition GStreamer.h:16
@ ForceVideoDecoderNVIDIA
Definition GStreamer.h:17
@ ForceVideoDecoderVAAPI
Definition GStreamer.h:18
@ ForceVideoDecoderVideoToolbox
Definition GStreamer.h:20
@ ForceVideoDecoderHardware
Definition GStreamer.h:23
@ ForceVideoDecoderDirectX3D
Definition GStreamer.h:19
void _logDecoderRanks()
Definition GStreamer.cc:277
void _prioritizeByHardwareClass(GstRegistry *registry, uint16_t prioritizedRank, bool requireHardware)
Definition GStreamer.cc:377
void _registerPlugins()
Definition GStreamer.cc:59
void _logPlugin(gpointer data, gpointer)
Definition GStreamer.cc:221