LCOV - code coverage report
Current view: top level - src/lib/memio.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 80.0 % 220 176
Test Date: 2025-11-16 07:16:50 Functions: 93.3 % 15 14

            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/memio.h"
      27              : #include "gpacmessages.h"
      28              : #include "lib/caps.h"
      29              : #include "lib/pid.h"
      30              : #include "post-process/common.h"
      31              : #include "post-process/registry.h"
      32              : #include <gst/video/video-event.h>
      33              : 
      34              : static GF_Err
      35              : gpac_default_memin_process_cb(GF_Filter* filter);
      36              : 
      37              : static Bool
      38              : gpac_default_memin_process_event_cb(GF_Filter* filter,
      39              :                                     const GF_FilterEvent* evt);
      40              : 
      41              : static GF_Err
      42              : gpac_default_memout_initialize_cb(GF_Filter* filter);
      43              : 
      44              : static GF_Err
      45              : gpac_default_memout_process_cb(GF_Filter* filter);
      46              : 
      47              : static Bool
      48              : gpac_default_memout_process_event_cb(GF_Filter* filter,
      49              :                                      const GF_FilterEvent* evt);
      50              : 
      51              : static Bool
      52              : gpac_default_memout_use_alias_cb(GF_Filter* filter,
      53              :                                  const char* url,
      54              :                                  const char* mime);
      55              : 
      56              : static GF_FilterProbeScore
      57              : gpac_default_memout_probe_url_cb(const char* url, const char* mime);
      58              : 
      59              : static GF_Err
      60              : gpac_default_memout_configure_pid_cb(GF_Filter* filter,
      61              :                                      GF_FilterPid* PID,
      62              :                                      Bool is_remove);
      63              : 
      64              : static const GF_FilterCapability DefaultMemOutCaps[] = {
      65              :   CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
      66              :   CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "*"),
      67              : };
      68              : 
      69              : #define OFFS(_n) #_n, offsetof(GPAC_MemOutPrivateContext, _n)
      70              : static const GF_FilterArgs MemoutArgs[] = {
      71              :   { OFFS(dst),
      72              :     "location of destination resource",
      73              :     GF_PROP_NAME,
      74              :     NULL,
      75              :     NULL,
      76              :     0 },
      77              :   { OFFS(ext), "file extension", GF_PROP_NAME, NULL, NULL, 0 },
      78              :   { 0 }
      79              : };
      80              : 
      81              : GF_FilterRegister MemOutRegister = {
      82              :   .name = "memout",
      83              :   .args = MemoutArgs,
      84              :   .private_size = sizeof(GPAC_MemOutPrivateContext),
      85              :   .max_extra_pids = -1,
      86              :   .priority = -1,
      87              :   .flags =
      88              :     GF_FS_REG_FORCE_REMUX | GF_FS_REG_TEMP_INIT | GF_FS_REG_EXPLICIT_ONLY,
      89              :   .caps = DefaultMemOutCaps,
      90              :   .nb_caps = G_N_ELEMENTS(DefaultMemOutCaps),
      91              :   .initialize = gpac_default_memout_initialize_cb,
      92              :   .process = gpac_default_memout_process_cb,
      93              :   .process_event = gpac_default_memout_process_event_cb,
      94              :   .use_alias = gpac_default_memout_use_alias_cb,
      95              :   .probe_url = gpac_default_memout_probe_url_cb,
      96              :   .configure_pid = gpac_default_memout_configure_pid_cb,
      97              : };
      98              : 
      99              : GF_Err
     100           29 : gpac_memio_new(GPAC_SessionContext* sess, GPAC_MemIoDirection dir)
     101              : {
     102           29 :   GF_Err e = GF_OK;
     103           29 :   GF_Filter* memio = NULL;
     104              : 
     105           29 :   if (dir == GPAC_MEMIO_DIR_IN) {
     106           16 :     memio = sess->memin = gf_fs_new_filter(sess->session, "memin", 0, &e);
     107           16 :     if (!sess->memin) {
     108            0 :       GST_ELEMENT_ERROR(sess->element,
     109              :                         LIBRARY,
     110              :                         INIT,
     111              :                         (NULL),
     112              :                         ("Failed to create memin filter"));
     113            0 :       return e;
     114              :     }
     115           16 :     gf_filter_set_process_ckb(memio, gpac_default_memin_process_cb);
     116           16 :     gf_filter_set_process_event_ckb(memio, gpac_default_memin_process_event_cb);
     117              :   } else {
     118           13 :     gf_fs_add_filter_register(sess->session, &MemOutRegister);
     119           13 :     gchar* filter_name = "memout";
     120           13 :     gboolean link_to_last_filter = sess->params && sess->params->is_single;
     121              : 
     122              :     // Try to retrieve a destination
     123           13 :     const gchar* dst = NULL;
     124           13 :     if (sess->destination) {
     125              :       // If a destination is provided, use it
     126            1 :       dst = sess->destination;
     127            1 :       link_to_last_filter = TRUE;
     128           12 :     } else if (sess->params && sess->params->info &&
     129           12 :                sess->params->info->destination) {
     130              :       // If the session parameters have a destination, use it
     131            1 :       dst = sess->params->info->destination;
     132              :     }
     133              : 
     134              :     // If we have a specific destination, use it
     135           13 :     if (dst)
     136            2 :       filter_name = g_strdup_printf("memout:dst=%s", dst);
     137              : 
     138           13 :     memio = sess->memout = gf_fs_load_filter(sess->session, filter_name, &e);
     139           13 :     if (!sess->memout) {
     140            0 :       GST_ELEMENT_ERROR(
     141              :         sess->element, LIBRARY, INIT, (NULL), ("Failed to load memout filter"));
     142            0 :       return e;
     143              :     }
     144              : 
     145              :     // If we are in single filter mode (explicit destination), we explicitly
     146              :     // connect to the last loaded filter to avoid connecting to the memin filter
     147              :     // unnecessarily
     148           13 :     if (link_to_last_filter) {
     149           13 :       u32 count = gf_fs_get_filters_count(sess->session);
     150           13 :       GF_Filter* filter = gf_fs_get_filter(sess->session, count - 2);
     151           13 :       if (filter) {
     152              :         // Connect the memout filter to the last filter
     153           13 :         if (gf_filter_set_source(memio, filter, NULL) != GF_OK) {
     154            0 :           GST_ELEMENT_ERROR(sess->element,
     155              :                             LIBRARY,
     156              :                             INIT,
     157              :                             (NULL),
     158              :                             ("Failed to connect memout filter to the last "
     159              :                              "loaded filter %s",
     160              :                              gf_filter_get_name(filter)));
     161            0 :           return GF_BAD_PARAM;
     162              :         }
     163              :       } else {
     164            0 :         GST_ELEMENT_ERROR(sess->element,
     165              :                           LIBRARY,
     166              :                           INIT,
     167              :                           (NULL),
     168              :                           ("No filters found in the session"));
     169            0 :         return GF_BAD_PARAM;
     170              :       }
     171              :     }
     172              :   }
     173              : 
     174              :   // Set the runtime user data
     175           29 :   GPAC_MemIoContext* rt_udta = g_new0(GPAC_MemIoContext, 1);
     176           29 :   if (!rt_udta) {
     177            0 :     GST_ELEMENT_ERROR(sess->element,
     178              :                       LIBRARY,
     179              :                       INIT,
     180              :                       (NULL),
     181              :                       ("Failed to allocate memory for runtime user data"));
     182            0 :     return GF_OUT_OF_MEM;
     183              :   }
     184           29 :   gpac_return_if_fail(gf_filter_set_rt_udta(memio, rt_udta));
     185           29 :   rt_udta->dir = dir;
     186           29 :   rt_udta->global_offset = GST_CLOCK_TIME_NONE;
     187           29 :   rt_udta->sess = sess;
     188              : 
     189           29 :   return e;
     190              : }
     191              : 
     192              : void
     193           16 : gpac_memio_free(GPAC_SessionContext* sess)
     194              : {
     195           16 :   if (sess->memin)
     196           16 :     gf_free(gf_filter_get_rt_udta(sess->memin));
     197              : 
     198           16 :   if (sess->memout)
     199           13 :     gf_free(gf_filter_get_rt_udta(sess->memout));
     200           16 : }
     201              : 
     202              : void
     203           16 : gpac_memio_assign_queue(GPAC_SessionContext* sess,
     204              :                         GPAC_MemIoDirection dir,
     205              :                         GQueue* queue)
     206              : {
     207           16 :   GPAC_MemIoContext* rt_udta = gf_filter_get_rt_udta(
     208              :     dir == GPAC_MEMIO_DIR_IN ? sess->memin : sess->memout);
     209           16 :   if (!rt_udta) {
     210            0 :     GST_ELEMENT_ERROR(sess->element,
     211              :                       LIBRARY,
     212              :                       FAILED,
     213              :                       (NULL),
     214              :                       ("Failed to get runtime user data"));
     215            0 :     return;
     216              :   }
     217           16 :   rt_udta->queue = queue;
     218              : }
     219              : 
     220              : void
     221           36 : gpac_memio_set_eos(GPAC_SessionContext* sess, GF_FilterPid* pid)
     222              : {
     223           36 :   if (!sess->memin)
     224            0 :     return;
     225              : 
     226              :   // Set the EOS flag on the specific PID if provided
     227           36 :   if (pid) {
     228           20 :     gf_filter_pid_set_eos(pid);
     229              :   } else {
     230              :     // Set the EOS flag on all PIDs
     231           39 :     for (u32 i = 0; i < gf_filter_get_opid_count(sess->memin); i++) {
     232           23 :       GF_FilterPid* opid = gf_filter_get_opid(sess->memin, i);
     233           23 :       gf_filter_pid_set_eos(opid);
     234              :     }
     235              :   }
     236              : }
     237              : 
     238              : gboolean
     239           12 : gpac_memio_set_gst_caps(GPAC_SessionContext* sess, GstCaps* caps)
     240              : {
     241           12 :   if (!sess->memout)
     242            3 :     return TRUE;
     243              : 
     244              :   // Save the current caps
     245            9 :   guint cur_nb_caps = 0;
     246              :   const GF_FilterCapability* current_caps =
     247            9 :     gf_filter_get_caps(sess->memout, &cur_nb_caps);
     248              : 
     249              :   // Convert the caps to GF_FilterCapability
     250            9 :   guint new_nb_caps = 0;
     251            9 :   GF_FilterCapability* gf_caps = gpac_gstcaps_to_gfcaps(caps, &new_nb_caps);
     252            9 :   if (!gf_caps) {
     253            0 :     GST_ELEMENT_ERROR(sess->element,
     254              :                       STREAM,
     255              :                       FAILED,
     256              :                       (NULL),
     257              :                       ("Failed to convert the caps to GF_FilterCapability"));
     258            0 :     return FALSE;
     259              :   }
     260              : 
     261              :   // Set the capabilities
     262            9 :   if (gf_filter_override_caps(sess->memout, gf_caps, new_nb_caps) != GF_OK) {
     263            0 :     GST_ELEMENT_ERROR(sess->element,
     264              :                       STREAM,
     265              :                       FAILED,
     266              :                       (NULL),
     267              :                       ("Failed to set the caps on the memory output filter, "
     268              :                        "reverting to the previous caps"));
     269            0 :     gf_free(gf_caps);
     270            0 :     gf_filter_override_caps(sess->memout, current_caps, cur_nb_caps);
     271            0 :     return FALSE;
     272              :   }
     273              : 
     274              :   // Reconnect the pipeline
     275            9 :   u32 count = gf_fs_get_filters_count(sess->session);
     276           36 :   for (u32 i = 0; i < count; i++) {
     277           27 :     GF_Filter* filter = gf_fs_get_filter(sess->session, i);
     278           27 :     gf_filter_reconnect_output(filter, NULL);
     279              :   }
     280              : 
     281            9 :   return TRUE;
     282              : }
     283              : 
     284              : GPAC_FilterPPRet
     285         2529 : gpac_memio_consume(GPAC_SessionContext* sess, void** outptr)
     286              : {
     287         2529 :   if (!sess->memout)
     288           14 :     return GPAC_FILTER_PP_RET_NULL;
     289              : 
     290              :   // Context
     291         2515 :   guint32 pid_to_consume = 0;
     292         2515 :   GF_FilterPid* best_ipid = NULL;
     293         2515 :   GPAC_MemOutPIDContext* best_pctx = NULL;
     294         2515 :   GPAC_FilterPPRet ret = GPAC_FILTER_PP_RET_INVALID;
     295              : 
     296              :   // Find the PID to consume
     297        11410 :   for (u32 i = 0; i < gf_filter_get_ipid_count(sess->memout); i++) {
     298         8895 :     GF_FilterPid* ipid = gf_filter_get_ipid(sess->memout, i);
     299              :     GPAC_MemOutPIDContext* pctx =
     300         8895 :       (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(ipid);
     301         8895 :     GPAC_MemOutPIDFlags udta_flags = gf_filter_pid_get_udta_flags(ipid);
     302              : 
     303              :     // If we should not consume this PID, call the consume callback
     304              :     // and continue to the next one
     305         8895 :     if (udta_flags & GPAC_MEMOUT_PID_FLAG_DONT_CONSUME) {
     306         7975 :       ret |= pctx->entry->consume(sess->memout, ipid, NULL);
     307         7975 :       continue;
     308              :     }
     309              : 
     310              :     // Check if there are more than one PID to consume
     311          920 :     if (pid_to_consume > 0) {
     312            0 :       GST_ELEMENT_ERROR(sess->element,
     313              :                         STREAM,
     314              :                         FAILED,
     315              :                         (NULL),
     316              :                         ("Multiple PIDs to consume, this is not supported by "
     317              :                          "the memout filter"));
     318            0 :       return GPAC_FILTER_PP_RET_ERROR;
     319              :     }
     320              : 
     321              :     // We can consume this PID
     322          920 :     pid_to_consume++;
     323          920 :     best_ipid = ipid;
     324          920 :     best_pctx = pctx;
     325              :   }
     326              : 
     327         2515 :   if (!best_ipid) {
     328         1595 :     *outptr = NULL;
     329              :     // No PID to consume
     330              :     return ret == GPAC_FILTER_PP_RET_INVALID
     331              :              ? GPAC_FILTER_PP_RET_EMPTY
     332         1595 :              : ret; // If we have a signal, return it
     333              :   }
     334              : 
     335              :   // We can consume the PID
     336          920 :   ret |= best_pctx->entry->consume(sess->memout, best_ipid, outptr);
     337          920 :   return ret;
     338              : }
     339              : 
     340              : void
     341           20 : gpac_memio_set_global_offset(GPAC_SessionContext* sess,
     342              :                              const GstSegment* segment)
     343              : {
     344           20 :   if (!sess->memout)
     345            3 :     return;
     346              : 
     347           17 :   GPAC_MemIoContext* ctx = gf_filter_get_rt_udta(sess->memout);
     348           17 :   if (!ctx) {
     349            0 :     GST_ELEMENT_ERROR(sess->element,
     350              :                       LIBRARY,
     351              :                       FAILED,
     352              :                       (NULL),
     353              :                       ("Failed to get runtime user data"));
     354            0 :     return;
     355              :   }
     356              : 
     357              :   // Get the segment offset
     358           17 :   guint64 offset = segment->base + segment->start + segment->offset;
     359           17 :   if (offset == GST_CLOCK_TIME_NONE)
     360            0 :     return;
     361           17 :   if (ctx->global_offset == GST_CLOCK_TIME_NONE || !ctx->is_continuous) {
     362           17 :     ctx->global_offset = MIN(offset, ctx->global_offset);
     363            0 :   } else if (ctx->global_offset > offset) {
     364            0 :     GST_ELEMENT_WARNING(
     365              :       sess->element,
     366              :       STREAM,
     367              :       FAILED,
     368              :       (NULL),
     369              :       ("Cannot set a global offset smaller than the current one"));
     370              :   }
     371              : }
     372              : 
     373              : //////////////////////////////////////////////////////////////////////////
     374              : // #MARK: Default Callbacks
     375              : //////////////////////////////////////////////////////////////////////////
     376              : static GF_Err
     377       224171 : gpac_default_memin_process_cb(GF_Filter* filter)
     378              : {
     379       224171 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     380              : 
     381              :   // Flush the queue
     382       224171 :   GF_FilterPacket* packet = NULL;
     383       230695 :   while ((packet = g_queue_pop_head(ctx->queue)))
     384         6524 :     gf_filter_pck_send(packet);
     385              : 
     386       224171 :   return GF_OK;
     387              : }
     388              : 
     389              : static Bool
     390           29 : gpac_default_memin_process_event_cb(GF_Filter* filter,
     391              :                                     const GF_FilterEvent* evt)
     392              : {
     393           29 :   if (evt->base.type == GF_FEVT_TRANSPORT_HINTS) {
     394            8 :     GF_FilterPid* pid = evt->base.on_pid;
     395            8 :     GF_Fraction intra_period = evt->transport_hints.seg_duration;
     396            8 :     GpacPadPrivate* priv = gf_filter_pid_get_udta(pid);
     397            8 :     GstElement* element = gst_pad_get_parent_element(priv->self);
     398              : 
     399              :     // Set the IDR period
     400            8 :     priv->idr_period =
     401            8 :       gf_timestamp_rescale(intra_period.num, intra_period.den, GST_SECOND);
     402              : 
     403              :     // Determine the next IDR frame
     404            8 :     if (priv->idr_last != GST_CLOCK_TIME_NONE) {
     405            0 :       priv->idr_next = priv->idr_last + priv->idr_period;
     406              : 
     407              :       // Request a new IDR, immediately
     408              :       GstEvent* gst_event =
     409            0 :         gst_video_event_new_upstream_force_key_unit(priv->idr_next, TRUE, 1);
     410            0 :       if (!gst_pad_push_event(priv->self, gst_event)) {
     411            0 :         GST_ELEMENT_WARNING(element,
     412              :                             STREAM,
     413              :                             FAILED,
     414              :                             (NULL),
     415              :                             ("Failed to push the force key unit event"));
     416              :       }
     417              :     }
     418              : 
     419            8 :     return GF_TRUE;
     420              :   }
     421           21 :   return GF_FALSE;
     422              : }
     423              : 
     424              : static GF_Err
     425           21 : gpac_default_memout_initialize_cb(GF_Filter* filter)
     426              : {
     427              :   GPAC_MemOutPrivateContext* ctx =
     428           21 :     (GPAC_MemOutPrivateContext*)gf_filter_get_udta(filter);
     429              : 
     430              :   // ext only used if not an alias, otherwise figure out from dst
     431           21 :   const char* ext = gf_filter_is_alias(filter) ? NULL : ctx->ext;
     432           21 :   if (!ext && ctx->dst) {
     433           10 :     ext = gf_file_ext_start(ctx->dst);
     434           10 :     if (ext)
     435           10 :       ext++;
     436              :   }
     437              : 
     438           21 :   GF_LOG(GF_LOG_INFO,
     439              :          GF_LOG_CORE,
     440              :          ("memout initialize ext %s dst %s is_alias %d\n",
     441              :           ext ? ext : "none",
     442              :           ctx->dst ? ctx->dst : "none",
     443              :           gf_filter_is_alias(filter)));
     444           21 :   if (!ext)
     445           11 :     return GF_OK;
     446              : 
     447           10 :   ctx->caps[0].code = GF_PROP_PID_STREAM_TYPE;
     448           10 :   ctx->caps[0].val = PROP_UINT(GF_STREAM_FILE);
     449           10 :   ctx->caps[0].flags = GF_CAPS_INPUT;
     450              : 
     451           10 :   ctx->caps[1].code = GF_PROP_PID_FILE_EXT;
     452           10 :   ctx->caps[1].val = PROP_STRING(ext);
     453           10 :   ctx->caps[1].flags = GF_CAPS_INPUT;
     454           10 :   gf_filter_override_caps(filter, ctx->caps, 2);
     455              : 
     456           10 :   return GF_OK;
     457              : }
     458              : 
     459              : static GF_Err
     460          274 : gpac_default_memout_process_cb(GF_Filter* filter)
     461              : {
     462          274 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     463              : 
     464         1108 :   for (u32 i = 0; i < gf_filter_get_ipid_count(filter); i++) {
     465          834 :     GF_Err e = GF_OK;
     466          834 :     GF_FilterPid* ipid = gf_filter_get_ipid(filter, i);
     467              :     GPAC_MemOutPIDContext* pctx =
     468          834 :       (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(ipid);
     469              : 
     470              :     // Get the packet
     471          834 :     GF_FilterPacket* pck = gf_filter_pid_get_packet(ipid);
     472              : 
     473              :     // If we have a post-process context, process the packet
     474          834 :     if (pctx && pctx->entry)
     475          834 :       e = pctx->entry->post_process(filter, ipid, pck);
     476              : 
     477          834 :     if (pck)
     478          223 :       gf_filter_pid_drop_packet(ipid);
     479          834 :     if (e != GF_OK)
     480            0 :       return e;
     481              :   }
     482              : 
     483          274 :   return GF_OK;
     484              : }
     485              : 
     486              : static Bool
     487            0 : gpac_default_memout_process_event_cb(GF_Filter* filter,
     488              :                                      const GF_FilterEvent* evt)
     489              : {
     490              :   GPAC_MemOutPIDContext* pctx =
     491            0 :     (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(evt->base.on_pid);
     492              : 
     493              :   // If we have a post-process context, process the event
     494            0 :   if (pctx && pctx->entry)
     495            0 :     return pctx->entry->process_event(filter, evt);
     496            0 :   return GF_FALSE; // No post-process context, do not process the event
     497              : }
     498              : 
     499              : static Bool
     500            8 : gpac_default_memout_use_alias_cb(GF_Filter* filter,
     501              :                                  const char* url,
     502              :                                  const char* mime)
     503              : {
     504            8 :   return GF_TRUE; // Always allow alias usage
     505              : }
     506              : 
     507              : static GF_FilterProbeScore
     508            8 : gpac_default_memout_probe_url_cb(const char* url, const char* mime)
     509              : {
     510            8 :   return GF_FPROBE_SUPPORTED; // Support everything
     511              : }
     512              : 
     513              : static GF_Err
     514           19 : gpac_default_memout_configure_pid_cb(GF_Filter* filter,
     515              :                                      GF_FilterPid* pid,
     516              :                                      Bool is_remove)
     517              : {
     518           19 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     519           19 :   GPAC_MemOutPIDContext* pctx = gf_filter_pid_get_udta(pid);
     520           19 :   GPAC_MemOutPIDFlags udta = gf_filter_pid_get_udta_flags(pid);
     521              : 
     522           19 :   if (is_remove) {
     523            0 :     if (pctx) {
     524              :       // Free the post-process context if it exists
     525            0 :       if (pctx->entry)
     526            0 :         pctx->entry->ctx_free(pctx->private_ctx);
     527            0 :       g_free(pctx);
     528              :     }
     529            0 :     return GF_OK;
     530              :   }
     531              : 
     532           19 :   if (!udta) {
     533              :     GF_FilterEvent evt;
     534           19 :     gf_filter_pid_init_play_event(pid, &evt, 0, 1, "MemOut");
     535           19 :     gf_filter_pid_send_event(pid, &evt);
     536           19 :     gf_filter_pid_set_udta_flags(pid, GPAC_MEMOUT_PID_FLAG_INITIALIZED);
     537              :   } else {
     538              :     // If the PID is already initialized, we can skip the configuration
     539            0 :     if (udta & GPAC_MEMOUT_PID_FLAG_INITIALIZED) {
     540            0 :       GST_DEBUG_OBJECT(ctx->sess->element,
     541              :                        "PID %s is already initialized, proceeding with "
     542              :                        "configure_pid callback only",
     543              :                        gf_filter_pid_get_name(pid));
     544            0 :       return pctx->entry->configure_pid(filter, pid);
     545              :     }
     546              :   }
     547              : 
     548              :   // Allocate the post-process context
     549           19 :   pctx = g_new0(GPAC_MemOutPIDContext, 1);
     550           19 :   gf_filter_pid_set_udta(pid, pctx);
     551              : 
     552              :   // Check if there is a "dasher" upstream filter
     553           19 :   gboolean has_dasher = FALSE;
     554           19 :   GF_Filter* uf = gf_filter_pid_get_source_filter(pid);
     555           36 :   while (uf) {
     556           36 :     if (g_strcmp0(gf_filter_get_name(uf), "dasher") == 0) {
     557           10 :       has_dasher = TRUE;
     558           10 :       break;
     559              :     }
     560           26 :     GF_FilterPid* upid = gf_filter_get_ipid(uf, 0);
     561           26 :     if (!upid)
     562            9 :       break; // No upstream PID, stop checking
     563           17 :     uf = gf_filter_pid_get_source_filter(upid);
     564              :   }
     565              : 
     566              :   // Decide which post-process context to use
     567           19 :   if (has_dasher) {
     568              :     // If the upstream chain has dasher, we use the DASH post-process context,
     569              :     // regardless of whether it's connected to dasher directly or mp4mx
     570           10 :     pctx->entry = gpac_filter_get_post_process_registry_entry("dasher");
     571              :   } else {
     572              :     // Otherwise, use the post-process context based on connected filter name
     573            9 :     const gchar* source_name = gf_filter_pid_get_filter_name(pid);
     574            9 :     pctx->entry = gpac_filter_get_post_process_registry_entry(source_name);
     575              :   }
     576              : 
     577              :   // Create a new post-process context
     578           19 :   pctx->entry->ctx_init(&pctx->private_ctx);
     579              : 
     580              :   // Configure the PID with the post-process context
     581           19 :   return pctx->entry->configure_pid(filter, pid);
     582              : }
        

Generated by: LCOV version 2.0-1