static void gf_filter_process_task(GF_FSTask *task)
{
	GF_Err e;
	Bool skip_block_mode = GF_FALSE;
	GF_Filter *filter = task->filter;
	Bool force_block_state_check=GF_FALSE;
	assert(task->filter);
	assert(filter->freg);
	assert(filter->freg->process);
	task->can_swap = GF_TRUE;

	filter->schedule_next_time = 0;

	if (filter->disabled) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s is disabled, cancelling process\n", filter->name));
		gf_mx_p(task->filter->tasks_mx);
		task->filter->process_task_queued = 0;
		gf_mx_v(task->filter->tasks_mx);
		return;
	}

	if (filter->out_pid_connection_pending || filter->detached_pid_inst || filter->caps_negociate) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s has %s pending, requeuing process\n", filter->name, filter->out_pid_connection_pending ? "connections" : filter->caps_negociate ? "caps negociation" : "input pid reassignments"));
		//do not cancel the process task since it might have been triggered by the filter itself,
		//we would not longer call it
		task->requeue_request = GF_TRUE;

 		assert(filter->process_task_queued);
		//in we are during the graph resolution phase, to not ask for RT reschedule: this can post-pone process tasks and change their initial
		//scheduling order, resulting in random change of input pid declaration, for example:
		//fin1 -> reframe1 -> fA
		//fin2 -> reframe2 -> fA
		//if we postpone by 10 us finX process while wating for rfX->fA setup, depending on the CPU charge fin2 might be rescheduled before fin1
		//leading to pushing new/pending packets ro reframe2 before reframe1, and having fA declare its pid in the reverse order as the one expected
		//note that this is only valid for single-thread case, as in multithread we do not guarantee PID declaration order
		if (!filter->out_pid_connection_pending) {
			task->schedule_next_time = gf_sys_clock_high_res() + 10000;
			check_filter_error(filter, GF_OK, GF_TRUE);
		}
		return;
	}
	if (filter->removed || filter->finalized) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s has been %s, skipping process\n", filter->name, filter->finalized ? "finalized" : "removed"));
		return;
	}

	if (filter->prevent_blocking) skip_block_mode = GF_TRUE;
	else if (filter->session->in_final_flush) skip_block_mode = GF_TRUE;

	//blocking filter: remove filter process task - task will be reinserted upon unblock()
	if (!skip_block_mode && filter->would_block && (filter->would_block + filter->num_out_pids_not_connected == filter->num_output_pids ) ) {
		gf_mx_p(task->filter->tasks_mx);
		//it may happen that by the time we get the lock, the filter has been unblocked by another thread. If so, don't skip task
		if (filter->would_block) {
			filter->nb_tasks_done--;
			task->filter->process_task_queued = 0;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s blocked, skipping process\n", filter->name));
			gf_mx_v(task->filter->tasks_mx);
			return;
		}
		gf_mx_v(task->filter->tasks_mx);
	}
	if (filter->stream_reset_pending) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s has stream reset pending, postponing process\n", filter->name));
		filter->nb_tasks_done--;
		task->requeue_request = GF_TRUE;
		assert(filter->process_task_queued);
		return;
	}
	assert(filter->process_task_queued);
	assert(!filter->multi_sink_target);

	//the following breaks demuxers where PIDs are not all known from start: if we filter some pids due to user request,
	//we may end up with the following test true but not all PIDs yet declared, hence no more processing
	//we could add a filter cap for that, but for now we simply rely on the blocking mode algo only
#if 0
	if (filter->num_output_pids && (filter->num_out_pids_not_connected==filter->num_output_pids)) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s has no valid connected outputs, skipping process\n", filter->name));
		return;
	}
#endif

	//we have postponed packets on filter, flush them
	if (task->filter->postponed_packets) {
		while (gf_list_count(task->filter->postponed_packets)) {
			GF_FilterPacket *pck = gf_list_pop_front(task->filter->postponed_packets);
			e = gf_filter_pck_send_internal(pck, GF_FALSE);
			if (e==GF_PENDING_PACKET) {
				//packet is pending so was added at the end of our postponed queue - remove from queue and reinsert in front
				gf_list_del_item(task->filter->postponed_packets, pck);
				gf_list_insert(task->filter->postponed_packets, pck, 0);
				task->requeue_request = GF_TRUE;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s still has postponed packets, postponing process\n", filter->name));
				return;
			}
		}
		gf_list_del(task->filter->postponed_packets);
		task->filter->postponed_packets = NULL;
	}
	FSESS_CHECK_THREAD(filter)

	filter->nb_pck_io = 0;

	if (filter->nb_caps_renegociate) {
		gf_filter_renegociate_output(filter, GF_FALSE);
	}

	GF_LOG(GF_LOG_DEBUG, GF_LOG_FILTER, ("Filter %s process\n", filter->name));
	gf_rmt_begin_hash(filter->name, GF_RMT_AGGREGATE, &filter->rmt_hash);

	filter->in_process_callback = GF_TRUE;

#ifdef GPAC_MEMORY_TRACKING
	if (filter->session->check_allocs)
		e = gf_filter_process_check_alloc(filter);
	else
#endif
		e = filter->freg->process(filter);

	filter->in_process_callback = GF_FALSE;
	gf_rmt_end();

	//flush all pending pid init requests following the call to init
	if (filter->has_pending_pids) {
		filter->has_pending_pids=GF_FALSE;
		while (gf_fq_count(filter->pending_pids)) {
			GF_FilterPid *pid=gf_fq_pop(filter->pending_pids);
			gf_filter_pid_post_init_task(filter, pid);
		}
	}
	//no requeue if end of session
	if (session_should_abort(filter->session)) {
		return;
	}
	//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) {
		 	e = GF_OK;
		} else if (filter->process_task_queued) {
			e = GF_OK;
			force_block_state_check = GF_TRUE;
		}
	}

	if ((e==GF_EOS) || filter->removed || filter->finalized) {
		gf_mx_p(filter->tasks_mx);
		filter->process_task_queued = 0;
		gf_mx_v(filter->tasks_mx);
		return;
	}

	if ((e==GF_PROFILE_NOT_SUPPORTED) && filter->has_out_caps && !(filter->session->flags & GF_FS_FLAG_NO_REASSIGN)) {
		u32 i;
		//disconnect all other inputs, and post a re-init
		gf_mx_p(filter->tasks_mx);
		for (i=0; i<filter->num_input_pids; i++) {
			GF_FilterPidInst *a_pidinst = gf_list_get(filter->input_pids, i);

			GF_LOG(GF_LOG_WARNING, GF_LOG_FILTER, ("Codec/Profile not supported for filter %s - blacklisting as output from %s and retrying connections\n", filter->name, a_pidinst->pid->filter->name));

			gf_list_add(a_pidinst->pid->filter->blacklisted, (void *) filter->freg);

			gf_filter_relink_dst(a_pidinst);
		}
		filter->process_task_queued = 0;
		gf_mx_v(filter->tasks_mx);
		return;
	}
	check_filter_error(filter, e, GF_FALSE);

	//source filters, flush data if enough space available.
	if ( (!filter->num_output_pids || (filter->would_block + filter->num_out_pids_not_connected < filter->num_output_pids) )
		&& !filter->input_pids
		&& (e!=GF_EOS)
		&& !force_block_state_check
	) {
		if (filter->schedule_next_time)
			task->schedule_next_time = filter->schedule_next_time;
		task->requeue_request = GF_TRUE;
		assert(filter->process_task_queued);
	}
	//filter requested a requeue
	else if (filter->schedule_next_time) {
		if (!filter->session->in_final_flush) {
			task->schedule_next_time = filter->schedule_next_time;
			task->requeue_request = GF_TRUE;
			assert(filter->process_task_queued);
		}
	}
	//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
			&& (gf_fq_count(filter->tasks)<=1)
	) {
		//prune eos packets that could still be present
		if (filter->pending_packets && filter->session->in_final_flush) {
			u32 i;
			for (i=0; i<filter->num_input_pids; i++) {
				GF_FilterPidInst *pidi = gf_list_get(filter->input_pids, i);
				gf_filter_pid_get_packet((GF_FilterPid *)pidi);
			}
			if (!filter->num_input_pids)
				filter->pending_packets = 0;
		}
		task->requeue_request = GF_TRUE;
		assert(filter->process_task_queued);
	}
	else {
		assert (!filter->schedule_next_time);
		gf_filter_check_pending_tasks(filter, task);
		if (task->requeue_request) {
			assert(filter->process_task_queued);
		}
	}
}