Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include <algorithm>
21 : #include <stdexcept>
22 : #include <thread>
23 : #include <unordered_map>
24 : #include <unordered_set>
25 : #include <utility>
26 :
27 : #include "GstCapabilities.h"
28 : #include "GstMimeMapping.h"
29 : #include "RialtoServerLogging.h"
30 :
31 : namespace
32 : {
33 34 : const char *toString(const GstElementFactoryListType &listType)
34 : {
35 34 : switch (listType)
36 : {
37 0 : case GST_ELEMENT_FACTORY_TYPE_ANY:
38 0 : return "Any";
39 0 : case GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS:
40 0 : return "AudioVideo Sinks";
41 0 : case GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER:
42 0 : return "Audio Encoder";
43 0 : case GST_ELEMENT_FACTORY_TYPE_DECODABLE:
44 0 : return "Decodable";
45 13 : case GST_ELEMENT_FACTORY_TYPE_DECODER:
46 13 : return "Decoder";
47 0 : case GST_ELEMENT_FACTORY_TYPE_DECRYPTOR:
48 0 : return "Decryptor";
49 0 : case GST_ELEMENT_FACTORY_TYPE_DEMUXER:
50 0 : return "Demuxer";
51 0 : case GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER:
52 0 : return "Depayloader";
53 0 : case GST_ELEMENT_FACTORY_TYPE_ENCODER:
54 0 : return "Encoder";
55 0 : case GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR:
56 0 : return "Encryptor";
57 0 : case GST_ELEMENT_FACTORY_TYPE_FORMATTER:
58 0 : return "Formatter";
59 0 : case GST_ELEMENT_FACTORY_TYPE_HARDWARE:
60 0 : return "Hardware";
61 0 : case GST_ELEMENT_FACTORY_TYPE_MAX_ELEMENTS:
62 0 : return "Max Elements";
63 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_ANY:
64 0 : return "Media Any";
65 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO:
66 0 : return "Media Audio";
67 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE:
68 0 : return "Media Image";
69 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA:
70 0 : return "Media Metadata";
71 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE:
72 0 : return "Media Subtitle";
73 0 : case GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO:
74 0 : return "Media Video";
75 0 : case GST_ELEMENT_FACTORY_TYPE_MUXER:
76 0 : return "Muxer";
77 0 : case GST_ELEMENT_FACTORY_TYPE_PARSER:
78 0 : return "Parser";
79 0 : case GST_ELEMENT_FACTORY_TYPE_PAYLOADER:
80 0 : return "Payloader";
81 21 : case GST_ELEMENT_FACTORY_TYPE_SINK:
82 21 : return "Sink";
83 0 : case GST_ELEMENT_FACTORY_TYPE_SRC:
84 0 : return "Source";
85 0 : case GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER:
86 0 : return "Video Encoder";
87 0 : default:
88 0 : return "Unknown";
89 : }
90 : }
91 : } // namespace
92 :
93 : namespace firebolt::rialto::server
94 : {
95 : std::weak_ptr<IGstCapabilitiesFactory> GstCapabilitiesFactory::m_factory;
96 :
97 2 : std::shared_ptr<IGstCapabilitiesFactory> IGstCapabilitiesFactory::getFactory()
98 : {
99 2 : std::shared_ptr<IGstCapabilitiesFactory> factory = GstCapabilitiesFactory::m_factory.lock();
100 :
101 2 : if (!factory)
102 : {
103 : try
104 : {
105 2 : factory = std::make_shared<GstCapabilitiesFactory>();
106 : }
107 0 : catch (const std::exception &e)
108 : {
109 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer capabilities factory, reason: %s", e.what());
110 : }
111 :
112 2 : GstCapabilitiesFactory::m_factory = factory;
113 : }
114 :
115 2 : return factory;
116 : }
117 :
118 2 : std::unique_ptr<IGstCapabilities> GstCapabilitiesFactory::createGstCapabilities()
119 : {
120 2 : RIALTO_SERVER_LOG_DEBUG("GstCapabilities: CreateGstCapabilities: entry");
121 :
122 2 : std::unique_ptr<IGstCapabilities> gstCapabilities;
123 : try
124 : {
125 : std::shared_ptr<firebolt::rialto::wrappers::IGstWrapperFactory> gstWrapperFactory =
126 2 : firebolt::rialto::wrappers::IGstWrapperFactory::getFactory();
127 2 : std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper;
128 :
129 2 : if ((!gstWrapperFactory) || (!(gstWrapper = gstWrapperFactory->getGstWrapper())))
130 : {
131 0 : throw std::runtime_error("Cannot create GstWrapper");
132 : }
133 :
134 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapperFactory> glibWrapperFactory =
135 2 : firebolt::rialto::wrappers::IGlibWrapperFactory::getFactory();
136 2 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper;
137 :
138 2 : if ((!glibWrapperFactory) || (!(glibWrapper = glibWrapperFactory->getGlibWrapper())))
139 : {
140 0 : throw std::runtime_error("Cannot create GlibWrapper");
141 : }
142 :
143 : std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapperFactory> rdkGstreamerUtilsWrapperFactory =
144 2 : firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapperFactory::getFactory();
145 2 : std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> rdkGstreamerUtilsWrapper;
146 :
147 4 : if ((!rdkGstreamerUtilsWrapperFactory) ||
148 4 : (!(rdkGstreamerUtilsWrapper = rdkGstreamerUtilsWrapperFactory->createRdkGstreamerUtilsWrapper())))
149 : {
150 0 : throw std::runtime_error("Cannot create RdkGstreamerUtilsWrapper");
151 : }
152 :
153 4 : gstCapabilities = std::make_unique<GstCapabilities>(gstWrapper, glibWrapper, rdkGstreamerUtilsWrapper,
154 2 : IGstInitialiser::instance());
155 : }
156 0 : catch (const std::exception &e)
157 : {
158 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer capabilities, reason: %s", e.what());
159 : }
160 :
161 2 : return gstCapabilities;
162 : }
163 :
164 23 : GstCapabilities::GstCapabilities(
165 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
166 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
167 : const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> &rdkGstreamerUtilsWrapper,
168 23 : const IGstInitialiser &gstInitialiser)
169 23 : : m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_rdkGstreamerUtilsWrapper{rdkGstreamerUtilsWrapper},
170 46 : m_gstInitialiser{gstInitialiser}
171 : {
172 23 : RIALTO_SERVER_LOG_DEBUG("GstCapabilities: constructor - GstCapabilities performs GStreamer element queries only");
173 : // Initialize capabilities with empty defaults - will be populated by element queries
174 23 : m_initialisationThread = std::thread(
175 23 : [this]()
176 : {
177 23 : std::unique_lock lock{m_initialisationMutex};
178 :
179 23 : m_gstInitialiser.waitForInitialisation();
180 23 : fillSupportedMimeTypes();
181 23 : fillSupportedCapabilities();
182 23 : m_isInitialised = true;
183 23 : m_initialisationCv.notify_all();
184 46 : });
185 23 : }
186 :
187 46 : GstCapabilities::~GstCapabilities()
188 : {
189 23 : if (m_initialisationThread.joinable())
190 : {
191 23 : m_initialisationThread.join();
192 : }
193 46 : }
194 :
195 13 : std::vector<std::string> GstCapabilities::getSupportedMimeTypes(MediaSourceType sourceType)
196 : {
197 13 : waitForInitialisation();
198 :
199 13 : std::vector<std::string> supportedMimeTypesSource;
200 13 : std::string type;
201 13 : if (sourceType == MediaSourceType::VIDEO)
202 : {
203 6 : type = "video/";
204 : }
205 7 : else if (sourceType == MediaSourceType::AUDIO)
206 : {
207 6 : type = "audio/";
208 : }
209 1 : else if (sourceType == MediaSourceType::SUBTITLE)
210 : {
211 3 : return {"text/vtt", "text/ttml", "text/cc"};
212 : }
213 : else
214 : {
215 0 : RIALTO_SERVER_LOG_WARN("Unsupported media type");
216 0 : return {};
217 : }
218 :
219 12 : std::copy_if(m_supportedMimeTypes.begin(), m_supportedMimeTypes.end(), std::back_inserter(supportedMimeTypesSource),
220 22 : [&type](const std::string &supportedMimeType) { return supportedMimeType.find(type) == 0; });
221 :
222 12 : return supportedMimeTypesSource;
223 13 : }
224 :
225 40 : bool GstCapabilities::isMimeTypeSupported(const std::string &mimeType)
226 : {
227 40 : waitForInitialisation();
228 40 : return m_supportedMimeTypes.find(mimeType) != m_supportedMimeTypes.end();
229 : }
230 :
231 5 : std::vector<std::string> GstCapabilities::getSupportedProperties(MediaSourceType mediaType,
232 : const std::vector<std::string> &propertyNames)
233 : {
234 5 : waitForInitialisation();
235 :
236 : // Get gstreamer element factories. The following flag settings will fetch both SINK and DECODER types
237 : // of gstreamer classes...
238 5 : GstElementFactoryListType factoryListType{GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_DECODER |
239 : GST_ELEMENT_FACTORY_TYPE_PARSER};
240 : {
241 : // If MediaSourceType::AUDIO is specified then adjust the flag so that we
242 : // restrict the list to gstreamer AUDIO element types (and likewise for video and subtitle)...
243 : static const std::unordered_map<MediaSourceType, GstElementFactoryListType>
244 : kLookupExtraConditions{{MediaSourceType::AUDIO, GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO},
245 : {MediaSourceType::VIDEO, GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO},
246 7 : {MediaSourceType::SUBTITLE, GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE}};
247 5 : auto i = kLookupExtraConditions.find(mediaType);
248 5 : if (i != kLookupExtraConditions.end())
249 5 : factoryListType |= i->second;
250 : }
251 :
252 5 : GList *factories{m_gstWrapper->gstElementFactoryListGetElements(factoryListType, GST_RANK_NONE)};
253 :
254 : // Scan all returned elements for the specified properties...
255 10 : std::unordered_set<std::string> propertiesToLookFor{propertyNames.begin(), propertyNames.end()};
256 5 : std::vector<std::string> propertiesFound;
257 10 : for (GList *iter = factories; iter != nullptr && !propertiesToLookFor.empty(); iter = iter->next)
258 : {
259 5 : GstElementFactory *factory = GST_ELEMENT_FACTORY(iter->data);
260 :
261 : // WORKAROUND: initialising element "rtkv1sink" causes that another playback's video goes black
262 : // we don't need to scan this element, so ignore it
263 15 : if (std::string{GST_OBJECT_NAME(GST_OBJECT(factory))} == "rtkv1sink")
264 : {
265 1 : RIALTO_SERVER_LOG_DEBUG("Ignoring rtkv1sink element");
266 1 : continue;
267 : }
268 :
269 4 : GType elementType = m_gstWrapper->gstElementFactoryGetElementType(factory);
270 4 : if (elementType == G_TYPE_INVALID)
271 1 : continue;
272 3 : gpointer elementClass = m_glibWrapper->gTypeClassRef(elementType);
273 3 : if (elementClass)
274 : {
275 : GParamSpec **props;
276 : guint nProps;
277 3 : props = m_glibWrapper->gObjectClassListProperties(G_OBJECT_CLASS(elementClass), &nProps);
278 3 : if (props)
279 : {
280 9 : for (guint j = 0; j < nProps && !propertiesToLookFor.empty(); ++j)
281 : {
282 12 : std::string propName{props[j]->name};
283 6 : auto it = propertiesToLookFor.find(propName);
284 6 : if (it != propertiesToLookFor.end())
285 : {
286 4 : RIALTO_SERVER_LOG_DEBUG("Found property '%s'", propName.c_str());
287 4 : propertiesFound.push_back(std::move(propName));
288 4 : propertiesToLookFor.erase(it);
289 : }
290 6 : }
291 3 : m_glibWrapper->gFree(props);
292 : }
293 3 : m_glibWrapper->gTypeClassUnref(elementClass);
294 : }
295 : }
296 :
297 : // Some sinks do not specifically support the "audio-fade" property, but the mechanism is supported through the use
298 : // of the rdk_gstreamer_utils library. Check for audio fade support if the property is required and we haven't found it in the sinks.
299 15 : if (propertiesToLookFor.find("audio-fade") != propertiesToLookFor.end())
300 : {
301 3 : bool socAudioFadeSupported = m_rdkGstreamerUtilsWrapper->isSocAudioFadeSupported();
302 3 : if (socAudioFadeSupported)
303 : {
304 1 : RIALTO_SERVER_LOG_DEBUG("Audio fade property is supported by the SoC");
305 2 : propertiesFound.push_back("audio-fade"); // Add "audio-fade" if supported by SoC
306 : }
307 : }
308 : // Cleanup
309 5 : m_gstWrapper->gstPluginFeatureListFree(factories);
310 10 : return propertiesFound;
311 5 : }
312 :
313 23 : void GstCapabilities::fillSupportedMimeTypes()
314 : {
315 23 : std::vector<GstCaps *> supportedCaps;
316 23 : appendSupportedCapsFromFactoryType(GST_ELEMENT_FACTORY_TYPE_DECODER, supportedCaps);
317 :
318 : // Only append caps from decoder parser if they can link with the decoder
319 23 : appendLinkableCapsFromParserDecoderChains(supportedCaps);
320 :
321 : // Sink caps do not require decoder support
322 23 : appendSupportedCapsFromFactoryType(GST_ELEMENT_FACTORY_TYPE_SINK, supportedCaps);
323 :
324 23 : if (supportedCaps.empty())
325 : {
326 13 : RIALTO_SERVER_LOG_WARN("There are no supported caps");
327 13 : return;
328 : }
329 :
330 10 : m_supportedMimeTypes = firebolt::rialto::server::convertFromCapsVectorToMimeSet(supportedCaps, m_gstWrapper);
331 :
332 29 : for (GstCaps *caps : supportedCaps)
333 : {
334 19 : m_gstWrapper->gstCapsUnref(caps);
335 : }
336 23 : }
337 :
338 23 : void GstCapabilities::fillSupportedCapabilities()
339 : {
340 : // Populate audio decoder capabilities from supported MIME types
341 : // Separate audio and video MIME types and create capability objects with codec-specific data
342 23 : std::vector<firebolt::rialto::common::AudioDecoderCapability> audioCapabilities;
343 23 : std::vector<firebolt::rialto::common::VideoDecoderCapability> videoCapabilities;
344 :
345 45 : for (const auto &mimeType : m_supportedMimeTypes)
346 : {
347 22 : if (mimeType.find("audio/") == 0)
348 : {
349 : // Create audio capability with codec-specific fields based on MIME type
350 : // Each capability MUST have at least one codec field populated to avoid empty serialization
351 10 : firebolt::rialto::common::AudioDecoderCapability audioCap;
352 :
353 10 : if (mimeType.find("audio/x-opus") != std::string::npos || mimeType == "audio/opus")
354 : {
355 : // Opus codec with default profile capability
356 1 : audioCap.opus = firebolt::rialto::common::OpusCapability{
357 1 : firebolt::rialto::common::AudioProfileCapability{0, 2, 48000, 16}};
358 : }
359 9 : else if (mimeType.find("audio/x-flac") != std::string::npos || mimeType == "audio/flac")
360 : {
361 : // FLAC codec with default profile capability
362 0 : audioCap.flac = firebolt::rialto::common::FlacCapability{
363 0 : firebolt::rialto::common::AudioProfileCapability{0, 8, 192000, 24}};
364 : }
365 9 : else if (mimeType.find("audio/aac") != std::string::npos)
366 : {
367 : // AAC codec with default profile capability
368 2 : audioCap.aac = firebolt::rialto::common::AacCapability{};
369 2 : audioCap.aac->profiles[firebolt::rialto::common::AacProfile::LC] =
370 : firebolt::rialto::common::AudioProfileCapability{0, 2, 48000, 16};
371 : }
372 7 : else if (mimeType.find("audio/mp3") != std::string::npos)
373 : {
374 : // MP3 codec with default profile capability
375 1 : audioCap.mp3 = firebolt::rialto::common::Mp3Capability{
376 1 : firebolt::rialto::common::AudioProfileCapability{0, 2, 48000, 16}};
377 : }
378 6 : else if (mimeType.find("audio/x-eac3") != std::string::npos || mimeType == "audio/eac3")
379 : {
380 : // Dolby EAC3 codec with default profile capability
381 2 : audioCap.dolbyEac3 = firebolt::rialto::common::DolbyEac3Capability{};
382 2 : audioCap.dolbyEac3->profiles[firebolt::rialto::common::DolbyEac3Profile::PLUS] =
383 : firebolt::rialto::common::AudioProfileCapability{0, 6, 48000, 16};
384 : }
385 4 : else if (mimeType.find("audio/x-ac3") != std::string::npos || mimeType == "audio/ac3")
386 : {
387 : // Dolby AC3 codec with default profile capability
388 0 : audioCap.dolbyAc3 = firebolt::rialto::common::DolbyAc3Capability{};
389 0 : audioCap.dolbyAc3->profiles[firebolt::rialto::common::DolbyAc3Profile::STANDARD] =
390 : firebolt::rialto::common::AudioProfileCapability{0, 6, 48000, 16};
391 : }
392 4 : else if (mimeType.find("audio/x-vorbis") != std::string::npos || mimeType == "audio/vorbis")
393 : {
394 : // Vorbis codec with default profile capability
395 0 : audioCap.vorbis = firebolt::rialto::common::VorbisCapability{
396 0 : firebolt::rialto::common::AudioProfileCapability{0, 8, 192000, 16}};
397 : }
398 : else
399 : {
400 4 : RIALTO_SERVER_LOG_WARN("Unknown audio MIME type '%s'", mimeType.c_str());
401 : }
402 :
403 10 : audioCapabilities.push_back(std::move(audioCap));
404 : }
405 12 : else if (mimeType.find("video/") == 0)
406 : {
407 : // Create video capability with codec-specific data based on MIME type
408 : // Initialize with empty codec capabilities - will be populated based on MIME type
409 12 : firebolt::rialto::common::VideoDecoderCapability videoCap;
410 :
411 12 : if (mimeType.find("video/h264") != std::string::npos)
412 : {
413 : // H.264 codec with default profile
414 : firebolt::rialto::common::H264Profile profile;
415 5 : profile.type = firebolt::rialto::common::H264ProfileType::H264_MAIN;
416 5 : profile.maxLevel = firebolt::rialto::common::H264Level::H264_LEVEL_5_2;
417 5 : profile.maxBitrateInBps = 0; // No bitrate limit
418 5 : videoCap.codecCapabilities.h264 = firebolt::rialto::common::H264CodecCapability{};
419 5 : videoCap.codecCapabilities.h264->profiles.push_back(profile);
420 : }
421 7 : else if (mimeType.find("video/h265") != std::string::npos || mimeType.find("video/hevc") != std::string::npos)
422 : {
423 : // H.265/HEVC codec with default profile
424 : firebolt::rialto::common::H265Profile profile;
425 5 : profile.type = firebolt::rialto::common::H265ProfileType::H265_MAIN;
426 5 : profile.maxLevel = firebolt::rialto::common::H265Level::H265_LEVEL_5_2;
427 5 : profile.maxBitrateInBps = 0; // No bitrate limit
428 5 : videoCap.codecCapabilities.h265 = firebolt::rialto::common::H265CodecCapability{};
429 5 : videoCap.codecCapabilities.h265->profiles.push_back(profile);
430 : }
431 2 : else if (mimeType.find("video/x-vp9") != std::string::npos || mimeType == "video/vp9")
432 : {
433 : // VP9 codec with default profile
434 : firebolt::rialto::common::Vp9Profile profile;
435 0 : profile.type = firebolt::rialto::common::Vp9ProfileType::VP9_PROFILE_0;
436 0 : profile.maxLevel = firebolt::rialto::common::Vp9Level::VP9_LEVEL_5_2;
437 0 : profile.maxBitrateInBps = 0; // No bitrate limit
438 0 : videoCap.codecCapabilities.vp9 = firebolt::rialto::common::Vp9CodecCapability{};
439 0 : videoCap.codecCapabilities.vp9->profiles.push_back(profile);
440 : }
441 2 : else if (mimeType.find("video/x-av1") != std::string::npos || mimeType == "video/av1")
442 : {
443 : // AV1 codec with default profile
444 : firebolt::rialto::common::Av1Profile profile;
445 1 : profile.type = firebolt::rialto::common::Av1ProfileType::AV1_MAIN;
446 1 : profile.maxLevel = firebolt::rialto::common::Av1Level::AV1_LEVEL_6_2;
447 1 : profile.maxBitrateInBps = 0; // No bitrate limit
448 1 : videoCap.codecCapabilities.av1 = firebolt::rialto::common::Av1CodecCapability{};
449 1 : videoCap.codecCapabilities.av1->profiles.push_back(profile);
450 : }
451 : else
452 : {
453 1 : RIALTO_SERVER_LOG_WARN("Unknown video MIME type '%s', using H.264 as fallback", mimeType.c_str());
454 : }
455 :
456 12 : videoCapabilities.push_back(std::move(videoCap));
457 : }
458 : }
459 :
460 : // Initialize audio decoder capabilities if we found audio MIME types
461 23 : if (!audioCapabilities.empty())
462 : {
463 4 : m_audioDecoderCapabilities.capabilities = std::move(audioCapabilities);
464 4 : RIALTO_SERVER_LOG_INFO("Populated %zu audio decoder capabilities from GStreamer",
465 : m_audioDecoderCapabilities.capabilities.size());
466 : }
467 :
468 : // Initialize video decoder capabilities if we found video MIME types
469 23 : if (!videoCapabilities.empty())
470 : {
471 6 : m_videoDecoderCapabilities.capabilities = std::move(videoCapabilities);
472 6 : RIALTO_SERVER_LOG_INFO("Populated %zu video decoder capabilities from GStreamer",
473 : m_videoDecoderCapabilities.capabilities.size());
474 : }
475 23 : }
476 :
477 23 : void GstCapabilities::appendLinkableCapsFromParserDecoderChains(std::vector<GstCaps *> &supportedCaps)
478 : {
479 23 : if (supportedCaps.empty())
480 : {
481 16 : return;
482 : }
483 :
484 9 : std::vector<GstCaps *> decoderSupportedCaps = supportedCaps;
485 :
486 : GList *parserFactories =
487 9 : m_gstWrapper->gstElementFactoryListGetElements(GST_ELEMENT_FACTORY_TYPE_PARSER, GST_RANK_MARGINAL);
488 9 : if (!parserFactories)
489 : {
490 2 : RIALTO_SERVER_LOG_WARN("Could not find any parser");
491 2 : return;
492 : }
493 :
494 15 : for (GstCaps *decoderCaps : decoderSupportedCaps)
495 : {
496 17 : for (GList *factoriesIter = parserFactories; factoriesIter; factoriesIter = factoriesIter->next)
497 : {
498 9 : GstElementFactory *factory = static_cast<GstElementFactory *>(factoriesIter->data);
499 9 : const GList *kParserPadTemplates = m_gstWrapper->gstElementFactoryGetStaticPadTemplates(factory);
500 :
501 9 : if (canCreateParserDecoderChain(decoderCaps, kParserPadTemplates))
502 : {
503 7 : addAllUniqueSinkPadsCapsToVector(supportedCaps, kParserPadTemplates);
504 : }
505 : }
506 : }
507 :
508 7 : m_gstWrapper->gstPluginFeatureListFree(parserFactories);
509 9 : }
510 :
511 46 : void GstCapabilities::appendSupportedCapsFromFactoryType(const GstElementFactoryListType &type,
512 : std::vector<GstCaps *> &supportedCaps)
513 : {
514 46 : GList *factories = m_gstWrapper->gstElementFactoryListGetElements(type, GST_RANK_MARGINAL);
515 46 : if (!factories)
516 : {
517 34 : RIALTO_SERVER_LOG_WARN("Could not find any %s", toString(type));
518 34 : return;
519 : }
520 :
521 25 : for (GList *factoriesIter = factories; factoriesIter; factoriesIter = factoriesIter->next)
522 : {
523 13 : GstElementFactory *factory = static_cast<GstElementFactory *>(factoriesIter->data);
524 13 : const GList *kPadTemplates = m_gstWrapper->gstElementFactoryGetStaticPadTemplates(factory);
525 :
526 13 : addAllUniqueSinkPadsCapsToVector(supportedCaps, kPadTemplates);
527 : }
528 :
529 12 : m_gstWrapper->gstPluginFeatureListFree(factories);
530 : }
531 :
532 9 : bool GstCapabilities::canCreateParserDecoderChain(GstCaps *decoderCaps, const GList *kParserPadTemplates)
533 : {
534 21 : for (const GList *padTemplateIter = kParserPadTemplates; padTemplateIter; padTemplateIter = padTemplateIter->next)
535 : {
536 19 : GstStaticPadTemplate *padTemplate = static_cast<GstStaticPadTemplate *>(padTemplateIter->data);
537 19 : if (padTemplate->direction == GST_PAD_SRC)
538 : {
539 10 : GstCaps *padTemplateCaps = m_gstWrapper->gstStaticCapsGet(&padTemplate->static_caps);
540 :
541 : // check if parser's src pad can be connected to decoder's sink pad
542 10 : bool canIntersect = m_gstWrapper->gstCapsCanIntersect(decoderCaps, padTemplateCaps);
543 10 : m_gstWrapper->gstCapsUnref(padTemplateCaps);
544 10 : if (canIntersect)
545 : {
546 7 : return true;
547 : }
548 : }
549 : }
550 :
551 2 : return false;
552 : }
553 :
554 20 : void GstCapabilities::addAllUniqueSinkPadsCapsToVector(std::vector<GstCaps *> &capsVector, const GList *padTemplates)
555 : {
556 52 : for (const GList *padTemplateIter = padTemplates; padTemplateIter; padTemplateIter = padTemplateIter->next)
557 : {
558 32 : GstStaticPadTemplate *padTemplate = static_cast<GstStaticPadTemplate *>(padTemplateIter->data);
559 32 : if (padTemplate->direction == GST_PAD_SINK)
560 : {
561 21 : GstCaps *padTemplateCaps = m_gstWrapper->gstStaticCapsGet(&padTemplate->static_caps);
562 21 : if (!isCapsInVector(capsVector, padTemplateCaps))
563 : {
564 19 : capsVector.push_back(padTemplateCaps);
565 : }
566 : else
567 : {
568 2 : m_gstWrapper->gstCapsUnref(padTemplateCaps);
569 : }
570 : }
571 : }
572 20 : }
573 :
574 21 : bool GstCapabilities::isCapsInVector(const std::vector<GstCaps *> &capsVector, GstCaps *caps) const
575 : {
576 21 : return std::find_if(capsVector.begin(), capsVector.end(), [&](const GstCaps *comparedCaps)
577 56 : { return m_gstWrapper->gstCapsIsStrictlyEqual(caps, comparedCaps); }) != capsVector.end();
578 : }
579 :
580 61 : void GstCapabilities::waitForInitialisation()
581 : {
582 61 : std::unique_lock lock{m_initialisationMutex};
583 134 : m_initialisationCv.wait(lock, [this]() { return m_isInitialised; });
584 61 : }
585 :
586 3 : bool GstCapabilities::isVideoMaster(bool &isVideoMaster)
587 : {
588 3 : waitForInitialisation();
589 :
590 3 : GstRegistry *reg = m_gstWrapper->gstRegistryGet();
591 3 : if (!reg)
592 : {
593 1 : RIALTO_SERVER_LOG_ERROR("Failed get the gst registry");
594 1 : return false;
595 : }
596 2 : GstPluginFeature *feature{nullptr};
597 2 : isVideoMaster = true;
598 2 : if (nullptr != (feature = m_gstWrapper->gstRegistryLookupFeature(reg, "amlhalasink")))
599 : {
600 1 : isVideoMaster = false;
601 1 : m_gstWrapper->gstObjectUnref(feature);
602 : }
603 2 : return true;
604 : }
605 :
606 0 : firebolt::rialto::common::AudioDecoderCapabilities GstCapabilities::getSupportedAudioCapabilities()
607 : {
608 0 : waitForInitialisation();
609 0 : return m_audioDecoderCapabilities;
610 : }
611 :
612 0 : firebolt::rialto::common::VideoDecoderCapabilities GstCapabilities::getSupportedVideoCapabilities()
613 : {
614 0 : waitForInitialisation();
615 0 : return m_videoDecoderCapabilities;
616 : }
617 :
618 : } // namespace firebolt::rialto::server
|