From 93f9892b54fead492b45e1f399e6ce833411aabc Mon Sep 17 00:00:00 2001 From: jeanlf Date: Fri, 19 Apr 2024 19:46:44 +0200 Subject: [PATCH] FilterSession fixes - fixes in link #PIDNAME adressing - return error if no output pid on reconnect call - fixed potential deadlock when defer linking is used with blocking session - fixed possible bug in linking to filters with any streamtype as writeuf --- include/gpac/filters.h | 4 +-- src/filter_core/filter.c | 10 +++++-- src/filter_core/filter_pid.c | 51 ++++++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/include/gpac/filters.h b/include/gpac/filters.h index 1f1cc6ab79..6ca21f2ab2 100644 --- a/include/gpac/filters.h +++ b/include/gpac/filters.h @@ -759,7 +759,6 @@ void *gf_fs_get_rt_udta(GF_FilterSession *session); */ Bool gf_fs_fire_event(GF_FilterSession *session, GF_Filter *filter, GF_FilterEvent *evt, Bool upstream); - /*! callback functions for external monitoring of filter creation or destruction \param udta user data passed back to callback \param do_activate if true context must be activated for calling thread, otherwise context is no longer used @@ -775,6 +774,7 @@ typedef GF_Err (*gf_fs_gl_activate)(void *udta, Bool do_activate); */ GF_Err gf_fs_set_external_gl_provider(GF_FilterSession *session, gf_fs_gl_activate on_gl_activate, void *udta); + /*! Flags for debug info*/ typedef enum { @@ -2902,7 +2902,7 @@ void gf_filter_send_event(GF_Filter *filter, GF_FilterEvent *evt, Bool upstream) /*! Trigger reconnection of output PIDs of a filter. This is needed when inserting a filter in the chain while the session is running \param filter the target filter \param for_pid reconnects only the given output PID - if NULL, reconnect all output PIDs -\return error if any +\return error if any, GF_EOS if no output pids available */ GF_Err gf_filter_reconnect_output(GF_Filter *filter, GF_FilterPid *for_pid); diff --git a/src/filter_core/filter.c b/src/filter_core/filter.c index 11cb06d688..a20fd6d054 100644 --- a/src/filter_core/filter.c +++ b/src/filter_core/filter.c @@ -2881,7 +2881,10 @@ static void gf_filter_check_pending_tasks(GF_Filter *filter, GF_FSTask *task) gf_assert(filter->process_task_queued); if (safe_int_dec(&filter->process_task_queued) == 0) { //we have pending packets, auto-post and requeue - if (filter->pending_packets && filter->num_input_pids) { + if (filter->pending_packets && filter->num_input_pids + //do NOT do this if running in prevent play mode and blocking mode, as user is likely expecting fs_run() to return until the play event is sent + && !filter->session->non_blocking && !(filter->session->flags & GF_FS_FLAG_PREVENT_PLAY) + ) { safe_int_inc(&filter->process_task_queued); task->requeue_request = GF_TRUE; } @@ -3157,7 +3160,7 @@ static void gf_filter_process_task(GF_FSTask *task) //if eos but we still have pending packets or process tasks queued, move to GF_OK so that //we evaluate the blocking state if (e==GF_EOS) { - if (filter->postponed_packets) { + if (filter->postponed_packets && filter->num_input_pids) { e = GF_OK; } else if (filter->process_task_queued) { e = GF_OK; @@ -3213,6 +3216,7 @@ static void gf_filter_process_task(GF_FSTask *task) //last task for filter but pending packets and not blocking, requeue in main scheduler else if ((filter->would_block < filter->num_output_pids) && filter->pending_packets + && (filter->nb_pids_playing>0) && (gf_fq_count(filter->tasks)<=1) ) { //prune eos packets that could still be present @@ -5243,6 +5247,8 @@ GF_Err gf_filter_reconnect_output(GF_Filter *filter, GF_FilterPid *for_pid) if (for_pid) { if (PID_IS_INPUT(for_pid)) return GF_BAD_PARAM; } + if (!filter->num_output_pids) + return GF_EOS; //in case we had pending output pids if (filter->deferred_link) { filter->deferred_link = GF_FALSE; diff --git a/src/filter_core/filter_pid.c b/src/filter_core/filter_pid.c index b931f6ee35..3fd5f90c8e 100644 --- a/src/filter_core/filter_pid.c +++ b/src/filter_core/filter_pid.c @@ -1560,6 +1560,7 @@ static Bool filter_pid_check_fragment(GF_FilterPid *src_pid, char *frag_name, Bo { char *psep; u32 comp_type=0; + u32 stream_type=0; Bool is_neg = GF_FALSE; const GF_PropertyEntry *pent; const GF_PropertyEntry *pent_val=NULL; @@ -1575,7 +1576,7 @@ static Bool filter_pid_check_fragment(GF_FilterPid *src_pid, char *frag_name, Bo if (pent) { u32 matched=0; u32 type=0; - u32 ptype = pent->prop.value.uint; + stream_type = pent->prop.value.uint; if (!strnicmp(frag_name, "audio", 5)) { matched=5; @@ -1599,22 +1600,22 @@ static Bool filter_pid_check_fragment(GF_FilterPid *src_pid, char *frag_name, Bo pent = gf_filter_pid_get_property_entry(src_pid, GF_PROP_PID_ISOM_HANDLER); if (pent && (pent->prop.value.uint == gf_4cc_parse(frag_name)) ) { matched=4; - type = ptype; + type = stream_type; } } } //stream is encrypted and desired type is not, get original stream type - if ((ptype == GF_STREAM_ENCRYPTED) && type && (type != GF_STREAM_ENCRYPTED) ) { + if ((stream_type == GF_STREAM_ENCRYPTED) && type && (type != GF_STREAM_ENCRYPTED) ) { pent = gf_filter_pid_get_property_entry(src_pid, GF_PROP_PID_ORIG_STREAM_TYPE); - if (pent) ptype = pent->prop.value.uint; + if (pent) stream_type = pent->prop.value.uint; } if (matched && - ( (!is_neg && (type != ptype)) || (is_neg && (type == ptype)) ) + ( (!is_neg && (type != stream_type)) || (is_neg && (type == stream_type)) ) ) { //special case: if we request a non-file stream but the pid is a file, we will need a demux to //move from file to A/V/... streams, so we accept any #MEDIA from file streams - if (ptype == GF_STREAM_FILE) { + if (stream_type == GF_STREAM_FILE) { *prop_not_found = GF_TRUE; return GF_TRUE; } @@ -1674,17 +1675,29 @@ static Bool filter_pid_check_fragment(GF_FilterPid *src_pid, char *frag_name, Bo } } + //no prop, no '=' separator this is #PIDNAME addressing not solved in filter_source_id_match if (!psep) { - *prop_not_found = GF_TRUE; - GF_LOG(GF_LOG_WARNING, GF_LOG_FILTER, ("PID addressing %s not recognized, ignoring and assuming match\n", frag_name )); - return GF_TRUE; + if (!strcmp(frag_name, src_pid->name)) return GF_TRUE; + //if pid is from a source filter (no inputs) of type file, allow further connection as PIDNAME is likely the name of a demuxed PID + if ((stream_type == GF_STREAM_FILE) && !src_pid->filter->num_input_pids) { + return GF_TRUE; + } + //otherwise walk up the chain for 1->1 filters and check PID names - this allows using the filename as PIDNAME on demuxed PIDs + GF_Filter *src_f = src_pid->filter; + if (src_f->num_input_pids==1) { + GF_FilterPidInst *pidi = gf_list_get(src_f->input_pids, 0); + if (!strcmp(frag_name, pidi->pid->name)) return GF_TRUE; + src_f = pidi->pid->filter; + } + *prop_not_found = GF_FALSE; + return GF_FALSE; } Bool is_equal = GF_FALSE; Bool use_not_equal = GF_FALSE; GF_PropertyValue prop_val; u32 p4cc = 0; - char c=psep[0]; + char c = psep[0]; psep[0] = 0; pent=NULL; @@ -4300,15 +4313,31 @@ static Bool gf_filter_pid_needs_explicit_resolution(GF_FilterPid *pid, GF_Filter caps = dst->forced_caps ? dst->forced_caps : dst->freg->caps; nb_caps = dst->forced_caps ? dst->nb_forced_caps : dst->freg->nb_caps; + Bool matched=GF_FALSE; + Bool mismatched=GF_FALSE; for (i=0; iflags & GF_CAPFLAG_INPUT)) continue; + if (!(cap->flags & GF_CAPFLAG_EXCLUDED) && (cap->code == GF_PROP_PID_STREAM_TYPE)) { + switch (cap->val.value.uint) { + case GF_STREAM_FILE: + case GF_STREAM_ENCRYPTED: + break; + default: + if (stream_type->value.uint == cap->val.value.uint) matched = GF_TRUE; + else mismatched = GF_TRUE; + break; + } + } + if (cap->code != GF_PROP_PID_CODECID) continue; if (cap->val.value.uint==GF_CODECID_RAW) dst_has_raw_cid_in = GF_TRUE; } - + //not file, not encrypted and mismatch of stream type, we need explicit filter + if (mismatched && !matched) + return GF_TRUE; for (i=0; i