static GF_Err gf_isom_dump_ttxt_track(GF_ISOFile *the_file, u32 track, FILE *dump, GF_TextDumpType dump_type)
{
	u32 i, j, count, di, nb_descs, shift_offset[20], so_count;
	u64 last_DTS;
	u32 len;
	GF_Box *a;
	Bool has_scroll;
	char szDur[100];
	GF_Tx3gSampleEntryBox *txt_e;
	Bool box_dump = (dump_type==GF_TEXTDUMPTYPE_TTXT_BOXES) ? GF_TRUE : GF_FALSE;
	Bool skip_empty = (dump_type==GF_TEXTDUMPTYPE_TTXT_CHAP) ? GF_TRUE : GF_FALSE;

	GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, track);
	if (!trak) return GF_BAD_PARAM;
	switch (trak->Media->handler->handlerType) {
	case GF_ISOM_MEDIA_TEXT:
	case GF_ISOM_MEDIA_SUBT:
		break;
	default:
		return GF_BAD_PARAM;
	}

	txt_e = (GF_Tx3gSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
	switch (txt_e->type) {
	case GF_ISOM_BOX_TYPE_TX3G:
	case GF_ISOM_BOX_TYPE_TEXT:
		break;
	case GF_ISOM_BOX_TYPE_STPP:
	case GF_ISOM_BOX_TYPE_SBTT:
	default:
		return GF_BAD_PARAM;
	}

	if (box_dump) {
		gf_fprintf(dump, "<TextTrack trackID=\"%d\" version=\"1.1\">\n", gf_isom_get_track_id(the_file, track) );
	} else {
		gf_fprintf(dump, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
		gf_fprintf(dump, "<!-- GPAC 3GPP Text Stream -->\n");

		gf_fprintf(dump, "<TextStream version=\"1.1\">\n");
	}
	gf_fprintf(dump, "<TextStreamHeader width=\"%d\" height=\"%d\" layer=\"%d\" translation_x=\"%d\" translation_y=\"%d\">\n", trak->Header->width >> 16 , trak->Header->height >> 16, trak->Header->layer, trak->Header->matrix[6] >> 16, trak->Header->matrix[7] >> 16);

	nb_descs = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
	for (i=0; i<nb_descs; i++) {
		txt_e = (GF_Tx3gSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
		if (!txt_e) break;

		if (box_dump) {
			gf_isom_box_dump((GF_Box*) txt_e, dump);
		} else if  (txt_e->type==GF_ISOM_BOX_TYPE_TX3G) {
			gf_fprintf(dump, "<TextSampleDescription horizontalJustification=\"");
			switch (txt_e->horizontal_justification) {
			case 1:
				gf_fprintf(dump, "center");
				break;
			case -1:
				gf_fprintf(dump, "right");
				break;
			default:
				gf_fprintf(dump, "left");
				break;
			}
			gf_fprintf(dump, "\" verticalJustification=\"");
			switch (txt_e->vertical_justification) {
			case 1:
				gf_fprintf(dump, "center");
				break;
			case -1:
				gf_fprintf(dump, "bottom");
				break;
			default:
				gf_fprintf(dump, "top");
				break;
			}
			gf_fprintf(dump, "\" ");
			tx3g_dump_rgba8(dump, "backColor", txt_e->back_color);
			gf_fprintf(dump, " verticalText=\"%s\"", (txt_e->displayFlags & GF_TXT_VERTICAL) ? "yes" : "no");
			gf_fprintf(dump, " fillTextRegion=\"%s\"", (txt_e->displayFlags & GF_TXT_FILL_REGION) ? "yes" : "no");
			gf_fprintf(dump, " continuousKaraoke=\"%s\"", (txt_e->displayFlags & GF_TXT_KARAOKE) ? "yes" : "no");
			has_scroll = GF_FALSE;
			if (txt_e->displayFlags & GF_TXT_SCROLL_IN) {
				has_scroll = GF_TRUE;
				if (txt_e->displayFlags & GF_TXT_SCROLL_OUT) gf_fprintf(dump, " scroll=\"InOut\"");
				else gf_fprintf(dump, " scroll=\"In\"");
			} else if (txt_e->displayFlags & GF_TXT_SCROLL_OUT) {
				has_scroll = GF_TRUE;
				gf_fprintf(dump, " scroll=\"Out\"");
			} else {
				gf_fprintf(dump, " scroll=\"None\"");
			}
			if (has_scroll) {
				u32 mode = (txt_e->displayFlags & GF_TXT_SCROLL_DIRECTION)>>7;
				switch (mode) {
				case GF_TXT_SCROLL_CREDITS:
					gf_fprintf(dump, " scrollMode=\"Credits\"");
					break;
				case GF_TXT_SCROLL_MARQUEE:
					gf_fprintf(dump, " scrollMode=\"Marquee\"");
					break;
				case GF_TXT_SCROLL_DOWN:
					gf_fprintf(dump, " scrollMode=\"Down\"");
					break;
				case GF_TXT_SCROLL_RIGHT:
					gf_fprintf(dump, " scrollMode=\"Right\"");
					break;
				default:
					gf_fprintf(dump, " scrollMode=\"Unknown\"");
					break;
				}
			}
			gf_fprintf(dump, ">\n");
			gf_fprintf(dump, "<FontTable>\n");
			if (txt_e->font_table) {
				for (j=0; j<txt_e->font_table->entry_count; j++) {
					gf_fprintf(dump, "<FontTableEntry fontName=\"%s\" fontID=\"%d\"/>\n", txt_e->font_table->fonts[j].fontName, txt_e->font_table->fonts[j].fontID);

				}
			}
			gf_fprintf(dump, "</FontTable>\n");
			if ((txt_e->default_box.bottom == txt_e->default_box.top) || (txt_e->default_box.right == txt_e->default_box.left)) {
				txt_e->default_box.top = txt_e->default_box.left = 0;
				txt_e->default_box.right = trak->Header->width / 65536;
				txt_e->default_box.bottom = trak->Header->height / 65536;
			}
			tx3g_dump_box_nobox(dump, &txt_e->default_box);
			tx3g_dump_style_nobox(dump, &txt_e->default_style, NULL, 0);
			gf_fprintf(dump, "</TextSampleDescription>\n");
		} else {
			GF_TextSampleEntryBox *text = (GF_TextSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
			gf_fprintf(dump, "<TextSampleDescription horizontalJustification=\"");
			switch (text->textJustification) {
			case 1:
				gf_fprintf(dump, "center");
				break;
			case -1:
				gf_fprintf(dump, "right");
				break;
			default:
				gf_fprintf(dump, "left");
				break;
			}
			gf_fprintf(dump, "\"");

			tx3g_dump_rgb16(dump, " backColor", text->background_color);

			if ((text->default_box.bottom == text->default_box.top) || (text->default_box.right == text->default_box.left)) {
				text->default_box.top = text->default_box.left = 0;
				text->default_box.right = trak->Header->width / 65536;
				text->default_box.bottom = trak->Header->height / 65536;
			}

			if (text->displayFlags & GF_TXT_SCROLL_IN) {
				if (text->displayFlags & GF_TXT_SCROLL_OUT) gf_fprintf(dump, " scroll=\"InOut\"");
				else gf_fprintf(dump, " scroll=\"In\"");
			} else if (text->displayFlags & GF_TXT_SCROLL_OUT) {
				gf_fprintf(dump, " scroll=\"Out\"");
			} else {
				gf_fprintf(dump, " scroll=\"None\"");
			}
			gf_fprintf(dump, ">\n");

			tx3g_dump_box_nobox(dump, &text->default_box);
			gf_fprintf(dump, "</TextSampleDescription>\n");
		}
	}
	gf_fprintf(dump, "</TextStreamHeader>\n");

	last_DTS = 0;
	count = gf_isom_get_sample_count(the_file, track);
	for (i=0; i<count; i++) {
		GF_BitStream *bs;
		GF_TextSample *s_txt;
		GF_ISOSample *s = gf_isom_get_sample(the_file, track, i+1, &di);
		if (!s) continue;

		bs = gf_bs_new(s->data, s->dataLength, GF_BITSTREAM_READ);
		s_txt = gf_isom_parse_text_sample(bs);
		gf_bs_del(bs);

		if (skip_empty && (s_txt->len<1)) {
			gf_isom_sample_del(&s);
			gf_isom_delete_text_sample(s_txt);
			gf_set_progress("TTXT Extract", i, count);
			continue;
		}

		gf_fprintf(dump, "<TextSample sampleTime=\"%s\" sampleDescriptionIndex=\"%d\"", tx3g_format_time(s->DTS, trak->Media->mediaHeader->timeScale, szDur, GF_FALSE), di);

		if (!box_dump) {
			if (s_txt->highlight_color) {
				gf_fprintf(dump, " ");
				tx3g_dump_rgba8(dump, "highlightColor", s_txt->highlight_color->hil_color);
			}
			if (s_txt->scroll_delay) {
				Double delay = s_txt->scroll_delay->scroll_delay;
				delay /= trak->Media->mediaHeader->timeScale;
				gf_fprintf(dump, " scrollDelay=\"%g\"", delay);
			}
			if (s_txt->wrap) gf_fprintf(dump, " wrap=\"%s\"", (s_txt->wrap->wrap_flag==0x01) ? "Automatic" : "None");
		}

		so_count = 0;

		gf_fprintf(dump, " xml:space=\"preserve\">");
		if (!s_txt->len) {
			last_DTS = (u32) trak->Media->mediaHeader->duration;
		} else {
			unsigned short utf16Line[10000];
			last_DTS = s->DTS;
			/*UTF16*/
			if ((s_txt->len>2) && ((unsigned char) s_txt->text[0] == (unsigned char) 0xFE) && ((unsigned char) s_txt->text[1] == (unsigned char) 0xFF)) {
				/*copy 2 more chars because the lib always add 2 '0' at the end for UTF16 end of string*/
				memcpy((char *) utf16Line, s_txt->text+2, sizeof(char) * (s_txt->len));
				len = gf_utf8_wcslen((const u16*)utf16Line);
			} else {
				char *str;
				str = s_txt->text;
				len = gf_utf8_mbstowcs((u16*)utf16Line, 10000, (const char **) &str);
			}
			if (len != GF_UTF8_FAIL) {
				utf16Line[len] = 0;
				for (j=0; j<len; j++) {
					if ((utf16Line[j]=='\n') || (utf16Line[j]=='\r') || (utf16Line[j]==0x85) || (utf16Line[j]==0x2028) || (utf16Line[j]==0x2029) ) {
						gf_fprintf(dump, "\n");
						if ((utf16Line[j]=='\r') && (utf16Line[j+1]=='\n')) {
							shift_offset[so_count] = j;
							so_count++;
							j++;
						}
					}
					else {
						switch (utf16Line[j]) {
						case '\'':
							gf_fprintf(dump, "&apos;");
							break;
						case '\"':
							gf_fprintf(dump, "&quot;");
							break;
						case '&':
							gf_fprintf(dump, "&amp;");
							break;
						case '>':
							gf_fprintf(dump, "&gt;");
							break;
						case '<':
							gf_fprintf(dump, "&lt;");
							break;
						default:
							if (utf16Line[j] < 128) {
								gf_fprintf(dump, "%c", (u8) utf16Line[j]);
							} else {
								gf_fprintf(dump, "&#%d;", utf16Line[j]);
							}
							break;
						}
					}
				}
			}
		}

		if (box_dump) {

			if (s_txt->highlight_color)
				gf_isom_box_dump((GF_Box*) s_txt->highlight_color, dump);
			if (s_txt->scroll_delay)
				gf_isom_box_dump((GF_Box*) s_txt->scroll_delay, dump);
			if (s_txt->wrap)
				gf_isom_box_dump((GF_Box*) s_txt->wrap, dump);
			if (s_txt->box)
				gf_isom_box_dump((GF_Box*) s_txt->box, dump);
			if (s_txt->styles)
				gf_isom_box_dump((GF_Box*) s_txt->styles, dump);
		} else {

			if (s_txt->box) tx3g_dump_box_nobox(dump, &s_txt->box->box);
			if (s_txt->styles) {
				for (j=0; j<s_txt->styles->entry_count; j++) {
					tx3g_dump_style_nobox(dump, &s_txt->styles->styles[j], shift_offset, so_count);
				}
			}
		}
		j=0;
		while ((a = (GF_Box *)gf_list_enum(s_txt->others, &j))) {
			if (box_dump) {
				gf_isom_box_dump((GF_Box*) a, dump);
				continue;
			}

			switch (a->type) {
			case GF_ISOM_BOX_TYPE_HLIT:
				gf_fprintf(dump, "<Highlight ");
				tx3g_print_char_offsets(dump, ((GF_TextHighlightBox *)a)->startcharoffset, ((GF_TextHighlightBox *)a)->endcharoffset, shift_offset, so_count);
				gf_fprintf(dump, "/>\n");
				break;
			case GF_ISOM_BOX_TYPE_HREF:
			{
				GF_TextHyperTextBox *ht = (GF_TextHyperTextBox *)a;
				gf_fprintf(dump, "<HyperLink ");
				tx3g_print_char_offsets(dump, ht->startcharoffset, ht->endcharoffset, shift_offset, so_count);
				gf_fprintf(dump, "URL=\"%s\" URLToolTip=\"%s\"/>\n", ht->URL ? ht->URL : "", ht->URL_hint ? ht->URL_hint : "");
			}
			break;
			case GF_ISOM_BOX_TYPE_BLNK:
				gf_fprintf(dump, "<Blinking ");
				tx3g_print_char_offsets(dump, ((GF_TextBlinkBox *)a)->startcharoffset, ((GF_TextBlinkBox *)a)->endcharoffset, shift_offset, so_count);
				gf_fprintf(dump, "/>\n");
				break;
			case GF_ISOM_BOX_TYPE_KROK:
			{
				u32 k;
				Double t;
				GF_TextKaraokeBox *krok = (GF_TextKaraokeBox *)a;
				t = krok->highlight_starttime;
				t /= trak->Media->mediaHeader->timeScale;
				gf_fprintf(dump, "<Karaoke startTime=\"%g\">\n", t);
				for (k=0; k<krok->nb_entries; k++) {
					t = krok->records[k].highlight_endtime;
					t /= trak->Media->mediaHeader->timeScale;
					gf_fprintf(dump, "<KaraokeRange ");
					tx3g_print_char_offsets(dump, krok->records[k].start_charoffset, krok->records[k].end_charoffset, shift_offset, so_count);
					gf_fprintf(dump, "endTime=\"%g\"/>\n", t);
				}
				gf_fprintf(dump, "</Karaoke>\n");
			}
				break;
			}
		}

		gf_fprintf(dump, "</TextSample>\n");
		gf_isom_sample_del(&s);
		gf_isom_delete_text_sample(s_txt);
		gf_set_progress("TTXT Extract", i, count);
	}
	if (!skip_empty && (last_DTS < trak->Media->mediaHeader->duration)) {
		gf_fprintf(dump, "<TextSample sampleTime=\"%s\" text=\"\" />\n", tx3g_format_time(trak->Media->mediaHeader->duration, trak->Media->mediaHeader->timeScale, szDur, GF_FALSE));
	}

	if (box_dump) {
		gf_fprintf(dump, "</TextTrack>\n");
	} else {
		gf_fprintf(dump, "</TextStream>\n");
	}
	if (count) gf_set_progress("TTXT Extract", count, count);
	return GF_OK;
}