static GF_Err writegen_push_ttml(GF_GenDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *in_pck)
{
	const GF_PropertyValue *subs = gf_filter_pck_get_property(in_pck, GF_PROP_PCK_SUBS);
	char *ttml_text = NULL;
	GF_Err e = GF_OK;
	u32 ttml_text_size;
	GF_DOMParser *dom;
	u32 txt_size, nb_children;
	u32 i, k, div_idx;
	GF_XMLNode *root_pck, *p_global, *p_pck, *body_pck, *body_global;

	if (subs) {
		if (subs->value.data.size < 14)
			return GF_NON_COMPLIANT_BITSTREAM;
		txt_size = subs->value.data.ptr[4];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[5];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[6];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[7];
		if (txt_size>data_size)
			return GF_NON_COMPLIANT_BITSTREAM;
	} else {
		txt_size = data_size;
	}
	ttml_text_size = txt_size + 2;
	ttml_text = gf_malloc(sizeof(char) * ttml_text_size);
	if (!ttml_text) return GF_OUT_OF_MEM;

	memcpy(ttml_text, data, txt_size);
	ttml_text[txt_size] = 0;
	ttml_text[txt_size+1] = 0;

	dom = gf_xml_dom_new();
	if (!dom) return GF_OUT_OF_MEM;
	e = gf_xml_dom_parse_string(dom, ttml_text);
	if (e) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[XML] Invalid TTML doc: %s\n\tXML text was:\n%s", gf_xml_dom_get_error(dom), ttml_text));
		goto exit;
	}
	root_pck = gf_xml_dom_get_root(dom);

	//subsamples, replace all data embedded as subsample with base64 encoding
	if (subs && root_pck) {
		e = ttml_embed_data(root_pck, data+txt_size, data_size-txt_size, subs->value.data.ptr+14, subs->value.data.size-14);
		if (e) goto exit;
	}

	if (!ctx->ttml_root) {
		ctx->ttml_root = gf_xml_dom_detach_root(dom);
		goto exit;
	}


	body_pck = ttml_get_body(root_pck);
	body_global = ttml_get_body(ctx->ttml_root);
	div_idx = 0;
	nb_children = body_pck ? gf_list_count(body_pck->content) : 0;
	for (k=0; k<nb_children; k++) {
		GF_XMLAttribute *div_reg = NULL;
		GF_XMLNode *div_global, *div_pck;
		div_pck = gf_list_get(body_pck->content, k);
		if (div_pck->type) continue;
		if (strcmp(div_pck->name, "div")) continue;

		if (ctx->merge_region)
			div_reg = ttml_get_attr(div_pck, "region");

		//merge input doc
		div_global = ttml_locate_div(body_global, div_reg ? div_reg->value : NULL, div_idx);

		if (!div_global) {
			gf_list_rem(body_pck->content, k);
			gf_list_insert(body_global->content, div_pck, div_idx+1);
			div_idx++;
			continue;
		}
		div_idx++;

		i=0;
		while ( (p_pck = gf_list_enum(div_pck->content, &i)) ) {
			s32 idx;
			GF_XMLNode *txt;
			u32 j=0;
			Bool found = GF_FALSE;
			if (p_pck->type) continue;
			if (strcmp(p_pck->name, "p")) continue;
			while ( (p_global = gf_list_enum(div_global->content, &j)) ) {
				if (p_global->type) continue;
				if (strcmp(p_global->name, "p")) continue;

				if (ttml_same_attr(p_pck, p_global)) {
					found = GF_TRUE;
					break;
				}
			}
			if (found) continue;

			//insert this p - if last entry in global div is text, insert before
			txt = gf_list_last(div_global->content);
			if (txt && txt->type) {
				idx = gf_list_count(div_global->content) - 1;
			} else {
				idx = gf_list_count(div_global->content);
			}

			i--;
			gf_list_rem(div_pck->content, i);
			if (i) {
				txt = gf_list_get(div_pck->content, i-1);
				if (txt->type) {
					i--;
					gf_list_rem(div_pck->content, i);
					gf_list_insert(div_global->content, txt, idx);
					idx++;
				}
			}
			gf_list_insert(div_global->content, p_pck, idx);

		}
	}

