Skip to content

Commit

Permalink
FilterSession fixes
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
jeanlf committed Apr 19, 2024
1 parent 3231cfd commit 93f9892
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 15 deletions.
4 changes: 2 additions & 2 deletions include/gpac/filters.h
Expand Up @@ -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
Expand All @@ -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
{
Expand Down Expand Up @@ -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);

Expand Down
10 changes: 8 additions & 2 deletions src/filter_core/filter.c
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
51 changes: 40 additions & 11 deletions src/filter_core/filter_pid.c
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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; i<nb_caps; i++) {
const GF_FilterCapability *cap = &caps[i];
if (!(cap->flags & 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<nb_caps; i++) {
const GF_FilterCapability *cap = &caps[i];
Expand Down

0 comments on commit 93f9892

Please sign in to comment.