if (evt->frag_size.is_last) {
		sctx->llhls_done = GF_TRUE;
	} else {
		ctx->force_hls_ll_manifest = GF_TRUE;
	}
}

static Bool dasher_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
{
	u32 i, count;
	Bool flush_mpd = GF_FALSE;
	GF_DasherCtx *ctx = gf_filter_get_udta(filter);

	ctx->last_evt_check_time = 0;

	if (evt->base.type == GF_FEVT_RESUME) {
		//only process resume event when coming from main output PID, but always cancel it
		//this is needed in case the output filter where the resume event was initiated consumes both
		//manifest and segment PIDs, as is the case with httpout
		if (evt->base.on_pid == ctx->opid)
			dasher_resume_subdur(filter, ctx);
		return GF_TRUE;
	}
	if (evt->base.type == GF_FEVT_CONNECT_FAIL) {
		ctx->in_error = GF_TRUE;
		gf_filter_pid_set_eos(ctx->opid);
		if (ctx->opid_alt)
			gf_filter_pid_set_eos(ctx->opid_alt);
		return GF_TRUE;
	}

	if (evt->base.type == GF_FEVT_PLAY) {
		ctx->is_playing = GF_TRUE;
		if (!ctx->sfile && !ctx->stl && !ctx->use_cues) {
			GF_FilterEvent anevt;
			GF_FEVT_INIT(anevt, GF_FEVT_ENCODE_HINTS, NULL)
			count = gf_list_count(ctx->pids);
			for (i=0; i<count; i++) {
				GF_DashStream *ds = gf_list_get(ctx->pids, i);
				anevt.base.on_pid = ds->ipid;
				anevt.encode_hints.intra_period = ds->dash_dur;
				gf_filter_pid_send_event(ds->ipid, &anevt);
			}
		}
		return GF_FALSE;
	}
	if (evt->base.type == GF_FEVT_STOP) {
		ctx->is_playing = GF_FALSE;
		return GF_FALSE;
	}

	if (evt->base.type == GF_FEVT_FRAGMENT_SIZE) {
		dasher_process_hls_ll(ctx, evt);
		return GF_TRUE;
	}
	if (evt->base.type != GF_FEVT_SEGMENT_SIZE) return GF_FALSE;

	if (ctx->forward_mode==DASHER_FWD_ALL)
		return GF_TRUE;

	count = gf_list_count(ctx->pids);
	for (i=0; i<count; i++) {
		u64 r_start, r_end;
		GF_DashStream *ds = gf_list_get(ctx->pids, i);
		if (ds->opid != evt->base.on_pid) continue;

		if (ds->muxed_base)
			ds = ds->muxed_base;

		if (ctx->store_seg_states && !evt->seg_size.is_init) {
			GF_DASH_SegmentContext *sctx = gf_list_pop_front(ds->pending_segment_states);
			if (!sctx || !ctx->nb_seg_url_pending) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[Dasher] Broken muxer, received segment size info event but no pending segments\n"));
				return GF_TRUE;
			}
			assert(sctx);
			assert(ctx->nb_seg_url_pending);
			ctx->nb_seg_url_pending--;
			sctx->file_size = 1 + (u32) (evt->seg_size.media_range_end - evt->seg_size.media_range_start);
			sctx->file_offset = evt->seg_size.media_range_start;
			sctx->index_size = 1 + (u32) (evt->seg_size.idx_range_end - evt->seg_size.idx_range_start);
			sctx->index_offset = evt->seg_size.idx_range_start;

			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[Dasher] Got segment size event for %s\n", sctx->filename));

			if (sctx->llhls_mode) {
				sctx->llhls_done = GF_TRUE;
				//reset frags of past segments
				s32 idx, reset_until = gf_list_find(ds->rep->state_seg_list, sctx);
				for (idx=reset_until-4; idx>=0; idx--) {
					GF_DASH_SegmentContext *prev_sctx = gf_list_get(ds->rep->state_seg_list, idx);
					if (!prev_sctx->llhls_mode)
						break;

					//send file delete events
					if (prev_sctx->llhls_mode>1) {
						u32 k;
						for (k=0; k<prev_sctx->nb_frags; k++) {
							GF_FilterEvent anevt;
							char szPath[GF_MAX_PATH];
							sprintf(szPath, "%s.%d", prev_sctx->filepath, k+1);
							GF_FEVT_INIT(anevt, GF_FEVT_FILE_DELETE, ds->opid);
							anevt.file_del.url = szPath;
							gf_filter_pid_send_event(ds->opid, &anevt);
						}
					}
					prev_sctx->llhls_mode = 0;
				}
				ctx->force_hls_ll_manifest = GF_TRUE;
			}
		}

		//in state mode we store everything
		//don't set segment sizes in template mode
		if (ctx->tpl) continue;
		//only set size/index size for init segment when doing onDemand/single index
		if (ctx->sseg && !evt->seg_size.is_init) continue;

		if (evt->seg_size.media_range_end) {
			r_start = evt->seg_size.media_range_start;
			r_end = evt->seg_size.media_range_end;
		} else {
			r_start = evt->seg_size.idx_range_start;
			r_end = evt->seg_size.idx_range_end;
		}
		//init segment or representation index, set it in on demand and main single source
		if ((ctx->sfile || ctx->sseg) && (evt->seg_size.is_init==1))  {
			GF_MPD_URL *url, **s_url;

			if (evt->seg_size.is_shift) {
				u32 j, nb_segs = gf_list_count(ds->rep->state_seg_list);
				//we assume the shifted index start range is the previous init segment end range
				//which is always the case for isobmf muxer (the only one using is_shift)
				u64 diff = 1 + (u32) (evt->seg_size.idx_range_end - evt->seg_size.idx_range_start);

				for (j=0; j<nb_segs; j++) {
					GF_DASH_SegmentContext *sctx = gf_list_get(ds->rep->state_seg_list, j);
					sctx->file_offset += diff;
				}
			}

			if (ds->rep->segment_list) {
				if (!evt->seg_size.media_range_start && !evt->seg_size.media_range_end) {
					if (ds->rep->segment_list->initialization_segment) {
						gf_mpd_url_free(ds->rep->segment_list->initialization_segment);
						ds->rep->segment_list->initialization_segment = NULL;
					}
					continue;
				}
			}

			if (ds->rep->segment_base && !evt->seg_size.media_range_end) {
				if (! ds->rep->segment_base->index_range) {
					GF_SAFEALLOC(ds->rep->segment_base->index_range, GF_MPD_ByteRange);
				}
				if (ds->rep->segment_base->index_range) {
					ds->rep->segment_base->index_range->start_range = r_start;
					ds->rep->segment_base->index_range->end_range = r_end;
					ds->rep->segment_base->index_range_exact = GF_TRUE;
				}
				flush_mpd = GF_TRUE;
				continue;
			}

			GF_SAFEALLOC(url, GF_MPD_URL);
			if (!url) return GF_TRUE;

			GF_SAFEALLOC(url->byte_range, GF_MPD_ByteRange);
			if (!url->byte_range) return GF_TRUE;
			url->byte_range->start_range = r_start;
			url->byte_range->end_range = r_end;

			s_url = NULL;
			if (ds->rep->segment_base) {
				if (evt->seg_size.media_range_end) s_url = &ds->rep->segment_base->initialization_segment;
			} else {
				assert(ds->rep->segment_list);
				if (evt->seg_size.media_range_end) s_url = &ds->rep->segment_list->initialization_segment;
				else s_url = &ds->rep->segment_list->representation_index;
			}
			assert(s_url);
			if (*s_url) gf_mpd_url_free(*s_url);
			*s_url = url;
		} else if (ds->rep->segment_list && !evt->seg_size.is_init) {
			GF_MPD_SegmentURL *url = gf_list_pop_front(ds->pending_segment_urls);
			if (!url || !ctx->nb_seg_url_pending) {
				if (!ds->done) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[Dasher] Broken muxer, received segment size info event but no pending segments\n"));
				}
				return GF_TRUE;
			}
			ctx->nb_seg_url_pending--;

			if (!url->media && ctx->sfile) {
				GF_SAFEALLOC(url->media_range, GF_MPD_ByteRange);
				if (url->media_range) {
					url->media_range->start_range = evt->seg_size.media_range_start;
					url->media_range->end_range = evt->seg_size.media_range_end;
				}
			}
			//patch in test mode, old arch was not generating the index size for segment lists
			if (evt->seg_size.idx_range_end && (!gf_sys_old_arch_compat() || ctx->sfile) ) {
				GF_SAFEALLOC(url->index_range, GF_MPD_ByteRange);
				if (url->index_range) {
					url->index_range->start_range = evt->seg_size.idx_range_start;
					url->index_range->end_range = evt->seg_size.idx_range_end;
				}
			}
		}
	}
	if (!ctx->sseg || !flush_mpd) return GF_TRUE;

	flush_mpd = GF_TRUE;
	for (i=0; i<count; i++) {
		GF_DashStream *ds = gf_list_get(ctx->pids, i);
		if (!ds->rep) continue;
		if (! ds->rep->segment_base) continue;
		if (ds->rep->segment_base->index_range) continue;
		flush_mpd = GF_FALSE;
		break;