LCOV - code coverage report
Current view: top level - src/lib/properties.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 69.1 % 223 154
Test Date: 2025-09-18 00:43:48 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_FilterSession* session = gf_fs_new_defaults(0U);
     158            8 :   guint num_filters = gf_fs_filters_registers_count(session);
     159              : 
     160              :   // Get the list seperator
     161              :   GF_Err e;
     162            8 :   GF_Filter* dummy = gf_fs_new_filter(session, "dummy", 0, &e);
     163            8 :   char sep_list = (char)gf_filter_get_sep(dummy, GF_FS_SEP_LIST);
     164              : 
     165              :   const GF_FilterRegister* filter;
     166          459 :   for (guint i = 0; i < num_filters; i++) {
     167          459 :     filter = gf_fs_get_filter_register(session, i);
     168          459 :     if (!g_strcmp0(filter->name, filter_name))
     169            8 :       break;
     170          451 :     filter = NULL;
     171              :   }
     172            8 :   gf_fs_del(session);
     173            8 :   g_assert(filter);
     174              : 
     175            8 :   guint option_idx = 0;
     176          606 :   while (filter->args && filter->args[option_idx].arg_name) {
     177              :     // Skip hidden options
     178          598 :     if (filter->args[option_idx].flags & GF_ARG_HINT_HIDE)
     179           25 :       goto skip;
     180              : 
     181              :     // Check if the option name is valid
     182          573 :     if (!g_param_spec_is_valid_name(filter->args[option_idx].arg_name))
     183            0 :       goto skip;
     184              : 
     185              :     // Check if the option is already registered
     186          573 :     if (g_object_class_find_property(gobject_class,
     187          573 :                                      filter->args[option_idx].arg_name))
     188            1 :       goto skip;
     189              : 
     190              :     // Check if the option is blacklisted
     191              :     GList* item;
     192         1215 :     for (item = blacklist; item; item = item->next)
     193          651 :       if (!g_strcmp0(filter->args[option_idx].arg_name, item->data))
     194            8 :         goto skip;
     195              : 
     196              : #define SPEC_INSTALL(type, ...)                            \
     197              :   g_object_class_install_property(                         \
     198              :     gobject_class,                                         \
     199              :     GPAC_PROP_FILTER_OFFSET + option_idx,                  \
     200              :     g_param_spec_##type(filter->args[option_idx].arg_name, \
     201              :                         filter->args[option_idx].arg_name, \
     202              :                         filter->args[option_idx].arg_desc, \
     203              :                         __VA_ARGS__,                       \
     204              :                         G_PARAM_WRITABLE));
     205              : 
     206              :     // Special case for enum values
     207          564 :     if (filter->args[option_idx].min_max_enum &&
     208          106 :         strstr(filter->args[option_idx].min_max_enum, "|")) {
     209          106 :       SPEC_INSTALL(string, NULL);
     210          106 :       goto skip;
     211              :     }
     212              : 
     213              :     // Parse the default value
     214              :     const GF_PropertyValue p =
     215          458 :       gf_props_parse_value(filter->args[option_idx].arg_type,
     216          458 :                            filter->args[option_idx].arg_name,
     217          458 :                            filter->args[option_idx].arg_default_val,
     218          458 :                            filter->args[option_idx].min_max_enum,
     219              :                            sep_list);
     220              : 
     221              :     // Register the option
     222          458 :     switch (filter->args[option_idx].arg_type) {
     223           25 :       case GF_PROP_SINT:
     224           25 :         SPEC_INSTALL(int, G_MININT, G_MAXINT, p.value.sint);
     225           25 :         break;
     226           41 :       case GF_PROP_UINT:
     227           41 :         SPEC_INSTALL(uint, 0, G_MAXUINT, (guint)p.value.uint);
     228           41 :         break;
     229            1 :       case GF_PROP_LSINT:
     230            1 :         SPEC_INSTALL(int64, G_MININT64, G_MAXINT64, (gint64)p.value.longsint);
     231            1 :         break;
     232            2 :       case GF_PROP_LUINT:
     233            2 :         SPEC_INSTALL(uint64, 0, G_MAXUINT64, (guint64)p.value.longuint);
     234            2 :         break;
     235           11 :       case GF_PROP_FLOAT:
     236              :       case GF_PROP_FRACTION: {
     237           11 :         gfloat fval = 0.0F;
     238           11 :         if (p.value.lfrac.den != 0)
     239            0 :           fval = (gfloat)p.value.frac.num / (gfloat)p.value.frac.den;
     240           11 :         SPEC_INSTALL(float, -G_MAXFLOAT, G_MAXFLOAT, fval);
     241           11 :         break;
     242              :       }
     243           19 :       case GF_PROP_DOUBLE:
     244              :       case GF_PROP_FRACTION64: {
     245           19 :         gdouble dval = 0.0;
     246           19 :         if (p.value.lfrac.den != 0)
     247            4 :           dval = (gdouble)p.value.lfrac.num / (gdouble)p.value.lfrac.den;
     248           19 :         SPEC_INSTALL(double, -G_MAXDOUBLE, G_MAXDOUBLE, dval);
     249           19 :         break;
     250              :       }
     251          282 :       case GF_PROP_BOOL:
     252          282 :         SPEC_INSTALL(boolean, p.value.boolean);
     253          282 :         break;
     254           68 :       case GF_PROP_STRING:
     255           68 :         SPEC_INSTALL(string, p.value.string);
     256           68 :         break;
     257            9 :       default:
     258            9 :         SPEC_INSTALL(string, NULL);
     259            9 :         break;
     260              :     }
     261              : 
     262              : #undef SPEC_INSTALL
     263              : 
     264          598 :   skip:
     265          598 :     option_idx++;
     266              :   }
     267            8 : }
     268              : 
     269              : void
     270           12 : gpac_install_global_properties(GObjectClass* gobject_class)
     271              : {
     272              :   // Install the visible global properties
     273           12 :   const GF_GPACArg* args = gf_sys_get_options();
     274           12 :   for (u32 i = GPAC_PROP_GLOBAL_OFFSET;
     275           60 :        visible_properties[i - GPAC_PROP_GLOBAL_OFFSET].name;
     276           48 :        i++) {
     277              :     // Find the property in the global properties
     278         1224 :     for (u32 j = 0; args[j].name; j++) {
     279         1224 :       const GF_GPACArg* arg = &args[j];
     280         1224 :       const GPAC_Arg* prop = &visible_properties[i - GPAC_PROP_GLOBAL_OFFSET];
     281         1224 :       if (!g_strcmp0(prop->name, arg->name)) {
     282           48 :         g_object_class_install_property(
     283              :           gobject_class,
     284              :           i,
     285           48 :           prop->is_simple ? g_param_spec_boolean(arg->name,
     286           48 :                                                  arg->name,
     287           48 :                                                  arg->description,
     288              :                                                  FALSE,
     289              :                                                  G_PARAM_READWRITE)
     290            0 :                           : g_param_spec_string(arg->name,
     291            0 :                                                 arg->name,
     292            0 :                                                 arg->description,
     293              :                                                 NULL,
     294              :                                                 G_PARAM_READWRITE));
     295           48 :         break;
     296              :       }
     297              :     }
     298              :   }
     299           12 : }
     300              : 
     301              : gboolean
     302           14 : gpac_set_property(GPAC_PropertyContext* ctx,
     303              :                   guint property_id,
     304              :                   const GValue* value,
     305              :                   GParamSpec* pspec)
     306              : {
     307           14 :   if (g_param_value_defaults(pspec, value))
     308            0 :     return TRUE;
     309              : 
     310           14 :   if (IS_TOP_LEVEL_PROPERTY(property_id)) {
     311            5 :     switch (property_id) {
     312            4 :       case GPAC_PROP_GRAPH:
     313            4 :         g_free(ctx->graph);
     314            4 :         ctx->graph = g_value_dup_string(value);
     315            4 :         break;
     316            0 :       case GPAC_PROP_PRINT_STATS:
     317            0 :         ctx->print_stats = g_value_get_boolean(value);
     318            0 :         break;
     319            0 :       case GPAC_PROP_SYNC:
     320            0 :         ctx->sync = g_value_get_boolean(value);
     321            0 :         break;
     322            1 :       case GPAC_PROP_DESTINATION:
     323            1 :         g_free(ctx->destination);
     324            1 :         ctx->destination = g_value_dup_string(value);
     325            1 :         break;
     326            0 :       default:
     327            0 :         return FALSE;
     328              :     }
     329            9 :   } else if (IS_FILTER_PROPERTY(property_id)) {
     330              :     // Get the value as a string
     331              :     gchar* value_str;
     332            7 :     if (G_VALUE_HOLDS_STRING(value))
     333            0 :       value_str = g_value_dup_string(value);
     334            7 :     else if (G_VALUE_HOLDS_BOOLEAN(value))
     335            0 :       value_str = g_strdup(g_value_get_boolean(value) ? "true" : "false");
     336              :     else
     337            7 :       value_str = g_strdup_value_contents(value);
     338              : 
     339              :     // No value, return
     340            7 :     if (!value_str)
     341            0 :       return TRUE;
     342              : 
     343              :     // Convert snake case to kebab case
     344              :     // GLib uses kebab case for command line arguments, so we have to convert it
     345              :     // back to snake case
     346            7 :     gchar* param = g_strdup(g_param_spec_get_name(pspec));
     347           37 :     for (gchar* c = param; *c; c++)
     348           30 :       if (*c == '-')
     349            0 :         *c = '_';
     350              : 
     351              :     // Add the property to the list
     352            7 :     gchar* property = g_strdup_printf("--%s=%s", param, value_str);
     353            7 :     ctx->properties = g_list_append(ctx->properties, property);
     354            7 :     g_free(value_str);
     355            7 :     g_free(param);
     356            7 :     return TRUE;
     357            2 :   } else if (IS_GLOBAL_PROPERTY(property_id)) {
     358              :     // Check if the property is visible and if it is simple
     359              :     gboolean is_simple, is_visible;
     360            0 :     gpac_get_property_attributes(pspec, &is_simple, &is_visible);
     361              : 
     362              :     // If the property is not visible, return
     363            0 :     if (!is_visible)
     364            0 :       return FALSE;
     365              : 
     366              :     // Add the property to the list
     367              :     gchar* property;
     368            0 :     if (is_simple)
     369            0 :       property = g_strdup_printf("-%s", g_param_spec_get_name(pspec));
     370              :     else
     371            0 :       property = g_strdup_printf(
     372              :         "--%s=%s", g_param_spec_get_name(pspec), g_value_get_string(value));
     373            0 :     ctx->properties = g_list_append(ctx->properties, property);
     374              :   } else {
     375              :     // Unknown property or not handled here
     376            2 :     return FALSE;
     377              :   }
     378            5 :   return TRUE;
     379              : }
     380              : 
     381              : gboolean
     382            0 : gpac_get_property(GPAC_PropertyContext* ctx,
     383              :                   guint property_id,
     384              :                   GValue* value,
     385              :                   GParamSpec* pspec)
     386              : {
     387            0 :   if (IS_TOP_LEVEL_PROPERTY(property_id)) {
     388            0 :     switch (property_id) {
     389            0 :       case GPAC_PROP_GRAPH:
     390            0 :         g_value_set_string(value, ctx->graph);
     391            0 :         break;
     392            0 :       case GPAC_PROP_PRINT_STATS:
     393            0 :         g_value_set_boolean(value, ctx->print_stats);
     394            0 :         break;
     395            0 :       case GPAC_PROP_SYNC:
     396            0 :         g_value_set_boolean(value, ctx->sync);
     397            0 :         break;
     398            0 :       case GPAC_PROP_DESTINATION:
     399            0 :         g_value_set_string(value, ctx->destination);
     400            0 :         break;
     401            0 :       default:
     402            0 :         return FALSE;
     403              :     }
     404            0 :   } else if (IS_GLOBAL_PROPERTY(property_id)) {
     405              :     gboolean is_simple, is_visible;
     406            0 :     gpac_get_property_attributes(pspec, &is_simple, &is_visible);
     407            0 :     g_assert(is_visible);
     408              :     const gchar* prop_val =
     409            0 :       gf_sys_find_global_arg(g_param_spec_get_name(pspec));
     410              : 
     411            0 :     if (is_simple)
     412            0 :       g_value_set_boolean(value, prop_val != NULL);
     413              :     else
     414            0 :       g_value_set_string(value, prop_val);
     415            0 :   } else if (IS_ELEMENT_PROPERTY(property_id)) {
     416              :     // Handled in the element
     417            0 :     return FALSE;
     418              :   } else {
     419              :     // Unknown property or not handled here
     420            0 :     g_warn_if_reached();
     421              :   }
     422            0 :   return TRUE;
     423              : }
     424              : 
     425              : gboolean
     426           16 : gpac_apply_properties(GPAC_PropertyContext* ctx)
     427              : {
     428              :   // Add the default properties
     429           16 :   g_autolist(GList) override_list = NULL;
     430           16 :   for (u32 i = 0; override_properties[i].name; i++) {
     431            0 :     const GF_GPACArg* arg = &override_properties[i];
     432            0 :     gchar* property = g_strdup_printf("--%s=%s", arg->name, arg->val);
     433            0 :     override_list = g_list_append(override_list, property);
     434              :   }
     435              : 
     436              :   // Free the previous arguments
     437           16 :   if (ctx->props_as_argv) {
     438            9 :     for (u32 i = 0; ctx->props_as_argv[i]; i++)
     439            6 :       g_free(ctx->props_as_argv[i]);
     440            3 :     g_free((void*)ctx->props_as_argv);
     441            3 :     ctx->props_as_argv = NULL;
     442              :   }
     443              : 
     444              :   // Allocate the arguments array
     445           16 :   u32 num_properties =
     446           16 :     g_list_length(ctx->properties) + g_list_length(override_list);
     447              :   // +1 for the executable name
     448           16 :   num_properties++;
     449              :   // +1 for the NULL termination
     450           16 :   num_properties++;
     451              : 
     452           16 :   ctx->props_as_argv = (gchar**)g_malloc0_n(num_properties, sizeof(gchar*));
     453              : 
     454              :   // Add the executable name
     455           16 :   ctx->props_as_argv[0] = g_strdup("gst");
     456              : 
     457              :   void* item;
     458           26 :   for (u32 i = 0; i < g_list_length(ctx->properties); i++) {
     459           10 :     item = g_list_nth_data(ctx->properties, i);
     460           20 :     ctx->props_as_argv[i + 1] = (gchar*)g_strdup(item);
     461              :   }
     462           16 :   for (u32 i = 0; i < g_list_length(override_list); i++) {
     463            0 :     item = g_list_nth_data(override_list, i);
     464            0 :     ctx->props_as_argv[i + 1 + g_list_length(ctx->properties)] = (gchar*)item;
     465              :   }
     466              : 
     467              :   // Add the NULL termination
     468           16 :   ctx->props_as_argv[num_properties - 1] = NULL;
     469              : 
     470              :   // Set the gpac system arguments
     471           16 :   gpac_return_val_if_fail(
     472              :     gf_sys_set_args((s32)num_properties - 1, (const char**)ctx->props_as_argv),
     473              :     FALSE);
     474              : 
     475           16 :   return TRUE;
     476              : }
        

Generated by: LCOV version 2.0-1