61#ifdef QGC_GST_STATIC_BUILD
62 #ifdef GST_PLUGIN_androidmedia_FOUND
63 GST_PLUGIN_STATIC_REGISTER(androidmedia);
65 #ifdef GST_PLUGIN_applemedia_FOUND
66 GST_PLUGIN_STATIC_REGISTER(applemedia);
68 GST_PLUGIN_STATIC_REGISTER(coreelements);
69 #ifdef GST_PLUGIN_d3d_FOUND
70 GST_PLUGIN_STATIC_REGISTER(d3d);
72 #ifdef GST_PLUGIN_d3d11_FOUND
73 GST_PLUGIN_STATIC_REGISTER(d3d11);
75 #ifdef GST_PLUGIN_d3d12_FOUND
76 GST_PLUGIN_STATIC_REGISTER(d3d12);
78 #ifdef GST_PLUGIN_dav1d_FOUND
79 GST_PLUGIN_STATIC_REGISTER(dav1d);
81 #ifdef GST_PLUGIN_dxva_FOUND
82 GST_PLUGIN_STATIC_REGISTER(dxva);
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);
91 #ifdef GST_PLUGIN_nvcodec_FOUND
92 GST_PLUGIN_STATIC_REGISTER(nvcodec);
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);
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);
110 GST_PLUGIN_STATIC_REGISTER(videoparsersbad);
111 GST_PLUGIN_STATIC_REGISTER(vpx);
112 #ifdef GST_PLUGIN_vulkan_FOUND
113 GST_PLUGIN_STATIC_REGISTER(vulkan);
118 GST_PLUGIN_STATIC_REGISTER(qml6);
121 GST_PLUGIN_STATIC_REGISTER(qgc);
127 const gchar *function,
130 GstDebugMessage *message,
135 if (level > gst_debug_category_get_threshold(category)) {
139 QMessageLogger log(file, line, function);
141 char *object_info = gst_info_strdup_printf(
"%" GST_PTR_FORMAT,
static_cast<void*
>(
object));
144 case GST_LEVEL_ERROR:
145 log.critical(GStreamerAPILog,
"%s %s", object_info, gst_debug_message_get(message));
147 case GST_LEVEL_WARNING:
148 log.warning(GStreamerAPILog,
"%s %s", object_info, gst_debug_message_get(message));
150 case GST_LEVEL_FIXME:
152 log.info(GStreamerAPILog,
"%s %s", object_info, gst_debug_message_get(message));
154 case GST_LEVEL_DEBUG:
157 case GST_LEVEL_TRACE:
158 case GST_LEVEL_MEMDUMP:
160 log.debug(GStreamerAPILog,
"%s %s", object_info, gst_debug_message_get(message));
166 g_clear_pointer(&object_info, g_free);
171 const QString appDir = QCoreApplication::applicationDirPath();
172 qCDebug(GStreamerLog) <<
"App Directory:" << appDir;
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");
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());
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");
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());
237 GstRegistry *registry = gst_registry_get();
239 qCDebug(GStreamerLog) <<
"Installed GStreamer Plugins:";
240 GList *plugins = gst_registry_get_plugin_list(registry);
242 g_list_free(plugins);
244 static constexpr const char *pluginNames[2] = {
"qml6",
"qgc"};
245 for (
const char *name : pluginNames) {
246 GstPlugin *plugin = gst_registry_find_plugin(registry, name);
248 qCCritical(GStreamerLog) << name <<
"plugin NOT found.";
252 gst_clear_object(&plugin);
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");
263#ifdef QGC_GST_STATIC_BUILD
264 qCCritical(GStreamerLog) <<
"Please update the list of static plugins in GStreamer.cc";
266 if (!pluginPath.isEmpty()) {
267 qCCritical(GStreamerLog) <<
"Please check in GST_PLUGIN_PATH=" << pluginPath;
269 qCCritical(GStreamerLog) <<
"Please set GST_PLUGIN_PATH to the path of your plugin";
279 GList *decoderFactories = gst_element_factory_list_get_elements(
280 static_cast<GstElementFactoryListType
>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
283 if (!decoderFactories) {
284 qCDebug(GStreamerDecoderRanksLog) <<
"No video decoder factories found.";
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);
292 if (!lhsFactory && !rhsFactory) {
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);
310 return lhsRank > rhsRank ? -1 : 1;
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);
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);
325 GstPlugin *plugin = gst_plugin_feature_get_plugin(feature);
327 qCDebug(GStreamerDecoderRanksLog) <<
" " << gst_plugin_get_name(plugin) <<
"/" << featureName <<
"-" << decoderKlass <<
":" << rank;
328 gst_object_unref(plugin);
330 qCDebug(GStreamerDecoderRanksLog) <<
" " << featureName <<
"-" << decoderKlass <<
":" << rank;
334 gst_plugin_feature_list_free(decoderFactories);
339 static constexpr uint16_t NewRank = GST_RANK_NONE;
341 qCCritical(GStreamerLog) <<
"Invalid registry!";
345 const char* softDecoders[] = {
"avdec_h264",
"avdec_h265",
"avdec_mjpeg",
"avdec_mpeg2video",
"avdec_mpeg4",
346 "avdec_vp8",
"avdec_vp9",
"dav1ddec",
"vp8dec",
"vp9dec"};
348 for (
const char *name : softDecoders) {
349 GstPluginFeature *feature = gst_registry_lookup_feature(registry, name);
351 qCDebug(GStreamerLog) <<
"Setting software decoder rank low:" << name <<
" rank:" << NewRank;
352 gst_plugin_feature_set_rank(feature, NewRank);
353 gst_object_unref(feature);
355 qCDebug(GStreamerLog) <<
"Software decoder not found:" << name;
362 if (!registry || !featureName) {
366 GstPluginFeature *feature = gst_registry_lookup_feature(registry, featureName);
368 qCDebug(GStreamerLog) <<
"Failed to change ranking of feature. Feature does not exist:" << featureName;
372 qCDebug(GStreamerLog) <<
" Changing feature (" << featureName <<
") to use rank:" << rank;
373 gst_plugin_feature_set_rank(feature, rank);
374 gst_clear_object(&feature);
380 qCCritical(GStreamerLog) <<
"Failed to get gstreamer registry.";
384 GList *decoderFactories = gst_element_factory_list_get_elements(
385 static_cast<GstElementFactoryListType
>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
388 if (!decoderFactories) {
389 qCDebug(GStreamerLog) <<
"No decoder factories available while prioritizing"
390 << (requireHardware ?
"hardware" :
"software") <<
"decoders";
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);
407 const gchar *featureName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
416 if (matchedFactories == 0) {
417 qCWarning(GStreamerLog) <<
"No" << (requireHardware ?
"hardware" :
"software")
418 <<
"video decoder factories found to reprioritize.";
422 if(requireHardware) {
423 qCCritical(GstVideoReceiverLog) <<
"Set the software decoder rank low.";
427 gst_plugin_feature_list_free(decoderFactories);
432 GstRegistry *registry = gst_registry_get();
435 qCCritical(GStreamerLog) <<
"Failed to get gstreamer registry.";
439 static constexpr uint16_t PrioritizedRank = GST_RANK_PRIMARY + 1;
453 for (
const char *name : {
"vaav1dec",
"vah264dec",
"vah265dec",
"vajpegdec",
"vampeg2dec",
"vavp8dec",
"vavp9dec"}) {
458 for (
const char *name : {
"nvav1dec",
"nvh264dec",
"nvh265dec",
"nvjpegdec",
"nvmpeg2videodec",
"nvmpeg4videodec",
"nvmpegvideodec",
"nvvp8dec",
"nvvp9dec"}) {
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" }) {
470 for (
const char *name : {
"vtdec_hw",
"vtdec"}) {
475 for (
const char *name : {
"qsvh264dec",
"qsvh265dec",
"qsvjpegdec",
"qsvvp9dec",
"msdkav1dec",
"msdkh264dec",
"msdkh265dec",
"msdkmjpegdec",
"msdkmpeg2dec",
"msdkvc1dec",
"msdkvp8dec",
"msdkvp9dec"}) {
480 for (
const char *name : {
"vulkanh264dec",
"vulkanh265dec"}) {
485 qCWarning(GStreamerLog) <<
"Can't handle decode option:" << option;
494 if (qEnvironmentVariableIsEmpty(
"GST_DEBUG")) {
495 int gstDebugLevel = 0;
500 gst_debug_set_default_threshold(
static_cast<GstDebugLevel
>(gstDebugLevel));
503 gst_debug_remove_log_function(gst_debug_log_default);
504 gst_debug_add_log_function(
_qtGstLog,
nullptr,
nullptr);
506 const QStringList args = QCoreApplication::arguments();
507 int gstArgc = args.size();
509 QByteArrayList argData;
510 argData.reserve(gstArgc);
512 QVarLengthArray<char*, 16> rawArgv;
513 rawArgv.reserve(gstArgc);
515 for (
const QString &arg : args) {
516 argData.append(arg.toUtf8());
517 rawArgv.append(argData.last().data());
520 char **argvPtr = rawArgv.data();
521 GError *
error =
nullptr;
522 const gboolean ok = gst_init_check(&gstArgc, &argvPtr, &
error);
524 qCritical(GStreamerLog) <<
"Failed to initialize GStreamer:" <<
error->message;
525 g_clear_error(&
error);
529 const gchar *version = gst_version_string();
530 qCDebug(GStreamerLog) << QString(
"GStreamer Initialized (Version: %1)").arg(version);
535 qCCritical(GStreamerLog) <<
"Failed to verify plugins - Check your GStreamer setup";
542 GstElement *sink = gst_element_factory_make(
"qml6glsink",
nullptr);
544 qCCritical(GStreamerLog) <<
"failed to init qml6glsink";
548 gst_clear_object(&sink);