exit:
	if (ttml_text) gf_free(ttml_text);
	gf_xml_dom_del(dom);
	return e;
}
static GF_Err writegen_push_ttml(GF_GenDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *in_pck)
{
	const GF_PropertyValue *subs = gf_filter_pck_get_property(in_pck, GF_PROP_PCK_SUBS);
	char *ttml_text = NULL;
	GF_Err e = GF_OK;
	u32 ttml_text_size;
	GF_DOMParser *dom;
	u32 txt_size, nb_children;
	u32 i, k, div_idx;
	GF_XMLNode *root_pck, *p_global, *p_pck, *body_pck, *body_global;

	if (subs) {
		if (subs->value.data.size < 14)
			return GF_NON_COMPLIANT_BITSTREAM;
		txt_size = subs->value.data.ptr[4];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[5];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[6];
		txt_size <<= 8;
		txt_size |= subs->value.data.ptr[7];
		if (txt_size>data_size)
			return GF_NON_COMPLIANT_BITSTREAM;
	} else {
		txt_size = data_size;
	}
	ttml_text_size = txt_size + 2;
	ttml_text = gf_malloc(sizeof(char) * ttml_text_size);
	if (!ttml_text) return GF_OUT_OF_MEM;

	memcpy(ttml_text, data, txt_size);
	ttml_text[txt_size] = 0;
	ttml_text[txt_size+1] = 0;

	dom = gf_xml_dom_new();
	if (!dom) return GF_OUT_OF_MEM;
	e = gf_xml_dom_parse_string(dom, ttml_text);
	if (e) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[XML] Invalid TTML doc: %s\n\tXML text was:\n%s", gf_xml_dom_get_error(dom), ttml_text));
		goto exit;
	}
	root_pck = gf_xml_dom_get_root(dom);

	 
	if (subs && root_pck) {
		e = ttml_embed_data(root_pck, data+txt_size, data_size-txt_size, subs->value.data.ptr+14, subs->value.data.size-14);
		if (e) goto exit;
	}

	if (!ctx->ttml_root) {
		ctx->ttml_root = gf_xml_dom_detach_root(dom);
		goto exit;
	}


	body_pck = ttml_get_body(root_pck);
	body_global = ttml_get_body(ctx->ttml_root);
	div_idx = 0;
	nb_children = body_pck ? gf_list_count(body_pck->content) : 0;
	for (k=0; k<nb_children; k++) {
		GF_XMLAttribute *div_reg = NULL;
		GF_XMLNode *div_global, *div_pck;
		div_pck = gf_list_get(body_pck->content, k);
		if (div_pck->type) continue;
		if (strcmp(div_pck->name, "div")) continue;

		if (ctx->merge_region)
			div_reg = ttml_get_attr(div_pck, "region");

		 
		div_global = ttml_locate_div(body_global, div_reg ? div_reg->value : NULL, div_idx);

		if (!div_global) {
			gf_list_rem(body_pck->content, k);
			gf_list_insert(body_global->content, div_pck, div_idx+1);
			div_idx++;
			continue;
		}
		div_idx++;

		i=0;
		while ( (p_pck = gf_list_enum(div_pck->content, &i)) ) {
			s32 idx;
			GF_XMLNode *txt;
			u32 j=0;
			Bool found = GF_FALSE;
			if (p_pck->type) continue;
			if (strcmp(p_pck->name, "p")) continue;
			while ( (p_global = gf_list_enum(div_global->content, &j)) ) {
				if (p_global->type) continue;
				if (strcmp(p_global->name, "p")) continue;

				if (ttml_same_attr(p_pck, p_global)) {
					found = GF_TRUE;
					break;
				}
			}
			if (found) continue;

			 
			txt = gf_list_last(div_global->content);
			if (txt && txt->type) {
				idx = gf_list_count(div_global->content) - 1;
			} else {
				idx = gf_list_count(div_global->content);
			}

			i--;
			gf_list_rem(div_pck->content, i);
			if (i) {
				txt = gf_list_get(div_pck->content, i-1);
				if (txt->type) {
					i--;
					gf_list_rem(div_pck->content, i);
					gf_list_insert(div_global->content, txt, idx);
					idx++;
				}
			}
			gf_list_insert(div_global->content, p_pck, idx);

		}
	}

exit:
	if (ttml_text) gf_free(ttml_text);
	gf_xml_dom_del(dom);
	return e;
}