LCOV - code coverage report
Current view: top level - media/server/gstplayer/source - GstTextTrackSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 1.6 % 247 4
Test Date: 2026-10-23 12:56:16 Functions: 6.2 % 16 1

            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 2024 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 "GstProtectionMetadataHelperFactory.h"
      21              : #include "GstRialtoTextTrackSinkPrivate.h"
      22              : #include "GstTextTrackSinkFactory.h"
      23              : #include "RialtoServerLogging.h"
      24              : #include <atomic>
      25              : #include <cinttypes>
      26              : #include <cstdlib>
      27              : #include <gst/base/gstbasetransform.h>
      28              : #include <gst/gst.h>
      29              : #include <stdexcept>
      30              : G_BEGIN_DECLS
      31              : 
      32              : enum
      33              : {
      34              :     PROP_0,
      35              :     PROP_MUTE,
      36              :     PROP_TEXT_TRACK_IDENTIFIER,
      37              :     PROP_VIDEO_DECODER,
      38              :     PROP_POSITION,
      39              :     PROP_OFFSET,
      40              :     PROP_LAST
      41              : };
      42              : 
      43              : #define GST_RIALTO_TEXT_TRACK_SINK_TYPE (gst_rialto_text_track_sink_get_type())
      44              : #define GST_RIALTO_TEXT_TRACK_SINK(obj)                                                                                \
      45              :     (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSink))
      46              : #define GST_RIALTO_TEXT_TRACK_SINK_CLASS(klass)                                                                        \
      47              :     (G_TYPE_CHECK_CLASS_CAST((klass), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSinkClass))
      48              : 
      49              : typedef struct _GstRialtoTextTrackSink GstRialtoTextTrackSink;
      50              : typedef struct _GstRialtoTextTrackSinkClass GstRialtoTextTrackSinkClass;
      51              : typedef struct firebolt::rialto::server::GstRialtoTextTrackSinkPrivate GstRialtoTextTrackSinkPrivate;
      52              : 
      53              : GType gst_rialto_text_track_sink_get_type(void); // NOLINT(build/function_format)
      54              : 
      55              : struct _GstRialtoTextTrackSink
      56              : {
      57              :     GstBaseSink parent;
      58              :     GstRialtoTextTrackSinkPrivate *priv;
      59              : };
      60              : 
      61              : struct _GstRialtoTextTrackSinkClass
      62              : {
      63              :     GstBaseSink parentClass;
      64              : };
      65              : 
      66              : G_END_DECLS
      67              : 
      68              : static GstStaticPadTemplate sinkTemplate =
      69              :     GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
      70              :                             GST_STATIC_CAPS("application/ttml+xml; text/vtt; application/x-subtitle-vtt; text/x-raw; "
      71              :                                             "subtitle/x-subtitle-cc"));
      72              : 
      73              : GST_DEBUG_CATEGORY(gst_rialto_text_track_sink_debug_category);
      74              : #define GST_CAT_DEFAULT gst_rialto_text_track_sink_debug_category
      75              : 
      76              : #define gst_rialto_text_track_sink_parent_class parent_class
      77            0 : G_DEFINE_TYPE_WITH_PRIVATE(GstRialtoTextTrackSink, gst_rialto_text_track_sink, GST_TYPE_BASE_SINK);
      78              : 
      79              : static void gst_rialto_text_track_sink_finalize(GObject *object);         // NOLINT(build/function_format)
      80              : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, // NOLINT(build/function_format)
      81              :                                                        GstBuffer *buffer);
      82              : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps); // NOLINT(build/function_format)
      83              : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink);                   // NOLINT(build/function_format)
      84              : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink);                    // NOLINT(build/function_format)
      85              : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event);  // NOLINT(build/function_format)
      86              : static GstStateChangeReturn
      87              : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition); // NOLINT(build/function_format)
      88              : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
      89              :                                                     GValue *value, GParamSpec *pspec);
      90              : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
      91              :                                                     const GValue *value, GParamSpec *pspec);
      92              : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query); // NOLINT(build/function_format)
      93              : 
      94            0 : static void gst_rialto_text_track_sink_class_init(GstRialtoTextTrackSinkClass *klass) // NOLINT(build/function_format)
      95              : {
      96            0 :     GST_DEBUG_CATEGORY_INIT(gst_rialto_text_track_sink_debug_category, "rialto_text_track_sink", 0,
      97              :                             "TextTrack Sink for Rialto");
      98              : 
      99            0 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
     100            0 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
     101            0 :     GstBaseSinkClass *baseSinkClass = GST_BASE_SINK_CLASS(klass);
     102              : 
     103            0 :     gobjectClass->finalize = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_finalize);
     104            0 :     gobjectClass->get_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_get_property);
     105            0 :     gobjectClass->set_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_property);
     106            0 :     baseSinkClass->start = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_start);
     107            0 :     baseSinkClass->stop = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_stop);
     108            0 :     baseSinkClass->render = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_render);
     109            0 :     baseSinkClass->set_caps = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_caps);
     110            0 :     baseSinkClass->event = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_event);
     111            0 :     elementClass->change_state = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_change_state);
     112            0 :     elementClass->query = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_query);
     113              : 
     114            0 :     g_object_class_install_property(gobjectClass, PROP_MUTE,
     115              :                                     g_param_spec_boolean("mute", "Mute", "Mute subtitles", FALSE, G_PARAM_READWRITE));
     116              : 
     117            0 :     g_object_class_install_property(gobjectClass, PROP_TEXT_TRACK_IDENTIFIER,
     118              :                                     g_param_spec_string("text-track-identifier", "Text Track Identifier",
     119              :                                                         "Identifier of text track", nullptr,
     120              :                                                         GParamFlags(G_PARAM_READWRITE)));
     121              : 
     122            0 :     g_object_class_install_property(gobjectClass, PROP_VIDEO_DECODER,
     123              :                                     g_param_spec_pointer("video-decoder", "Video Decoder", "Video Decoder",
     124              :                                                          GParamFlags(G_PARAM_WRITABLE)));
     125              : 
     126            0 :     g_object_class_install_property(gobjectClass, PROP_POSITION,
     127              :                                     g_param_spec_uint64("position", "Position", "Position", 0, G_MAXUINT64, 0,
     128              :                                                         GParamFlags(G_PARAM_READWRITE)));
     129              : 
     130            0 :     g_object_class_install_property(gobjectClass, PROP_OFFSET,
     131              :                                     g_param_spec_uint64("offset", "Offset", "Offset", 0, G_MAXUINT64, 0,
     132              :                                                         GParamFlags(G_PARAM_WRITABLE)));
     133              : 
     134            0 :     gst_element_class_add_pad_template(elementClass, gst_static_pad_template_get(&sinkTemplate));
     135            0 :     gst_element_class_set_static_metadata(elementClass, "Rialto TextTrack Sink", "Sink/Parser/Subtitle",
     136              :                                           "Rialto TextTrack Sink", "SKY");
     137              : }
     138              : 
     139            0 : static void gst_rialto_text_track_sink_init(GstRialtoTextTrackSink *self) // NOLINT(build/function_format)
     140              : {
     141              :     GstRialtoTextTrackSinkPrivate *priv =
     142            0 :         reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
     143              : 
     144            0 :     self->priv = new (priv) GstRialtoTextTrackSinkPrivate();
     145              : 
     146            0 :     gst_base_sink_set_async_enabled(GST_BASE_SINK(self), FALSE);
     147              : }
     148              : 
     149            0 : static void gst_rialto_text_track_sink_finalize(GObject *object) // NOLINT(build/function_format)
     150              : {
     151            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(object);
     152              :     GstRialtoTextTrackSinkPrivate *priv =
     153            0 :         reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
     154              : 
     155            0 :     priv->~GstRialtoTextTrackSinkPrivate();
     156              : 
     157            0 :     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
     158              : }
     159              : 
     160            0 : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink) // NOLINT(build/function_format)
     161              : {
     162            0 :     const std::string kDisplay{"westeros-asplayer-subtitles"};
     163            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
     164              :     try
     165              :     {
     166            0 :         self->priv->m_textTrackSession =
     167            0 :             firebolt::rialto::server::ITextTrackSessionFactory::getFactory().createTextTrackSession(kDisplay);
     168              :     }
     169            0 :     catch (const std::exception &e)
     170              :     {
     171            0 :         RIALTO_SERVER_LOG_WARN("Failed to create TextTrack session, reason: '%s'", e.what());
     172            0 :         return true;
     173              :     }
     174              : 
     175            0 :     GST_INFO_OBJECT(sink, "Successfully started TextTrack sink");
     176            0 :     return true;
     177              : }
     178              : 
     179            0 : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink) // NOLINT(build/function_format)
     180              : {
     181            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
     182            0 :     self->priv->m_textTrackSession.reset();
     183              : 
     184            0 :     GST_INFO_OBJECT(sink, "Successfully stopped TextTrack sink");
     185            0 :     return true;
     186              : }
     187              : 
     188            0 : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, GstBuffer *buffer) // NOLINT(build/function_format)
     189              : {
     190            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     191            0 :     if (!textTrackSink->priv->m_textTrackSession)
     192              :     {
     193            0 :         GST_LOG_OBJECT(textTrackSink, "No TextTrack session, dropping buffer");
     194            0 :         return GST_FLOW_OK;
     195              :     }
     196              : 
     197              :     GstMapInfo info;
     198            0 :     if (gst_buffer_map(buffer, &info, GST_MAP_READ))
     199              :     {
     200            0 :         std::string data(reinterpret_cast<char *>(info.data), info.size);
     201            0 :         int64_t displayOffset{0};
     202            0 :         if (GST_BUFFER_OFFSET_NONE != GST_BUFFER_OFFSET(buffer))
     203              :         {
     204            0 :             displayOffset = static_cast<int64_t>(GST_BUFFER_OFFSET(buffer));
     205              :         }
     206            0 :         textTrackSink->priv->m_textTrackSession->sendData(data, 0 - displayOffset);
     207              : 
     208            0 :         gst_buffer_unmap(buffer, &info);
     209              :     }
     210              :     else
     211              :     {
     212            0 :         GST_ERROR_OBJECT(textTrackSink, "Failed to map buffer");
     213            0 :         return GST_FLOW_ERROR;
     214              :     }
     215              : 
     216            0 :     return GST_FLOW_OK;
     217              : }
     218              : 
     219            0 : static gboolean gst_rialto_text_track_sink_set_position(GstRialtoTextTrackSink *textTrackSink) // NOLINT(build/function_format)
     220              : {
     221            0 :     if (!textTrackSink->priv->m_textTrackSession)
     222              :     {
     223            0 :         GST_DEBUG_OBJECT(textTrackSink, "No TextTrack session, position not set");
     224            0 :         return FALSE;
     225              :     }
     226              : 
     227            0 :     uint64_t positionWithOffset = textTrackSink->priv->m_position.value_or(0) + textTrackSink->priv->m_offset.value_or(0);
     228              : 
     229            0 :     GST_DEBUG_OBJECT(textTrackSink,
     230              :                      "Setting position to %" GST_TIME_FORMAT " (pts %" GST_TIME_FORMAT ", offset %" GST_TIME_FORMAT ")",
     231              :                      GST_TIME_ARGS(positionWithOffset), GST_TIME_ARGS(textTrackSink->priv->m_position.value_or(0)),
     232              :                      GST_TIME_ARGS(textTrackSink->priv->m_offset.value_or(0)));
     233              : 
     234            0 :     textTrackSink->priv->m_textTrackSession->setPosition(positionWithOffset / GST_MSECOND);
     235            0 :     return TRUE;
     236              : }
     237              : 
     238            0 : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps) // NOLINT(build/function_format)
     239              : {
     240            0 :     GST_INFO_OBJECT(sink, "Setting caps %" GST_PTR_FORMAT, caps);
     241            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     242              : 
     243            0 :     GstStructure *structure = gst_caps_get_structure(caps, 0);
     244            0 :     const gchar *mimeName = gst_structure_get_name(structure);
     245              : 
     246            0 :     if (!textTrackSink->priv->m_textTrackSession)
     247              :     {
     248            0 :         GST_WARNING_OBJECT(sink, "No TextTrack session, subtitles of type '%s' will not be displayed", mimeName);
     249            0 :         return TRUE;
     250              :     }
     251              : 
     252            0 :     if (g_str_has_prefix(mimeName, "text/vtt") || g_str_has_prefix(mimeName, "application/x-subtitle-vtt"))
     253              :     {
     254            0 :         GST_INFO_OBJECT(sink, "Setting session to WebVTT");
     255            0 :         textTrackSink->priv->m_textTrackSession->setSessionWebVTTSelection();
     256              :     }
     257            0 :     else if (g_str_has_prefix(mimeName, "application/ttml+xml"))
     258              :     {
     259            0 :         GST_INFO_OBJECT(sink, "Setting session to TTML");
     260            0 :         textTrackSink->priv->m_textTrackSession->setSessionTTMLSelection();
     261              :     }
     262            0 :     else if (g_str_has_prefix(mimeName, "subtitle/x-subtitle-cc"))
     263              :     {
     264            0 :         GST_INFO_OBJECT(sink, "Setting session to CC");
     265            0 :         std::string identifier = "CC1";
     266            0 :         if (textTrackSink->priv->m_textTrackIdentifier.empty())
     267              :         {
     268            0 :             GST_WARNING_OBJECT(sink, "No text track identifier set, defaulting to %s", identifier.c_str());
     269              :         }
     270              :         else
     271              :         {
     272            0 :             identifier = textTrackSink->priv->m_textTrackIdentifier;
     273              :         }
     274            0 :         textTrackSink->priv->m_textTrackSession->setSessionCCSelection(identifier);
     275              : 
     276            0 :         if (textTrackSink->priv->m_videoDecoderIdentifier)
     277              :         {
     278            0 :             textTrackSink->priv->m_textTrackSession->associateVideoDecoder(textTrackSink->priv->m_videoDecoderIdentifier);
     279              :         }
     280              :     }
     281              :     else
     282              :     {
     283            0 :         GST_ERROR_OBJECT(sink, "Invalid mime name '%s'", mimeName);
     284            0 :         return FALSE;
     285              :     }
     286              : 
     287            0 :     textTrackSink->priv->m_textTrackSession->mute(textTrackSink->priv->m_isMuted);
     288              : 
     289            0 :     std::unique_lock lock{textTrackSink->priv->m_mutex};
     290            0 :     textTrackSink->priv->m_capsSet = true;
     291            0 :     bool wasAnyQueued = textTrackSink->priv->m_queuedPosition.has_value() ||
     292            0 :                         textTrackSink->priv->m_queuedOffset.has_value();
     293            0 :     if (textTrackSink->priv->m_queuedPosition.has_value())
     294              :     {
     295            0 :         textTrackSink->priv->m_position = textTrackSink->priv->m_queuedPosition;
     296            0 :         textTrackSink->priv->m_queuedPosition.reset();
     297              :     }
     298            0 :     if (textTrackSink->priv->m_queuedOffset.has_value())
     299              :     {
     300            0 :         textTrackSink->priv->m_offset = textTrackSink->priv->m_queuedOffset;
     301            0 :         textTrackSink->priv->m_queuedOffset.reset();
     302              :     }
     303            0 :     if (wasAnyQueued)
     304              :     {
     305            0 :         gst_rialto_text_track_sink_set_position(textTrackSink);
     306              :     }
     307              : 
     308            0 :     return TRUE;
     309              : }
     310              : 
     311            0 : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event) // NOLINT(build/function_format)
     312              : {
     313            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     314            0 :     GST_DEBUG_OBJECT(textTrackSink, "handling event %" GST_PTR_FORMAT, event);
     315              : 
     316            0 :     switch (GST_EVENT_TYPE(event))
     317              :     {
     318            0 :     case GST_EVENT_FLUSH_START:
     319              :     {
     320            0 :         if (textTrackSink->priv->m_textTrackSession &&
     321            0 :             !textTrackSink->priv->m_textTrackSession->resetSession(textTrackSink->priv->m_isMuted))
     322              :         {
     323            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to reset TextTrack session");
     324              :         }
     325            0 :         break;
     326              :     }
     327            0 :     case GST_EVENT_FLUSH_STOP:
     328              :     {
     329            0 :         break;
     330              :     }
     331            0 :     case GST_EVENT_CUSTOM_DOWNSTREAM:
     332              :     case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
     333              :     {
     334            0 :         if (gst_event_has_name(event, "current-pts"))
     335              :         {
     336            0 :             uint64_t pts = 0;
     337            0 :             const GstStructure *structure = gst_event_get_structure(event);
     338            0 :             if (structure)
     339              :             {
     340            0 :                 if (gst_structure_get_uint64(structure, "pts", &pts))
     341              :                 {
     342            0 :                     if (pts == GST_CLOCK_TIME_NONE)
     343              :                     {
     344            0 :                         GST_ERROR_OBJECT(textTrackSink, "Invalid PTS value");
     345            0 :                         return FALSE;
     346              :                     }
     347              : 
     348            0 :                     std::unique_lock lock{textTrackSink->priv->m_mutex};
     349            0 :                     textTrackSink->priv->m_position = pts;
     350              : 
     351            0 :                     gst_rialto_text_track_sink_set_position(textTrackSink);
     352              :                 }
     353              :                 else
     354              :                 {
     355            0 :                     GST_ERROR_OBJECT(textTrackSink, "Failed to get PTS from structure");
     356            0 :                     return FALSE;
     357              :                 }
     358              :             }
     359              :             else
     360              :             {
     361            0 :                 GST_ERROR_OBJECT(textTrackSink, "Failed to get structure from event");
     362            0 :                 return FALSE;
     363              :             }
     364              :         }
     365            0 :         break;
     366              :     }
     367            0 :     default:
     368              :     {
     369            0 :         break;
     370              :     }
     371              :     }
     372              : 
     373            0 :     return GST_BASE_SINK_CLASS(parent_class)->event(sink, event);
     374              : }
     375              : 
     376              : static GstStateChangeReturn
     377            0 : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition) // NOLINT(build/function_format)
     378              : {
     379            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(element);
     380              : 
     381            0 :     GstState current_state = GST_STATE_TRANSITION_CURRENT(transition);
     382            0 :     GstState next_state = GST_STATE_TRANSITION_NEXT(transition);
     383            0 :     GST_INFO_OBJECT(textTrackSink, "State change: (%s) -> (%s)", gst_element_state_get_name(current_state),
     384              :                     gst_element_state_get_name(next_state));
     385              : 
     386            0 :     switch (transition)
     387              :     {
     388            0 :     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
     389              :     {
     390            0 :         if (textTrackSink->priv->m_textTrackSession && !textTrackSink->priv->m_textTrackSession->play())
     391              :         {
     392            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to play textTrack session");
     393              :         }
     394            0 :         break;
     395              :     }
     396            0 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     397              :     {
     398            0 :         if (textTrackSink->priv->m_textTrackSession && !textTrackSink->priv->m_textTrackSession->pause())
     399              :         {
     400            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to pause textTrack session");
     401              :         }
     402              : 
     403            0 :         break;
     404              :     }
     405            0 :     default:
     406            0 :         break;
     407              :     }
     408              : 
     409            0 :     GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
     410            0 :     if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
     411              :     {
     412            0 :         GST_WARNING_OBJECT(textTrackSink, "State change failed");
     413            0 :         return result;
     414              :     }
     415              : 
     416            0 :     return GST_STATE_CHANGE_SUCCESS;
     417              : }
     418              : 
     419            0 : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
     420              :                                                     GValue *value, GParamSpec *pspec)
     421              : {
     422            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
     423            0 :     if (!textTrackSink)
     424              :     {
     425            0 :         GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
     426            0 :         return;
     427              :     }
     428            0 :     GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
     429              : 
     430            0 :     switch (propId)
     431              :     {
     432            0 :     case PROP_MUTE:
     433              :     {
     434            0 :         g_value_set_boolean(value, priv->m_isMuted.load());
     435            0 :         break;
     436              :     }
     437            0 :     case PROP_TEXT_TRACK_IDENTIFIER:
     438              :     {
     439            0 :         g_value_set_string(value, priv->m_textTrackIdentifier.c_str());
     440            0 :         break;
     441              :     }
     442            0 :     case PROP_POSITION:
     443              :     {
     444              :         // Thunder ITextTrack does not provide getPosition API so we are unable to determine current position
     445            0 :         g_value_set_uint64(value, GST_CLOCK_TIME_NONE);
     446            0 :         break;
     447              :     }
     448            0 :     default:
     449            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     450            0 :         break;
     451              :     }
     452              : }
     453              : 
     454            0 : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
     455              :                                                     const GValue *value, GParamSpec *pspec)
     456              : {
     457            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
     458            0 :     if (!textTrackSink)
     459              :     {
     460            0 :         GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
     461            0 :         return;
     462              :     }
     463            0 :     GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
     464              : 
     465            0 :     switch (propId)
     466              :     {
     467            0 :     case PROP_MUTE:
     468              :     {
     469            0 :         priv->m_isMuted = g_value_get_boolean(value);
     470            0 :         if (priv->m_textTrackSession)
     471              :         {
     472            0 :             priv->m_textTrackSession->mute(priv->m_isMuted);
     473              :         }
     474            0 :         break;
     475              :     }
     476            0 :     case PROP_TEXT_TRACK_IDENTIFIER:
     477              :     {
     478            0 :         priv->m_textTrackIdentifier = g_value_get_string(value);
     479            0 :         if (priv->m_textTrackSession && priv->m_textTrackSession->isClosedCaptions())
     480              :         {
     481            0 :             priv->m_textTrackSession->setSessionCCSelection(priv->m_textTrackIdentifier);
     482              :         }
     483              : 
     484            0 :         break;
     485              :     }
     486            0 :     case PROP_VIDEO_DECODER:
     487              :     {
     488            0 :         priv->m_videoDecoderIdentifier = g_value_get_pointer(value);
     489              : 
     490            0 :         if (priv->m_textTrackSession && priv->m_textTrackSession->isClosedCaptions())
     491              :         {
     492            0 :             priv->m_textTrackSession->associateVideoDecoder(priv->m_videoDecoderIdentifier);
     493              :         }
     494              : 
     495            0 :         break;
     496              :     }
     497            0 :     case PROP_POSITION:
     498              :     {
     499            0 :         guint64 position = g_value_get_uint64(value);
     500            0 :         std::unique_lock lock{priv->m_mutex};
     501            0 :         if (priv->m_textTrackSession && priv->m_capsSet)
     502              :         {
     503            0 :             priv->m_position = position;
     504            0 :             gst_rialto_text_track_sink_set_position(textTrackSink);
     505              :         }
     506              :         else
     507              :         {
     508            0 :             priv->m_queuedPosition = position;
     509              :         }
     510            0 :         break;
     511              :     }
     512            0 :     case PROP_OFFSET:
     513              :     {
     514            0 :         uint64_t offset = g_value_get_uint64(value);
     515            0 :         std::unique_lock lock{priv->m_mutex};
     516            0 :         if (priv->m_textTrackSession && priv->m_capsSet)
     517              :         {
     518            0 :             priv->m_offset = offset;
     519            0 :             gst_rialto_text_track_sink_set_position(textTrackSink);
     520              :         }
     521              :         else
     522              :         {
     523            0 :             priv->m_queuedOffset = offset;
     524              :         }
     525            0 :         break;
     526              :     }
     527              : 
     528            0 :     default:
     529            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     530            0 :         break;
     531              :     }
     532              : }
     533              : 
     534            0 : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query) // NOLINT(build/function_format)
     535              : {
     536            0 :     GstRialtoTextTrackSink *sink = GST_RIALTO_TEXT_TRACK_SINK(element);
     537            0 :     GST_DEBUG_OBJECT(sink, "handling query '%s'", GST_QUERY_TYPE_NAME(query));
     538            0 :     switch (GST_QUERY_TYPE(query))
     539              :     {
     540            0 :     case GST_QUERY_POSITION:
     541              :     {
     542              :         GstFormat fmt;
     543            0 :         gst_query_parse_position(query, &fmt, NULL);
     544            0 :         switch (fmt)
     545              :         {
     546            0 :         case GST_FORMAT_TIME:
     547              :         {
     548              :             // GST_CLOCK_TIME_NONE has to be returned here, because otherwise whole pipeline returns incorrect position
     549            0 :             gst_query_set_position(query, fmt, GST_CLOCK_TIME_NONE);
     550            0 :             break;
     551              :         }
     552            0 :         default:
     553            0 :             break;
     554              :         }
     555            0 :         return TRUE;
     556              :     }
     557            0 :     default:
     558            0 :         break;
     559              :     }
     560            0 :     GstElement *parent = GST_ELEMENT(&sink->parent);
     561            0 :     return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
     562              : }
     563              : 
     564              : namespace firebolt::rialto::server
     565              : {
     566            1 : std::shared_ptr<IGstTextTrackSinkFactory> IGstTextTrackSinkFactory::createFactory()
     567              : {
     568            1 :     std::shared_ptr<IGstTextTrackSinkFactory> factory;
     569              : 
     570              :     try
     571              :     {
     572            1 :         factory = std::make_shared<GstTextTrackSinkFactory>();
     573              :     }
     574            0 :     catch (const std::exception &e)
     575              :     {
     576            0 :         RIALTO_SERVER_LOG_ERROR("Failed to create the textTrackSink element factory, reason: %s", e.what());
     577              :     }
     578              : 
     579            1 :     return factory;
     580              : }
     581              : 
     582            0 : GstElement *GstTextTrackSinkFactory::createGstTextTrackSink() const
     583              : {
     584            0 :     GstElement *elem = GST_ELEMENT(g_object_new(GST_RIALTO_TEXT_TRACK_SINK_TYPE, nullptr));
     585              : 
     586            0 :     return elem;
     587              : }
     588              : 
     589              : }; // namespace firebolt::rialto::server
        

Generated by: LCOV version 2.0-1