📄 text_import.c
字号:
else if (!stricmp(att->name, "right")) box->right = atoi(att->value); }}void ttxt_parse_text_style(GF_MediaImporter *import, GF_XMLNode *n, GF_StyleRecord *style){ u32 i=0; GF_XMLAttribute *att; memset(style, 0, sizeof(GF_StyleRecord)); style->fontID = 1; style->font_size = TTXT_DEFAULT_FONT_SIZE; style->text_color = 0xFFFFFFFF; while ( (att=(GF_XMLAttribute *)gf_list_enum(n->attributes, &i))) { if (!stricmp(att->name, "fromChar")) style->startCharOffset = atoi(att->value); else if (!stricmp(att->name, "toChar")) style->endCharOffset = atoi(att->value); else if (!stricmp(att->name, "fontID")) style->fontID = atoi(att->value); else if (!stricmp(att->name, "fontSize")) style->font_size = atoi(att->value); else if (!stricmp(att->name, "color")) style->text_color = ttxt_get_color(import, att->value); else if (!stricmp(att->name, "styles")) { if (strstr(att->value, "Bold")) style->style_flags |= GF_TXT_STYLE_BOLD; if (strstr(att->value, "Italic")) style->style_flags |= GF_TXT_STYLE_ITALIC; if (strstr(att->value, "Underlined")) style->style_flags |= GF_TXT_STYLE_UNDERLINED; } }}char *ttxt_parse_string(GF_MediaImporter *import, char *str, Bool strip_lines){ u32 i=0; u32 k=0; u32 len = strlen(str); u32 state = 0; if (!strip_lines) { for (i=0; i<len; i++) { if ((str[i] == '\r') && (str[i+1] == '\n')) { i++; } str[k] = str[i]; k++; } str[k]=0; return str; } if (str[0]!='\'') return str; for (i=0; i<len; i++) { if (str[i] == '\'') { if (!state) { if (k) { str[k]='\n'; k++; } state = !state; } else if (state) { if ( (i+1==len) || ((str[i+1]==' ') || (str[i+1]=='\n') || (str[i+1]=='\r') || (str[i+1]=='\t') || (str[i+1]=='\'')) ) { state = !state; } else { str[k] = str[i]; k++; } } } else if (state) { str[k] = str[i]; k++; } } str[k]=0; return str;}static void ttxt_import_progress(void *cbk, u32 cur_samp, u32 count){ gf_set_progress("TTXT Loading", cur_samp, count);}static GF_Err gf_text_import_ttxt(GF_MediaImporter *import){ GF_Err e; Bool last_sample_empty; u32 i, j, k, track, ID, nb_samples, nb_descs, nb_children; u64 last_sample_duration; GF_XMLAttribute *att; GF_DOMParser *parser; GF_XMLNode *root, *node, *ext; if (import->flags==GF_IMPORT_PROBE_ONLY) return GF_OK; parser = gf_xml_dom_new(); e = gf_xml_dom_parse(parser, import->in_name, ttxt_import_progress, import); if (e) { gf_import_message(import, e, "Error parsing TTXT file: Line %d - %s", gf_xml_dom_get_line(parser), gf_xml_dom_get_error(parser)); gf_xml_dom_del(parser); return e; } root = gf_xml_dom_get_root(parser); e = GF_OK; if (strcmp(root->name, "TextStream")) { e = gf_import_message(import, GF_BAD_PARAM, "Invalid Timed Text file - expecting \"TextStream\" got %s", "TextStream", root->name); goto exit; } /*setup track in 3GP format directly (no ES desc)*/ ID = (import->esd) ? import->esd->ESID : 0; track = gf_isom_new_track(import->dest, ID, GF_ISOM_MEDIA_TEXT, 1000); if (!track) { e = gf_isom_last_error(import->dest); goto exit; } gf_isom_set_track_enabled(import->dest, track, 1); /*some MPEG-4 setup*/ if (import->esd) { if (!import->esd->ESID) import->esd->ESID = gf_isom_get_track_id(import->dest, track); if (!import->esd->decoderConfig) import->esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); import->esd->slConfig->timestampResolution = 1000; import->esd->decoderConfig->streamType = GF_STREAM_TEXT; import->esd->decoderConfig->objectTypeIndication = 0x08; if (import->esd->OCRESID) gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_OCR, import->esd->OCRESID); } gf_text_import_set_language(import, track); gf_import_message(import, GF_OK, "Timed Text (GPAC TTXT) Import"); last_sample_empty = 0; last_sample_duration = 0; nb_descs = 0; nb_samples = 0; nb_children = gf_list_count(root->content); i=0; while ( (node = (GF_XMLNode*)gf_list_enum(root->content, &i))) { if (node->type) { nb_children--; continue; } if (!strcmp(node->name, "TextStreamHeader")) { GF_XMLNode *sdesc; s32 w, h, tx, ty, layer; w = TTXT_DEFAULT_WIDTH; h = TTXT_DEFAULT_HEIGHT; tx = ty = layer = 0; nb_children--; j=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) { if (!strcmp(att->name, "width")) w = atoi(att->value); else if (!strcmp(att->name, "height")) h = atoi(att->value); else if (!strcmp(att->name, "layer")) layer = atoi(att->value); else if (!strcmp(att->name, "translation_x")) tx = atoi(att->value); else if (!strcmp(att->name, "translation_y")) ty = atoi(att->value); } gf_isom_set_track_layout_info(import->dest, track, w<<16, h<<16, tx<<16, ty<<16, (s16) layer); j=0; while ( (sdesc=(GF_XMLNode*)gf_list_enum(node->content, &j))) { if (sdesc->type) continue; if (!strcmp(sdesc->name, "TextSampleDescription")) { GF_TextSampleDescriptor td; u32 idx; memset(&td, 0, sizeof(GF_TextSampleDescriptor)); td.tag = GF_ODF_TEXT_CFG_TAG; td.vert_justif = (s8) -1; td.default_style.fontID = 1; td.default_style.font_size = TTXT_DEFAULT_FONT_SIZE; k=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(sdesc->attributes, &k))) { if (!strcmp(att->name, "horizontalJustification")) { if (!stricmp(att->value, "center")) td.horiz_justif = 1; else if (!stricmp(att->value, "right")) td.horiz_justif = (s8) -1; else if (!stricmp(att->value, "left")) td.horiz_justif = 0; } else if (!strcmp(att->name, "verticalJustification")) { if (!stricmp(att->value, "center")) td.vert_justif = 1; else if (!stricmp(att->value, "bottom")) td.vert_justif = (s8) -1; else if (!stricmp(att->value, "top")) td.vert_justif = 0; } else if (!strcmp(att->name, "backColor")) td.back_color = ttxt_get_color(import, att->value); else if (!strcmp(att->name, "verticalText") && !stricmp(att->value, "yes") ) td.displayFlags |= GF_TXT_VERTICAL; else if (!strcmp(att->name, "fillTextRegion") && !stricmp(att->value, "yes") ) td.displayFlags |= GF_TXT_FILL_REGION; else if (!strcmp(att->name, "continuousKaraoke") && !stricmp(att->value, "yes") ) td.displayFlags |= GF_TXT_KARAOKE; else if (!strcmp(att->name, "scroll")) { if (!stricmp(att->value, "inout")) td.displayFlags |= GF_TXT_SCROLL_IN | GF_TXT_SCROLL_OUT; else if (!stricmp(att->value, "in")) td.displayFlags |= GF_TXT_SCROLL_IN; else if (!stricmp(att->value, "out")) td.displayFlags |= GF_TXT_SCROLL_OUT; } else if (!strcmp(att->name, "scrollMode")) { u32 scroll_mode = GF_TXT_SCROLL_CREDITS; if (!stricmp(att->value, "Credits")) scroll_mode = GF_TXT_SCROLL_CREDITS; else if (!stricmp(att->value, "Marquee")) scroll_mode = GF_TXT_SCROLL_MARQUEE; else if (!stricmp(att->value, "Right")) scroll_mode = GF_TXT_SCROLL_RIGHT; else if (!stricmp(att->value, "Down")) scroll_mode = GF_TXT_SCROLL_DOWN; td.displayFlags |= ((scroll_mode<<7) & GF_TXT_SCROLL_DIRECTION); } } k=0; while ( (ext=(GF_XMLNode*)gf_list_enum(sdesc->content, &k))) { if (ext->type) continue; if (!strcmp(ext->name, "TextBox")) ttxt_parse_text_box(import, ext, &td.default_pos); else if (!strcmp(ext->name, "Style")) ttxt_parse_text_style(import, ext, &td.default_style); else if (!strcmp(ext->name, "FontTable")) { GF_XMLNode *ftable; u32 z=0; while ( (ftable=(GF_XMLNode*)gf_list_enum(ext->content, &z))) { u32 m; if (ftable->type || strcmp(ftable->name, "FontTableEntry")) continue; td.font_count += 1; td.fonts = (GF_FontRecord*)realloc(td.fonts, sizeof(GF_FontRecord)*td.font_count); m=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(ftable->attributes, &m))) { if (!stricmp(att->name, "fontID")) td.fonts[td.font_count-1].fontID = atoi(att->value); else if (!stricmp(att->name, "fontName")) td.fonts[td.font_count-1].fontName = strdup(att->value); } } } } if (import->flags & GF_IMPORT_SKIP_TXT_BOX) { td.default_pos.top = td.default_pos.left = td.default_pos.right = td.default_pos.bottom = 0; } else { if ((td.default_pos.bottom==td.default_pos.top) || (td.default_pos.right==td.default_pos.left)) { td.default_pos.top = td.default_pos.left = 0; td.default_pos.right = w; td.default_pos.bottom = h; } } if (!td.fonts) { td.font_count = 1; td.fonts = (GF_FontRecord*)malloc(sizeof(GF_FontRecord)); td.fonts[0].fontID = 1; td.fonts[0].fontName = strdup("Serif"); } gf_isom_new_text_description(import->dest, track, &td, NULL, NULL, &idx); for (k=0; k<td.font_count; k++) free(td.fonts[k].fontName); free(td.fonts); nb_descs ++; } } } /*sample text*/ else if (!strcmp(node->name, "TextSample")) { GF_ISOSample *s; GF_TextSample * samp; u32 ts, descIndex; Bool has_text = 0; if (!nb_descs) { e = gf_import_message(import, GF_BAD_PARAM, "Invalid Timed Text file - text stream header not found or empty"); goto exit; } samp = gf_isom_new_text_sample(); ts = 0; descIndex = 1; last_sample_empty = 0; j=0; while ( (att=(GF_XMLAttribute*)gf_list_enum(node->attributes, &j))) { if (!strcmp(att->name, "sampleTime")) { u32 h, m, s, ms; if (sscanf(att->value, "%d:%d:%d.%d", &h, &m, &s, &ms) == 4) { ts = (h*3600 + m*60 + s)*1000 + ms; } else { ts = (u32) (atof(att->value) * 1000); } } else if (!strcmp(att->name, "sampleDescriptionIndex")) descIndex = atoi(att->value); else if (!strcmp(att->name, "text")) { u32 len; char *str = ttxt_parse_string(import, att->value, 1); len = strlen(str); gf_isom_text_add_text(samp, str, len); last_sample_empty = len ? 0 : 1; has_text = 1; } else if (!strcmp(att->name, "scrollDelay")) gf_isom_text_set_scroll_delay(samp, (u32) (1000*atoi(att->value))); else if (!strcmp(att->name, "highlightColor")) gf_isom_text_set_highlight_color_argb(samp, ttxt_get_color(import, att->value)); else if (!strcmp(att->name, "wrap") && !strcmp(att->value, "Automatic")) gf_isom_text_set_wrap(samp, 0x01); } /*get all modifiers*/ j=0; while ( (ext=(GF_XMLNode*)gf_list_enum(node->content, &j))) { if (!has_text && (ext->type==GF_XML_TEXT_TYPE)) { u32 len; char *str = ttxt_parse_string(import, ext->name, 0); len = strlen(str); gf_isom_text_add_text(samp, str, len); last_sample_empty = len ? 0 : 1; has_text = 1; } if (ext->type) continue; if (!stricmp(ext->name, "Style")) { GF_StyleRecord r; ttxt_parse_text_style(import, ext, &r); gf_isom_text_add_style(samp, &r); } else if (!stricmp(ext->name, "TextBox")) { GF_BoxRecord r; ttxt_parse_text_box(import, ext, &r); gf_isom_text_set_box(samp, r.top, r.left, r.bottom, r.right); } else if (!stricmp(ext->name, "Highlight")) { u16 start, end; start = end = 0; k=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(ext->attributes, &k))) { if (!strcmp(att->name, "fromChar")) start = atoi(att->value); else if (!strcmp(att->name, "toChar")) end = atoi(att->value); } gf_isom_text_add_highlight(samp, start, end); } else if (!stricmp(ext->name, "Blinking")) { u16 start, end; start = end = 0; k=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(ext->attributes, &k))) { if (!strcmp(att->name, "fromChar")) start = atoi(att->value); else if (!strcmp(att->name, "toChar")) end = atoi(att->value); } gf_isom_text_add_blink(samp, start, end); } else if (!stricmp(ext->name, "HyperLink")) { u16 start, end; char *url, *url_tt; start = end = 0; url = url_tt = NULL; k=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(ext->attributes, &k))) { if (!strcmp(att->name, "fromChar")) start = atoi(att->value); else if (!strcmp(att->name, "toChar")) end = atoi(att->value); else if (!strcmp(att->name, "URL")) url = strdup(att->value); else if (!strcmp(att->name, "URLToolTip")) url_tt = strdup(att->value); } gf_isom_text_add_hyperlink(samp, url, url_tt, start, end); if (url) free(url); if (url_tt) free(url_tt); } else if (!stricmp(ext->name, "Karaoke")) { u32 startTime; GF_XMLNode *krok; startTime = 0; k=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(ext->attributes, &k))) { if (!strcmp(att->name, "startTime")) startTime = (u32) (1000*atof(att->value)); } gf_isom_text_add_karaoke(samp, startTime); k=0; while ( (krok=(GF_XMLNode*)gf_list_enum(ext->content, &k))) { u16 start, end; u32 endTime, m; if (krok->type) continue; if (strcmp(krok->name, "KaraokeRange")) continue; start = end = 0; endTime = 0; m=0; while ( (att=(GF_XMLAttribute *)gf_list_enum(krok->attributes, &m))) { if (!strcmp(att->name, "fromChar")) start = atoi(att->value); else if (!strcmp(att->name, "toChar")) end = atoi(att->value); else if (!strcmp(att->name, "endTime")) endTime = (u32) (1000*atof(att->value)); } gf_isom_text_set_karaoke_segment(samp, endTime, start, end); } } } /*in MP4 we must start at T=0, so add an empty sample*/ if (ts && !nb_samples) { GF_TextSample * firstsamp = gf_isom_new_text_sample(); s = gf_isom_text_to_sample(firstsamp); s->DTS = 0; gf_isom_add_sample(import->dest, track, 1, s); nb_samples++; gf_isom_delete_text_sample(firstsamp); gf_isom_sample_del(&s); } s = gf_isom_text_to_sample(samp); gf_isom_delete_text_sample(samp); s->DTS = ts; if (last_sample_empty) { last_sample_duration = s->DTS - last_sample_duration; } else { last_sample_duration = s->DTS; } e = gf_isom_add_sample(import->dest, track, descIndex, s); if (e) goto exit; gf_isom_sample_del(&s); nb_samples++; gf_set_progress("Importing TTXT", nb_samples, nb_children); if (import->duration && (ts>import->duration)) break; } } if (last_sample_empty) { gf_isom_remove_sample(import->dest, track, nb_samples); gf_isom_set_last_sample_duration(import->dest, track, (u32) last_sample_duration); } gf_set_progress("Importing TTXT", nb_samples, nb_samples);exit: gf_xml_dom_del(parser); return e;}u32 tx3g_get_color(GF_MediaImporter *import, char *value){ u32 r, g, b, a; u32 res, v; r = g = b = a = 0; if (sscanf(value, "%d%%, %d%%, %d%%, %d%%", &r, &g, &b, &a) != 4) { gf_import_message(import, GF_OK, "Warning: color badly formatted"); } v = (u32) (a*255/100); res = (v&0xFF); res<<=8; v = (u32) (r*255/100); res |= (v&0xFF); res<<=8; v = (u32) (g*255/100); res |= (v&0xFF); res<<=8; v = (u32) (b*255/100);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -