QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GStreamerHelpers.cc
Go to the documentation of this file.
1#include "GStreamerHelpers.h"
3
4#include <gst/rtsp/gstrtspurl.h>
5#include <QtCore/QLatin1String>
6#include <QtCore/QString>
7
8QGC_LOGGING_CATEGORY(GStreamerHelpersLog, "Video.GStreamer.GStreamerHelpers")
9
10namespace GStreamer
11{
12
13gboolean
14isValidRtspUri(const gchar *uri_str)
15{
16 if (!uri_str) {
17 return FALSE;
18 }
19
20 GstRTSPUrl *url = NULL;
21 GstRTSPResult res;
22
23 if (!gst_uri_is_valid(uri_str)) {
24 return FALSE;
25 }
26
27 res = gst_rtsp_url_parse(uri_str, &url);
28 if ((res != GST_RTSP_OK) || (url == NULL)) {
29 if (url) {
30 gst_rtsp_url_free(url);
31 }
32 return FALSE;
33 }
34
35 const gboolean hasHost = (url->host && url->host[0] != '\0');
36 gst_rtsp_url_free(url);
37 return hasHost;
38}
39
40bool isHardwareDecoderFactory(GstElementFactory *factory)
41{
42 if (!factory) {
43 return false;
44 }
45
46 const gchar *factoryName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
47 if (!factoryName) {
48 return false;
49 }
50
51 const QString nameLower = QString::fromUtf8(factoryName).toLower();
52
53 // Android MediaCodec: exclude software wrappers, accept remaining as hardware
54 if (nameLower.startsWith("amcviddec-omxgoogle") || nameLower.startsWith("amcviddec-c2android")) {
55 return false;
56 }
57 if (nameLower.startsWith("amcviddec-")) {
58 return true;
59 }
60
61 const auto containsHardware = [](const gchar *value) {
62 if (!value) return false;
63 gchar *lower = g_ascii_strdown(value, -1);
64 bool found = (g_strrstr(lower, "hardware") != nullptr);
65 g_free(lower);
66 return found;
67 };
68
69 if (containsHardware(gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS))) {
70 return true;
71 }
72
73 if (containsHardware(gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_DESCRIPTION))) {
74 return true;
75 }
76
77 static constexpr QLatin1String kHardwareTags[] = {
78 QLatin1String("va"),
79 QLatin1String("nv"),
80 QLatin1String("qsv"),
81 QLatin1String("msdk"),
82 QLatin1String("vulkan"),
83 QLatin1String("d3d"),
84 QLatin1String("dxva"),
85 QLatin1String("vtdec"),
86 QLatin1String("metal"),
87 };
88
89 for (const auto &tag : kHardwareTags) {
90 if (nameLower.contains(tag)) {
91 return true;
92 }
93 }
94
95 return false;
96}
97
98namespace {
99
100void changeFeatureRank(GstRegistry *registry, const char *featureName, uint16_t rank)
101{
102 if (!registry || !featureName) {
103 return;
104 }
105
106 GstPluginFeature *feature = gst_registry_lookup_feature(registry, featureName);
107 if (!feature) {
108 qCDebug(GStreamerHelpersLog) << "Failed to change ranking of feature. Feature does not exist:" << featureName;
109 return;
110 }
111
112 qCDebug(GStreamerHelpersLog) << " Changing feature (" << featureName << ") to use rank:" << rank;
113 gst_plugin_feature_set_rank(feature, rank);
114 gst_clear_object(&feature);
115}
116
117void lowerDecoderRanksByClass(GstRegistry *registry, bool lowerHardware)
118{
119 static constexpr uint16_t NewRank = GST_RANK_NONE;
120 if (!registry) {
121 qCCritical(GStreamerHelpersLog) << "Invalid registry!";
122 return;
123 }
124
125 GList *decoderFactories = gst_element_factory_list_get_elements(
126 static_cast<GstElementFactoryListType>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
127 GST_RANK_NONE);
128
129 for (GList *node = decoderFactories; node != nullptr; node = node->next) {
130 GstElementFactory *factory = GST_ELEMENT_FACTORY(node->data);
131 if (!factory) {
132 continue;
133 }
134
135 if (GStreamer::isHardwareDecoderFactory(factory) != lowerHardware) {
136 continue;
137 }
138
139 const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
140 if (!name) {
141 continue;
142 }
143
144 qCDebug(GStreamerHelpersLog) << "Lowering" << (lowerHardware ? "hardware" : "software") << "decoder rank:" << name;
145 gst_plugin_feature_set_rank(GST_PLUGIN_FEATURE(factory), NewRank);
146 }
147
148 gst_plugin_feature_list_free(decoderFactories);
149}
150
151void prioritizeByHardwareClass(GstRegistry *registry, uint16_t prioritizedRank, bool requireHardware)
152{
153 if (!registry) {
154 qCCritical(GStreamerHelpersLog) << "Failed to get gstreamer registry.";
155 return;
156 }
157
158 GList *decoderFactories = gst_element_factory_list_get_elements(
159 static_cast<GstElementFactoryListType>(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO),
160 GST_RANK_NONE);
161
162 if (!decoderFactories) {
163 qCDebug(GStreamerHelpersLog) << "No decoder factories available while prioritizing"
164 << (requireHardware ? "hardware" : "software") << "decoders";
165 return;
166 }
167
168 qCDebug(GStreamerHelpersLog) << "Prioritizing" << (requireHardware ? "hardware" : "software")
169 << "video decoders with rank:" << prioritizedRank;
170 int matchedFactories = 0;
171 for (GList *node = decoderFactories; node != nullptr; node = node->next) {
172 GstElementFactory *factory = GST_ELEMENT_FACTORY(node->data);
173 if (!factory) {
174 continue;
175 }
176
177 if (GStreamer::isHardwareDecoderFactory(factory) != requireHardware) {
178 continue;
179 }
180
181 const gchar *featureName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
182 if (!featureName) {
183 continue;
184 }
185
186 changeFeatureRank(registry, featureName, prioritizedRank);
187 ++matchedFactories;
188 }
189
190 if (matchedFactories == 0) {
191 qCWarning(GStreamerHelpersLog) << "No" << (requireHardware ? "hardware" : "software")
192 << "video decoder factories found to reprioritize.";
193 }
194
195 qCDebug(GStreamerHelpersLog) << "Lowering" << (requireHardware ? "software" : "hardware") << "decoder ranks.";
196 lowerDecoderRanksByClass(registry, !requireHardware);
197
198 gst_plugin_feature_list_free(decoderFactories);
199}
200
201} // anonymous namespace
202
204{
205 GstRegistry *registry = gst_registry_get();
206
207 if (!registry) {
208 qCCritical(GStreamerHelpersLog) << "Failed to get gstreamer registry.";
209 return;
210 }
211
212 static constexpr uint16_t PrioritizedRank = GST_RANK_PRIMARY + 1;
213
214 switch (option) {
216 // HW-decoder GPU caps (GLMemory/DMABuf/VAMemory) auto-plug to system memory via gldownload/vapostproc.
217 break;
219 prioritizeByHardwareClass(registry, PrioritizedRank, false);
220 break;
222 prioritizeByHardwareClass(registry, PrioritizedRank, true);
223 break;
225 for (const char *name : {"vaav1dec", "vah264dec", "vah265dec", "vajpegdec", "vampeg2dec", "vavp8dec", "vavp9dec"}) {
226 changeFeatureRank(registry, name, PrioritizedRank);
227 }
228 break;
230 for (const char *name : {"nvav1dec", "nvh264dec", "nvh265dec", "nvjpegdec", "nvmpeg2videodec", "nvmpeg4videodec", "nvmpegvideodec", "nvvp8dec", "nvvp9dec"}) {
231 changeFeatureRank(registry, name, PrioritizedRank);
232 }
233 break;
235 for (const char *name : {"d3d11av1dec", "d3d11h264dec", "d3d11h265dec", "d3d11mpeg2dec", "d3d11vp8dec", "d3d11vp9dec",
236 "d3d12av1dec", "d3d12h264dec", "d3d12h265dec", "d3d12mpeg2dec", "d3d12vp8dec", "d3d12vp9dec",
237 "dxvaav1decoder", "dxvah264decoder", "dxvah265decoder", "dxvampeg2decoder", "dxvavp8decoder", "dxvavp9decoder"}) {
238 changeFeatureRank(registry, name, PrioritizedRank);
239 }
240 break;
242 for (const char *name : {"vtdec_hw", "vtdec"}) {
243 changeFeatureRank(registry, name, PrioritizedRank);
244 }
245 break;
247 for (const char *name : {"qsvh264dec", "qsvh265dec", "qsvjpegdec", "qsvvp9dec", "msdkav1dec", "msdkh264dec", "msdkh265dec", "msdkmjpegdec", "msdkmpeg2dec", "msdkvc1dec", "msdkvp8dec", "msdkvp9dec"}) {
248 changeFeatureRank(registry, name, PrioritizedRank);
249 }
250 break;
252 for (const char *name : {"vulkanh264dec", "vulkanh265dec"}) {
253 changeFeatureRank(registry, name, PrioritizedRank);
254 }
255 break;
256 default:
257 qCWarning(GStreamerHelpersLog) << "Can't handle decode option:" << option;
258 break;
259 }
260}
261
262} // namespace GStreamer
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void setCodecPriorities(VideoDecoderOptions option)
VideoDecoderOptions
Definition GStreamer.h:10
@ ForceVideoDecoderDefault
Definition GStreamer.h:11
@ ForceVideoDecoderIntel
Definition GStreamer.h:17
@ ForceVideoDecoderVulkan
Definition GStreamer.h:18
@ ForceVideoDecoderSoftware
Definition GStreamer.h:12
@ ForceVideoDecoderNVIDIA
Definition GStreamer.h:13
@ ForceVideoDecoderVAAPI
Definition GStreamer.h:14
@ ForceVideoDecoderVideoToolbox
Definition GStreamer.h:16
@ ForceVideoDecoderHardware
Definition GStreamer.h:19
@ ForceVideoDecoderDirectX3D
Definition GStreamer.h:15
bool isHardwareDecoderFactory(GstElementFactory *factory)
gboolean isValidRtspUri(const gchar *uri_str)