LCOV - code coverage report
Current view: top level - source - RialtoGStreamerMSEVideoSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.9 % 143 140
Test Date: 2026-07-31 11:15:42 Functions: 100.0 % 7 7

            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              : #include <gst/gst.h>
      20              : #include <inttypes.h>
      21              : #include <stdint.h>
      22              : 
      23              : #include "GStreamerEMEUtils.h"
      24              : #include "GStreamerMSEUtils.h"
      25              : #include "IMediaPipelineCapabilities.h"
      26              : #include "PullModeVideoPlaybackDelegate.h"
      27              : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
      28              : #include "RialtoGStreamerMSEVideoSink.h"
      29              : 
      30              : using namespace firebolt::rialto::client;
      31              : 
      32              : GST_DEBUG_CATEGORY_STATIC(RialtoMSEVideoSinkDebug);
      33              : #define GST_CAT_DEFAULT RialtoMSEVideoSinkDebug
      34              : 
      35              : #define rialto_mse_video_sink_parent_class parent_class
      36          212 : G_DEFINE_TYPE_WITH_CODE(RialtoMSEVideoSink, rialto_mse_video_sink, RIALTO_TYPE_MSE_BASE_SINK,
      37              :                         GST_DEBUG_CATEGORY_INIT(RialtoMSEVideoSinkDebug, "rialtomsevideosink", 0,
      38              :                                                 "rialto mse video sink"));
      39              : 
      40              : enum
      41              : {
      42              :     PROP_0,
      43              :     PROP_WINDOW_SET,
      44              :     PROP_MAX_VIDEO_WIDTH,
      45              :     PROP_MAX_VIDEO_HEIGHT,
      46              :     PROP_MAX_VIDEO_WIDTH_DEPRECATED,
      47              :     PROP_MAX_VIDEO_HEIGHT_DEPRECATED,
      48              :     PROP_FRAME_STEP_ON_PREROLL,
      49              :     PROP_IMMEDIATE_OUTPUT,
      50              :     PROP_SYNCMODE_STREAMING,
      51              :     PROP_SHOW_VIDEO_WINDOW,
      52              :     PROP_IS_MASTER,
      53              :     PROP_VIDEO_PTS,
      54              :     PROP_REPORT_DECODE_ERRORS,
      55              :     PROP_QUEUED_FRAMES,
      56              :     PROP_LAST
      57              : };
      58              : 
      59              : enum
      60              : {
      61              :     SIGNAL_FIRST_VIDEO_FRAME_RECEIVED,
      62              :     SIGNAL_LAST
      63              : };
      64              : 
      65              : static guint g_signals[SIGNAL_LAST] = {0};
      66              : 
      67            1 : void rialto_mse_video_handle_rialto_server_sent_first_video_frame_received(RialtoMSEVideoSink *sink)
      68              : {
      69            1 :     GST_INFO_OBJECT(sink, "Sending first frame received signal");
      70            1 :     g_signal_emit(G_OBJECT(sink), g_signals[SIGNAL_FIRST_VIDEO_FRAME_RECEIVED], 0, 0, nullptr);
      71              : }
      72              : 
      73          208 : static GstStateChangeReturn rialto_mse_video_sink_change_state(GstElement *element, GstStateChange transition)
      74              : {
      75          208 :     RialtoMSEVideoSink *sink = RIALTO_MSE_VIDEO_SINK(element);
      76          208 :     if (GST_STATE_CHANGE_NULL_TO_READY == transition)
      77              :     {
      78           69 :         GST_INFO_OBJECT(sink, "RialtoMSEVideoSink state change to READY. Initializing delegate");
      79           69 :         auto delegate = std::make_shared<PullModeVideoPlaybackDelegate>(element);
      80           69 :         delegate->createControlBackend();
      81           69 :         rialto_mse_base_sink_initialise_delegate(RIALTO_MSE_BASE_SINK(sink), delegate);
      82              :     }
      83          208 :     GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
      84          208 :     if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
      85              :     {
      86            1 :         GST_WARNING_OBJECT(sink, "State change failed");
      87            1 :         return result;
      88              :     }
      89              : 
      90          207 :     return result;
      91              : }
      92              : 
      93           20 : static void rialto_mse_video_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
      94              : {
      95           20 :     switch (propId)
      96              :     {
      97            5 :     case PROP_WINDOW_SET:
      98              :     {
      99            5 :         g_value_set_string(value, "0,0,1920,1080"); // Set default value
     100            5 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
     101              :                                                  value);
     102            5 :         break;
     103              :     }
     104            1 :     case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
     105            1 :         GST_WARNING_OBJECT(object, "MaxVideoWidth property is deprecated. Use 'max-video-width' instead");
     106              :     case PROP_MAX_VIDEO_WIDTH:
     107              :     {
     108            2 :         g_value_set_uint(value, 0); // Set default value
     109            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     110            2 :                                                  IPlaybackDelegate::Property::MaxVideoWidth, value);
     111            2 :         break;
     112              :     }
     113            1 :     case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
     114            1 :         GST_WARNING_OBJECT(object, "MaxVideoHeight property is deprecated. Use 'max-video-height' instead");
     115              :     case PROP_MAX_VIDEO_HEIGHT:
     116              :     {
     117            2 :         g_value_set_uint(value, 0); // Set default value
     118            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     119            2 :                                                  IPlaybackDelegate::Property::MaxVideoHeight, value);
     120            2 :         break;
     121              :     }
     122            1 :     case PROP_FRAME_STEP_ON_PREROLL:
     123              :     {
     124            1 :         g_value_set_boolean(value, FALSE); // Set default value
     125            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     126            1 :                                                  IPlaybackDelegate::Property::FrameStepOnPreroll, value);
     127            1 :         break;
     128              :     }
     129            3 :     case PROP_QUEUED_FRAMES:
     130              :     {
     131            3 :         g_value_set_uint(value, 0); // Set default value
     132            3 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     133            3 :                                                  IPlaybackDelegate::Property::QueuedFrames, value);
     134            3 :         break;
     135              :     }
     136            3 :     case PROP_IMMEDIATE_OUTPUT:
     137              :     {
     138            3 :         g_value_set_boolean(value, FALSE); // Set default value
     139            3 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     140            3 :                                                  IPlaybackDelegate::Property::ImmediateOutput, value);
     141            3 :         break;
     142              :     }
     143            1 :     case PROP_IS_MASTER:
     144              :     {
     145            1 :         g_value_set_boolean(value, TRUE); // Set default value
     146              :         std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
     147            1 :             firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
     148            1 :         bool isMaster{false};
     149            1 :         if (mediaPlayerCapabilities && mediaPlayerCapabilities->isVideoMaster(isMaster))
     150              :         {
     151            1 :             g_value_set_boolean(value, isMaster);
     152              :         }
     153            1 :         break;
     154              :     }
     155            2 :     case PROP_VIDEO_PTS:
     156              :     {
     157            2 :         g_value_set_int64(value, 0); // Set default value
     158            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::VideoPts,
     159              :                                                  value);
     160            2 :         break;
     161              :     }
     162            1 :     default:
     163            1 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     164            1 :         break;
     165              :     }
     166           20 : }
     167              : 
     168           28 : static void rialto_mse_video_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
     169              : {
     170           28 :     switch (propId)
     171              :     {
     172            4 :     case PROP_WINDOW_SET:
     173              :     {
     174            4 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
     175              :                                                  value);
     176            4 :         break;
     177              :     }
     178            2 :     case PROP_MAX_VIDEO_WIDTH:
     179              :     case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
     180            2 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     181            2 :                                                  IPlaybackDelegate::Property::MaxVideoWidth, value);
     182            2 :         break;
     183            2 :     case PROP_MAX_VIDEO_HEIGHT:
     184              :     case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
     185            2 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     186            2 :                                                  IPlaybackDelegate::Property::MaxVideoHeight, value);
     187            2 :         break;
     188            5 :     case PROP_FRAME_STEP_ON_PREROLL:
     189              :     {
     190            5 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     191            5 :                                                  IPlaybackDelegate::Property::FrameStepOnPreroll, value);
     192            5 :         break;
     193              :     }
     194            4 :     case PROP_REPORT_DECODE_ERRORS:
     195              :     {
     196            4 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     197            4 :                                                  IPlaybackDelegate::Property::ReportDecodeErrors, value);
     198            4 :         break;
     199              :     }
     200            4 :     case PROP_IMMEDIATE_OUTPUT:
     201              :     {
     202            4 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     203            4 :                                                  IPlaybackDelegate::Property::ImmediateOutput, value);
     204            4 :         break;
     205              :     }
     206            4 :     case PROP_SYNCMODE_STREAMING:
     207              :     {
     208            4 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     209            4 :                                                  IPlaybackDelegate::Property::SyncmodeStreaming, value);
     210            4 :         break;
     211              :     }
     212            2 :     case PROP_SHOW_VIDEO_WINDOW:
     213              :     {
     214            2 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     215            2 :                                                  IPlaybackDelegate::Property::ShowVideoWindow, value);
     216            2 :         break;
     217              :     }
     218            1 :     default:
     219            1 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     220            1 :         break;
     221              :     }
     222           28 : }
     223              : 
     224           69 : static void rialto_mse_video_sink_init(RialtoMSEVideoSink *sink)
     225              : {
     226           69 :     RialtoMSEBaseSinkPrivate *basePriv = sink->parent.priv;
     227              : 
     228           69 :     if (!rialto_mse_base_sink_initialise_sinkpad(RIALTO_MSE_BASE_SINK(sink)))
     229              :     {
     230            0 :         GST_ERROR_OBJECT(sink, "Failed to initialise VIDEO sink. Sink pad initialisation failed.");
     231            0 :         return;
     232              :     }
     233              : 
     234           69 :     gst_pad_set_chain_function(basePriv->m_sinkPad, rialto_mse_base_sink_chain);
     235           69 :     gst_pad_set_event_function(basePriv->m_sinkPad, rialto_mse_base_sink_event);
     236              : }
     237              : 
     238            1 : static void rialto_mse_video_sink_class_init(RialtoMSEVideoSinkClass *klass)
     239              : {
     240            1 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
     241            1 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
     242            1 :     gobjectClass->get_property = rialto_mse_video_sink_get_property;
     243            1 :     gobjectClass->set_property = rialto_mse_video_sink_set_property;
     244            1 :     elementClass->change_state = rialto_mse_video_sink_change_state;
     245              : 
     246            1 :     g_object_class_install_property(gobjectClass, PROP_WINDOW_SET,
     247              :                                     g_param_spec_string("rectangle", "rectangle", "Window Set Format: x,y,width,height",
     248              :                                                         nullptr, GParamFlags(G_PARAM_READWRITE)));
     249              : 
     250            1 :     g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH,
     251              :                                     g_param_spec_uint("max-video-width",
     252              :                                                       "max video width", "Maximum width of video frames to be decoded. Should only be set for video only streams.",
     253              :                                                       0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
     254              : 
     255            1 :     g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT,
     256              :                                     g_param_spec_uint("max-video-height",
     257              :                                                       "max video height", "Maximum height of video frames to be decoded. should only be set for video only streams.",
     258              :                                                       0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
     259              : 
     260            1 :     g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH_DEPRECATED,
     261              :                                     g_param_spec_uint("maxVideoWidth", "maxVideoWidth", "[DEPRECATED] Use max-video-width",
     262              :                                                       0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
     263              : 
     264            1 :     g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT_DEPRECATED,
     265              :                                     g_param_spec_uint("maxVideoHeight", "maxVideoHeight", "[DEPRECATED] max-video-height",
     266              :                                                       0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
     267              : 
     268            1 :     g_object_class_install_property(gobjectClass, PROP_FRAME_STEP_ON_PREROLL,
     269              :                                     g_param_spec_boolean("frame-step-on-preroll", "frame step on preroll",
     270              :                                                          "allow frame stepping on preroll into pause", FALSE,
     271              :                                                          G_PARAM_READWRITE));
     272            1 :     g_object_class_install_property(gobjectClass, PROP_REPORT_DECODE_ERRORS,
     273              :                                     g_param_spec_boolean("report-decode-errors", "Report decode errors",
     274              :                                                          "Enable reporting of decode errors", FALSE, G_PARAM_WRITABLE));
     275              : 
     276            1 :     g_object_class_install_property(gobjectClass, PROP_QUEUED_FRAMES,
     277              :                                     g_param_spec_uint("queued-frames", "Queued frames",
     278              :                                                       "Number of frames currently queued in decoder", 0, G_MAXUINT, 0,
     279              :                                                       G_PARAM_READABLE));
     280            1 :     g_object_class_install_property(gobjectClass, PROP_IS_MASTER,
     281              :                                     g_param_spec_boolean("is-master", "is master",
     282              :                                                          "Checks if the platform is video master", TRUE,
     283              :                                                          G_PARAM_READABLE));
     284            1 :     g_object_class_install_property(gobjectClass, PROP_VIDEO_PTS,
     285              :                                     g_param_spec_int64("video_pts", "video PTS", "current video PTS value", G_MININT64,
     286              :                                                        G_MAXINT64, 0, G_PARAM_READABLE));
     287            1 :     g_object_class_install_property(gobjectClass, PROP_SHOW_VIDEO_WINDOW,
     288              :                                     g_param_spec_boolean("show-video-window", "make video window visible",
     289              :                                                          "true: visible, false: hidden", TRUE, G_PARAM_WRITABLE));
     290              : 
     291            1 :     g_signals[SIGNAL_FIRST_VIDEO_FRAME_RECEIVED] = g_signal_new("first-video-frame-callback", G_TYPE_FROM_CLASS(klass),
     292              :                                                                 (GSignalFlags)(G_SIGNAL_RUN_LAST), 0, nullptr, nullptr,
     293              :                                                                 g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2,
     294              :                                                                 G_TYPE_UINT, G_TYPE_POINTER);
     295              : 
     296              :     std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
     297            1 :         firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
     298            1 :     if (mediaPlayerCapabilities)
     299              :     {
     300              :         std::vector<std::string> supportedMimeTypes =
     301            1 :             mediaPlayerCapabilities->getSupportedMimeTypes(firebolt::rialto::MediaSourceType::VIDEO);
     302              : 
     303            1 :         rialto_mse_sink_setup_supported_caps(elementClass, supportedMimeTypes);
     304              : 
     305            2 :         const std::string kImmediateOutputPropertyName{"immediate-output"};
     306            1 :         const std::string kSyncmodeStreamingPropertyName{"syncmode-streaming"};
     307              :         const std::vector<std::string> kPropertyNamesToSearch{kImmediateOutputPropertyName,
     308            4 :                                                               kSyncmodeStreamingPropertyName};
     309              :         std::vector<std::string> supportedProperties{
     310            1 :             mediaPlayerCapabilities->getSupportedProperties(firebolt::rialto::MediaSourceType::VIDEO,
     311            1 :                                                             kPropertyNamesToSearch)};
     312              : 
     313            3 :         for (const auto &propertyName : supportedProperties)
     314              :         {
     315            2 :             if (kImmediateOutputPropertyName == propertyName)
     316              :             {
     317            1 :                 g_object_class_install_property(gobjectClass, PROP_IMMEDIATE_OUTPUT,
     318              :                                                 g_param_spec_boolean(kImmediateOutputPropertyName.c_str(),
     319              :                                                                      "immediate output", "immediate output", TRUE,
     320              :                                                                      GParamFlags(G_PARAM_READWRITE)));
     321              :             }
     322            1 :             else if (kSyncmodeStreamingPropertyName == propertyName)
     323              :             {
     324            1 :                 g_object_class_install_property(gobjectClass, PROP_SYNCMODE_STREAMING,
     325              :                                                 g_param_spec_boolean("syncmode-streaming", "Streaming Sync Mode",
     326              :                                                                      "Enable/disable OTT streaming sync mode", FALSE,
     327              :                                                                      G_PARAM_WRITABLE));
     328              :             }
     329              :         }
     330              :     }
     331              :     else
     332              :     {
     333            0 :         GST_ERROR("Failed to get supported mime types for VIDEO");
     334              :     }
     335              : 
     336            1 :     gst_element_class_set_details_simple(elementClass, "Rialto Video Sink", "Decoder/Video/Sink/Video",
     337              :                                          "Communicates with Rialto Server", "Sky");
     338            2 : }
        

Generated by: LCOV version 2.0-1