static GF_Err dasher_stream_period_changed(GF_Filter *filter, GF_DasherCtx *ctx, GF_DashStream *ds, Bool is_new_period_request)
{
	GF_Err e = GF_OK;
	//period switching, check the stream is still scheduled - if so and not done, flush it, update period duration
	s32 res = gf_list_find(ctx->current_period->streams, ds);
	//force end of segment if stream is not yet done and in current period
	if ((res>=0) && !ds->done && !ds->seg_done) {
		GF_DashStream *base_ds;

		base_ds = ds->muxed_base ? ds->muxed_base : ds;
		if (is_new_period_request) {
			GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[Dasher] New period requested during PID %s reconfiguration\n", gf_filter_pid_get_name(ds->ipid) ));
		} else {
			GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[Dasher] PID %s config changed during active period, forcing period switch\n", gf_filter_pid_get_name(ds->ipid) ));
		}
		ds->seg_done = GF_TRUE;
		if(base_ds->nb_comp_done >= base_ds->nb_comp) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[Dasher] Invalid new period: %u components processed (max %u expected)\n", base_ds->nb_comp_done, base_ds->nb_comp));
			e = GF_BAD_PARAM;
			goto exit;
		}
		base_ds->nb_comp_done ++;
		ds->first_cts_in_next_seg = ds->est_first_cts_in_next_seg;

		if (base_ds->nb_comp_done == base_ds->nb_comp) {
			dasher_flush_segment(ctx, base_ds, GF_TRUE);
		}

		ctx->force_period_switch = GF_TRUE;
		dasher_update_period_duration(ctx, GF_TRUE);
	}
	//remove stream from period
	if (res>=0) {
		//force an EOS on this stream for ondemand / side index generation flush
		if (ds->opid)
			gf_filter_pid_set_eos(ds->opid);
		ds->rep_init = GF_FALSE;
		//indicate this input is moved to next period. If a scheduled input is muxed with this one in the current period
		//it will abort its current segment
		ds->forced_period_switch = GF_TRUE;
		ds->presentation_time_offset = 0;
		gf_list_rem(ctx->current_period->streams, res);
	} else {
		//stream is not in current period, and this is not an explicit new period request
		//if the period was not ready (not yet setup), add to current streams
		//this is needed for cases such as HEVC tiling where secondary pids are added after the main pid is configured
		//see issue 1849
		if (!is_new_period_request && ctx->period_not_ready && !ds->rep) {
			gf_list_add(ctx->current_period->streams, ds);
			ds->period = ctx->current_period;
			ds->request_period_switch = 0;
			e = GF_OK;
			goto exit;
		}
	}
	ds->request_period_switch = 0;

	//this is tricky, when reassigning period IDs in the middle of a stream, we may have cases where some streams
	//are ready several packets before other streams due to processing delay, which results in period switch signal not
	//happening at the same time
	if (is_new_period_request && !ds->rep && ctx->current_period->period && gf_list_count(ctx->current_period->streams)) {
		Bool inject_in_period = GF_FALSE;
		if (ds->period_id && ctx->current_period->period->ID && !strcmp(ds->period_id, ctx->current_period->period->ID))
			inject_in_period = GF_TRUE;
		else if ((ctx->period_idx>0) && (ds->period_start.num<0) && ((s32) -ds->period_start.num == ctx->period_idx))
			inject_in_period = GF_TRUE;
		else if (ds->period_start.num * 1000 == ctx->current_period->period->start * ds->period_start.den)
			inject_in_period = GF_TRUE;

		if (inject_in_period) {
			gf_list_add(ctx->current_period->streams, ds);
			ds->period = ctx->current_period;
			dasher_setup_period(filter, ctx, ds);
			//force a MPD publish asap
			if (ctx->dmode != GF_DASH_STATIC)
				ctx->mpd->publishTime = 0;
			e = GF_OK;
			goto exit;
		}
	}
	gf_list_add(ctx->next_period->streams, ds);
	ds->period = ctx->next_period;

exit:

	ds->stl = ctx->stl;
	if (ctx->sigfrag) {
		const GF_PropertyValue *p = gf_filter_pid_get_property_str(ds->ipid, "source_template");
		if (p) {
			p = gf_filter_pid_get_property_str(ds->ipid, "stl_timescale");
			if (p && p->value.uint) {
				ds->stl = GF_TRUE;
				ds->mpd_timescale = p->value.uint;
			}
			else
				ds->stl = GF_FALSE;
		}
	}
	return e;
}