LCOV - code coverage report
Current view: top level - src/lib/properties.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 70.7 % 225 159
Test Date: 2026-04-07 16:20:57 Functions: 71.4 % 7 5

            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 "lib/properties.h"
      27              : #include "gpacmessages.h"
      28              : #include <gpac/filters.h>
      29              : 
      30              : typedef struct
      31              : {
      32              :   const gchar* name;
      33              :   gboolean has_value; // if true, treat as "-arg=<value>" instead of "-arg"
      34              : } GPAC_Arg;
      35              : #define GPAC_DEF_ARG(name, has_value) { name, has_value }
      36              : 
      37              : // Define the override properties
      38              : static GF_GPACArg override_properties[] = {
      39              :   { 0 },
      40              : };
      41              : 
      42              : // Define the visible properties with their default values
      43              : static GPAC_Arg visible_properties[] = {
      44              :   GPAC_DEF_ARG("for-test", FALSE),
      45              :   GPAC_DEF_ARG("old-arch", FALSE),
      46              :   GPAC_DEF_ARG("strict-error", FALSE),
      47              :   GPAC_DEF_ARG("broken-cert", FALSE),
      48              :   GPAC_DEF_ARG("full-link", FALSE),
      49              :   GPAC_DEF_ARG("sched", TRUE),
      50              :   { 0 },
      51              : };
      52              : 
      53              : void
      54            0 : gpac_get_property_attributes(GParamSpec* pspec,
      55              :                              gboolean* has_value,
      56              :                              gboolean* is_visible)
      57              : {
      58            0 :   *is_visible = FALSE;
      59            0 :   *has_value = FALSE;
      60            0 :   for (u32 i = 0; visible_properties[i].name; i++) {
      61            0 :     if (!g_strcmp0(g_param_spec_get_name(pspec), visible_properties[i].name)) {
      62            0 :       *has_value = visible_properties[i].has_value;
      63            0 :       *is_visible = TRUE;
      64            0 :       break;
      65              :     }
      66              :   }
      67            0 : }
      68              : 
      69              : void
      70           22 : gpac_install_local_properties(GObjectClass* gobject_class,
      71              :                               GPAC_PropertyId first_prop,
      72              :                               ...)
      73              : {
      74              :   // Initialize the variable argument list
      75              :   va_list args;
      76           22 :   GPAC_PropertyId prop = first_prop;
      77           22 :   va_start(args, first_prop);
      78              : 
      79           52 :   while (prop != GPAC_PROP_0) {
      80           30 :     switch (prop) {
      81            4 :       case GPAC_PROP_GRAPH:
      82            4 :         g_object_class_install_property(
      83              :           gobject_class,
      84              :           prop,
      85              :           g_param_spec_string("graph",
      86              :                               "Graph",
      87              :                               "Filter graph to use in gpac session",
      88              :                               NULL,
      89              :                               G_PARAM_READWRITE));
      90            4 :         break;
      91              : 
      92           12 :       case GPAC_PROP_PRINT_STATS:
      93           12 :         g_object_class_install_property(
      94              :           gobject_class,
      95              :           prop,
      96              :           g_param_spec_boolean("print-stats",
      97              :                                "Print Stats",
      98              :                                "Print filter session stats after execution",
      99              :                                FALSE,
     100              :                                G_PARAM_READWRITE));
     101           12 :         break;
     102              : 
     103            4 :       case GPAC_PROP_SYNC:
     104            4 :         g_object_class_install_property(
     105              :           gobject_class,
     106              :           prop,
     107              :           g_param_spec_boolean(
     108              :             "sync",
     109              :             "Sync",
     110              :             "Enable synchronization on the internal fakesink",
     111              :             FALSE,
     112              :             G_PARAM_READWRITE));
     113            4 :         break;
     114              : 
     115            4 :       case GPAC_PROP_DESTINATION:
     116            4 :         g_object_class_install_property(
     117              :           gobject_class,
     118              :           prop,
     119              :           g_param_spec_string("destination",
     120              :                               "Destination",
     121              :                               "Destination to use for the filter session. Adds "
     122              :                               "a new sink to the graph",
     123              :                               NULL,
     124              :                               G_PARAM_READWRITE));
     125            4 :         break;
     126              : 
     127            6 :       case GPAC_PROP_SEGDUR:
     128            6 :         g_object_class_install_property(
     129              :           gobject_class,
     130              :           prop,
     131              :           g_param_spec_float(
     132              :             "segdur",
     133              :             "Segment Duration",
     134              :             "Duration of each segment in seconds. This option is handled from "
     135              :             "the GStreamer side and not relayed to gpac",
     136              :             0,
     137              :             G_MAXFLOAT,
     138              :             0,
     139              :             G_PARAM_READWRITE));
     140            6 :         break;
     141              : 
     142            0 :       default:
     143            0 :         break;
     144              :     }
     145              : 
     146              :     // Get the next property
     147           30 :     prop = va_arg(args, GPAC_PropertyId);
     148              :   }
     149              : 
     150              :   // End the variable argument list
     151           22 :   va_end(args);
     152           22 : }
     153              : 
     154              : void
     155            8 : gpac_install_filter_properties(GObjectClass* gobject_class,
     156              :                                GList* blacklist,
     157              :                                const gchar* filter_name)
     158              : {
     159            8 :   gf_sys_init(GF_MemTrackerNone, NULL);
     160            8 :   GF_FilterSession* session = gf_fs_new_defaults(0U);
     161            8 :   guint num_filters = gf_fs_filters_registers_count(session);
     162              : 
     163              :   // Get the list seperator
     164              :   GF_Err e;
     165            8 :   GF_Filter* dummy = gf_fs_new_filter(session, "dummy", 0, &e);
     166            8 :   char sep_list = (char)gf_filter_get_sep(dummy, GF_FS_SEP_LIST);
     167              : 
     168              :   const GF_FilterRegister* filter;
     169          459 :   for (guint i = 0; i < num_filters; i++) {
     170          459 :     filter = gf_fs_get_filter_register(session, i);
     171          459 :     if (!g_strcmp0(filter->name, filter_name))
     172            8 :       break;
     173          451 :     filter = NULL;
     174              :   }
     175            8 :   gf_fs_del(session);
     176            8 :   gf_sys_close();
     177            8 :   g_assert(filter);
     178              : 
     179            8 :   guint option_idx = 0;
     180          619 :   while (filter->args && filter->args[option_idx].arg_name) {
     181              :     // Skip hidden options
     182          611 :     if (filter->args[option_idx].flags & GF_ARG_HINT_HIDE)
     183           25 :       goto skip;
     184              : 
     185              :     // Check if the option name is valid
     186          586 :     if (!g_param_spec_is_valid_name(filter->args[option_idx].arg_name))
     187            0 :       goto skip;
     188              : 
     189              :     // Check if the option is already registered
     190          586 :     if (g_object_class_find_property(gobject_class,
     191          586 :                                      filter->args[option_idx].arg_name))
     192            1 :       goto skip;
     193              : 
     194              :     // Check if the option is blacklisted
     195              :     GList* item;
     196         1248 :     for (item = blacklist; item; item = item->next)
     197          671 :       if (!g_strcmp0(filter->args[option_idx].arg_name, item->data))
     198            8 :         goto skip;
     199              : 
     200              : #define SPEC_INSTALL(type, ...)                            \
     201              :   g_object_class_install_property(                         \
     202              :     gobject_class,                                         \
     203              :     GPAC_PROP_FILTER_OFFSET + option_idx,                  \
     204              :     g_param_spec_##type(filter->args[option_idx].arg_name, \
     205              :                         filter->args[option_idx].arg_name, \
     206              :                         filter->args[option_idx].arg_desc, \
     207              :                         __VA_ARGS__,                       \
     208              :                         G_PARAM_WRITABLE));
     209              : 
     210              :     // Special case for enum values
     211          577 :     if (filter->args[option_idx].min_max_enum &&
     212          110 :         strstr(filter->args[option_idx].min_max_enum, "|")) {
     213          110 :       SPEC_INSTALL(string, NULL);
     214          110 :       goto skip;
     215              :     }
     216              : 
     217              :     // Parse the default value
     218              :     const GF_PropertyValue p =
     219          467 :       gf_props_parse_value(filter->args[option_idx].arg_type,
     220          467 :                            filter->args[option_idx].arg_name,
     221          467 :                            filter->args[option_idx].arg_default_val,
     222          467 :                            filter->args[option_idx].min_max_enum,
     223              :                            sep_list);
     224              : 
     225              :     // Register the option
     226          467 :     switch (filter->args[option_idx].arg_type) {
     227           25 :       case GF_PROP_SINT:
     228           25 :         SPEC_INSTALL(int, G_MININT, G_MAXINT, p.value.sint);
     229           25 :         break;
     230           45 :       case GF_PROP_UINT:
     231           45 :         SPEC_INSTALL(uint, 0, G_MAXUINT, (guint)p.value.uint);
     232           45 :         break;
     233            1 :       case GF_PROP_LSINT:
     234            1 :         SPEC_INSTALL(int64, G_MININT64, G_MAXINT64, (gint64)p.value.longsint);
     235            1 :         break;
     236            2 :       case GF_PROP_LUINT:
     237            2 :         SPEC_INSTALL(uint64, 0, G_MAXUINT64, (guint64)p.value.longuint);
     238            2 :         break;
     239           11 :       case GF_PROP_FLOAT:
     240              :       case GF_PROP_FRACTION: {
     241           11 :         gfloat fval = 0.0F;
     242           11 :         if (p.value.lfrac.den != 0)
     243            0 :           fval = (gfloat)p.value.frac.num / (gfloat)p.value.frac.den;
     244           11 :         SPEC_INSTALL(float, -G_MAXFLOAT, G_MAXFLOAT, fval);
     245           11 :         break;
     246              :       }
     247           19 :       case GF_PROP_DOUBLE:
     248              :       case GF_PROP_FRACTION64: {
     249           19 :         gdouble dval = 0.0;
     250           19 :         if (p.value.lfrac.den != 0)
     251            4 :           dval = (gdouble)p.value.lfrac.num / (gdouble)p.value.lfrac.den;
     252           19 :         SPEC_INSTALL(double, -G_MAXDOUBLE, G_MAXDOUBLE, dval);
     253           19 :         break;
     254              :       }
     255          284 :       case GF_PROP_BOOL:
     256          284 :         SPEC_INSTALL(boolean, p.value.boolean);
     257          284 :         break;
     258           71 :       case GF_PROP_STRING:
     259           71 :         SPEC_INSTALL(string, p.value.string);
     260           71 :         break;
     261            9 :       default:
     262            9 :         SPEC_INSTALL(string, NULL);
     263            9 :         break;
     264              :     }
     265              : 
     266              : #undef SPEC_INSTALL
     267              : 
     268          611 :   skip:
     269          611 :     option_idx++;
     270              :   }
     271            8 : }
     272              : 
     273              : void
     274           12 : gpac_install_global_properties(GObjectClass* gobject_class)
     275              : {
     276              :   // Install the visible global properties
     277           12 :   const GF_GPACArg* args = gf_sys_get_options();
     278           12 :   for (u32 i = GPAC_PROP_GLOBAL_OFFSET;
     279           84 :        visible_properties[i - GPAC_PROP_GLOBAL_OFFSET].name;
     280           72 :        i++) {
     281              :     // Find the property in the global properties
     282         2820 :     for (u32 j = 0; args[j].name; j++) {
     283         2820 :       const GF_GPACArg* arg = &args[j];
     284         2820 :       const GPAC_Arg* prop = &visible_properties[i - GPAC_PROP_GLOBAL_OFFSET];
     285         2820 :       if (!g_strcmp0(prop->name, arg->name)) {
     286           72 :         g_object_class_install_property(
     287              :           gobject_class,
     288              :           i,
     289           72 :           prop->has_value
     290           12 :             ? g_param_spec_string(
     291           12 :                 arg->name, arg->name, arg->description, NULL, G_PARAM_READWRITE)
     292           60 :             : g_param_spec_boolean(arg->name,
     293           60 :                                    arg->name,
     294           60 :                                    arg->description,
     295              :                                    FALSE,
     296              :                                    G_PARAM_READWRITE));
     297           72 :         break;
     298              :       }
     299              :     }
     300              :   }
     301           12 : }
     302              : 
     303              : gboolean
     304           14 : gpac_set_property(GPAC_PropertyContext* ctx,
     305              :                   guint property_id,
     306              :                   const GValue* value,
     307              :                   GParamSpec* pspec)
     308              : {
     309           14 :   if (g_param_value_defaults(pspec, value))
     310            0 :     return TRUE;
     311              : 
     312           14 :   if (IS_TOP_LEVEL_PROPERTY(property_id)) {
     313            5 :     switch (property_id) {
     314            4 :       case GPAC_PROP_GRAPH:
     315            4 :         g_free(ctx->graph);
     316            4 :         ctx->graph = g_value_dup_string(value);
     317            4 :         break;
     318            0 :       case GPAC_PROP_PRINT_STATS:
     319            0 :         ctx->print_stats = g_value_get_boolean(value);
     320            0 :         break;
     321            0 :       case GPAC_PROP_SYNC:
     322            0 :         ctx->sync = g_value_get_boolean(value);
     323            0 :         break;
     324            1 :       case GPAC_PROP_DESTINATION:
     325            1 :         g_free(ctx->destination);
     326            1 :         ctx->destination = g_value_dup_string(value);
     327            1 :         break;
     328            0 :       default:
     329            0 :         return FALSE;
     330              :     }
     331            9 :   } else if (IS_FILTER_PROPERTY(property_id)) {
     332              :     // Get the value as a string
     333              :     gchar* value_str;
     334            7 :     if (G_VALUE_HOLDS_STRING(value))
     335            0 :       value_str = g_value_dup_string(value);
     336            7 :     else if (G_VALUE_HOLDS_BOOLEAN(value))
     337            0 :       value_str = g_strdup(g_value_get_boolean(value) ? "true" : "false");
     338              :     else
     339            7 :       value_str = g_strdup_value_contents(value);
     340              : 
     341              :     // No value, return
     342            7 :     if (!value_str)
     343            0 :       return TRUE;
     344              : 
     345              :     // Convert snake case to kebab case
     346              :     // GLib uses kebab case for command line arguments, so we have to convert it
     347              :     // back to snake case
     348            7 :     gchar* param = g_strdup(g_param_spec_get_name(pspec));
     349           37 :     for (gchar* c = param; *c; c++)
     350           30 :       if (*c == '-')
     351            0 :         *c = '_';
     352              : 
     353              :     // Add the property to the list
     354            7 :     gchar* property = g_strdup_printf("--%s=%s", param, value_str);
     355            7 :     ctx->properties = g_list_append(ctx->properties, property);
     356            7 :     g_free(value_str);
     357            7 :     g_free(param);
     358            7 :     return TRUE;
     359            2 :   } else if (IS_GLOBAL_PROPERTY(property_id)) {
     360              :     // Check if the property is visible and if it has a value
     361              :     gboolean has_value, is_visible;
     362            0 :     gpac_get_property_attributes(pspec, &has_value, &is_visible);
     363              : 
     364              :     // If the property is not visible, return
     365            0 :     if (!is_visible)
     366            0 :       return FALSE;
     367              : 
     368              :     // Add the property to the list
     369              :     gchar* property;
     370            0 :     if (has_value)
     371            0 :       property = g_strdup_printf(
     372              :         "-%s=%s", g_param_spec_get_name(pspec), g_value_get_string(value));
     373              :     else
     374            0 :       property = g_strdup_printf("-%s", g_param_spec_get_name(pspec));
     375            0 :     ctx->properties = g_list_append(ctx->properties, property);
     376              :   } else {
     377              :     // Unknown property or not handled here
     378            2 :     return FALSE;
     379              :   }
     380            5 :   return TRUE;
     381              : }
     382              : 
     383              : gboolean
     384            0 : gpac_get_property(GPAC_PropertyContext* ctx,
     385              :                   guint property_id,
     386              :                   GValue* value,
     387              :                   GParamSpec* pspec)
     388              : {
     389            0 :   if (IS_TOP_LEVEL_PROPERTY(property_id)) {
     390            0 :     switch (property_id) {
     391            0 :       case GPAC_PROP_GRAPH:
     392            0 :         g_value_set_string(value, ctx->graph);
     393            0 :         break;
     394            0 :       case GPAC_PROP_PRINT_STATS:
     395            0 :         g_value_set_boolean(value, ctx->print_stats);
     396            0 :         break;
     397            0 :       case GPAC_PROP_SYNC:
     398            0 :         g_value_set_boolean(value, ctx->sync);
     399            0 :         break;
     400            0 :       case GPAC_PROP_DESTINATION:
     401            0 :         g_value_set_string(value, ctx->destination);
     402            0 :         break;
     403            0 :       default:
     404            0 :         return FALSE;
     405              :     }
     406            0 :   } else if (IS_GLOBAL_PROPERTY(property_id)) {
     407              :     gboolean has_value, is_visible;
     408            0 :     gpac_get_property_attributes(pspec, &has_value, &is_visible);
     409            0 :     g_assert(is_visible);
     410              :     const gchar* prop_val =
     411            0 :       gf_sys_find_global_arg(g_param_spec_get_name(pspec));
     412              : 
     413            0 :     if (has_value)
     414            0 :       g_value_set_string(value, prop_val);
     415              :     else
     416            0 :       g_value_set_boolean(value, prop_val != NULL);
     417            0 :   } else if (IS_ELEMENT_PROPERTY(property_id)) {
     418              :     // Handled in the element
     419            0 :     return FALSE;
     420              :   } else {
     421              :     // Unknown property or not handled here
     422            0 :     g_warn_if_reached();
     423              :   }
     424            0 :   return TRUE;
     425              : }
     426              : 
     427              : gboolean
     428           16 : gpac_apply_properties(GPAC_PropertyContext* ctx)
     429              : {
     430              :   // Add the default properties
     431           16 :   g_autolist(GList) override_list = NULL;
     432           16 :   for (u32 i = 0; override_properties[i].name; i++) {
     433            0 :     const GF_GPACArg* arg = &override_properties[i];
     434            0 :     gchar* property = g_strdup_printf("--%s=%s", arg->name, arg->val);
     435            0 :     override_list = g_list_append(override_list, property);
     436              :   }
     437              : 
     438              :   // Free the previous arguments
     439           16 :   if (ctx->props_as_argv) {
     440            9 :     for (u32 i = 0; ctx->props_as_argv[i]; i++)
     441            6 :       g_free(ctx->props_as_argv[i]);
     442            3 :     g_free((void*)ctx->props_as_argv);
     443            3 :     ctx->props_as_argv = NULL;
     444              :   }
     445              : 
     446              :   // Allocate the arguments array
     447           16 :   u32 num_properties =
     448           16 :     g_list_length(ctx->properties) + g_list_length(override_list);
     449              :   // +1 for the executable name
     450           16 :   num_properties++;
     451              :   // +1 for the NULL termination
     452           16 :   num_properties++;
     453              : 
     454           16 :   ctx->props_as_argv = (gchar**)g_malloc0_n(num_properties, sizeof(gchar*));
     455              : 
     456              :   // Add the executable name
     457           16 :   ctx->props_as_argv[0] = g_strdup("gst");
     458              : 
     459              :   void* item;
     460           26 :   for (u32 i = 0; i < g_list_length(ctx->properties); i++) {
     461           10 :     item = g_list_nth_data(ctx->properties, i);
     462           20 :     ctx->props_as_argv[i + 1] = (gchar*)g_strdup(item);
     463              :   }
     464           16 :   for (u32 i = 0; i < g_list_length(override_list); i++) {
     465            0 :     item = g_list_nth_data(override_list, i);
     466            0 :     ctx->props_as_argv[i + 1 + g_list_length(ctx->properties)] = (gchar*)item;
     467              :   }
     468              : 
     469              :   // Add the NULL termination
     470           16 :   ctx->props_as_argv[num_properties - 1] = NULL;
     471              : 
     472              :   // Set the gpac system arguments
     473           16 :   gpac_return_val_if_fail(
     474              :     gf_sys_set_args((s32)num_properties - 1, (const char**)ctx->props_as_argv),
     475              :     FALSE);
     476              : 
     477           16 :   return TRUE;
     478              : }
        

Generated by: LCOV version 2.0-1