LCOV - code coverage report
Current view: top level - src/lib/properties.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 69.3 % 225 156
Test Date: 2026-03-11 21:42:04 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 is_simple; // if true, treat as "-arg" instead of "--arg=..."
      34              : } GPAC_Arg;
      35              : #define GPAC_DEF_ARG(name, is_simple) { name, is_simple }
      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", TRUE),
      45              :   GPAC_DEF_ARG("old-arch", TRUE),
      46              :   GPAC_DEF_ARG("strict-error", TRUE),
      47              :   GPAC_DEF_ARG("broken-cert", TRUE),
      48              :   { 0 },
      49              : };
      50              : 
      51              : void
      52            0 : gpac_get_property_attributes(GParamSpec* pspec,
      53              :                              gboolean* is_simple,
      54              :                              gboolean* is_visible)
      55              : {
      56            0 :   *is_visible = FALSE;
      57            0 :   *is_simple = FALSE;
      58            0 :   for (u32 i = 0; visible_properties[i].name; i++) {
      59            0 :     if (!g_strcmp0(g_param_spec_get_name(pspec), visible_properties[i].name)) {
      60            0 :       *is_simple = visible_properties[i].is_simple;
      61            0 :       *is_visible = TRUE;
      62            0 :       break;
      63              :     }
      64              :   }
      65            0 : }
      66              : 
      67              : void
      68           22 : gpac_install_local_properties(GObjectClass* gobject_class,
      69              :                               GPAC_PropertyId first_prop,
      70              :                               ...)
      71              : {
      72              :   // Initialize the variable argument list
      73              :   va_list args;
      74           22 :   GPAC_PropertyId prop = first_prop;
      75           22 :   va_start(args, first_prop);
      76              : 
      77           52 :   while (prop != GPAC_PROP_0) {
      78           30 :     switch (prop) {
      79            4 :       case GPAC_PROP_GRAPH:
      80            4 :         g_object_class_install_property(
      81              :           gobject_class,
      82              :           prop,
      83              :           g_param_spec_string("graph",
      84              :                               "Graph",
      85              :                               "Filter graph to use in gpac session",
      86              :                               NULL,
      87              :                               G_PARAM_READWRITE));
      88            4 :         break;
      89              : 
      90           12 :       case GPAC_PROP_PRINT_STATS:
      91           12 :         g_object_class_install_property(
      92              :           gobject_class,
      93              :           prop,
      94              :           g_param_spec_boolean("print-stats",
      95              :                                "Print Stats",
      96              :                                "Print filter session stats after execution",
      97              :                                FALSE,
      98              :                                G_PARAM_READWRITE));
      99           12 :         break;
     100              : 
     101            4 :       case GPAC_PROP_SYNC:
     102            4 :         g_object_class_install_property(
     103              :           gobject_class,
     104              :           prop,
     105              :           g_param_spec_boolean(
     106              :             "sync",
     107              :             "Sync",
     108              :             "Enable synchronization on the internal fakesink",
     109              :             FALSE,
     110              :             G_PARAM_READWRITE));
     111            4 :         break;
     112              : 
     113            4 :       case GPAC_PROP_DESTINATION:
     114            4 :         g_object_class_install_property(
     115              :           gobject_class,
     116              :           prop,
     117              :           g_param_spec_string("destination",
     118              :                               "Destination",
     119              :                               "Destination to use for the filter session. Adds "
     120              :                               "a new sink to the graph",
     121              :                               NULL,
     122              :                               G_PARAM_READWRITE));
     123            4 :         break;
     124              : 
     125            6 :       case GPAC_PROP_SEGDUR:
     126            6 :         g_object_class_install_property(
     127              :           gobject_class,
     128              :           prop,
     129              :           g_param_spec_float(
     130              :             "segdur",
     131              :             "Segment Duration",
     132              :             "Duration of each segment in seconds. This option is handled from "
     133              :             "the GStreamer side and not relayed to gpac",
     134              :             0,
     135              :             G_MAXFLOAT,
     136              :             0,
     137              :             G_PARAM_READWRITE));
     138            6 :         break;
     139              : 
     140            0 :       default:
     141            0 :         break;
     142              :     }
     143              : 
     144              :     // Get the next property
     145           30 :     prop = va_arg(args, GPAC_PropertyId);
     146              :   }
     147              : 
     148              :   // End the variable argument list
     149           22 :   va_end(args);
     150           22 : }
     151              : 
     152              : void
     153            8 : gpac_install_filter_properties(GObjectClass* gobject_class,
     154              :                                GList* blacklist,
     155              :                                const gchar* filter_name)
     156              : {
     157            8 :   gf_sys_init(GF_MemTrackerNone, NULL);
     158            8 :   GF_FilterSession* session = gf_fs_new_defaults(0U);
     159            8 :   guint num_filters = gf_fs_filters_registers_count(session);
     160              : 
     161              :   // Get the list seperator
     162              :   GF_Err e;
     163            8 :   GF_Filter* dummy = gf_fs_new_filter(session, "dummy", 0, &e);
     164            8 :   char sep_list = (char)gf_filter_get_sep(dummy, GF_FS_SEP_LIST);
     165              : 
     166              :   const GF_FilterRegister* filter;
     167          459 :   for (guint i = 0; i < num_filters; i++) {
     168          459 :     filter = gf_fs_get_filter_register(session, i);
     169          459 :     if (!g_strcmp0(filter->name, filter_name))
     170            8 :       break;
     171          451 :     filter = NULL;
     172              :   }
     173            8 :   gf_fs_del(session);
     174            8 :   gf_sys_close();
     175            8 :   g_assert(filter);
     176              : 
     177            8 :   guint option_idx = 0;
     178          619 :   while (filter->args && filter->args[option_idx].arg_name) {
     179              :     // Skip hidden options
     180          611 :     if (filter->args[option_idx].flags & GF_ARG_HINT_HIDE)
     181           25 :       goto skip;
     182              : 
     183              :     // Check if the option name is valid
     184          586 :     if (!g_param_spec_is_valid_name(filter->args[option_idx].arg_name))
     185            0 :       goto skip;
     186              : 
     187              :     // Check if the option is already registered
     188          586 :     if (g_object_class_find_property(gobject_class,
     189          586 :                                      filter->args[option_idx].arg_name))
     190            1 :       goto skip;
     191              : 
     192              :     // Check if the option is blacklisted
     193              :     GList* item;
     194         1248 :     for (item = blacklist; item; item = item->next)
     195          671 :       if (!g_strcmp0(filter->args[option_idx].arg_name, item->data))
     196            8 :         goto skip;
     197              : 
     198              : #define SPEC_INSTALL(type, ...)                            \
     199              :   g_object_class_install_property(                         \
     200              :     gobject_class,                                         \
     201              :     GPAC_PROP_FILTER_OFFSET + option_idx,                  \
     202              :     g_param_spec_##type(filter->args[option_idx].arg_name, \
     203              :                         filter->args[option_idx].arg_name, \
     204              :                         filter->args[option_idx].arg_desc, \
     205              :                         __VA_ARGS__,                       \
     206              :                         G_PARAM_WRITABLE));
     207              : 
     208              :     // Special case for enum values
     209          577 :     if (filter->args[option_idx].min_max_enum &&
     210          110 :         strstr(filter->args[option_idx].min_max_enum, "|")) {
     211          110 :       SPEC_INSTALL(string, NULL);
     212          110 :       goto skip;
     213              :     }
     214              : 
     215              :     // Parse the default value
     216              :     const GF_PropertyValue p =
     217          467 :       gf_props_parse_value(filter->args[option_idx].arg_type,
     218          467 :                            filter->args[option_idx].arg_name,
     219          467 :                            filter->args[option_idx].arg_default_val,
     220          467 :                            filter->args[option_idx].min_max_enum,
     221              :                            sep_list);
     222              : 
     223              :     // Register the option
     224          467 :     switch (filter->args[option_idx].arg_type) {
     225           25 :       case GF_PROP_SINT:
     226           25 :         SPEC_INSTALL(int, G_MININT, G_MAXINT, p.value.sint);
     227           25 :         break;
     228           45 :       case GF_PROP_UINT:
     229           45 :         SPEC_INSTALL(uint, 0, G_MAXUINT, (guint)p.value.uint);
     230           45 :         break;
     231            1 :       case GF_PROP_LSINT:
     232            1 :         SPEC_INSTALL(int64, G_MININT64, G_MAXINT64, (gint64)p.value.longsint);
     233            1 :         break;
     234            2 :       case GF_PROP_LUINT:
     235            2 :         SPEC_INSTALL(uint64, 0, G_MAXUINT64, (guint64)p.value.longuint);
     236            2 :         break;
     237           11 :       case GF_PROP_FLOAT:
     238              :       case GF_PROP_FRACTION: {
     239           11 :         gfloat fval = 0.0F;
     240           11 :         if (p.value.lfrac.den != 0)
     241            0 :           fval = (gfloat)p.value.frac.num / (gfloat)p.value.frac.den;
     242           11 :         SPEC_INSTALL(float, -G_MAXFLOAT, G_MAXFLOAT, fval);
     243           11 :         break;
     244              :       }
     245           19 :       case GF_PROP_DOUBLE:
     246              :       case GF_PROP_FRACTION64: {
     247           19 :         gdouble dval = 0.0;
     248           19 :         if (p.value.lfrac.den != 0)
     249            4 :           dval = (gdouble)p.value.lfrac.num / (gdouble)p.value.lfrac.den;
     250           19 :         SPEC_INSTALL(double, -G_MAXDOUBLE, G_MAXDOUBLE, dval);
     251           19 :         break;
     252              :       }
     253          284 :       case GF_PROP_BOOL:
     254          284 :         SPEC_INSTALL(boolean, p.value.boolean);
     255          284 :         break;
     256           71 :       case GF_PROP_STRING:
     257           71 :         SPEC_INSTALL(string, p.value.string);
     258           71 :         break;
     259            9 :       default:
     260            9 :         SPEC_INSTALL(string, NULL);
     261            9 :         break;
     262              :     }
     263              : 
     264              : #undef SPEC_INSTALL
     265              : 
     266          611 :   skip:
     267          611 :     option_idx++;
     268              :   }
     269            8 : }
     270              : 
     271              : void
     272           12 : gpac_install_global_properties(GObjectClass* gobject_class)
     273              : {
     274              :   // Install the visible global properties
     275           12 :   const GF_GPACArg* args = gf_sys_get_options();
     276           12 :   for (u32 i = GPAC_PROP_GLOBAL_OFFSET;
     277           60 :        visible_properties[i - GPAC_PROP_GLOBAL_OFFSET].name;
     278           48 :        i++) {
     279              :     // Find the property in the global properties
     280         1224 :     for (u32 j = 0; args[j].name; j++) {
     281         1224 :       const GF_GPACArg* arg = &args[j];
     282         1224 :       const GPAC_Arg* prop = &visible_properties[i - GPAC_PROP_GLOBAL_OFFSET];
     283         1224 :       if (!g_strcmp0(prop->name, arg->name)) {
     284           48 :         g_object_class_install_property(
     285              :           gobject_class,
     286              :           i,
     287           48 :           prop->is_simple ? g_param_spec_boolean(arg->name,
     288           48 :                                                  arg->name,
     289           48 :                                                  arg->description,
     290              :                                                  FALSE,
     291              :                                                  G_PARAM_READWRITE)
     292            0 :                           : g_param_spec_string(arg->name,
     293            0 :                                                 arg->name,
     294            0 :                                                 arg->description,
     295              :                                                 NULL,
     296              :                                                 G_PARAM_READWRITE));
     297           48 :         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 is simple
     361              :     gboolean is_simple, is_visible;
     362            0 :     gpac_get_property_attributes(pspec, &is_simple, &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 (is_simple)
     371            0 :       property = g_strdup_printf("-%s", g_param_spec_get_name(pspec));
     372              :     else
     373            0 :       property = g_strdup_printf(
     374              :         "--%s=%s", g_param_spec_get_name(pspec), g_value_get_string(value));
     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 is_simple, is_visible;
     408            0 :     gpac_get_property_attributes(pspec, &is_simple, &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 (is_simple)
     414            0 :       g_value_set_boolean(value, prop_val != NULL);
     415              :     else
     416            0 :       g_value_set_string(value, prop_val);
     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