LCOV - code coverage report
Current view: top level - src/lib/memio.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 79.5 % 224 178
Test Date: 2025-09-18 00:43:48 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           29 : gpac_memio_set_eos(GPAC_SessionContext* sess, gboolean eos)
     222              : {
     223           29 :   if (!sess->memin)
     224            0 :     return;
     225              : 
     226           29 :   GPAC_MemIoContext* rt_udta = gf_filter_get_rt_udta(sess->memin);
     227           29 :   if (!rt_udta) {
     228            0 :     GST_ELEMENT_ERROR(sess->element,
     229              :                       LIBRARY,
     230              :                       FAILED,
     231              :                       (NULL),
     232              :                       ("Failed to get runtime user data"));
     233            0 :     return;
     234              :   }
     235           29 :   rt_udta->eos = eos;
     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         2541 : gpac_memio_consume(GPAC_SessionContext* sess, void** outptr)
     286              : {
     287         2541 :   if (!sess->memout)
     288           14 :     return GPAC_FILTER_PP_RET_NULL;
     289              : 
     290              :   // Context
     291         2527 :   guint32 pid_to_consume = 0;
     292         2527 :   GF_FilterPid* best_ipid = NULL;
     293         2527 :   GPAC_MemOutPIDContext* best_pctx = NULL;
     294         2527 :   GPAC_FilterPPRet ret = GPAC_FILTER_PP_RET_INVALID;
     295              : 
     296              :   // Find the PID to consume
     297        11490 :   for (u32 i = 0; i < gf_filter_get_ipid_count(sess->memout); i++) {
     298         8963 :     GF_FilterPid* ipid = gf_filter_get_ipid(sess->memout, i);
     299              :     GPAC_MemOutPIDContext* pctx =
     300         8963 :       (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(ipid);
     301         8963 :     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         8963 :     if (udta_flags & GPAC_MEMOUT_PID_FLAG_DONT_CONSUME) {
     306         8045 :       ret |= pctx->entry->consume(sess->memout, ipid, NULL);
     307         8045 :       continue;
     308              :     }
     309              : 
     310              :     // Check if there are more than one PID to consume
     311          918 :     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          918 :     pid_to_consume++;
     323          918 :     best_ipid = ipid;
     324          918 :     best_pctx = pctx;
     325              :   }
     326              : 
     327         2527 :   if (!best_ipid) {
     328         1609 :     *outptr = NULL;
     329              :     // No PID to consume
     330              :     return ret == GPAC_FILTER_PP_RET_INVALID
     331              :              ? GPAC_FILTER_PP_RET_EMPTY
     332         1609 :              : ret; // If we have a signal, return it
     333              :   }
     334              : 
     335              :   // We can consume the PID
     336          918 :   ret |= best_pctx->entry->consume(sess->memout, best_ipid, outptr);
     337          918 :   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       226621 : gpac_default_memin_process_cb(GF_Filter* filter)
     378              : {
     379       226621 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     380              : 
     381              :   // Flush the queue
     382       226621 :   GF_FilterPacket* packet = NULL;
     383       233145 :   while ((packet = g_queue_pop_head(ctx->queue)))
     384         6524 :     gf_filter_pck_send(packet);
     385              : 
     386              :   // All packets are sent, check if the EOS is set
     387       226621 :   if (ctx->eos) {
     388              :     // Set the EOS on all output PIDs
     389           33 :     for (guint i = 0; i < gf_filter_get_opid_count(filter); i++)
     390           20 :       gf_filter_pid_set_eos(gf_filter_get_opid(filter, i));
     391           13 :     return GF_EOS;
     392              :   }
     393              : 
     394       226608 :   return GF_OK;
     395              : }
     396              : 
     397              : static Bool
     398           29 : gpac_default_memin_process_event_cb(GF_Filter* filter,
     399              :                                     const GF_FilterEvent* evt)
     400              : {
     401           29 :   if (evt->base.type == GF_FEVT_TRANSPORT_HINTS) {
     402            8 :     GF_FilterPid* pid = evt->base.on_pid;
     403            8 :     GF_Fraction intra_period = evt->transport_hints.seg_duration;
     404            8 :     GpacPadPrivate* priv = gf_filter_pid_get_udta(pid);
     405            8 :     GstElement* element = gst_pad_get_parent_element(priv->self);
     406              : 
     407              :     // Set the IDR period
     408            8 :     priv->idr_period =
     409            8 :       gf_timestamp_rescale(intra_period.num, intra_period.den, GST_SECOND);
     410              : 
     411              :     // Determine the next IDR frame
     412            8 :     if (priv->idr_last != GST_CLOCK_TIME_NONE) {
     413            0 :       priv->idr_next = priv->idr_last + priv->idr_period;
     414              : 
     415              :       // Request a new IDR, immediately
     416              :       GstEvent* gst_event =
     417            0 :         gst_video_event_new_upstream_force_key_unit(priv->idr_next, TRUE, 1);
     418            0 :       if (!gst_pad_push_event(priv->self, gst_event)) {
     419            0 :         GST_ELEMENT_WARNING(element,
     420              :                             STREAM,
     421              :                             FAILED,
     422              :                             (NULL),
     423              :                             ("Failed to push the force key unit event"));
     424              :       }
     425              :     }
     426              : 
     427            8 :     return GF_TRUE;
     428              :   }
     429           21 :   return GF_FALSE;
     430              : }
     431              : 
     432              : static GF_Err
     433           21 : gpac_default_memout_initialize_cb(GF_Filter* filter)
     434              : {
     435              :   GPAC_MemOutPrivateContext* ctx =
     436           21 :     (GPAC_MemOutPrivateContext*)gf_filter_get_udta(filter);
     437              : 
     438              :   // ext only used if not an alias, otherwise figure out from dst
     439           21 :   const char* ext = gf_filter_is_alias(filter) ? NULL : ctx->ext;
     440           21 :   if (!ext && ctx->dst) {
     441           10 :     ext = gf_file_ext_start(ctx->dst);
     442           10 :     if (ext)
     443           10 :       ext++;
     444              :   }
     445              : 
     446           21 :   GF_LOG(GF_LOG_INFO,
     447              :          GF_LOG_CORE,
     448              :          ("memout initialize ext %s dst %s is_alias %d\n",
     449              :           ext ? ext : "none",
     450              :           ctx->dst ? ctx->dst : "none",
     451              :           gf_filter_is_alias(filter)));
     452           21 :   if (!ext)
     453           11 :     return GF_OK;
     454              : 
     455           10 :   ctx->caps[0].code = GF_PROP_PID_STREAM_TYPE;
     456           10 :   ctx->caps[0].val = PROP_UINT(GF_STREAM_FILE);
     457           10 :   ctx->caps[0].flags = GF_CAPS_INPUT;
     458              : 
     459           10 :   ctx->caps[1].code = GF_PROP_PID_FILE_EXT;
     460           10 :   ctx->caps[1].val = PROP_STRING(ext);
     461           10 :   ctx->caps[1].flags = GF_CAPS_INPUT;
     462           10 :   gf_filter_override_caps(filter, ctx->caps, 2);
     463              : 
     464           10 :   return GF_OK;
     465              : }
     466              : 
     467              : static GF_Err
     468          262 : gpac_default_memout_process_cb(GF_Filter* filter)
     469              : {
     470          262 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     471              : 
     472         1036 :   for (u32 i = 0; i < gf_filter_get_ipid_count(filter); i++) {
     473          774 :     GF_Err e = GF_OK;
     474          774 :     GF_FilterPid* ipid = gf_filter_get_ipid(filter, i);
     475              :     GPAC_MemOutPIDContext* pctx =
     476          774 :       (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(ipid);
     477              : 
     478              :     // Get the packet
     479          774 :     GF_FilterPacket* pck = gf_filter_pid_get_packet(ipid);
     480              : 
     481              :     // If we have a post-process context, process the packet
     482          774 :     if (pctx && pctx->entry)
     483          774 :       e = pctx->entry->post_process(filter, ipid, pck);
     484              : 
     485          774 :     if (pck)
     486          211 :       gf_filter_pid_drop_packet(ipid);
     487          774 :     if (e != GF_OK)
     488            0 :       return e;
     489              :   }
     490              : 
     491          262 :   return GF_OK;
     492              : }
     493              : 
     494              : static Bool
     495            0 : gpac_default_memout_process_event_cb(GF_Filter* filter,
     496              :                                      const GF_FilterEvent* evt)
     497              : {
     498              :   GPAC_MemOutPIDContext* pctx =
     499            0 :     (GPAC_MemOutPIDContext*)gf_filter_pid_get_udta(evt->base.on_pid);
     500              : 
     501              :   // If we have a post-process context, process the event
     502            0 :   if (pctx && pctx->entry)
     503            0 :     return pctx->entry->process_event(filter, evt);
     504            0 :   return GF_FALSE; // No post-process context, do not process the event
     505              : }
     506              : 
     507              : static Bool
     508            8 : gpac_default_memout_use_alias_cb(GF_Filter* filter,
     509              :                                  const char* url,
     510              :                                  const char* mime)
     511              : {
     512            8 :   return GF_TRUE; // Always allow alias usage
     513              : }
     514              : 
     515              : static GF_FilterProbeScore
     516            8 : gpac_default_memout_probe_url_cb(const char* url, const char* mime)
     517              : {
     518            8 :   return GF_FPROBE_SUPPORTED; // Support everything
     519              : }
     520              : 
     521              : static GF_Err
     522           19 : gpac_default_memout_configure_pid_cb(GF_Filter* filter,
     523              :                                      GF_FilterPid* pid,
     524              :                                      Bool is_remove)
     525              : {
     526           19 :   GPAC_MemIoContext* ctx = (GPAC_MemIoContext*)gf_filter_get_rt_udta(filter);
     527           19 :   GPAC_MemOutPIDContext* pctx = gf_filter_pid_get_udta(pid);
     528           19 :   GPAC_MemOutPIDFlags udta = gf_filter_pid_get_udta_flags(pid);
     529              : 
     530           19 :   if (is_remove) {
     531            0 :     if (pctx) {
     532              :       // Free the post-process context if it exists
     533            0 :       if (pctx->entry)
     534            0 :         pctx->entry->ctx_free(pctx->private_ctx);
     535            0 :       g_free(pctx);
     536              :     }
     537            0 :     return GF_OK;
     538              :   }
     539              : 
     540           19 :   if (!udta) {
     541              :     GF_FilterEvent evt;
     542           19 :     gf_filter_pid_init_play_event(pid, &evt, 0, 1, "MemOut");
     543           19 :     gf_filter_pid_send_event(pid, &evt);
     544           19 :     gf_filter_pid_set_udta_flags(pid, GPAC_MEMOUT_PID_FLAG_INITIALIZED);
     545              :   } else {
     546              :     // If the PID is already initialized, we can skip the configuration
     547            0 :     if (udta & GPAC_MEMOUT_PID_FLAG_INITIALIZED) {
     548            0 :       GST_DEBUG_OBJECT(ctx->sess->element,
     549              :                        "PID %s is already initialized, proceeding with "
     550              :                        "configure_pid callback only",
     551              :                        gf_filter_pid_get_name(pid));
     552            0 :       return pctx->entry->configure_pid(filter, pid);
     553              :     }
     554              :   }
     555              : 
     556              :   // Allocate the post-process context
     557           19 :   pctx = g_new0(GPAC_MemOutPIDContext, 1);
     558           19 :   gf_filter_pid_set_udta(pid, pctx);
     559              : 
     560              :   // Check if there is a "dasher" upstream filter
     561           19 :   gboolean has_dasher = FALSE;
     562           19 :   GF_Filter* uf = gf_filter_pid_get_source_filter(pid);
     563           36 :   while (uf) {
     564           36 :     if (g_strcmp0(gf_filter_get_name(uf), "dasher") == 0) {
     565           10 :       has_dasher = TRUE;
     566           10 :       break;
     567              :     }
     568           26 :     GF_FilterPid* upid = gf_filter_get_ipid(uf, 0);
     569           26 :     if (!upid)
     570            9 :       break; // No upstream PID, stop checking
     571           17 :     uf = gf_filter_pid_get_source_filter(upid);
     572              :   }
     573              : 
     574              :   // Decide which post-process context to use
     575           19 :   if (has_dasher) {
     576              :     // If the upstream chain has dasher, we use the DASH post-process context,
     577              :     // regardless of whether it's connected to dasher directly or mp4mx
     578           10 :     pctx->entry = gpac_filter_get_post_process_registry_entry("dasher");
     579              :   } else {
     580              :     // Otherwise, use the post-process context based on connected filter name
     581            9 :     const gchar* source_name = gf_filter_pid_get_filter_name(pid);
     582            9 :     pctx->entry = gpac_filter_get_post_process_registry_entry(source_name);
     583              :   }
     584              : 
     585              :   // Create a new post-process context
     586           19 :   pctx->entry->ctx_init(&pctx->private_ctx);
     587              : 
     588              :   // Configure the PID with the post-process context
     589           19 :   return pctx->entry->configure_pid(filter, pid);
     590              : }
        

Generated by: LCOV version 2.0-1