📄 timedtext_dec.c
字号:
gf_node_changed((GF_Node *) n, NULL); if (txt->box) { br = txt->box->box; } else { br = td->default_pos; } if (!br.right || !br.bottom) { br.top = br.left = 0; br.right = priv->cfg->text_width; br.bottom = priv->cfg->text_height; } thw = br.right - br.left; thh = br.bottom - br.top; if (!thw || !thh) { br.top = br.left = 0; thw = priv->cfg->text_width; thh = priv->cfg->text_height; } priv->dlist->size.x = priv->rec_box->size.x = INT2FIX(thw); priv->dlist->size.y = priv->rec_box->size.y = INT2FIX(thh); gf_node_changed((GF_Node *) priv->rec_box, NULL); form = (M_Form *) ttd_create_node(priv, TAG_MPEG4_Form, NULL); form->size.x = INT2FIX(thw); form->size.y = INT2FIX(thh); thw /= 2; thh /= 2; tw = priv->cfg->text_width; th = priv->cfg->text_height; /*check translation, we must not get out of scene size - not supported in GPAC*/ offset = br.left - tw/2 + thw; if (offset + thw < - tw/2) offset = - tw/2 + thw; else if (offset - thw > tw/2) offset = tw/2 - thw; priv->tr_box->translation.x = INT2FIX(offset); offset = th/2 - br.top - thh; if (offset + thh > th/2) offset = th/2 - thh; else if (offset - thh < -th/2) offset = -th/2 + thh; priv->tr_box->translation.y = INT2FIX(offset); gf_node_dirty_set((GF_Node *)priv->tr_box, 0, 1); if (priv->scroll_type) { priv->ts_scroll->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_scroll); gf_node_changed((GF_Node *) priv->ts_scroll, NULL); } priv->scroll_mode = 0; if (td->displayFlags & GF_TXT_SCROLL_IN) priv->scroll_mode |= GF_TXT_SCROLL_IN; if (td->displayFlags & GF_TXT_SCROLL_OUT) priv->scroll_mode |= GF_TXT_SCROLL_OUT; priv->scroll_type = 0; if (priv->scroll_mode) { priv->scroll_type = (td->displayFlags & GF_TXT_SCROLL_DIRECTION)>>7; priv->scroll_type ++; } /*no sample duration, cannot determine scroll rate, so just show*/ if (!sample_duration) priv->scroll_type = 0; /*no scroll*/ if (!priv->scroll_mode) priv->scroll_type = 0; if (priv->scroll_type) { priv->tr_scroll = (M_Transform2D *) ttd_create_node(priv, TAG_MPEG4_Transform2D, NULL); gf_node_list_add_child( &priv->dlist->children, (GF_Node*)priv->tr_scroll); gf_node_register((GF_Node *) priv->tr_scroll, (GF_Node *) priv->dlist); gf_node_list_add_child( &priv->tr_scroll->children, (GF_Node*)form); gf_node_register((GF_Node *) form, (GF_Node *) priv->tr_scroll); priv->tr_scroll->translation.x = priv->tr_scroll->translation.y = (priv->scroll_mode & GF_TXT_SCROLL_IN) ? -INT2FIX(1000) : 0; /*if no delay, text is in motion for the duration of the sample*/ priv->scroll_time = FIX_ONE; priv->scroll_delay = 0; if (txt->scroll_delay) { priv->scroll_delay = gf_divfix(INT2FIX(txt->scroll_delay->scroll_delay), INT2FIX(sample_duration)); if (priv->scroll_delay>FIX_ONE) priv->scroll_delay = FIX_ONE; priv->scroll_time = (FIX_ONE - priv->scroll_delay); } /*if both scroll (in and out), use same scroll duration for both*/ if ((priv->scroll_mode & GF_TXT_SCROLL_IN) && (priv->scroll_mode & GF_TXT_SCROLL_OUT)) priv->scroll_time /= 2; } else { gf_node_list_add_child( &priv->dlist->children, (GF_Node*)form); gf_node_register((GF_Node *) form, (GF_Node *) priv->dlist); priv->tr_scroll = NULL; } if (is_utf_16) { memcpy((char *) utf16_text, txt->text, sizeof(char) * txt->len); ((char *) utf16_text)[txt->len] = 0; ((char *) utf16_text)[txt->len+1] = 0; char_count = txt->len / 2; } else { char *p = txt->text; char_count = gf_utf8_mbstowcs(utf16_text, 2500, (const char **) &p); } chunks = gf_list_new(); /*flatten all modifiers*/ if (!txt->styles || !txt->styles->entry_count) { GF_SAFEALLOC(tc, TTDTextChunk); tc->end_char = char_count; gf_list_add(chunks, tc); } else { GF_StyleRecord *srec = NULL; char_offset = 0; for (i=0; i<txt->styles->entry_count; i++) { TTDTextChunk *tc; srec = &txt->styles->styles[i]; if (srec->startCharOffset==srec->endCharOffset) continue; /*handle not continuous modifiers*/ if (char_offset < srec->startCharOffset) { GF_SAFEALLOC(tc, TTDTextChunk); tc->start_char = char_offset; tc->end_char = srec->startCharOffset; gf_list_add(chunks, tc); } GF_SAFEALLOC(tc, TTDTextChunk); tc->start_char = srec->startCharOffset; tc->end_char = srec->endCharOffset; tc->srec = srec; gf_list_add(chunks, tc); char_offset = srec->endCharOffset; } if (srec->endCharOffset<char_count) { GF_SAFEALLOC(tc, TTDTextChunk); tc->start_char = char_offset; tc->end_char = char_count; gf_list_add(chunks, tc); } } /*apply all other modifiers*/ i=0; while ((a = (GF_Box*)gf_list_enum(txt->others, &i))) { TTD_SplitChunks(txt, char_count, chunks, a); } while (gf_list_count(chunks)) { tc = (TTDTextChunk*)gf_list_get(chunks, 0); gf_list_rem(chunks, 0); TTD_NewTextChunk(priv, td, form, utf16_text, tc); free(tc); } gf_list_del(chunks); if (form->groupsIndex.vals[form->groupsIndex.count-1] != -1) ttd_add_line(form); /*rewrite form groupIndex - group is fine (eg one child per group)*/ idx.count = form->groupsIndex.count; idx.vals = form->groupsIndex.vals; form->groupsIndex.vals = NULL; form->groupsIndex.count = 0; nb_lines = 0; start_idx = 0; for (i=0; i<idx.count; i++) { if (idx.vals[i] == -1) { s32 *id; u32 j; /*only one item in line, no need for alignment, but still add a group (we could use the item as a group but that would complicate the alignment generation)*/ if (start_idx==i-1) { gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = idx.vals[start_idx]; gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; } else { /*spread horizontal 0 pixels (eg align) all items in line*/ gf_sg_vrml_mf_append(&form->constraints, GF_SG_VRML_MFSTRING, (void **) &s); s->buffer = strdup(vertical ? "SV 0" : "SH 0"); for (j=start_idx; j<i; j++) { gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = idx.vals[j]; /*also add a group for the line, for final justif*/ gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = idx.vals[j]; } gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; /*mark end of group*/ gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; } start_idx = i+1; nb_lines ++; } } free(idx.vals); /*finally add constraints on lines*/ start_idx = gf_node_list_get_count(form->children) + 1; /*horizontal alignment*/ gf_sg_vrml_mf_append(&form->constraints, GF_SG_VRML_MFSTRING, (void **) &s); if (vertical) { switch (td->vert_justif) { case 1: s->buffer = strdup("AV"); break;/*center*/ case -1: s->buffer = strdup("AB"); break;/*bottom*/ default: s->buffer = strdup("AT"); break;/*top*/ } } else { switch (td->horiz_justif) { case 1: s->buffer = strdup("AH"); break;/*center*/ case -1: s->buffer = strdup("AR"); break;/*right*/ default: s->buffer = strdup("AL"); break;/*left*/ } } gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = 0; for (i=0; i<nb_lines; i++) { gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = i+start_idx; } gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; /*vertical alignment: first align all items vertically, 0 pixel */ gf_sg_vrml_mf_append(&form->constraints, GF_SG_VRML_MFSTRING, (void **) &s); s->buffer = strdup(vertical ? "SH 0" : "SV 0"); gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = 0; for (i=0; i<nb_lines; i++) { gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = i+start_idx; } gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; /*define a group with every item drawn*/ count = gf_node_list_get_count(form->children); for (i=0; i<count; i++) { gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = i+1; } gf_sg_vrml_mf_append(&form->groups, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; gf_sg_vrml_mf_append(&form->constraints, GF_SG_VRML_MFSTRING, (void **) &s); if (vertical) { switch (td->horiz_justif) { case 1: s->buffer = strdup("AH"); break;/*center*/ case -1: s->buffer = strdup("AR"); break;/*right*/ default: s->buffer = strdup("AL"); break;/*left*/ } } else { switch (td->vert_justif) { case 1: s->buffer = strdup("AV"); break;/*center*/ case -1: s->buffer = strdup("AB"); break;/*bottom*/ default: s->buffer = strdup("AT"); break;/*top*/ } } gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = 0; gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = start_idx + nb_lines; gf_sg_vrml_mf_append(&form->groupsIndex, GF_SG_VRML_MFINT32, (void **) &id); (*id) = -1; gf_node_dirty_set((GF_Node *)form, 0, 1); gf_node_changed((GF_Node *)form, NULL); gf_node_changed((GF_Node *) priv->dlist, NULL); if (gf_list_count(priv->blink_nodes)) { /*restart time sensor*/ priv->ts_blink->startTime = gf_node_get_scene_time((GF_Node *) priv->ts_blink); gf_node_changed((GF_Node *) priv->ts_blink, NULL); } priv->is_active = 1; /*scroll timer also acts as AU timer*/ priv->ts_scroll->startTime = gf_node_get_scene_time((GF_Node *) priv->ts_scroll); priv->ts_scroll->stopTime = priv->ts_scroll->startTime - 1.0; priv->ts_scroll->cycleInterval = sample_duration; priv->ts_scroll->cycleInterval /= priv->cfg->timescale; priv->ts_scroll->cycleInterval -= 0.1; gf_node_changed((GF_Node *) priv->ts_scroll, NULL);}static GF_Err TTD_ProcessData(GF_SceneDecoder*plug, char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 AU_time, u32 mmlevel){ GF_BitStream *bs; GF_Err e = GF_OK; TTDPriv *priv = (TTDPriv *)plug->privateStack; bs = gf_bs_new(inBuffer, inBufferLength, GF_BITSTREAM_READ); while (gf_bs_available(bs)) { GF_TextSample *txt; Bool is_utf_16; u32 type, length, sample_index, sample_duration; is_utf_16 = gf_bs_read_int(bs, 1); gf_bs_read_int(bs, 4); type = gf_bs_read_int(bs, 3); length = gf_bs_read_u16(bs); /*currently only full text samples are supported*/ if (type != 1) { gf_bs_del(bs); return GF_NOT_SUPPORTED; } sample_index = gf_bs_read_u8(bs); /*duration*/ sample_duration = gf_bs_read_u24(bs); length -= 8; /*txt length is parsed with the sample*/ txt = gf_isom_parse_texte_sample(bs); TTD_ApplySample(priv, txt, sample_index, is_utf_16, sample_duration); gf_isom_delete_text_sample(txt); /*since we support only TTU(1), no need to go on*/ break; } gf_bs_del(bs); return e;}Bool TTD_CanHandleStream(GF_BaseDecoder *ifce, u32 StreamType, u32 ObjectType, char *decSpecInfo, u32 decSpecInfoSize, u32 PL){ TTDPriv *priv = (TTDPriv *)ifce->privateStack; if (StreamType!=GF_STREAM_TEXT) return 0; if (ObjectType!=0x08) return 0; priv->PL = PL; return 1;}void DeleteTimedTextDec(GF_BaseDecoder *plug){ TTDPriv *priv = (TTDPriv *)plug->privateStack; /*in case something went wrong*/ if (priv->cfg) gf_odf_desc_del((GF_Descriptor *) priv->cfg); free(priv); free(plug);}GF_BaseDecoder *NewTimedTextDec(){ TTDPriv *priv; GF_SceneDecoder *tmp; GF_SAFEALLOC(tmp, GF_SceneDecoder); if (!tmp) return NULL; GF_SAFEALLOC(priv, TTDPriv); tmp->privateStack = priv; tmp->AttachStream = TTD_AttachStream; tmp->DetachStream = TTD_DetachStream; tmp->GetCapabilities = TTD_GetCapabilities; tmp->SetCapabilities = TTD_SetCapabilities; tmp->ProcessData = TTD_ProcessData; tmp->AttachScene = TTD_AttachScene; tmp->CanHandleStream = TTD_CanHandleStream; tmp->ReleaseScene = TTD_ReleaseScene; GF_REGISTER_MODULE_INTERFACE(tmp, GF_SCENE_DECODER_INTERFACE, "GPAC TimedText Decoder", "gpac distribution") return (GF_BaseDecoder *) tmp;}GF_EXPORTBool QueryInterface(u32 InterfaceType){ switch (InterfaceType) { case GF_SCENE_DECODER_INTERFACE: return 1; case GF_NET_CLIENT_INTERFACE: return 1; default: return 0; }}#ifndef GPAC_READ_ONLYvoid DeleteTTReader(void *ifce);void *NewTTReader();#endifGF_EXPORTGF_BaseInterface *LoadInterface(u32 InterfaceType){ switch (InterfaceType) { case GF_SCENE_DECODER_INTERFACE: return (GF_BaseInterface *)NewTimedTextDec();#ifndef GPAC_READ_ONLY case GF_NET_CLIENT_INTERFACE: return (GF_BaseInterface *)NewTTReader();#endif default: return NULL; }}GF_EXPORTvoid ShutdownInterface(GF_BaseInterface *ifce){ switch (ifce->InterfaceType) { case GF_SCENE_DECODER_INTERFACE: DeleteTimedTextDec((GF_BaseDecoder *)ifce); break;#ifndef GPAC_READ_ONLY case GF_NET_CLIENT_INTERFACE: DeleteTTReader(ifce); break;#endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -