LCOV - code coverage report
Current view: top level - src/lib/session.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 47.2 % 163 77
Test Date: 2025-09-18 00:43:48 Functions: 75.0 % 8 6

            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/session.h"
      27              : #include "lib/memio.h"
      28              : #include <gpac/list.h>
      29              : 
      30              : #define SEP_LINK 5
      31              : #define SEP_FRAG 2
      32              : 
      33              : GF_Err
      34            0 : process_link_directive(char* link,
      35              :                        GF_Filter* filter,
      36              :                        GF_List* loaded_filters,
      37              :                        char* ext_link)
      38              : {
      39            0 :   char* link_prev_filter_ext = NULL;
      40              :   GF_Filter* link_from;
      41            0 :   Bool reverse_order = GF_FALSE;
      42            0 :   s32 link_filter_idx = -1;
      43              : 
      44            0 :   if (!filter) {
      45            0 :     u32 idx = 0, count = gf_list_count(loaded_filters);
      46            0 :     if (!ext_link || !count)
      47            0 :       return GF_BAD_PARAM;
      48            0 :     ext_link[0] = 0;
      49            0 :     if (link[1] == GF_FS_DEFAULT_SEPS[SEP_LINK])
      50            0 :       idx = (u32)strtoul(link + 2, NULL, 10);
      51              :     else {
      52            0 :       idx = (u32)strtoul(link + 1, NULL, 10);
      53            0 :       if (count - 1 < idx)
      54            0 :         return GF_BAD_PARAM;
      55            0 :       idx = count - 1 - idx;
      56              :     }
      57            0 :     ext_link[0] = GF_FS_DEFAULT_SEPS[SEP_LINK];
      58            0 :     filter = gf_list_get(loaded_filters, idx);
      59            0 :     link = ext_link;
      60              :   }
      61              : 
      62            0 :   char* ext = strchr(link, GF_FS_DEFAULT_SEPS[SEP_FRAG]);
      63            0 :   if (ext) {
      64            0 :     ext[0] = 0;
      65            0 :     link_prev_filter_ext = ext + 1;
      66              :   }
      67            0 :   if (strlen(link) > 1) {
      68            0 :     if (link[1] == GF_FS_DEFAULT_SEPS[SEP_LINK]) {
      69            0 :       reverse_order = GF_TRUE;
      70            0 :       link++;
      71              :     }
      72            0 :     link_filter_idx = 0;
      73            0 :     if (strlen(link) > 1) {
      74            0 :       link_filter_idx = (s32)strtol(link + 1, NULL, 10);
      75            0 :       if (link_filter_idx < 0)
      76            0 :         return GF_BAD_PARAM;
      77              :     }
      78              :   } else
      79            0 :     link_filter_idx = 0;
      80            0 :   if (ext)
      81            0 :     ext[0] = GF_FS_DEFAULT_SEPS[SEP_FRAG];
      82              : 
      83            0 :   if (reverse_order)
      84            0 :     link_from = gf_list_get(loaded_filters, (u32)link_filter_idx);
      85              :   else
      86            0 :     link_from = gf_list_get(
      87            0 :       loaded_filters, gf_list_count(loaded_filters) - 1 - (u32)link_filter_idx);
      88              : 
      89            0 :   if (!link_from)
      90            0 :     return GF_BAD_PARAM;
      91            0 :   gf_filter_set_source(filter, link_from, link_prev_filter_ext);
      92            0 :   return GF_OK;
      93              : }
      94              : 
      95              : gboolean
      96           16 : gpac_session_init(GPAC_SessionContext* ctx,
      97              :                   GstElement* element,
      98              :                   GstGpacParams* params)
      99              : {
     100           16 :   ctx->session = gf_fs_new_defaults(GF_FS_FLAG_NON_BLOCKING);
     101           16 :   ctx->element = element;
     102           16 :   ctx->params = params;
     103           16 :   return ctx->session != NULL;
     104              : }
     105              : 
     106              : gboolean
     107           16 : gpac_session_close(GPAC_SessionContext* ctx, gboolean print_stats)
     108              : {
     109           16 :   if (ctx->session) {
     110           16 :     if (ctx->had_data_flow) {
     111              :       // Run the filter chain until the end
     112           14 :       gpac_session_run(ctx, TRUE);
     113              :     }
     114              : 
     115              :     // Stop the session
     116           16 :     gf_fs_stop(ctx->session);
     117              : 
     118              :     // Print session stats
     119           16 :     if (print_stats) {
     120            0 :       gf_log_set_tools_levels("app@info", 1);
     121            0 :       gf_fs_print_connections(ctx->session);
     122            0 :       gf_fs_print_stats(ctx->session);
     123            0 :       gf_log_set_tools_levels("app@warning", 1);
     124              :     }
     125              : 
     126           16 :     gpac_memio_free(ctx);
     127              : 
     128              :     // Reset the session context
     129           16 :     gf_fs_del(ctx->session);
     130           16 :     ctx->session = NULL;
     131           16 :     ctx->memin = NULL;
     132              :   }
     133           16 :   return TRUE;
     134              : }
     135              : 
     136              : void
     137           16 : gpac_session_abort(GPAC_SessionContext* ctx)
     138              : {
     139           16 :   if (ctx->session)
     140           16 :     gf_fs_abort(ctx->session, GF_FS_FLUSH_FAST);
     141           16 : }
     142              : 
     143              : GF_Err
     144         2525 : gpac_session_run(GPAC_SessionContext* ctx, gboolean flush)
     145              : {
     146         2525 :   if (!ctx->session)
     147            0 :     return GF_BAD_PARAM;
     148         2525 :   gf_filter_post_process_task(ctx->memin);
     149              : 
     150         2525 :   GF_Err e = GF_OK;
     151         2525 :   guint32 steps = 100;
     152              :   do {
     153       252553 :     e = gf_fs_run(ctx->session);
     154       252553 :   } while (!gf_fs_is_last_task(ctx->session) &&
     155       252298 :            (flush || (e == GF_OK && steps--)));
     156              : 
     157              :   // Check errors
     158         2525 :   e = gf_fs_get_last_connect_error(ctx->session);
     159         2525 :   if (e != GF_OK) {
     160            0 :     GST_ELEMENT_ERROR(ctx->element,
     161              :                       LIBRARY,
     162              :                       FAILED,
     163              :                       ("Failed to connect filters: %s", gf_error_to_string(e)),
     164              :                       (NULL));
     165            0 :     return e;
     166              :   }
     167         2525 :   e = gf_fs_get_last_process_error(ctx->session);
     168         2525 :   if (e != GF_OK) {
     169            0 :     GST_ELEMENT_ERROR(ctx->element,
     170              :                       LIBRARY,
     171              :                       FAILED,
     172              :                       ("Failed to process filters: %s", gf_error_to_string(e)),
     173              :                       (NULL));
     174            0 :     return e;
     175              :   }
     176              : 
     177              :   // Mark that we had data flow
     178         2525 :   if (!flush)
     179         2498 :     ctx->had_data_flow = TRUE;
     180              : 
     181         2525 :   return GF_OK;
     182              : }
     183              : 
     184              : GF_Err
     185           16 : gpac_session_open(GPAC_SessionContext* ctx, gchar* graph)
     186              : {
     187              :   // Initialize the variables
     188           16 :   GF_Err e = GF_OK;
     189              : 
     190              :   // Check if the session is initialized
     191           16 :   if (G_UNLIKELY(!ctx->session)) {
     192            0 :     GST_ELEMENT_ERROR(
     193              :       ctx->element,
     194              :       STREAM,
     195              :       FAILED,
     196              :       (NULL),
     197              :       ("Failed to open gpac filter session, session not initialized"));
     198            0 :     return GF_BAD_PARAM;
     199              :   }
     200              : 
     201           16 :   if (!graph)
     202            0 :     return GF_OK;
     203              : 
     204              :   // Load the graph
     205           16 :   GF_List* links_directives = gf_list_new();
     206           16 :   GF_List* loaded_filters = gf_list_new();
     207           16 :   gchar** nodes = g_strsplit(graph, " ", -1);
     208              : 
     209              :   // We must have a memory input filter, add it so that it can be referenced
     210           16 :   if (!ctx->memin) {
     211            0 :     GST_ELEMENT_ERROR(ctx->element,
     212              :                       LIBRARY,
     213              :                       FAILED,
     214              :                       (NULL),
     215              :                       ("Memory input filter is missing"));
     216            0 :     return GF_BAD_PARAM;
     217              :   }
     218           16 :   gf_list_add(loaded_filters, ctx->memin);
     219              : 
     220              :   // Loop through the nodes
     221           32 :   for (guint i = 0; nodes[i]; i++) {
     222           16 :     GF_Filter* filter = NULL;
     223           16 :     gboolean f_loaded = FALSE;
     224           16 :     gchar* node = nodes[i];
     225              : 
     226              :     // Check if this is an input or output node
     227           16 :     if (!strcmp(node, "-i")) {
     228            0 :       filter = gf_fs_load_source(ctx->session, nodes[++i], NULL, NULL, &e);
     229            0 :       f_loaded = TRUE;
     230           16 :     } else if (!strcmp(node, "-o")) {
     231            3 :       filter = gf_fs_load_destination(ctx->session, nodes[++i], NULL, NULL, &e);
     232            3 :       f_loaded = TRUE;
     233              :     } else {
     234           13 :       if (node[0] == '-') {
     235            0 :         GST_ELEMENT_WARNING(
     236              :           ctx->element,
     237              :           STREAM,
     238              :           FAILED,
     239              :           (NULL),
     240              :           ("Cannot parse global option within graph: %s", node));
     241              :       }
     242              :     }
     243              : 
     244           16 :     if (!f_loaded) {
     245           13 :       if (node[0] == GF_FS_DEFAULT_SEPS[SEP_LINK]) {
     246            0 :         char* next_sep = NULL;
     247            0 :         if (node[1] == GF_FS_DEFAULT_SEPS[SEP_LINK])
     248            0 :           next_sep = strchr(node + 2, GF_FS_DEFAULT_SEPS[SEP_LINK]);
     249              :         else
     250            0 :           next_sep = strchr(node + 1, GF_FS_DEFAULT_SEPS[SEP_LINK]);
     251            0 :         if (next_sep) {
     252            0 :           if (process_link_directive(node, NULL, loaded_filters, next_sep)) {
     253            0 :             GST_ERROR("Failed to process link directive: %s", node);
     254            0 :             e = GF_BAD_PARAM;
     255            0 :             goto finish;
     256              :           }
     257            0 :           continue;
     258              :         }
     259            0 :         gf_list_add(links_directives, node);
     260            0 :         continue;
     261              :       }
     262              : 
     263           13 :       if (ctx->destination) {
     264            1 :         if (strstr(node, "dasher")) {
     265              :           // We need to append "mname" option to the filter name
     266            1 :           const gchar* dst = ctx->destination;
     267            1 :           const gchar* after_slash = strrchr(ctx->destination, '/');
     268            1 :           dst = after_slash ? after_slash + 1 : ctx->destination;
     269            1 :           gchar* new_node = g_strdup_printf("%s:gpac:mname=%s", node, dst);
     270            1 :           node = new_node;
     271              :         }
     272              :       }
     273              : 
     274           13 :       filter = gf_fs_load_filter(ctx->session, node, &e);
     275              :     }
     276              : 
     277           16 :     if (G_UNLIKELY(!filter)) {
     278            0 :       GST_ERROR(
     279              :         "Failed to load filter \"%s\": %s", node, gf_error_to_string(e));
     280            0 :       e = GF_BAD_PARAM;
     281            0 :       goto finish;
     282              :     }
     283              : 
     284           16 :     while (gf_list_count(links_directives)) {
     285            0 :       char* link = gf_list_pop_front(links_directives);
     286            0 :       if (process_link_directive(link, filter, loaded_filters, NULL)) {
     287            0 :         GST_ERROR("Failed to process link directive: %s", link);
     288            0 :         e = GF_BAD_PARAM;
     289            0 :         goto finish;
     290              :       }
     291              :     }
     292           16 :     gf_list_add(loaded_filters, filter);
     293              :   }
     294              : 
     295           16 : finish:
     296           16 :   gf_list_del(links_directives);
     297           16 :   gf_list_del(loaded_filters);
     298           16 :   g_strfreev(nodes);
     299              : 
     300           16 :   return e;
     301              : }
     302              : 
     303              : GF_Filter*
     304            0 : gpac_session_load_filter(GPAC_SessionContext* ctx, const gchar* filter_name)
     305              : {
     306            0 :   GF_Err e = GF_OK;
     307            0 :   GF_Filter* filter = gf_fs_load_filter(ctx->session, filter_name, &e);
     308            0 :   if (!filter) {
     309            0 :     GST_ELEMENT_ERROR(
     310              :       ctx->element,
     311              :       STREAM,
     312              :       FAILED,
     313              :       ("Failed to load filter \"%s\": %s", filter_name, gf_error_to_string(e)),
     314              :       (NULL));
     315              :   }
     316            0 :   return filter;
     317              : }
     318              : 
     319              : gboolean
     320           16 : gpac_session_has_output(GPAC_SessionContext* ctx)
     321              : {
     322           16 :   u32 count = gf_fs_get_filters_count(ctx->session);
     323           16 :   for (u32 i = 0; i < count; i++) {
     324           16 :     GF_Filter* filter = gf_fs_get_filter(ctx->session, i);
     325           16 :     if (gf_filter_is_sink(filter))
     326           16 :       return TRUE;
     327              :   }
     328            0 :   return FALSE;
     329              : }
        

Generated by: LCOV version 2.0-1