LCOV - code coverage report
Current view: top level - source - RialtoGStreamerMSEBaseSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.3 % 165 144
Test Date: 2026-02-11 10:03:53 Functions: 100.0 % 17 17

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2022 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              : #define USE_GLIB 1
      20              : 
      21              : #include <cstring>
      22              : #include <limits>
      23              : 
      24              : #include <gst/gst.h>
      25              : 
      26              : #include "ControlBackend.h"
      27              : #include "GStreamerUtils.h"
      28              : #include "IClientLogControl.h"
      29              : #include "IMediaPipeline.h"
      30              : #include "LogToGstHandler.h"
      31              : #include "RialtoGStreamerMSEBaseSink.h"
      32              : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
      33              : 
      34              : GST_DEBUG_CATEGORY_STATIC(RialtoMSEBaseSinkDebug);
      35              : #define GST_CAT_DEFAULT RialtoMSEBaseSinkDebug
      36              : 
      37              : #define rialto_mse_base_sink_parent_class parent_class
      38         4211 : G_DEFINE_TYPE_WITH_CODE(RialtoMSEBaseSink, rialto_mse_base_sink, GST_TYPE_ELEMENT,
      39              :                         G_ADD_PRIVATE(RialtoMSEBaseSink)
      40              :                             GST_DEBUG_CATEGORY_INIT(RialtoMSEBaseSinkDebug, "rialtomsebasesink", 0,
      41              :                                                     "rialto mse base sink"));
      42              : 
      43              : enum
      44              : {
      45              :     PROP_0,
      46              :     PROP_IS_SINGLE_PATH_STREAM,
      47              :     PROP_N_STREAMS,
      48              :     PROP_HAS_DRM,
      49              :     PROP_STATS,
      50              :     PROP_LAST_SAMPLE,
      51              :     PROP_ENABLE_LAST_SAMPLE,
      52              :     PROP_LAST
      53              : };
      54              : 
      55              : enum
      56              : {
      57              :     SIGNAL_UNDERFLOW,
      58              :     SIGNAL_LAST
      59              : };
      60              : 
      61              : static guint g_signals[SIGNAL_LAST] = {0};
      62              : 
      63          297 : void rialto_mse_base_sink_initialise_delegate(RialtoMSEBaseSink *sink, const std::shared_ptr<IPlaybackDelegate> &delegate)
      64              : {
      65          297 :     std::unique_lock lock{sink->priv->m_sinkMutex};
      66          297 :     sink->priv->m_delegate = delegate;
      67              : 
      68          299 :     for (auto &[type, value] : sink->priv->m_queuedProperties)
      69              :     {
      70            2 :         delegate->setProperty(type, &value);
      71            2 :         g_value_unset(&value);
      72              :     }
      73          297 :     sink->priv->m_queuedProperties.clear();
      74              : }
      75              : 
      76         1782 : static std::shared_ptr<IPlaybackDelegate> rialto_mse_base_sink_get_delegate(RialtoMSEBaseSink *sink)
      77              : {
      78         1782 :     std::unique_lock lock{sink->priv->m_sinkMutex};
      79         1782 :     if (!sink->priv->m_delegate)
      80              :     {
      81            3 :         GST_ERROR_OBJECT(sink, "Sink delegate not initialized");
      82              :     }
      83         3564 :     return sink->priv->m_delegate;
      84         1782 : }
      85              : 
      86           45 : static gboolean rialto_mse_base_sink_send_event(GstElement *element, GstEvent *event)
      87              : {
      88           45 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(element)))
      89              :     {
      90           45 :         return delegate->handleSendEvent(event);
      91              :     }
      92            0 :     return FALSE;
      93              : }
      94              : 
      95          219 : gboolean rialto_mse_base_sink_event(GstPad *pad, GstObject *parent, GstEvent *event)
      96              : {
      97          219 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(parent)))
      98              :     {
      99          219 :         return delegate->handleEvent(pad, parent, event);
     100              :     }
     101            0 :     return FALSE;
     102              : }
     103              : 
     104           36 : GstFlowReturn rialto_mse_base_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
     105              : {
     106           36 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(parent)))
     107              :     {
     108           36 :         return delegate->handleBuffer(buf);
     109              :     }
     110            0 :     return GST_FLOW_ERROR;
     111              : }
     112              : 
     113           38 : static gboolean rialto_mse_base_sink_query(GstElement *element, GstQuery *query)
     114              : {
     115           38 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(element);
     116           38 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     117              :     {
     118           38 :         std::optional<gboolean> result{delegate->handleQuery(query)};
     119           38 :         if (result.has_value())
     120              :         {
     121            8 :             return result.value();
     122              :         }
     123           30 :         GstElement *parent = GST_ELEMENT(&sink->parent);
     124           30 :         return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
     125           38 :     }
     126            0 :     return FALSE;
     127              : }
     128              : 
     129          958 : static GstStateChangeReturn rialto_mse_base_sink_change_state(GstElement *element, GstStateChange transition)
     130              : {
     131          958 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(element);
     132          958 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     133              :     {
     134          957 :         GstStateChangeReturn status = delegate->changeState(transition);
     135          957 :         if (GST_STATE_CHANGE_FAILURE != status)
     136              :         {
     137          950 :             if (GST_STATE_CHANGE_READY_TO_NULL == transition)
     138              :             {
     139          291 :                 sink->priv->m_delegate.reset();
     140              :             }
     141          950 :             GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
     142          950 :             if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
     143              :             {
     144            0 :                 GST_WARNING_OBJECT(sink, "State change failed");
     145            0 :                 return result;
     146              :             }
     147          950 :             else if (result == GST_STATE_CHANGE_ASYNC)
     148              :             {
     149            0 :                 return GST_STATE_CHANGE_ASYNC;
     150              :             }
     151              :         }
     152          957 :         return status;
     153          958 :     }
     154            1 :     return GST_STATE_CHANGE_FAILURE;
     155              : }
     156              : 
     157           58 : void rialto_mse_base_sink_handle_get_property(RialtoMSEBaseSink *sink, const IPlaybackDelegate::Property &property,
     158              :                                               GValue *value)
     159              : {
     160           58 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     161              :     {
     162           58 :         delegate->getProperty(property, value);
     163              :     }
     164              :     else // Copy queued value if present
     165              :     {
     166            0 :         std::unique_lock lock{sink->priv->m_sinkMutex};
     167            0 :         if (sink->priv->m_queuedProperties.find(property) != sink->priv->m_queuedProperties.end())
     168              :         {
     169            0 :             g_value_copy(&sink->priv->m_queuedProperties[property], value);
     170              :         }
     171           58 :     }
     172              : }
     173              : 
     174          428 : void rialto_mse_base_sink_handle_set_property(RialtoMSEBaseSink *sink, const IPlaybackDelegate::Property &property,
     175              :                                               const GValue *value)
     176              : {
     177          428 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     178              :     {
     179          426 :         delegate->setProperty(property, value);
     180              :     }
     181              :     else
     182              :     {
     183            2 :         std::unique_lock lock{sink->priv->m_sinkMutex};
     184            2 :         sink->priv->m_queuedProperties[property] = G_VALUE_INIT;
     185            2 :         g_value_init(&(sink->priv->m_queuedProperties[property]), G_VALUE_TYPE(value));
     186            2 :         g_value_copy(value, &(sink->priv->m_queuedProperties[property]));
     187          430 :     }
     188          428 : }
     189              : 
     190           11 : static void rialto_mse_base_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
     191              : {
     192           11 :     switch (propId)
     193              :     {
     194            1 :     case PROP_IS_SINGLE_PATH_STREAM:
     195              :         // Set default value if it can't be acquired
     196            1 :         g_value_set_boolean(value, FALSE);
     197            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     198            1 :                                                  IPlaybackDelegate::Property::IsSinglePathStream, value);
     199            1 :         break;
     200            1 :     case PROP_N_STREAMS:
     201              :         // Set default value if it can't be acquired
     202            1 :         g_value_set_int(value, 1);
     203            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     204            1 :                                                  IPlaybackDelegate::Property::NumberOfStreams, value);
     205            1 :         break;
     206            1 :     case PROP_HAS_DRM:
     207              :         // Set default value if it can't be acquired
     208            1 :         g_value_set_boolean(value, TRUE);
     209            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::HasDrm,
     210              :                                                  value);
     211            1 :         break;
     212            2 :     case PROP_STATS:
     213            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Stats, value);
     214            2 :         break;
     215            2 :     case PROP_ENABLE_LAST_SAMPLE:
     216            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     217            2 :                                                  IPlaybackDelegate::Property::EnableLastSample, value);
     218            2 :         break;
     219            4 :     case PROP_LAST_SAMPLE:
     220            4 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::LastSample,
     221              :                                                  value);
     222            4 :         break;
     223            0 :     default:
     224            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     225            0 :         break;
     226              :     }
     227           11 : }
     228              : 
     229          352 : static void rialto_mse_base_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
     230              : {
     231          352 :     switch (propId)
     232              :     {
     233          175 :     case PROP_IS_SINGLE_PATH_STREAM:
     234          175 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     235          175 :                                                  IPlaybackDelegate::Property::IsSinglePathStream, value);
     236          175 :         break;
     237          175 :     case PROP_N_STREAMS:
     238          175 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     239          175 :                                                  IPlaybackDelegate::Property::NumberOfStreams, value);
     240          175 :         break;
     241            1 :     case PROP_HAS_DRM:
     242            1 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::HasDrm,
     243              :                                                  value);
     244            1 :         break;
     245            1 :     case PROP_ENABLE_LAST_SAMPLE:
     246            1 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     247            1 :                                                  IPlaybackDelegate::Property::EnableLastSample, value);
     248            1 :         break;
     249            0 :     default:
     250            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     251            0 :         break;
     252              :     }
     253          352 : }
     254              : 
     255            1 : void rialto_mse_base_handle_rialto_server_sent_buffer_underflow(RialtoMSEBaseSink *sink)
     256              : {
     257            1 :     GST_WARNING_OBJECT(sink, "Sending underflow signal");
     258              :     // send 2 last parameters just to be compatible with RDK's buffer-underflow-callback signal signature
     259            1 :     g_signal_emit(G_OBJECT(sink), g_signals[SIGNAL_UNDERFLOW], 0, 0, nullptr);
     260              : }
     261              : 
     262          297 : bool rialto_mse_base_sink_initialise_sinkpad(RialtoMSEBaseSink *sink)
     263              : {
     264              :     GstPadTemplate *pad_template =
     265          297 :         gst_element_class_get_pad_template(GST_ELEMENT_CLASS(G_OBJECT_GET_CLASS(sink)), "sink");
     266          297 :     if (!pad_template)
     267              :     {
     268            0 :         GST_ERROR_OBJECT(sink, "Could not find sink pad template");
     269            0 :         return false;
     270              :     }
     271              : 
     272          297 :     GstPad *sinkPad = gst_pad_new_from_template(pad_template, "sink");
     273          297 :     if (!sinkPad)
     274              :     {
     275            0 :         GST_ERROR_OBJECT(sink, "Could not create sinkpad");
     276            0 :         return false;
     277              :     }
     278              : 
     279          297 :     gst_element_add_pad(GST_ELEMENT_CAST(sink), sinkPad);
     280          297 :     sink->priv->m_sinkPad = sinkPad;
     281              : 
     282          297 :     return true;
     283              : }
     284              : 
     285          297 : static void rialto_mse_base_sink_init(RialtoMSEBaseSink *sink)
     286              : {
     287          297 :     GST_INFO_OBJECT(sink, "Init: %" GST_PTR_FORMAT, sink);
     288          297 :     sink->priv = static_cast<RialtoMSEBaseSinkPrivate *>(rialto_mse_base_sink_get_instance_private(sink));
     289          297 :     new (sink->priv) RialtoMSEBaseSinkPrivate();
     290              : 
     291          297 :     GST_OBJECT_FLAG_SET(sink, GST_ELEMENT_FLAG_SINK);
     292              : }
     293              : 
     294          297 : static void rialto_mse_base_sink_finalize(GObject *object)
     295              : {
     296          297 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(object);
     297          297 :     RialtoMSEBaseSinkPrivate *priv = sink->priv;
     298          297 :     GST_INFO_OBJECT(sink, "Finalize: %" GST_PTR_FORMAT " %" GST_PTR_FORMAT, sink, priv);
     299              : 
     300          297 :     priv->~RialtoMSEBaseSinkPrivate();
     301          297 :     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
     302              : }
     303              : 
     304            1 : static void rialto_mse_base_sink_class_init(RialtoMSEBaseSinkClass *klass)
     305              : {
     306              :     std::shared_ptr<firebolt::rialto::IClientLogHandler> logToGstHandler =
     307            1 :         std::make_shared<firebolt::rialto::LogToGstHandler>();
     308            1 :     if (!firebolt::rialto::IClientLogControlFactory::createFactory()->createClientLogControl().registerLogHandler(logToGstHandler,
     309              :                                                                                                                   true))
     310              :     {
     311            0 :         GST_ERROR("Unable to preRegister log handler");
     312              :     }
     313              : 
     314            1 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
     315            1 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
     316              : 
     317            1 :     gst_element_class_set_metadata(elementClass, "Rialto MSE base sink", "Generic", "A sink for Rialto", "Sky");
     318              : 
     319            1 :     gobjectClass->finalize = rialto_mse_base_sink_finalize;
     320            1 :     gobjectClass->get_property = rialto_mse_base_sink_get_property;
     321            1 :     gobjectClass->set_property = rialto_mse_base_sink_set_property;
     322            1 :     elementClass->query = rialto_mse_base_sink_query;
     323            1 :     elementClass->send_event = rialto_mse_base_sink_send_event;
     324            1 :     elementClass->change_state = rialto_mse_base_sink_change_state;
     325              : 
     326            1 :     g_signals[SIGNAL_UNDERFLOW] = g_signal_new("buffer-underflow-callback", G_TYPE_FROM_CLASS(klass),
     327              :                                                (GSignalFlags)(G_SIGNAL_RUN_LAST), 0, nullptr, nullptr,
     328              :                                                g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT,
     329              :                                                G_TYPE_POINTER);
     330              : 
     331            1 :     g_object_class_install_property(gobjectClass, PROP_IS_SINGLE_PATH_STREAM,
     332              :                                     g_param_spec_boolean("single-path-stream", "single path stream",
     333              :                                                          "is single path stream", FALSE, GParamFlags(G_PARAM_READWRITE)));
     334              : 
     335            1 :     g_object_class_install_property(gobjectClass, PROP_N_STREAMS,
     336              :                                     g_param_spec_int("streams-number", "streams number", "streams number", 1, G_MAXINT,
     337              :                                                      1, GParamFlags(G_PARAM_READWRITE)));
     338              : 
     339            1 :     g_object_class_install_property(gobjectClass, PROP_HAS_DRM,
     340              :                                     g_param_spec_boolean("has-drm", "has drm", "has drm", TRUE,
     341              :                                                          GParamFlags(G_PARAM_READWRITE)));
     342            1 :     g_object_class_install_property(gobjectClass, PROP_STATS,
     343              :                                     g_param_spec_pointer("stats", NULL, "pointer to a gst_structure",
     344              :                                                          GParamFlags(G_PARAM_READABLE)));
     345              : 
     346            1 :     g_object_class_install_property(gobjectClass, PROP_ENABLE_LAST_SAMPLE,
     347              :                                     g_param_spec_boolean("enable-last-sample", "Enable Last Buffer",
     348              :                                                          "Enable the last-sample property", FALSE,
     349              :                                                          GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
     350              : 
     351            1 :     g_object_class_install_property(gobjectClass, PROP_LAST_SAMPLE,
     352              :                                     g_param_spec_boxed("last-sample", "Last Sample",
     353              :                                                        "The last sample received in the sink", GST_TYPE_SAMPLE,
     354              :                                                        GParamFlags(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
     355              : }
        

Generated by: LCOV version 2.0-1