LCOV - code coverage report
Current view: top level - src/elements/gstgpacsink.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 74.4 % 156 116
Test Date: 2025-09-18 00:43:48 Functions: 85.7 % 14 12

            Line data    Source code
       1              : /*
       2              :  *                      GPAC - Multimedia Framework C SDK
       3              :  *
       4              :  *                      Authors: Deniz Ugur, Romain Bouqueau, Sohaib Larbi
       5              :  *                      Copyright (c) Motion Spell
       6              :  *                              All rights reserved
       7              :  *
       8              :  *  This file is part of the GPAC/GStreamer wrapper
       9              :  *
      10              :  *  This GPAC/GStreamer wrapper is free software; you can redistribute it
      11              :  *  and/or modify it under the terms of the GNU Affero General Public License
      12              :  *  as published by the Free Software Foundation; either version 3, or (at
      13              :  *  your option) any later version.
      14              :  *
      15              :  *  This GPAC/GStreamer wrapper is distributed in the hope that it will be
      16              :  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      17              :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18              :  *  GNU Affero General Public License for more details.
      19              :  *
      20              :  *  You should have received a copy of the GNU Affero General Public
      21              :  *  License along with this library; see the file LICENSE.  If not, write to
      22              :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23              :  *
      24              :  */
      25              : 
      26              : #include "elements/gstgpacsink.h"
      27              : 
      28              : GST_DEBUG_CATEGORY_STATIC(gst_gpac_sink_debug);
      29              : #define GST_CAT_DEFAULT gst_gpac_sink_debug
      30              : 
      31              : // Define the element properties
      32              : #define gst_gpac_sink_parent_class parent_class
      33           61 : G_DEFINE_TYPE(GstGpacSink, gst_gpac_sink, GST_TYPE_BIN);
      34              : 
      35              : // #MARK: Properties
      36              : static void
      37            6 : gst_gpac_sink_set_property(GObject* object,
      38              :                            guint prop_id,
      39              :                            const GValue* value,
      40              :                            GParamSpec* pspec)
      41              : {
      42            6 :   GstGpacSink* gpac_sink = GST_GPAC_SINK(object);
      43            6 :   g_return_if_fail(GST_IS_GPAC_SINK(object));
      44              : 
      45            6 :   if (IS_TOP_LEVEL_PROPERTY(prop_id)) {
      46            5 :     switch (prop_id) {
      47            0 :       case GPAC_PROP_SYNC:
      48            0 :         g_object_set_property(G_OBJECT(gpac_sink->sink), pspec->name, value);
      49            0 :         return;
      50            5 :       default:
      51            5 :         break;
      52              :     }
      53              :   }
      54              : 
      55              :   // Relay the property to the internal transform element
      56            6 :   g_object_set_property(G_OBJECT(gpac_sink->tf), pspec->name, value);
      57              : }
      58              : 
      59              : static void
      60            0 : gst_gpac_sink_get_property(GObject* object,
      61              :                            guint prop_id,
      62              :                            GValue* value,
      63              :                            GParamSpec* pspec)
      64              : {
      65            0 :   GstGpacSink* gpac_sink = GST_GPAC_SINK(object);
      66            0 :   g_return_if_fail(GST_IS_GPAC_SINK(object));
      67              : 
      68            0 :   if (IS_TOP_LEVEL_PROPERTY(prop_id)) {
      69            0 :     switch (prop_id) {
      70            0 :       case GPAC_PROP_SYNC:
      71            0 :         g_object_get_property(G_OBJECT(gpac_sink->sink), pspec->name, value);
      72            0 :         return;
      73            0 :       default:
      74            0 :         break;
      75              :     }
      76              :   }
      77              : 
      78              :   // Relay the property to the internal transform element
      79            0 :   g_object_get_property(G_OBJECT(gpac_sink->tf), pspec->name, value);
      80              : }
      81              : 
      82              : // #MARK: Lifecycle
      83              : static void
      84            5 : gst_gpac_sink_reset(GstGpacSink* sink)
      85              : {
      86              :   // Remove the internal elements
      87            5 :   if (sink->tf) {
      88            0 :     gst_bin_remove(GST_BIN(sink), sink->tf);
      89            0 :     sink->tf = NULL;
      90              :   }
      91              : 
      92            5 :   if (sink->sink) {
      93            0 :     gst_bin_remove(GST_BIN(sink), sink->sink);
      94            0 :     sink->sink = NULL;
      95              :   }
      96            5 : }
      97              : 
      98              : // #MARK: Pad Management
      99              : static GstPad*
     100           11 : gst_gpac_sink_request_new_pad(GstElement* element,
     101              :                               GstPadTemplate* templ,
     102              :                               const gchar* pad_name,
     103              :                               const GstCaps* caps)
     104              : {
     105           11 :   GstGpacSink* gpac_sink = GST_GPAC_SINK(element);
     106           11 :   GstPad* pad = NULL;
     107           11 :   GstPad* peer = NULL;
     108              : 
     109              :   // Request a new pad from the aggregator
     110           11 :   peer = gst_element_request_pad(gpac_sink->tf, templ, pad_name, caps);
     111           11 :   if (!peer) {
     112            0 :     GST_ELEMENT_ERROR(gpac_sink,
     113              :                       STREAM,
     114              :                       FAILED,
     115              :                       (NULL),
     116              :                       ("Unable to request pad name from the aggregator"));
     117            0 :     return NULL;
     118              :   }
     119              : 
     120              :   // Create a ghost pad from the aggregator
     121           11 :   pad = gst_ghost_pad_new_from_template(gst_pad_get_name(peer), peer, templ);
     122           11 :   gst_pad_set_active(pad, TRUE);
     123           11 :   gst_element_add_pad(element, pad);
     124           11 :   gst_object_unref(peer);
     125              : 
     126           11 :   return pad;
     127              : }
     128              : 
     129              : static void
     130            0 : gst_gpac_sink_release_pad(GstElement* element, GstPad* pad)
     131              : {
     132            0 :   GstGpacSink* gpac_sink = GST_GPAC_SINK(element);
     133            0 :   GstPad* peer = gst_pad_get_peer(pad);
     134              : 
     135            0 :   if (peer) {
     136            0 :     gst_element_release_request_pad(gpac_sink->tf, peer);
     137            0 :     gst_object_unref(peer);
     138              :   }
     139              : 
     140            0 :   gst_object_ref(pad);
     141            0 :   gst_element_remove_pad(element, pad);
     142            0 :   gst_pad_set_active(pad, FALSE);
     143            0 :   gst_object_unref(pad);
     144            0 : }
     145              : 
     146              : // #MARK: Initialization
     147              : static void
     148            5 : gst_gpac_sink_init(GstGpacSink* sink)
     149              : {
     150            5 : }
     151              : 
     152              : static void
     153            5 : gst_gpac_sink_instance_init(GstGpacSink* sink)
     154              : {
     155            5 :   GstElement* element = GST_ELEMENT(sink);
     156            5 :   GObjectClass* klass = G_OBJECT_CLASS(G_TYPE_INSTANCE_GET_CLASS(
     157              :     G_OBJECT(element), GST_TYPE_GPAC_SINK, GstGpacSinkClass));
     158            5 :   GstGpacParams* params = GST_GPAC_GET_PARAMS(klass);
     159              : 
     160              :   // Reset the sink
     161            5 :   gst_gpac_sink_reset(sink);
     162              : 
     163              :   // Treat the bin as a sink
     164            5 :   GST_OBJECT_FLAG_SET(sink, GST_ELEMENT_FLAG_SINK);
     165              : 
     166              :   // Create the transform element for the subelement
     167            5 :   sink->tf = g_object_new(params->private_type, NULL);
     168              : 
     169              :   // Create a fake sink element
     170            5 :   sink->sink = gst_element_factory_make("fakesink", NULL);
     171              : 
     172              :   // Add and link the elements
     173            5 :   gst_bin_add_many(GST_BIN(sink), sink->tf, sink->sink, NULL);
     174            5 :   gst_element_link(sink->tf, sink->sink);
     175            5 : }
     176              : 
     177              : static void
     178            2 : gst_gpac_sink_class_init(GstGpacSinkClass* klass)
     179              : {
     180              :   // Initialize the class
     181            2 :   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
     182            2 :   GstElementClass* gstelement_class = GST_ELEMENT_CLASS(klass);
     183            2 :   GstBinClass* gstbin_class = GST_BIN_CLASS(klass);
     184            2 :   parent_class = g_type_class_peek_parent(klass);
     185              : 
     186              :   // Install the pad templates
     187            2 :   gpac_install_sink_pad_templates(gstelement_class);
     188              : 
     189              :   // Set the pad management functions
     190            2 :   gstelement_class->request_new_pad =
     191            2 :     GST_DEBUG_FUNCPTR(gst_gpac_sink_request_new_pad);
     192            2 :   gstelement_class->release_pad = GST_DEBUG_FUNCPTR(gst_gpac_sink_release_pad);
     193            2 : }
     194              : 
     195              : // #MARK: Registration
     196              : static void
     197            4 : gst_gpac_sink_subclass_init(GstGpacSinkClass* klass)
     198              : {
     199            4 :   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
     200            4 :   GstElementClass* gstelement_class = GST_ELEMENT_CLASS(klass);
     201            4 :   GstGpacParams* params = GST_GPAC_GET_PARAMS(klass);
     202              : 
     203              :   // Set the property handlers
     204            4 :   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_gpac_sink_set_property);
     205            4 :   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_gpac_sink_get_property);
     206              : 
     207              :   // Set the property handlers
     208            4 :   gpac_install_global_properties(gobject_class);
     209            4 :   gpac_install_local_properties(
     210              :     gobject_class, GPAC_PROP_PRINT_STATS, GPAC_PROP_SYNC, GPAC_PROP_0);
     211              : 
     212              :   // Add the subclass-specific properties and pad templates
     213            4 :   if (params->is_single) {
     214              :     // Set property blacklist
     215            2 :     GList* blacklist = NULL;
     216            2 :     if (params->info->default_options) {
     217            2 :       filter_option* opt = params->info->default_options;
     218            8 :       for (u32 i = 0; opt[i].name; i++) {
     219            6 :         if (opt[i].forced)
     220            4 :           blacklist = g_list_append(blacklist, (gpointer)opt[i].name);
     221              :       }
     222              :     }
     223              : 
     224              :     // Install the filter properties
     225            2 :     gpac_install_filter_properties(
     226            2 :       gobject_class, blacklist, params->info->filter_name);
     227            2 :     g_list_free(blacklist);
     228              : 
     229              :     // Install the signals
     230            2 :     if (params->info->signal_presets) {
     231            2 :       gpac_install_signals_by_presets(gobject_class,
     232            2 :                                       params->info->signal_presets);
     233              :     }
     234              : 
     235              :     // Check if we have any filter options to expose
     236            4 :     for (u32 i = 0; i < G_N_ELEMENTS(filter_options); i++) {
     237            2 :       filter_option_overrides* opts = &filter_options[i];
     238            2 :       if (g_strcmp0(opts->filter_name, params->info->filter_name) == 0) {
     239            0 :         for (u32 j = 0; opts->options[j]; j++) {
     240            0 :           guint32 prop_id = opts->options[j];
     241            0 :           gpac_install_local_properties(gobject_class, prop_id, GPAC_PROP_0);
     242              :         }
     243            0 :         break;
     244              :       }
     245              :     }
     246              : 
     247              :     // Register the internal element type
     248            2 :     params->private_type =
     249            2 :       gst_gpac_tf_register_custom(params->info, TRUE, TRUE);
     250              :   } else {
     251            2 :     gpac_install_src_pad_templates(gstelement_class);
     252            2 :     gpac_install_local_properties(
     253              :       gobject_class, GPAC_PROP_GRAPH, GPAC_PROP_DESTINATION, GPAC_PROP_0);
     254            2 :     gpac_install_all_signals(gobject_class);
     255              : 
     256              :     // We need an internal version of the transform element
     257            2 :     params->info = g_new0(subelement_info, 1);
     258            2 :     const subelement_info internal_element =
     259              :       GPAC_TF_SUBELEMENT("internal", NULL, NULL);
     260            2 :     memcpy(params->info, &internal_element, sizeof(subelement_info));
     261              : 
     262              :     // Register the internal element type
     263            2 :     params->private_type =
     264            2 :       gst_gpac_tf_register_custom(params->info, TRUE, FALSE);
     265              :   }
     266              : 
     267              :   // Set the metadata
     268            4 :   const gchar* longname = "gpac sink";
     269            4 :   if (params->is_single) {
     270            2 :     if (!g_strcmp0(params->info->filter_name, params->info->alias_name))
     271            0 :       longname = g_strdup_printf("gpac %s sink", params->info->filter_name);
     272              :     else
     273            2 :       longname = g_strdup_printf("gpac %s (%s) sink",
     274            2 :                                  params->info->alias_name,
     275            2 :                                  params->info->filter_name);
     276              :   }
     277            4 :   gst_element_class_set_static_metadata(
     278              :     gstelement_class,
     279              :     longname,
     280              :     "Aggregator/Sink",
     281              :     "Uses gpac filter session aggregate and process the incoming data",
     282              :     "Deniz Ugur <deniz.ugur@motionspell.com>");
     283            4 : }
     284              : 
     285              : gboolean
     286            2 : gst_gpac_sink_register(GstPlugin* plugin)
     287              : {
     288              :   GType type;
     289              :   GstGpacParams* params;
     290            2 :   GTypeInfo subclass_typeinfo = {
     291              :     sizeof(GstGpacSinkClass),
     292              :     NULL, // base_init
     293              :     NULL, // base_finalize
     294              :     (GClassInitFunc)gst_gpac_sink_subclass_init,
     295              :     NULL, // class_finalize
     296              :     NULL, // class_data
     297              :     sizeof(GstGpacSink),
     298              :     0,
     299              :     (GInstanceInitFunc)gst_gpac_sink_instance_init,
     300              :   };
     301              : 
     302            2 :   GST_DEBUG_CATEGORY_INIT(gst_gpac_sink_debug, "gpacsink", 0, "GPAC Sink");
     303              : 
     304              :   // Register the regular sink element
     305            2 :   GST_LOG("Registering regular gpac sink element");
     306            2 :   params = g_new0(GstGpacParams, 1);
     307            2 :   params->is_single = FALSE;
     308            2 :   type = g_type_register_static(
     309              :     GST_TYPE_GPAC_SINK, "GstGpacSinkRegular", &subclass_typeinfo, 0);
     310            2 :   g_type_set_qdata(type, GST_GPAC_PARAMS_QDATA, params);
     311            2 :   if (!gst_element_register(plugin, "gpacsink", GST_RANK_PRIMARY, type)) {
     312            0 :     GST_ERROR_OBJECT(plugin, "Failed to register regular gpac sink element");
     313            0 :     return FALSE;
     314              :   }
     315              : 
     316              :   // Register subelements
     317           10 :   for (u32 i = 0; i < G_N_ELEMENTS(subelements); i++) {
     318            8 :     subelement_info* info = &subelements[i];
     319              : 
     320            8 :     if (!(info->flags & GPAC_SE_SINK_ONLY)) {
     321            6 :       GST_DEBUG_OBJECT(plugin,
     322              :                        "Subelement %s is not a sink only element, skipping",
     323              :                        info->alias_name);
     324            6 :       continue;
     325              :     }
     326              : 
     327              :     // Register the regular sink element
     328            2 :     GST_LOG("Registering %s sink subelement", info->filter_name);
     329            2 :     params = g_new0(GstGpacParams, 1);
     330            2 :     params->is_single = TRUE;
     331            2 :     params->info = info;
     332            2 :     const gchar* name = g_strdup_printf("gpac%ssink", info->alias_name);
     333              :     const gchar* type_name =
     334            2 :       g_strdup_printf("GstGpacSink%c%s",
     335            2 :                       g_ascii_toupper(info->alias_name[0]),
     336            2 :                       info->alias_name + 1);
     337              : 
     338            2 :     type = g_type_register_static(
     339              :       GST_TYPE_GPAC_SINK, type_name, &subclass_typeinfo, 0);
     340            2 :     g_type_set_qdata(type, GST_GPAC_PARAMS_QDATA, params);
     341            2 :     if (!gst_element_register(plugin, name, GST_RANK_SECONDARY, type)) {
     342            0 :       GST_ERROR_OBJECT(
     343              :         plugin, "Failed to register %s sink subelement", info->alias_name);
     344            0 :       return FALSE;
     345              :     }
     346              :   }
     347              : 
     348            2 :   return TRUE;
     349              : }
     350              : 
     351            2 : GST_ELEMENT_REGISTER_DEFINE_CUSTOM(gpac_sink, gst_gpac_sink_register);
        

Generated by: LCOV version 2.0-1