LCOV - code coverage report
Current view: top level - media/server/gstplayer/source - GstTextTrackSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 2.1 % 189 4
Test Date: 2025-02-18 13:13:53 Functions: 6.7 % 15 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 "GstTextTrackSinkFactory.h"
      22              : #include "RialtoServerLogging.h"
      23              : #include <stdexcept>
      24              : 
      25              : #include "GstRialtoTextTrackSinkPrivate.h"
      26              : #include <atomic>
      27              : #include <cstdlib>
      28              : #include <gst/base/gstbasetransform.h>
      29              : #include <gst/gst.h>
      30              : G_BEGIN_DECLS
      31              : 
      32              : enum
      33              : {
      34              :     PROP_0,
      35              :     PROP_MUTE,
      36              :     PROP_TEXT_TRACK_IDENTIFIER,
      37              :     PROP_POSITION,
      38              :     PROP_LAST
      39              : };
      40              : 
      41              : #define GST_RIALTO_TEXT_TRACK_SINK_TYPE (gst_rialto_text_track_sink_get_type())
      42              : #define GST_RIALTO_TEXT_TRACK_SINK(obj)                                                                                \
      43              :     (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSink))
      44              : #define GST_RIALTO_TEXT_TRACK_SINK_CLASS(klass)                                                                        \
      45              :     (G_TYPE_CHECK_CLASS_CAST((klass), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSinkClass))
      46              : 
      47              : typedef struct _GstRialtoTextTrackSink GstRialtoTextTrackSink;
      48              : typedef struct _GstRialtoTextTrackSinkClass GstRialtoTextTrackSinkClass;
      49              : typedef struct firebolt::rialto::server::GstRialtoTextTrackSinkPrivate GstRialtoTextTrackSinkPrivate;
      50              : 
      51              : GType gst_rialto_text_track_sink_get_type(void); // NOLINT(build/function_format)
      52              : 
      53              : struct _GstRialtoTextTrackSink
      54              : {
      55              :     GstBaseSink parent;
      56              :     GstRialtoTextTrackSinkPrivate *priv;
      57              : };
      58              : 
      59              : struct _GstRialtoTextTrackSinkClass
      60              : {
      61              :     GstBaseSink parentClass;
      62              : };
      63              : 
      64              : G_END_DECLS
      65              : 
      66              : static GstStaticPadTemplate sinkTemplate =
      67              :     GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
      68              :                             GST_STATIC_CAPS("application/ttml+xml; text/vtt; application/x-subtitle-vtt; text/x-raw"));
      69              : 
      70              : GST_DEBUG_CATEGORY(gst_rialto_text_track_sink_debug_category);
      71              : #define GST_CAT_DEFAULT gst_rialto_text_track_sink_debug_category
      72              : 
      73              : #define gst_rialto_text_track_sink_parent_class parent_class
      74            0 : G_DEFINE_TYPE_WITH_PRIVATE(GstRialtoTextTrackSink, gst_rialto_text_track_sink, GST_TYPE_BASE_SINK);
      75              : 
      76              : static void gst_rialto_text_track_sink_finalize(GObject *object);         // NOLINT(build/function_format)
      77              : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, // NOLINT(build/function_format)
      78              :                                                        GstBuffer *buffer);
      79              : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps); // NOLINT(build/function_format)
      80              : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink);                   // NOLINT(build/function_format)
      81              : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink);                    // NOLINT(build/function_format)
      82              : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event);  // NOLINT(build/function_format)
      83              : static GstStateChangeReturn
      84              : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition); // NOLINT(build/function_format)
      85              : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
      86              :                                                     GValue *value, GParamSpec *pspec);
      87              : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
      88              :                                                     const GValue *value, GParamSpec *pspec);
      89              : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query); // NOLINT(build/function_format)
      90              : 
      91            0 : static void gst_rialto_text_track_sink_class_init(GstRialtoTextTrackSinkClass *klass) // NOLINT(build/function_format)
      92              : {
      93            0 :     GST_DEBUG_CATEGORY_INIT(gst_rialto_text_track_sink_debug_category, "rialto_text_track_sink", 0,
      94              :                             "TextTrack Sink for Rialto");
      95              : 
      96            0 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
      97            0 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
      98            0 :     GstBaseSinkClass *baseSinkClass = GST_BASE_SINK_CLASS(klass);
      99              : 
     100            0 :     gobjectClass->finalize = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_finalize);
     101            0 :     gobjectClass->get_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_get_property);
     102            0 :     gobjectClass->set_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_property);
     103            0 :     baseSinkClass->start = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_start);
     104            0 :     baseSinkClass->stop = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_stop);
     105            0 :     baseSinkClass->render = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_render);
     106            0 :     baseSinkClass->set_caps = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_caps);
     107            0 :     baseSinkClass->event = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_event);
     108            0 :     elementClass->change_state = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_change_state);
     109            0 :     elementClass->query = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_query);
     110              : 
     111            0 :     g_object_class_install_property(gobjectClass, PROP_MUTE,
     112              :                                     g_param_spec_boolean("mute", "Mute", "Mute subtitles", FALSE, G_PARAM_READWRITE));
     113              : 
     114            0 :     g_object_class_install_property(gobjectClass, PROP_TEXT_TRACK_IDENTIFIER,
     115              :                                     g_param_spec_string("text-track-identifier", "Text Track Identifier",
     116              :                                                         "Identifier of text track", nullptr,
     117              :                                                         GParamFlags(G_PARAM_READWRITE)));
     118            0 :     g_object_class_install_property(gobjectClass, PROP_POSITION,
     119              :                                     g_param_spec_uint64("position", "Position", "Position", 0, G_MAXUINT64, 0,
     120              :                                                         GParamFlags(G_PARAM_READWRITE)));
     121              : 
     122            0 :     gst_element_class_add_pad_template(elementClass, gst_static_pad_template_get(&sinkTemplate));
     123            0 :     gst_element_class_set_static_metadata(elementClass, "Rialto TextTrack Sink", "Sink/Parser/Subtitle",
     124              :                                           "Rialto TextTrack Sink", "SKY");
     125              : }
     126              : 
     127            0 : static void gst_rialto_text_track_sink_init(GstRialtoTextTrackSink *self) // NOLINT(build/function_format)
     128              : {
     129              :     GstRialtoTextTrackSinkPrivate *priv =
     130            0 :         reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
     131              : 
     132            0 :     self->priv = new (priv) GstRialtoTextTrackSinkPrivate();
     133              : 
     134            0 :     gst_base_sink_set_async_enabled(GST_BASE_SINK(self), FALSE);
     135              : }
     136              : 
     137            0 : static void gst_rialto_text_track_sink_finalize(GObject *object) // NOLINT(build/function_format)
     138              : {
     139            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(object);
     140              :     GstRialtoTextTrackSinkPrivate *priv =
     141            0 :         reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
     142              : 
     143            0 :     priv->~GstRialtoTextTrackSinkPrivate();
     144              : 
     145            0 :     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
     146              : }
     147              : 
     148            0 : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink) // NOLINT(build/function_format)
     149              : {
     150            0 :     const char *wayland_display = std::getenv("WAYLAND_DISPLAY");
     151            0 :     if (!wayland_display)
     152              :     {
     153            0 :         GST_ERROR_OBJECT(sink, "Failed to get WAYLAND_DISPLAY env variable");
     154            0 :         return false;
     155              :     }
     156              : 
     157            0 :     std::string display{wayland_display};
     158            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
     159              :     try
     160              :     {
     161            0 :         self->priv->m_textTrackSession =
     162            0 :             firebolt::rialto::server::ITextTrackSessionFactory::getFactory().createTextTrackSession(display);
     163              :     }
     164            0 :     catch (const std::exception &e)
     165              :     {
     166            0 :         GST_ERROR_OBJECT(sink, "Failed to create TextTrackSession. Reason '%s'", e.what());
     167            0 :         return false;
     168              :     }
     169              : 
     170            0 :     GST_INFO_OBJECT(sink, "Successfully started TextTrack sink");
     171            0 :     return true;
     172              : }
     173              : 
     174            0 : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink) // NOLINT(build/function_format)
     175              : {
     176            0 :     GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
     177            0 :     self->priv->m_textTrackSession.reset();
     178              : 
     179            0 :     GST_INFO_OBJECT(sink, "Successfully stopped TextTrack sink");
     180            0 :     return true;
     181              : }
     182              : 
     183            0 : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, GstBuffer *buffer) // NOLINT(build/function_format)
     184              : {
     185            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     186              : 
     187              :     GstMapInfo info;
     188            0 :     if (gst_buffer_map(buffer, &info, GST_MAP_READ))
     189              :     {
     190            0 :         std::string data(reinterpret_cast<char *>(info.data), info.size);
     191            0 :         textTrackSink->priv->m_textTrackSession->sendData(data);
     192              : 
     193            0 :         gst_buffer_unmap(buffer, &info);
     194              :     }
     195              :     else
     196              :     {
     197            0 :         GST_ERROR_OBJECT(textTrackSink, "Failed to map buffer");
     198            0 :         return GST_FLOW_ERROR;
     199              :     }
     200              : 
     201            0 :     return GST_FLOW_OK;
     202              : }
     203              : 
     204            0 : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps) // NOLINT(build/function_format)
     205              : {
     206            0 :     GST_INFO_OBJECT(sink, "Setting caps %" GST_PTR_FORMAT, caps);
     207            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     208              : 
     209            0 :     GstStructure *structure = gst_caps_get_structure(caps, 0);
     210            0 :     const gchar *mimeName = gst_structure_get_name(structure);
     211              : 
     212            0 :     if (g_str_has_prefix(mimeName, "text/vtt") || g_str_has_prefix(mimeName, "application/x-subtitle-vtt"))
     213              :     {
     214            0 :         GST_INFO_OBJECT(sink, "Setting session to WebVTT");
     215            0 :         textTrackSink->priv->m_textTrackSession->setSessionWebVTTSelection();
     216              :     }
     217            0 :     else if (g_str_has_prefix(mimeName, "application/ttml+xml"))
     218              :     {
     219            0 :         GST_INFO_OBJECT(sink, "Setting session to TTML");
     220            0 :         textTrackSink->priv->m_textTrackSession->setSessionTTMLSelection();
     221              :     }
     222            0 :     else if (g_str_has_prefix(mimeName, "text/x-raw"))
     223              :     {
     224            0 :         GST_INFO_OBJECT(sink, "Setting session to CC");
     225            0 :         textTrackSink->priv->m_textTrackSession->setSessionCCSelection(textTrackSink->priv->m_textTrackIdentifier);
     226              :     }
     227              :     else
     228              :     {
     229            0 :         GST_ERROR_OBJECT(sink, "Invalid mime name '%s'", mimeName);
     230            0 :         return FALSE;
     231              :     }
     232              : 
     233            0 :     textTrackSink->priv->m_textTrackSession->mute(textTrackSink->priv->m_isMuted);
     234              : 
     235            0 :     std::unique_lock lock{textTrackSink->priv->m_mutex};
     236            0 :     textTrackSink->priv->m_capsSet = true;
     237            0 :     if (textTrackSink->priv->m_queuedPosition.has_value())
     238              :     {
     239            0 :         textTrackSink->priv->m_textTrackSession->setPosition(textTrackSink->priv->m_queuedPosition.value() / GST_MSECOND);
     240            0 :         textTrackSink->priv->m_queuedPosition.reset();
     241              :     }
     242              : 
     243            0 :     return TRUE;
     244              : }
     245              : 
     246            0 : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event) // NOLINT(build/function_format)
     247              : {
     248            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
     249            0 :     GST_DEBUG_OBJECT(textTrackSink, "handling event %" GST_PTR_FORMAT, event);
     250              : 
     251            0 :     switch (GST_EVENT_TYPE(event))
     252              :     {
     253            0 :     case GST_EVENT_FLUSH_START:
     254              :     {
     255            0 :         if (!textTrackSink->priv->m_textTrackSession->resetSession())
     256              :         {
     257            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to reset TextTrack session");
     258              :         }
     259            0 :         break;
     260              :     }
     261            0 :     case GST_EVENT_FLUSH_STOP:
     262              :     {
     263            0 :         break;
     264              :     }
     265            0 :     default:
     266              :     {
     267            0 :         break;
     268              :     }
     269              :     }
     270              : 
     271            0 :     return GST_BASE_SINK_CLASS(parent_class)->event(sink, event);
     272              : }
     273              : 
     274              : static GstStateChangeReturn
     275            0 : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition) // NOLINT(build/function_format)
     276              : {
     277            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(element);
     278              : 
     279            0 :     GstState current_state = GST_STATE_TRANSITION_CURRENT(transition);
     280            0 :     GstState next_state = GST_STATE_TRANSITION_NEXT(transition);
     281            0 :     GST_INFO_OBJECT(textTrackSink, "State change: (%s) -> (%s)", gst_element_state_get_name(current_state),
     282              :                     gst_element_state_get_name(next_state));
     283              : 
     284            0 :     switch (transition)
     285              :     {
     286            0 :     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
     287              :     {
     288            0 :         if (!textTrackSink->priv->m_textTrackSession->play())
     289              :         {
     290            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to play textTrack session");
     291            0 :             return GST_STATE_CHANGE_FAILURE;
     292              :         }
     293            0 :         break;
     294              :     }
     295            0 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     296              :     {
     297            0 :         if (!textTrackSink->priv->m_textTrackSession->pause())
     298              :         {
     299            0 :             GST_ERROR_OBJECT(textTrackSink, "Failed to pause textTrack session");
     300            0 :             return GST_STATE_CHANGE_FAILURE;
     301              :         }
     302              : 
     303            0 :         break;
     304              :     }
     305            0 :     default:
     306            0 :         break;
     307              :     }
     308              : 
     309            0 :     GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
     310            0 :     if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
     311              :     {
     312            0 :         GST_WARNING_OBJECT(textTrackSink, "State change failed");
     313            0 :         return result;
     314              :     }
     315              : 
     316            0 :     return GST_STATE_CHANGE_SUCCESS;
     317              : }
     318              : 
     319            0 : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
     320              :                                                     GValue *value, GParamSpec *pspec)
     321              : {
     322            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
     323            0 :     if (!textTrackSink)
     324              :     {
     325            0 :         GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
     326            0 :         return;
     327              :     }
     328            0 :     GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
     329              : 
     330            0 :     switch (propId)
     331              :     {
     332            0 :     case PROP_MUTE:
     333              :     {
     334            0 :         g_value_set_boolean(value, priv->m_isMuted.load());
     335            0 :         break;
     336              :     }
     337            0 :     case PROP_TEXT_TRACK_IDENTIFIER:
     338              :     {
     339            0 :         g_value_set_string(value, priv->m_textTrackIdentifier.c_str());
     340            0 :         break;
     341              :     }
     342            0 :     case PROP_POSITION:
     343              :     {
     344              :         // Thunder ITextTrack does not provide getPosition API so we are unable to determine current position
     345            0 :         g_value_set_uint64(value, GST_CLOCK_TIME_NONE);
     346            0 :         break;
     347              :     }
     348            0 :     default:
     349            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     350            0 :         break;
     351              :     }
     352              : }
     353              : 
     354            0 : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
     355              :                                                     const GValue *value, GParamSpec *pspec)
     356              : {
     357            0 :     GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
     358            0 :     if (!textTrackSink)
     359              :     {
     360            0 :         GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
     361            0 :         return;
     362              :     }
     363            0 :     GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
     364              : 
     365            0 :     switch (propId)
     366              :     {
     367            0 :     case PROP_MUTE:
     368              :     {
     369            0 :         priv->m_isMuted = g_value_get_boolean(value);
     370            0 :         if (priv->m_textTrackSession)
     371              :         {
     372            0 :             priv->m_textTrackSession->mute(priv->m_isMuted);
     373              :         }
     374            0 :         break;
     375              :     }
     376            0 :     case PROP_TEXT_TRACK_IDENTIFIER:
     377              :     {
     378            0 :         priv->m_textTrackIdentifier = g_value_get_string(value);
     379            0 :         if (priv->m_textTrackSession)
     380              :         {
     381            0 :             priv->m_textTrackSession->setSessionCCSelection(priv->m_textTrackIdentifier);
     382              :         }
     383              : 
     384            0 :         break;
     385              :     }
     386            0 :     case PROP_POSITION:
     387              :     {
     388            0 :         guint64 position = g_value_get_uint64(value);
     389            0 :         std::unique_lock lock{priv->m_mutex};
     390            0 :         if (priv->m_textTrackSession && priv->m_capsSet)
     391              :         {
     392            0 :             priv->m_textTrackSession->setPosition(position / GST_MSECOND);
     393              :         }
     394              :         else
     395              :         {
     396            0 :             priv->m_queuedPosition = position;
     397              :         }
     398            0 :         break;
     399              :     }
     400            0 :     default:
     401            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     402            0 :         break;
     403              :     }
     404              : }
     405              : 
     406            0 : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query) // NOLINT(build/function_format)
     407              : {
     408            0 :     GstRialtoTextTrackSink *sink = GST_RIALTO_TEXT_TRACK_SINK(element);
     409            0 :     GST_DEBUG_OBJECT(sink, "handling query '%s'", GST_QUERY_TYPE_NAME(query));
     410            0 :     switch (GST_QUERY_TYPE(query))
     411              :     {
     412            0 :     case GST_QUERY_POSITION:
     413              :     {
     414              :         GstFormat fmt;
     415            0 :         gst_query_parse_position(query, &fmt, NULL);
     416            0 :         switch (fmt)
     417              :         {
     418            0 :         case GST_FORMAT_TIME:
     419              :         {
     420              :             // GST_CLOCK_TIME_NONE has to be returned here, because otherwise whole pipeline returns incorrect position
     421            0 :             gst_query_set_position(query, fmt, GST_CLOCK_TIME_NONE);
     422            0 :             break;
     423              :         }
     424            0 :         default:
     425            0 :             break;
     426              :         }
     427            0 :         return TRUE;
     428              :     }
     429            0 :     default:
     430            0 :         break;
     431              :     }
     432            0 :     GstElement *parent = GST_ELEMENT(&sink->parent);
     433            0 :     return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
     434              : }
     435              : 
     436              : namespace firebolt::rialto::server
     437              : {
     438            1 : std::shared_ptr<IGstTextTrackSinkFactory> IGstTextTrackSinkFactory::createFactory()
     439              : {
     440            1 :     std::shared_ptr<IGstTextTrackSinkFactory> factory;
     441              : 
     442              :     try
     443              :     {
     444            1 :         factory = std::make_shared<GstTextTrackSinkFactory>();
     445              :     }
     446            0 :     catch (const std::exception &e)
     447              :     {
     448            0 :         RIALTO_SERVER_LOG_ERROR("Failed to create the textTrackSink element factory, reason: %s", e.what());
     449              :     }
     450              : 
     451            1 :     return factory;
     452              : }
     453              : 
     454            0 : GstElement *GstTextTrackSinkFactory::createGstTextTrackSink() const
     455              : {
     456            0 :     GstElement *elem = GST_ELEMENT(g_object_new(GST_RIALTO_TEXT_TRACK_SINK_TYPE, nullptr));
     457              : 
     458            0 :     return elem;
     459              : }
     460              : 
     461              : }; // namespace firebolt::rialto::server
        

Generated by: LCOV version 2.0-1