LCOV - code coverage report
Current view: top level - media/server/gstplayer/source - GstCapabilities.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.9 % 307 233
Test Date: 2026-09-29 14:28:21 Functions: 91.3 % 23 21

            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
        

Generated by: LCOV version 2.0-1