📄 timedtext_dec.c
字号:
}}static void ttd_set_scroll_fraction(GF_Node *node){ Fixed frac; TTDPriv *priv = (TTDPriv *)gf_node_get_private(node); frac = priv->process_scroll->set_fraction; if (frac==FIX_ONE) priv->is_active = 0; if (!priv->tr_scroll) return; switch (priv->scroll_type - 1) { case GF_TXT_SCROLL_CREDITS: case GF_TXT_SCROLL_DOWN: priv->tr_scroll->translation.x = 0; if (priv->scroll_mode & GF_TXT_SCROLL_IN) { if (frac>priv->scroll_time) { priv->scroll_mode &= ~GF_TXT_SCROLL_IN; priv->tr_scroll->translation.y = 0; } else { priv->tr_scroll->translation.y = gf_muldiv(priv->dlist->size.y, frac, priv->scroll_time) - priv->dlist->size.y; } } else if (priv->scroll_mode & GF_TXT_SCROLL_OUT) { if (frac < FIX_ONE - priv->scroll_time) return; frac -= FIX_ONE - priv->scroll_time; if (priv->scroll_type - 1 == GF_TXT_SCROLL_DOWN) { priv->tr_scroll->translation.y = gf_muldiv(priv->dlist->size.y, frac, priv->scroll_time); } else { priv->tr_scroll->translation.y = gf_muldiv(priv->dlist->size.y, frac, priv->scroll_time); } } if (priv->scroll_type - 1 == GF_TXT_SCROLL_DOWN) priv->tr_scroll->translation.y *= -1; break; case GF_TXT_SCROLL_MARQUEE: case GF_TXT_SCROLL_RIGHT: priv->tr_scroll->translation.y = 0; if (priv->scroll_mode & GF_TXT_SCROLL_IN) { if (! (priv->scroll_mode & GF_TXT_SCROLL_OUT)) { if (frac<priv->scroll_delay) return; frac-=priv->scroll_delay; } if (frac>priv->scroll_time) { priv->scroll_mode &= ~GF_TXT_SCROLL_IN; priv->tr_scroll->translation.x = 0; } else { priv->tr_scroll->translation.x = gf_muldiv(priv->dlist->size.x, frac, priv->scroll_time) - priv->dlist->size.x; } } else if (priv->scroll_mode & GF_TXT_SCROLL_OUT) { if (frac < FIX_ONE - priv->scroll_time) return; frac -= FIX_ONE - priv->scroll_time; priv->tr_scroll->translation.x = gf_muldiv(priv->dlist->size.x, frac, priv->scroll_time); } if (priv->scroll_type - 1 == GF_TXT_SCROLL_MARQUEE) priv->tr_scroll->translation.x *= -1; break; default: break; } gf_node_changed((GF_Node *)priv->tr_scroll, NULL);}static void TTD_ResetDisplay(TTDPriv *priv){ gf_list_reset(priv->blink_nodes); gf_node_unregister_children((GF_Node*)priv->dlist, priv->dlist->children); priv->dlist->children = NULL; gf_node_changed((GF_Node *) priv->dlist, NULL); priv->tr_scroll = NULL;}char *TTD_FindFont(GF_TextSampleDescriptor *tsd, u32 ID){ u32 i; for (i=0; i<tsd->font_count; i++) { if (tsd->fonts[i].fontID==ID) return tsd->fonts[i].fontName; } return "SERIF";}static void ttd_add_item(M_Form *form){ s32 *new_gr; gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &new_gr); (*new_gr) = gf_node_list_get_count(form->children); gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &new_gr); (*new_gr) = -1; /*store line info*/ gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &new_gr); (*new_gr) = gf_node_list_get_count(form->children);}static void ttd_add_line(M_Form *form){ s32 *new_gr; gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &new_gr); (*new_gr) = -1;}typedef struct{ u32 start_char, end_char; GF_StyleRecord *srec; Bool is_hilight; u32 hilight_col; /*0 means RV*/ GF_TextHyperTextBox *hlink; Bool has_blink; /*karaoke not done yet*/ /*text wrapping is not supported - we will need to move to Layout (rather than form), and modify layout to handle new lines and proper scrolling*/} TTDTextChunk;static void TTD_NewTextChunk(TTDPriv *priv, GF_TextSampleDescriptor *tsd, M_Form *form, u16 *utf16_txt, TTDTextChunk *tc){ GF_Node *txt_model, *n2, *txt_material; M_Text *text; M_FontStyle *fs; char *fontName; char szStyle[1024]; u32 fontSize, styleFlags, color, i, start_char; if (!tc->srec) { fontName = TTD_FindFont(tsd, tsd->default_style.fontID); fontSize = tsd->default_style.font_size; styleFlags = tsd->default_style.style_flags; color = tsd->default_style.text_color; } else { fontName = TTD_FindFont(tsd, tc->srec->fontID); fontSize = tc->srec->font_size; styleFlags = tc->srec->style_flags; color = tc->srec->text_color; } /*create base model for text node. It will then be cloned for each text item*/ txt_model = ttd_create_node(priv, TAG_MPEG4_Shape, NULL); gf_node_register(txt_model, NULL); n2 = ttd_create_node(priv, TAG_MPEG4_Appearance, NULL); ((M_Shape *)txt_model)->appearance = n2; gf_node_register(n2, txt_model); txt_material = ttd_create_node(priv, TAG_MPEG4_Material2D, NULL); ((M_Appearance *)n2)->material = txt_material; gf_node_register(txt_material, n2); ((M_Material2D *)txt_material)->filled = 1; ((M_Material2D *)txt_material)->transparency = FIX_ONE - INT2FIX((color>>24) & 0xFF) / 255; ((M_Material2D *)txt_material)->emissiveColor.red = INT2FIX((color>>16) & 0xFF) / 255; ((M_Material2D *)txt_material)->emissiveColor.green = INT2FIX((color>>8) & 0xFF) / 255; ((M_Material2D *)txt_material)->emissiveColor.blue = INT2FIX((color) & 0xFF) / 255; /*force 0 lineWidth if blinking (the stupid MPEG-4 default values once again..)*/ if (tc->has_blink) { ((M_Material2D *)txt_material)->lineProps = ttd_create_node(priv, TAG_MPEG4_LineProperties, NULL); ((M_LineProperties *)((M_Material2D *)txt_material)->lineProps)->width = 0; gf_node_register(((M_Material2D *)txt_material)->lineProps, txt_material); } n2 = ttd_create_node(priv, TAG_MPEG4_Text, NULL); ((M_Shape *)txt_model)->geometry = n2; gf_node_register(n2, txt_model); text = (M_Text *) n2; fs = (M_FontStyle *) ttd_create_node(priv, TAG_MPEG4_FontStyle, NULL); free(fs->family.vals[0]); /*translate default fonts to MPEG-4/VRML names*/ if (!stricmp(fontName, "Serif")) fs->family.vals[0] = strdup("SERIF"); else if (!stricmp(fontName, "Sans-Serif")) fs->family.vals[0] = strdup("SANS"); else if (!stricmp(fontName, "Monospace")) fs->family.vals[0] = strdup("TYPEWRITER"); else fs->family.vals[0] = strdup(fontName); fs->size = INT2FIX(fontSize); free(fs->style.buffer); strcpy(szStyle, ""); if (styleFlags & GF_TXT_STYLE_BOLD) { if (styleFlags & GF_TXT_STYLE_ITALIC) strcpy(szStyle, "BOLDITALIC"); else strcpy(szStyle, "BOLD"); } else if (styleFlags & GF_TXT_STYLE_ITALIC) strcat(szStyle, "ITALIC"); if (!strlen(szStyle)) strcpy(szStyle, "PLAIN"); /*also underline for URLs*/ if ((styleFlags & GF_TXT_STYLE_UNDERLINED) || (tc->hlink && tc->hlink->URL)) strcat(szStyle, " UNDERLINED"); if (tc->is_hilight) { if (tc->hilight_col) { char szTxt[50]; sprintf(szTxt, " HIGHLIGHT#%x", tc->hilight_col); strcat(szStyle, szTxt); } else { strcat(szStyle, " HIGHLIGHT#RV"); } } /*a better way would be to draw the entire text box in a composite texture & bitmap but we can't really rely on text box size (in MP4Box, it actually defaults to the entire video area) and drawing a too large texture & bitmap could slow down rendering*/ if (priv->use_texture) strcat(szStyle, " TEXTURED"); fs->style.buffer = strdup(szStyle); fs->horizontal = (tsd->displayFlags & GF_TXT_VERTICAL) ? 0 : 1; text->fontStyle = (GF_Node *) fs; gf_node_register((GF_Node *)fs, (GF_Node *)text); gf_sg_vrml_mf_reset(&text->string, GF_SG_VRML_MFSTRING); if (tc->hlink && tc->hlink->URL) { SFURL *s; M_Anchor *anc = (M_Anchor *) ttd_create_node(priv, TAG_MPEG4_Anchor, NULL); gf_sg_vrml_mf_append(&anc->url, GF_SG_VRML_MFURL, (void **) &s); s->OD_ID = 0; s->url = strdup(tc->hlink->URL); if (tc->hlink->URL_hint) anc->description.buffer = strdup(tc->hlink->URL_hint); gf_node_list_add_child(& anc->children, txt_model); gf_node_register(txt_model, (GF_Node *)anc); txt_model = (GF_Node *)anc; gf_node_register((GF_Node *)anc, NULL); } start_char = tc->start_char; for (i=tc->start_char; i<tc->end_char; i++) { Bool new_line = 0; if ((utf16_txt[i] == '\n') || (utf16_txt[i] == '\r') || (utf16_txt[i] == 0x85) || (utf16_txt[i] == 0x2028) || (utf16_txt[i] == 0x2029)) new_line = 1; if (new_line || (i+1==tc->end_char) ) { SFString *st; if (i+1==tc->end_char) i++; if (i!=start_char) { char szLine[5000]; u32 len; s16 wsChunk[5000], *sp; /*spliting lines, duplicate node*/ n2 = gf_node_clone(priv->sg, txt_model, NULL); if (tc->hlink && tc->hlink->URL) { GF_Node *t = ((M_Anchor *)n2)->children->node; text = (M_Text *) ((M_Shape *)t)->geometry; txt_material = ((M_Appearance *) ((M_Shape *)t)->appearance)->material; } else { text = (M_Text *) ((M_Shape *)n2)->geometry; txt_material = ((M_Appearance *) ((M_Shape *)n2)->appearance)->material; } gf_sg_vrml_mf_reset(&text->string, GF_SG_VRML_MFSTRING); gf_node_list_add_child( &form->children, n2); gf_node_register(n2, (GF_Node *) form); ttd_add_item(form); /*clone node always register by default*/ gf_node_unregister(n2, NULL); if (tc->has_blink && txt_material) gf_list_add(priv->blink_nodes, txt_material); memcpy(wsChunk, &utf16_txt[start_char], sizeof(s16)*(i-start_char)); wsChunk[i-start_char] = 0; sp = &wsChunk[0]; len = gf_utf8_wcstombs(szLine, 5000, (const unsigned short **) &sp); szLine[len] = 0; gf_sg_vrml_mf_append(&text->string, GF_SG_VRML_MFSTRING, (void **) &st); st->buffer = strdup(szLine); } start_char = i+1; if (new_line) { ttd_add_line(form); if ((utf16_txt[i]=='\r') && (utf16_txt[i+1]=='\n')) i++; } } } gf_node_unregister(txt_model, NULL); return;}/*mod can be any of TextHighlight, TextKaraoke, TextHyperText, TextBlink*/void TTD_SplitChunks(GF_TextSample *txt, u32 nb_chars, GF_List *chunks, GF_Box *mod){ TTDTextChunk *tc; u32 start_char, end_char; u32 i; switch (mod->type) { /*these 3 can be safelly typecasted to the same struct for start/end char*/ case GF_ISOM_BOX_TYPE_HLIT: case GF_ISOM_BOX_TYPE_HREF: case GF_ISOM_BOX_TYPE_BLNK: start_char = ((GF_TextHighlightBox *)mod)->startcharoffset; end_char = ((GF_TextHighlightBox *)mod)->endcharoffset; break; case GF_ISOM_BOX_TYPE_KROK: default: return; } if (end_char>nb_chars) end_char = nb_chars; i=0; while ((tc = (TTDTextChunk *)gf_list_enum(chunks, &i))) { if (tc->end_char<=start_char) continue; /*need to split chunk at begin*/ if (tc->start_char<start_char) { TTDTextChunk *tc2; tc2 = (TTDTextChunk *) malloc(sizeof(TTDTextChunk)); memcpy(tc2, tc, sizeof(TTDTextChunk)); tc2->start_char = start_char; tc2->end_char = tc->end_char; tc->end_char = start_char; gf_list_insert(chunks, tc2, i+1); i++; tc = tc2; } /*need to split chunks at end*/ if (tc->end_char>end_char) { TTDTextChunk *tc2; tc2 = (TTDTextChunk *) malloc(sizeof(TTDTextChunk)); memcpy(tc2, tc, sizeof(TTDTextChunk)); tc2->start_char = tc->start_char; tc2->end_char = end_char; tc->start_char = end_char; gf_list_insert(chunks, tc2, i); i++; tc = tc2; } /*assign mod*/ switch (mod->type) { case GF_ISOM_BOX_TYPE_HLIT: tc->is_hilight = 1; if (txt->highlight_color) tc->hilight_col = txt->highlight_color->hil_color; break; case GF_ISOM_BOX_TYPE_HREF: tc->hlink = (GF_TextHyperTextBox *) mod; break; case GF_ISOM_BOX_TYPE_BLNK: tc->has_blink = 1; break; } /*done*/ if (tc->end_char==end_char) return; }}static void TTD_ApplySample(TTDPriv *priv, GF_TextSample *txt, u32 sdi, Bool is_utf_16, u32 sample_duration){ u32 i, nb_lines, start_idx, count; s32 *id, thw, thh, tw, th, offset; Bool vertical; MFInt32 idx; SFString *s; GF_BoxRecord br; M_Material2D *n; M_Form *form; u16 utf16_text[5000]; u32 char_offset, char_count; GF_List *chunks; TTDTextChunk *tc; GF_Box *a; GF_TextSampleDescriptor *td = NULL; /*stop timer sensor*/ if (gf_list_count(priv->blink_nodes)) { priv->ts_blink->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_blink); gf_node_changed((GF_Node *) priv->ts_blink, NULL); } priv->ts_scroll->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_scroll); gf_node_changed((GF_Node *) priv->ts_scroll, NULL); /*flush routes to avoid getting the set_fraction of the scroll sensor deactivation*/ gf_sg_activate_routes(priv->inlineScene->graph); TTD_ResetDisplay(priv); if (!sdi || !txt || !txt->len) return; i=0; while ((td = (GF_TextSampleDescriptor *)gf_list_enum(priv->cfg->sample_descriptions, &i))) { if (td->sample_index==sdi) break; td = NULL; } if (!td) return; vertical = (td->displayFlags & GF_TXT_VERTICAL) ? 1 : 0; /*set back color*/ /*do we fill the text box or the entire text track region*/ if (td->displayFlags & GF_TXT_FILL_REGION) { priv->mat_box->transparency = FIX_ONE; n = priv->mat_track; } else { priv->mat_track->transparency = FIX_ONE; n = priv->mat_box; } n->transparency = FIX_ONE - INT2FIX((td->back_color>>24) & 0xFF) / 255; n->emissiveColor.red = INT2FIX((td->back_color>>16) & 0xFF) / 255; n->emissiveColor.green = INT2FIX((td->back_color>>8) & 0xFF) / 255; n->emissiveColor.blue = INT2FIX((td->back_color) & 0xFF) / 255;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -