LCOV - code coverage report
Current view: top level - media/server/gstplayer/source - GstCapabilities.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 71.6 % 201 144
Test Date: 2025-02-18 13:13:53 Functions: 100.0 % 15 15

            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 <unordered_map>
      23              : #include <unordered_set>
      24              : 
      25              : #include "GstCapabilities.h"
      26              : #include "GstMimeMapping.h"
      27              : #include "RialtoServerLogging.h"
      28              : 
      29              : namespace
      30              : {
      31           26 : const char *toString(const GstElementFactoryListType &listType)
      32              : {
      33           26 :     switch (listType)
      34              :     {
      35            0 :     case GST_ELEMENT_FACTORY_TYPE_ANY:
      36            0 :         return "Any";
      37            0 :     case GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS:
      38            0 :         return "AudioVideo Sinks";
      39            0 :     case GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER:
      40            0 :         return "Audio Encoder";
      41            0 :     case GST_ELEMENT_FACTORY_TYPE_DECODABLE:
      42            0 :         return "Decodable";
      43            9 :     case GST_ELEMENT_FACTORY_TYPE_DECODER:
      44            9 :         return "Decoder";
      45            0 :     case GST_ELEMENT_FACTORY_TYPE_DECRYPTOR:
      46            0 :         return "Decryptor";
      47            0 :     case GST_ELEMENT_FACTORY_TYPE_DEMUXER:
      48            0 :         return "Demuxer";
      49            0 :     case GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER:
      50            0 :         return "Depayloader";
      51            0 :     case GST_ELEMENT_FACTORY_TYPE_ENCODER:
      52            0 :         return "Encoder";
      53            0 :     case GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR:
      54            0 :         return "Encryptor";
      55            0 :     case GST_ELEMENT_FACTORY_TYPE_FORMATTER:
      56            0 :         return "Formatter";
      57            0 :     case GST_ELEMENT_FACTORY_TYPE_HARDWARE:
      58            0 :         return "Hardware";
      59            0 :     case GST_ELEMENT_FACTORY_TYPE_MAX_ELEMENTS:
      60            0 :         return "Max Elements";
      61            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_ANY:
      62            0 :         return "Media Any";
      63            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO:
      64            0 :         return "Media Audio";
      65            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE:
      66            0 :         return "Media Image";
      67            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA:
      68            0 :         return "Media Metadata";
      69            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE:
      70            0 :         return "Media Subtitle";
      71            0 :     case GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO:
      72            0 :         return "Media Video";
      73            0 :     case GST_ELEMENT_FACTORY_TYPE_MUXER:
      74            0 :         return "Muxer";
      75            0 :     case GST_ELEMENT_FACTORY_TYPE_PARSER:
      76            0 :         return "Parser";
      77            0 :     case GST_ELEMENT_FACTORY_TYPE_PAYLOADER:
      78            0 :         return "Payloader";
      79           17 :     case GST_ELEMENT_FACTORY_TYPE_SINK:
      80           17 :         return "Sink";
      81            0 :     case GST_ELEMENT_FACTORY_TYPE_SRC:
      82            0 :         return "Source";
      83            0 :     case GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER:
      84            0 :         return "Video Encoder";
      85            0 :     default:
      86            0 :         return "Unknown";
      87              :     }
      88              : }
      89              : } // namespace
      90              : 
      91              : namespace firebolt::rialto::server
      92              : {
      93              : std::weak_ptr<IGstCapabilitiesFactory> GstCapabilitiesFactory::m_factory;
      94              : 
      95            2 : std::shared_ptr<IGstCapabilitiesFactory> IGstCapabilitiesFactory::getFactory()
      96              : {
      97            2 :     std::shared_ptr<IGstCapabilitiesFactory> factory = GstCapabilitiesFactory::m_factory.lock();
      98              : 
      99            2 :     if (!factory)
     100              :     {
     101              :         try
     102              :         {
     103            2 :             factory = std::make_shared<GstCapabilitiesFactory>();
     104              :         }
     105            0 :         catch (const std::exception &e)
     106              :         {
     107            0 :             RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer capabilities factory, reason: %s", e.what());
     108              :         }
     109              : 
     110            2 :         GstCapabilitiesFactory::m_factory = factory;
     111              :     }
     112              : 
     113            2 :     return factory;
     114              : }
     115              : 
     116            2 : std::unique_ptr<IGstCapabilities> GstCapabilitiesFactory::createGstCapabilities()
     117              : {
     118            2 :     std::unique_ptr<IGstCapabilities> gstCapabilities;
     119              :     try
     120              :     {
     121              :         std::shared_ptr<firebolt::rialto::wrappers::IGstWrapperFactory> gstWrapperFactory =
     122            2 :             firebolt::rialto::wrappers::IGstWrapperFactory::getFactory();
     123            2 :         std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper;
     124              : 
     125            2 :         if ((!gstWrapperFactory) || (!(gstWrapper = gstWrapperFactory->getGstWrapper())))
     126              :         {
     127            0 :             throw std::runtime_error("Cannot create GstWrapper");
     128              :         }
     129              : 
     130              :         std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapperFactory> glibWrapperFactory =
     131            2 :             firebolt::rialto::wrappers::IGlibWrapperFactory::getFactory();
     132            2 :         std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper;
     133              : 
     134            2 :         if ((!glibWrapperFactory) || (!(glibWrapper = glibWrapperFactory->getGlibWrapper())))
     135              :         {
     136            0 :             throw std::runtime_error("Cannot create GlibWrapper");
     137              :         }
     138              : 
     139              :         std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapperFactory> rdkGstreamerUtilsWrapperFactory =
     140            2 :             firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapperFactory::getFactory();
     141            2 :         std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> rdkGstreamerUtilsWrapper;
     142              : 
     143            4 :         if ((!rdkGstreamerUtilsWrapperFactory) ||
     144            4 :             (!(rdkGstreamerUtilsWrapper = rdkGstreamerUtilsWrapperFactory->createRdkGstreamerUtilsWrapper())))
     145              :         {
     146            0 :             throw std::runtime_error("Cannot create RdkGstreamerUtilsWrapper");
     147              :         }
     148              : 
     149            4 :         gstCapabilities = std::make_unique<GstCapabilities>(gstWrapper, glibWrapper, rdkGstreamerUtilsWrapper,
     150            2 :                                                             IGstInitialiser::instance());
     151              :     }
     152            0 :     catch (const std::exception &e)
     153              :     {
     154            0 :         RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer capabilities, reason: %s", e.what());
     155              :     }
     156              : 
     157            2 :     return gstCapabilities;
     158              : }
     159              : 
     160           19 : GstCapabilities::GstCapabilities(
     161              :     const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
     162              :     const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
     163              :     const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> &rdkGstreamerUtilsWrapper,
     164           19 :     const IGstInitialiser &gstInitialiser)
     165           19 :     : m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_rdkGstreamerUtilsWrapper{rdkGstreamerUtilsWrapper}
     166              : {
     167           19 :     gstInitialiser.waitForInitialisation();
     168           19 :     fillSupportedMimeTypes();
     169              : }
     170              : 
     171           13 : std::vector<std::string> GstCapabilities::getSupportedMimeTypes(MediaSourceType sourceType)
     172              : {
     173           13 :     std::vector<std::string> supportedMimeTypesSource;
     174           13 :     std::string type;
     175           13 :     if (sourceType == MediaSourceType::VIDEO)
     176              :     {
     177            6 :         type = "video/";
     178              :     }
     179            7 :     else if (sourceType == MediaSourceType::AUDIO)
     180              :     {
     181            6 :         type = "audio/";
     182              :     }
     183            1 :     else if (sourceType == MediaSourceType::SUBTITLE)
     184              :     {
     185            3 :         return {"text/vtt", "text/ttml"};
     186              :     }
     187              :     else
     188              :     {
     189            0 :         RIALTO_SERVER_LOG_WARN("Unsupported media type");
     190            0 :         return {};
     191              :     }
     192              : 
     193           12 :     std::copy_if(m_supportedMimeTypes.begin(), m_supportedMimeTypes.end(), std::back_inserter(supportedMimeTypesSource),
     194           21 :                  [&type](const std::string &supportedMimeType) { return supportedMimeType.find(type) == 0; });
     195              : 
     196           12 :     return supportedMimeTypesSource;
     197           13 : }
     198              : 
     199           39 : bool GstCapabilities::isMimeTypeSupported(const std::string &mimeType)
     200              : {
     201           39 :     return m_supportedMimeTypes.find(mimeType) != m_supportedMimeTypes.end();
     202              : }
     203              : 
     204            4 : std::vector<std::string> GstCapabilities::getSupportedProperties(MediaSourceType mediaType,
     205              :                                                                  const std::vector<std::string> &propertyNames)
     206              : {
     207              :     // Get gstreamer element factories. The following flag settings will fetch both SINK and DECODER types
     208              :     // of gstreamer classes...
     209            4 :     GstElementFactoryListType factoryListType{GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_DECODER |
     210              :                                               GST_ELEMENT_FACTORY_TYPE_PARSER};
     211              :     {
     212              :         // If MediaSourceType::AUDIO is specified then adjust the flag so that we
     213              :         // restrict the list to gstreamer AUDIO element types (and likewise for video and subtitle)...
     214              :         static const std::unordered_map<MediaSourceType, GstElementFactoryListType>
     215              :             kLookupExtraConditions{{MediaSourceType::AUDIO, GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO},
     216              :                                    {MediaSourceType::VIDEO, GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO},
     217            4 :                                    {MediaSourceType::SUBTITLE, GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE}};
     218            4 :         auto i = kLookupExtraConditions.find(mediaType);
     219            4 :         if (i != kLookupExtraConditions.end())
     220            4 :             factoryListType |= i->second;
     221              :     }
     222              : 
     223            4 :     GList *factories{m_gstWrapper->gstElementFactoryListGetElements(factoryListType, GST_RANK_NONE)};
     224              : 
     225              :     // Scan all returned elements for the specified properties...
     226            4 :     std::unordered_set<std::string> propertiesToLookFor{propertyNames.begin(), propertyNames.end()};
     227            4 :     std::vector<std::string> propertiesFound;
     228            8 :     for (GList *iter = factories; iter != nullptr && !propertiesToLookFor.empty(); iter = iter->next)
     229              :     {
     230            4 :         GstElementFactory *factory = GST_ELEMENT_FACTORY(iter->data);
     231              : 
     232              :         // WORKAROUND: initialising element "rtkv1sink" causes that another playback's video goes black
     233              :         // we don't need to scan this element, so ignore it
     234            4 :         if (std::string{GST_OBJECT_NAME(GST_OBJECT(factory))} == "rtkv1sink")
     235              :         {
     236            1 :             RIALTO_SERVER_LOG_DEBUG("Ignoring rtkv1sink element");
     237            1 :             continue;
     238              :         }
     239              : 
     240            3 :         GstElement *elementObj{nullptr};
     241              : 
     242              :         // We instantiate an object because fetching the class, even after gstPluginFeatureLoad,
     243              :         // was found to sometimes return a class with no properties. A code branch is
     244              :         // kept with this feature "supportedPropertiesViaClass"
     245            3 :         elementObj = m_gstWrapper->gstElementFactoryCreate(factory, nullptr);
     246            3 :         if (elementObj)
     247              :         {
     248              :             GParamSpec **props;
     249              :             guint nProps;
     250            3 :             props = m_glibWrapper->gObjectClassListProperties(G_OBJECT_GET_CLASS(elementObj), &nProps);
     251            3 :             if (props)
     252              :             {
     253            9 :                 for (guint j = 0; j < nProps && !propertiesToLookFor.empty(); ++j)
     254              :                 {
     255            6 :                     const std::string kPropName{props[j]->name};
     256            6 :                     auto it = propertiesToLookFor.find(kPropName);
     257            6 :                     if (it != propertiesToLookFor.end())
     258              :                     {
     259            4 :                         RIALTO_SERVER_LOG_DEBUG("Found property '%s'", kPropName.c_str());
     260            4 :                         propertiesFound.push_back(kPropName);
     261            4 :                         propertiesToLookFor.erase(it);
     262              :                     }
     263            6 :                 }
     264            3 :                 m_glibWrapper->gFree(props);
     265              :             }
     266            3 :             m_gstWrapper->gstObjectUnref(elementObj);
     267              :         }
     268              :     }
     269              : 
     270              :     // Some sinks do not specifically support the "audio-fade" property, but the mechanism is supported through the use
     271              :     // 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.
     272            4 :     if (propertiesToLookFor.find("audio-fade") != propertiesToLookFor.end())
     273              :     {
     274            2 :         bool socAudioFadeSupported = m_rdkGstreamerUtilsWrapper->isSocAudioFadeSupported();
     275            2 :         if (socAudioFadeSupported)
     276              :         {
     277            1 :             RIALTO_SERVER_LOG_DEBUG("Audio fade property is supported by the SoC");
     278            1 :             propertiesFound.push_back("audio-fade"); // Add "audio-fade" if supported by SoC
     279              :         }
     280              :     }
     281              :     // Cleanup
     282            4 :     m_gstWrapper->gstPluginFeatureListFree(factories);
     283            8 :     return propertiesFound;
     284            4 : }
     285              : 
     286           19 : void GstCapabilities::fillSupportedMimeTypes()
     287              : {
     288           19 :     std::vector<GstCaps *> supportedCaps;
     289           19 :     appendSupportedCapsFromFactoryType(GST_ELEMENT_FACTORY_TYPE_DECODER, supportedCaps);
     290              : 
     291              :     // Only append caps from decoder parser if they can link with the decoder
     292           19 :     appendLinkableCapsFromParserDecoderChains(supportedCaps);
     293              : 
     294              :     // Sink caps do not require decoder support
     295           19 :     appendSupportedCapsFromFactoryType(GST_ELEMENT_FACTORY_TYPE_SINK, supportedCaps);
     296              : 
     297           19 :     if (supportedCaps.empty())
     298              :     {
     299            9 :         RIALTO_SERVER_LOG_WARN("There are no supported caps");
     300            9 :         return;
     301              :     }
     302              : 
     303           10 :     m_supportedMimeTypes = firebolt::rialto::server::convertFromCapsVectorToMimeSet(supportedCaps, m_gstWrapper);
     304              : 
     305           29 :     for (GstCaps *caps : supportedCaps)
     306              :     {
     307           19 :         m_gstWrapper->gstCapsUnref(caps);
     308              :     }
     309              : }
     310              : 
     311           19 : void GstCapabilities::appendLinkableCapsFromParserDecoderChains(std::vector<GstCaps *> &supportedCaps)
     312              : {
     313           19 :     if (supportedCaps.empty())
     314              :     {
     315           12 :         return;
     316              :     }
     317              : 
     318            9 :     std::vector<GstCaps *> decoderSupportedCaps = supportedCaps;
     319              : 
     320              :     GList *parserFactories =
     321            9 :         m_gstWrapper->gstElementFactoryListGetElements(GST_ELEMENT_FACTORY_TYPE_PARSER, GST_RANK_MARGINAL);
     322            9 :     if (!parserFactories)
     323              :     {
     324            2 :         RIALTO_SERVER_LOG_WARN("Could not find any parser");
     325            2 :         return;
     326              :     }
     327              : 
     328           15 :     for (GstCaps *decoderCaps : decoderSupportedCaps)
     329              :     {
     330           17 :         for (GList *factoriesIter = parserFactories; factoriesIter; factoriesIter = factoriesIter->next)
     331              :         {
     332            9 :             GstElementFactory *factory = static_cast<GstElementFactory *>(factoriesIter->data);
     333            9 :             const GList *kParserPadTemplates = m_gstWrapper->gstElementFactoryGetStaticPadTemplates(factory);
     334              : 
     335            9 :             if (canCreateParserDecoderChain(decoderCaps, kParserPadTemplates))
     336              :             {
     337            7 :                 addAllUniqueSinkPadsCapsToVector(supportedCaps, kParserPadTemplates);
     338              :             }
     339              :         }
     340              :     }
     341              : 
     342            7 :     m_gstWrapper->gstPluginFeatureListFree(parserFactories);
     343            9 : }
     344              : 
     345           38 : void GstCapabilities::appendSupportedCapsFromFactoryType(const GstElementFactoryListType &type,
     346              :                                                          std::vector<GstCaps *> &supportedCaps)
     347              : {
     348           38 :     GList *factories = m_gstWrapper->gstElementFactoryListGetElements(type, GST_RANK_MARGINAL);
     349           38 :     if (!factories)
     350              :     {
     351           26 :         RIALTO_SERVER_LOG_WARN("Could not find any %s", toString(type));
     352           26 :         return;
     353              :     }
     354              : 
     355           25 :     for (GList *factoriesIter = factories; factoriesIter; factoriesIter = factoriesIter->next)
     356              :     {
     357           13 :         GstElementFactory *factory = static_cast<GstElementFactory *>(factoriesIter->data);
     358           13 :         const GList *kPadTemplates = m_gstWrapper->gstElementFactoryGetStaticPadTemplates(factory);
     359              : 
     360           13 :         addAllUniqueSinkPadsCapsToVector(supportedCaps, kPadTemplates);
     361              :     }
     362              : 
     363           12 :     m_gstWrapper->gstPluginFeatureListFree(factories);
     364              : }
     365              : 
     366            9 : bool GstCapabilities::canCreateParserDecoderChain(GstCaps *decoderCaps, const GList *kParserPadTemplates)
     367              : {
     368           21 :     for (const GList *padTemplateIter = kParserPadTemplates; padTemplateIter; padTemplateIter = padTemplateIter->next)
     369              :     {
     370           19 :         GstStaticPadTemplate *padTemplate = static_cast<GstStaticPadTemplate *>(padTemplateIter->data);
     371           19 :         if (padTemplate->direction == GST_PAD_SRC)
     372              :         {
     373           10 :             GstCaps *padTemplateCaps = m_gstWrapper->gstStaticCapsGet(&padTemplate->static_caps);
     374              : 
     375              :             // check if parser's src pad can be connected to decoder's sink pad
     376           10 :             bool canIntersect = m_gstWrapper->gstCapsCanIntersect(decoderCaps, padTemplateCaps);
     377           10 :             m_gstWrapper->gstCapsUnref(padTemplateCaps);
     378           10 :             if (canIntersect)
     379              :             {
     380            7 :                 return true;
     381              :             }
     382              :         }
     383              :     }
     384              : 
     385            2 :     return false;
     386              : }
     387              : 
     388           20 : void GstCapabilities::addAllUniqueSinkPadsCapsToVector(std::vector<GstCaps *> &capsVector, const GList *padTemplates)
     389              : {
     390           52 :     for (const GList *padTemplateIter = padTemplates; padTemplateIter; padTemplateIter = padTemplateIter->next)
     391              :     {
     392           32 :         GstStaticPadTemplate *padTemplate = static_cast<GstStaticPadTemplate *>(padTemplateIter->data);
     393           32 :         if (padTemplate->direction == GST_PAD_SINK)
     394              :         {
     395           21 :             GstCaps *padTemplateCaps = m_gstWrapper->gstStaticCapsGet(&padTemplate->static_caps);
     396           21 :             if (!isCapsInVector(capsVector, padTemplateCaps))
     397              :             {
     398           19 :                 capsVector.push_back(padTemplateCaps);
     399              :             }
     400              :             else
     401              :             {
     402            2 :                 m_gstWrapper->gstCapsUnref(padTemplateCaps);
     403              :             }
     404              :         }
     405              :     }
     406           20 : }
     407              : 
     408           21 : bool GstCapabilities::isCapsInVector(const std::vector<GstCaps *> &capsVector, GstCaps *caps) const
     409              : {
     410           21 :     return std::find_if(capsVector.begin(), capsVector.end(),
     411           14 :                         [&](const GstCaps *comparedCaps)
     412           56 :                         { return m_gstWrapper->gstCapsIsStrictlyEqual(caps, comparedCaps); }) != capsVector.end();
     413              : }
     414              : 
     415              : } // namespace firebolt::rialto::server
     416              : 
     417              : // namespace firebolt::rialto::server
        

Generated by: LCOV version 2.0-1