LCOV - code coverage report
Current view: top level - source - PullModeSubtitlePlaybackDelegate.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.9 % 136 129
Test Date: 2025-08-04 11:40:41 Functions: 100.0 % 7 7

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 Sky UK
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation;
       7              :  * version 2.1 of the License.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, write to the Free Software
      16              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      17              :  */
      18              : 
      19              : #include "PullModeSubtitlePlaybackDelegate.h"
      20              : #include "GstreamerCatLog.h"
      21              : 
      22              : #define GST_CAT_DEFAULT rialtoGStreamerCat
      23              : 
      24           21 : PullModeSubtitlePlaybackDelegate::PullModeSubtitlePlaybackDelegate(GstElement *sink) : PullModePlaybackDelegate(sink)
      25              : {
      26           21 :     m_mediaSourceType = firebolt::rialto::MediaSourceType::SUBTITLE;
      27           21 :     m_isAsync = false;
      28              : }
      29              : 
      30           66 : GstStateChangeReturn PullModeSubtitlePlaybackDelegate::changeState(GstStateChange transition)
      31              : {
      32           66 :     switch (transition)
      33              :     {
      34           12 :     case GST_STATE_CHANGE_READY_TO_PAUSED:
      35              :     {
      36           12 :         if (!attachToMediaClientAndSetStreamsNumber())
      37              :         {
      38            1 :             return GST_STATE_CHANGE_FAILURE;
      39              :         }
      40              :     }
      41              :     default:
      42           65 :         break;
      43              :     }
      44           65 :     return PullModePlaybackDelegate::changeState(transition);
      45              : }
      46              : 
      47           21 : gboolean PullModeSubtitlePlaybackDelegate::handleEvent(GstEvent *event)
      48              : {
      49           21 :     switch (GST_EVENT_TYPE(event))
      50              :     {
      51           13 :     case GST_EVENT_CAPS:
      52              :     {
      53              :         GstCaps *caps;
      54           13 :         gst_event_parse_caps(event, &caps);
      55           13 :         if (m_sourceAttached)
      56              :         {
      57            1 :             GST_INFO_OBJECT(m_sink, "Source already attached. Skip calling attachSource");
      58            1 :             break;
      59              :         }
      60              : 
      61           12 :         GST_INFO_OBJECT(m_sink, "Attaching SUBTITLE source with caps %" GST_PTR_FORMAT, caps);
      62              : 
      63           12 :         std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> subtitleSource{createMediaSource(caps)};
      64           12 :         if (subtitleSource)
      65              :         {
      66           12 :             std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
      67           12 :             if ((!client) || (!client->attachSource(subtitleSource, RIALTO_MSE_BASE_SINK(m_sink))))
      68              :             {
      69            1 :                 GST_ERROR_OBJECT(m_sink, "Failed to attach SUBTITLE source");
      70              :             }
      71              :             else
      72              :             {
      73           11 :                 m_sourceAttached = true;
      74           11 :                 if (m_isMuteQueued)
      75              :                 {
      76            1 :                     client->setMute(m_isMuted, m_sourceId);
      77            1 :                     m_isMuteQueued = false;
      78              :                 }
      79              : 
      80              :                 {
      81           11 :                     std::unique_lock lock{m_mutex};
      82           11 :                     if (m_isTextTrackIdentifierQueued)
      83              :                     {
      84            1 :                         client->setTextTrackIdentifier(m_textTrackIdentifier);
      85            1 :                         m_isTextTrackIdentifierQueued = false;
      86              :                     }
      87           11 :                 }
      88              : 
      89              :                 // check if READY -> PAUSED was requested before source was attached
      90           11 :                 if (GST_STATE_NEXT(m_sink) == GST_STATE_PAUSED)
      91              :                 {
      92           11 :                     client->pause(m_sourceId);
      93              :                 }
      94              :             }
      95           12 :         }
      96              :         else
      97              :         {
      98            0 :             GST_ERROR_OBJECT(m_sink, "Failed to create SUBTITLE source");
      99              :         }
     100              : 
     101           12 :         break;
     102              :     }
     103            4 :     case GST_EVENT_CUSTOM_DOWNSTREAM:
     104              :     case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
     105              :     {
     106            4 :         if (gst_event_has_name(event, "set-pts-offset"))
     107              :         {
     108            4 :             GST_DEBUG_OBJECT(m_sink, "Set pts offset event received");
     109            4 :             const GstStructure *structure{gst_event_get_structure(event)};
     110            4 :             guint64 ptsOffset{GST_CLOCK_TIME_NONE};
     111            4 :             if (gst_structure_get_uint64(structure, "pts-offset", &ptsOffset) == TRUE)
     112              :             {
     113            3 :                 std::unique_lock lock{m_sinkMutex};
     114            3 :                 if (!m_initialPositionSet)
     115              :                 {
     116            2 :                     GST_DEBUG_OBJECT(m_sink, "First segment not received yet. Queuing offset setting");
     117            2 :                     m_queuedOffset = static_cast<int64_t>(ptsOffset);
     118              :                 }
     119              :                 else
     120              :                 {
     121            1 :                     std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
     122            1 :                     if (client)
     123              :                     {
     124            1 :                         GST_DEBUG_OBJECT(m_sink, "Setting subtitle position to: %" GST_TIME_FORMAT,
     125              :                                          GST_TIME_ARGS(ptsOffset));
     126            1 :                         client->setSourcePosition(m_sourceId, ptsOffset, false, m_lastSegment.applied_rate,
     127              :                                                   m_lastSegment.stop);
     128              :                     }
     129              :                 }
     130            3 :             }
     131              :             else
     132              :             {
     133            1 :                 GST_WARNING_OBJECT(m_sink, "Unable to set pts offset. Value not present");
     134              :             }
     135              :         }
     136            4 :         break;
     137              :     }
     138            4 :     default:
     139            4 :         break;
     140              :     }
     141           21 :     return PullModePlaybackDelegate::handleEvent(event);
     142              : }
     143              : 
     144            6 : void PullModeSubtitlePlaybackDelegate::getProperty(const Property &type, GValue *value)
     145              : {
     146            6 :     std::shared_ptr<GStreamerMSEMediaPlayerClient> client{m_mediaPlayerManager.getMediaPlayerClient()};
     147              : 
     148            6 :     switch (type)
     149              :     {
     150            2 :     case Property::Mute:
     151              :     {
     152            2 :         if (!client)
     153              :         {
     154            1 :             g_value_set_boolean(value, m_isMuted);
     155            1 :             return;
     156              :         }
     157            1 :         g_value_set_boolean(value, client->getMute(m_sourceId));
     158            1 :         break;
     159              :     }
     160            2 :     case Property::TextTrackIdentifier:
     161              :     {
     162              :         {
     163            2 :             std::unique_lock lock{m_mutex};
     164            2 :             if (!client)
     165              :             {
     166            1 :                 g_value_set_string(value, m_textTrackIdentifier.c_str());
     167            1 :                 return;
     168              :             }
     169            2 :         }
     170            1 :         g_value_set_string(value, client->getTextTrackIdentifier().c_str());
     171              : 
     172            1 :         break;
     173              :     }
     174            1 :     case Property::WindowId:
     175              :     {
     176            1 :         g_value_set_uint(value, m_videoId);
     177            1 :         break;
     178              :     }
     179            1 :     case Property::Async:
     180              :     {
     181            1 :         g_value_set_boolean(value, m_isAsync);
     182            1 :         break;
     183              :     }
     184            0 :     default:
     185              :     {
     186            0 :         PullModePlaybackDelegate::getProperty(type, value);
     187            0 :         break;
     188              :     }
     189              :     }
     190            6 : }
     191              : 
     192           37 : void PullModeSubtitlePlaybackDelegate::setProperty(const Property &type, const GValue *value)
     193              : {
     194           37 :     std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
     195              : 
     196           37 :     switch (type)
     197              :     {
     198            3 :     case Property::Mute:
     199            3 :         m_isMuted = g_value_get_boolean(value);
     200            3 :         if (!client || !m_sourceAttached)
     201              :         {
     202            2 :             m_isMuteQueued = true;
     203            2 :             return;
     204              :         }
     205              : 
     206            1 :         client->setMute(m_isMuted, m_sourceId);
     207              : 
     208            1 :         break;
     209            4 :     case Property::TextTrackIdentifier:
     210              :     {
     211            4 :         const gchar *textTrackIdentifier = g_value_get_string(value);
     212            4 :         if (!textTrackIdentifier)
     213              :         {
     214            1 :             GST_WARNING_OBJECT(m_sink, "TextTrackIdentifier string not valid");
     215            1 :             break;
     216              :         }
     217              : 
     218            3 :         std::unique_lock lock{m_mutex};
     219            3 :         m_textTrackIdentifier = std::string(textTrackIdentifier);
     220            3 :         if (!client || !m_sourceAttached)
     221              :         {
     222            2 :             GST_DEBUG_OBJECT(m_sink, "Rectangle setting enqueued");
     223            2 :             m_isTextTrackIdentifierQueued = true;
     224              :         }
     225              :         else
     226              :         {
     227            1 :             client->setTextTrackIdentifier(m_textTrackIdentifier);
     228              :         }
     229              : 
     230            3 :         break;
     231              :     }
     232            1 :     case Property::WindowId:
     233              :     {
     234            1 :         m_videoId = g_value_get_uint(value);
     235            1 :         break;
     236              :     }
     237            1 :     case Property::Async:
     238              :     {
     239            1 :         m_isAsync = g_value_get_boolean(value);
     240            1 :         break;
     241              :     }
     242           28 :     default:
     243              :     {
     244           28 :         PullModePlaybackDelegate::setProperty(type, value);
     245           28 :         break;
     246              :     }
     247              :     }
     248           37 : }
     249              : 
     250            1 : void PullModeSubtitlePlaybackDelegate::handleQos(uint64_t processed, uint64_t dropped) const
     251              : {
     252            1 :     GstBus *bus = gst_element_get_bus(m_sink);
     253              :     /* Hardcode isLive to FALSE and set invalid timestamps */
     254            1 :     GstMessage *message = gst_message_new_qos(GST_OBJECT(m_sink), FALSE, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE,
     255              :                                               GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
     256              : 
     257            1 :     gst_message_set_qos_stats(message, GST_FORMAT_BUFFERS, processed, dropped);
     258            1 :     gst_bus_post(bus, message);
     259            1 :     gst_object_unref(bus);
     260              : }
     261              : 
     262              : std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource>
     263           12 : PullModeSubtitlePlaybackDelegate::createMediaSource(GstCaps *caps) const
     264              : {
     265           12 :     GstStructure *structure = gst_caps_get_structure(caps, 0);
     266           12 :     const gchar *mimeName = gst_structure_get_name(structure);
     267           12 :     if (mimeName)
     268              :     {
     269           12 :         std::string mimeType{};
     270           12 :         if (g_str_has_prefix(mimeName, "text/vtt") || g_str_has_prefix(mimeName, "application/x-subtitle-vtt"))
     271              :         {
     272            1 :             mimeType = "text/vtt";
     273              :         }
     274           11 :         else if (g_str_has_prefix(mimeName, "application/ttml+xml"))
     275              :         {
     276           11 :             mimeType = "text/ttml";
     277              :         }
     278              :         else
     279              :         {
     280            0 :             mimeType = mimeName;
     281              :         }
     282              : 
     283           12 :         GST_INFO_OBJECT(m_sink, "%s subtitle media source created", mimeType.c_str());
     284           12 :         return std::make_unique<firebolt::rialto::IMediaPipeline::MediaSourceSubtitle>(mimeType, m_textTrackIdentifier);
     285              :     }
     286              :     else
     287              :     {
     288            0 :         GST_ERROR_OBJECT(m_sink,
     289              :                          "Empty caps' structure name! Failed to set mime type when constructing subtitle media source");
     290              :     }
     291              : 
     292            0 :     return nullptr;
     293              : }
        

Generated by: LCOV version 2.0-1