⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timedtext_dec.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / 3GPP/MPEG4 timed text module * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <gpac/internal/terminal_dev.h>#include <gpac/internal/isomedia_dev.h>#include <gpac/utf.h>#include <gpac/constants.h>#include <gpac/nodes_mpeg4.h>/*	this decoder is simply a scene decoder generating its own scene graph based on input data, 	this scene graph is then used as an extra graph by the renderer, and manipulated by the decoder	for any time animation handling.	Translation from text to MPEG-4 scene graph:		* all modifiers (styles, hilight, etc) are unrolled into chunks forming a unique, linear 	sequence of text data (startChar, endChar) with associated styles & modifs		* chunks are mapped to classic MPEG-4/VRML text		* these chunks are then gathered in a Form node (supported by 2D and 3D renderers), with 	text truncation at each newline char.		* the Form then performs all alignment of the chunks	It could be possible to use Layout instead of form, BUT layout cannot handle new lines at the time being...	Currently supported for 3GP text streams:		* text box positioning & filling, dynamic text box		* text color		* proper alignment (H and V) with horizontal text. Vertical text may not be properly layed out (not fully tested)		* style Records (font, size, fontstyles, and colors change) - any nb per sample supported		* hilighting (static only) with color or reverse video - any nb per sample supported		* hypertext links - any nb per sample supported		* blinking - any nb per sample supported		* complete scrolling: in, out, in+out, up, down, right and left directions. All other		modifiers are supported when scrolling		* scroll delay	It does NOT support:		* dynamic hilighting (karaoke)		* wrap	The decoder only accepts complete timed text units TTU(1). In band reconfig (TTU(5) is not supported, 	nor fragmented TTUs (2, 3, 4).	UTF16 support should workbut MP4Box does not support it at encoding time.*/typedef struct {	GF_InlineScene *inlineScene;	GF_Terminal *app;	u32 PL, nb_streams;	GF_TextConfig *cfg;	GF_SceneGraph *sg;	/*avoid searching the graph for things we know...*/	M_Transform2D *tr_track, *tr_box, *tr_scroll;	M_Material2D *mat_track, *mat_box;	M_Layer2D *dlist;	M_Rectangle *rec_box;	M_TimeSensor *ts_blink, *ts_scroll;	M_ScalarInterpolator *process_blink, *process_scroll;	GF_Route *time_route;	GF_List *blink_nodes;	u32 scroll_type, scroll_mode;	Fixed scroll_time, scroll_delay;	Bool is_active, use_texture;} TTDPriv;static void ttd_set_blink_fraction(GF_Node *node);static void ttd_set_scroll_fraction(GF_Node *node);static void TTD_ResetDisplay(TTDPriv *priv);/*the WORST thing about 3GP in MPEG4 is positioning of the text track...*/static void TTD_UpdateSizeInfo(TTDPriv *priv){	u32 w, h;	Bool has_size;	s32 offset, thw, thh, vw, vh;	has_size = gf_sg_get_scene_size_info(priv->inlineScene->graph, &w, &h);	/*no size info is given in main scene, override by associated video size if any, or by text track size*/	if (!has_size) {		if (priv->cfg->has_vid_info && priv->cfg->video_width && priv->cfg->video_height) {			gf_sg_set_scene_size_info(priv->sg, priv->cfg->video_width, priv->cfg->video_height, 1);		} else {			gf_sg_set_scene_size_info(priv->sg, priv->cfg->text_width, priv->cfg->text_height, 1);		}		gf_sg_get_scene_size_info(priv->sg, &w, &h);		if (!w || !h) return;		gf_is_force_scene_size(priv->inlineScene, w, h);	}	if (!w || !h) return;	/*apply*/	gf_sg_set_scene_size_info(priv->sg, w, h, 1);	/*make sure the scene size is big enough to contain the text track after positioning. RESULTS ARE UNDEFINED	if offsets are negative: since MPEG-4 uses centered coord system, we must assume video is aligned to top-left*/	if (priv->cfg->has_vid_info) {		Bool set_size = 0;		vw = priv->cfg->horiz_offset; if (vw<0) vw = 0;		vh = priv->cfg->vert_offset; if (vh<0) vh = 0;		if (priv->cfg->text_width + (u32) vw > w) {			w = priv->cfg->text_width+vw;			set_size = 1;		}		if (priv->cfg->text_height + (u32) vh > h) {			h = priv->cfg->text_height+vh;			set_size = 1;		}		if (set_size) {			gf_sg_set_scene_size_info(priv->sg, w, h, 1);			gf_is_force_scene_size(priv->inlineScene, w, h);		}	} else {		/*otherwise override (mainly used for SRT & TTXT file direct loading*/		priv->cfg->text_width = w;		priv->cfg->text_height = h;	}	/*ok override video size with main scene size*/	priv->cfg->video_width = w;	priv->cfg->video_height = h;	vw = (s32) w;	vh = (s32) h;	thw = priv->cfg->text_width / 2;	thh = priv->cfg->text_height / 2;	/*check translation, we must not get out of scene size - not supported in GPAC*/	offset = priv->cfg->horiz_offset - vw/2 + thw;	/*safety checks ?	if (offset + thw < - vw/2) offset = - vw/2 + thw;	else if (offset - thw > vw/2) offset = vw/2 - thw;	*/	priv->tr_track->translation.x = INT2FIX(offset);		offset = vh/2 - priv->cfg->vert_offset - thh;	/*safety checks ?	if (offset + thh > vh/2) offset = vh/2 - thh;	else if (offset - thh < -vh/2) offset = -vh/2 + thh;	*/	priv->tr_track->translation.y = INT2FIX(offset);	gf_node_changed((GF_Node *)priv->tr_track, NULL);}static GF_Err TTD_GetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability *capability){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	switch (capability->CapCode) {	case GF_CODEC_WIDTH:		capability->cap.valueInt = priv->cfg->text_width;		return GF_OK;	case GF_CODEC_HEIGHT:		capability->cap.valueInt = priv->cfg->text_height;		return GF_OK;	case GF_CODEC_MEDIA_NOT_OVER:		capability->cap.valueInt = priv->is_active;		return GF_OK;	default:		capability->cap.valueInt = 0;		return GF_OK;	}}static GF_Err TTD_SetCapabilities(GF_BaseDecoder *plug, const GF_CodecCapability capability){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	if (capability.CapCode==GF_CODEC_SHOW_SCENE) {		if (capability.cap.valueInt) {			TTD_ResetDisplay(priv);			TTD_UpdateSizeInfo(priv);			gf_is_register_extra_graph(priv->inlineScene, priv->sg, 0);		} else {			gf_is_register_extra_graph(priv->inlineScene, priv->sg, 1);		}				}	return GF_OK;}GF_Err TTD_AttachScene(GF_SceneDecoder *plug, GF_InlineScene *scene, Bool is_scene_decoder){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	if (priv->nb_streams) return GF_BAD_PARAM;	/*timedtext cannot be a root scene object*/	if (is_scene_decoder) return GF_BAD_PARAM;	priv->inlineScene = scene;	priv->app = scene->root_od->term;	return GF_OK;}GF_Err TTD_ReleaseScene(GF_SceneDecoder *plug){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	if (priv->nb_streams) return GF_BAD_PARAM;	return GF_OK;}static GFINLINE void add_child(GF_Node *n1, GF_Node *par){	gf_node_list_add_child( & ((GF_ParentNode *)par)->children, n1);	gf_node_register(n1, par);}static GFINLINE GF_Node *ttd_create_node(TTDPriv *ttd, u32 tag, const char *def_name){	GF_Node *n = gf_node_new(ttd->sg, tag);	if (n) {		if (def_name) gf_node_set_id(n, gf_sg_get_next_available_node_id(ttd->sg), def_name);		gf_node_init(n);	}	return n;}static GF_Err TTD_AttachStream(GF_BaseDecoder *plug, 									 u16 ES_ID, 									 char *decSpecInfo, 									 u32 decSpecInfoSize, 									 u16 DependsOnES_ID,									 u32 objectTypeIndication, 									 Bool Upstream){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	GF_Err e;	GF_DefaultDescriptor dsi;	GF_Node *root, *n1, *n2;	const char *opt;	/*no scalable, no upstream*/	if (priv->nb_streams || Upstream) return GF_NOT_SUPPORTED;	if (!decSpecInfo || !decSpecInfoSize) return GF_NON_COMPLIANT_BITSTREAM;	priv->cfg = (GF_TextConfig *) gf_odf_desc_new(GF_ODF_TEXT_CFG_TAG);	dsi.tag = GF_ODF_DSI_TAG;	dsi.data = decSpecInfo;	dsi.dataLength = decSpecInfoSize;	e = gf_odf_get_text_config(&dsi, (u8) objectTypeIndication, priv->cfg);	if (e) {		gf_odf_desc_del((GF_Descriptor *) priv->cfg);		priv->cfg = NULL;		return e;	}	priv->nb_streams++;	if (!priv->cfg->timescale) priv->cfg->timescale = 1000;	priv->sg = gf_sg_new_subscene(priv->inlineScene->graph);	root = ttd_create_node(priv, TAG_MPEG4_OrderedGroup, NULL);	gf_sg_set_root_node(priv->sg, root);	gf_node_register(root, NULL);	/*root transform*/	priv->tr_track = (M_Transform2D *)ttd_create_node(priv, TAG_MPEG4_Transform2D, NULL);	add_child((GF_Node *) priv->tr_track, root);	TTD_UpdateSizeInfo(priv);	/*txt track background*/	n1 = ttd_create_node(priv, TAG_MPEG4_Shape, NULL);	add_child(n1, (GF_Node *) priv->tr_track);	((M_Shape *)n1)->appearance = ttd_create_node(priv, TAG_MPEG4_Appearance, NULL);	gf_node_register(((M_Shape *)n1)->appearance, n1);	priv->mat_track = (M_Material2D *) ttd_create_node(priv, TAG_MPEG4_Material2D, NULL);	priv->mat_track->filled = 1;	priv->mat_track->transparency = 1;	((M_Appearance *) ((M_Shape *)n1)->appearance)->material = (GF_Node *) priv->mat_track;	gf_node_register((GF_Node *) priv->mat_track, ((M_Shape *)n1)->appearance);	n2 = ttd_create_node(priv, TAG_MPEG4_Rectangle, NULL);	((M_Rectangle *)n2)->size.x = priv->cfg->text_width;	((M_Rectangle *)n2)->size.y = priv->cfg->text_height;	((M_Shape *)n1)->geometry = n2;	gf_node_register(n2, n1);	/*txt box background*/	priv->tr_box = (M_Transform2D *) ttd_create_node(priv, TAG_MPEG4_Transform2D, NULL);	add_child((GF_Node*) priv->tr_box, (GF_Node*)priv->tr_track);	n1 = ttd_create_node(priv, TAG_MPEG4_Shape, NULL);	add_child(n1, (GF_Node*)priv->tr_box);	((M_Shape *)n1)->appearance = ttd_create_node(priv, TAG_MPEG4_Appearance, NULL);	gf_node_register(((M_Shape *)n1)->appearance, n1);	priv->mat_box = (M_Material2D *) ttd_create_node(priv, TAG_MPEG4_Material2D, NULL);	priv->mat_box->filled = 1;	priv->mat_box->transparency = 1;	((M_Appearance *) ((M_Shape *)n1)->appearance)->material = (GF_Node *)priv->mat_box;	gf_node_register((GF_Node *)priv->mat_box, ((M_Shape *)n1)->appearance);	priv->rec_box = (M_Rectangle *) ttd_create_node(priv, TAG_MPEG4_Rectangle, NULL);	priv->rec_box->size.x = priv->cfg->text_width;	priv->rec_box->size.y = priv->cfg->text_height;	((M_Shape *)n1)->geometry = (GF_Node *) priv->rec_box;	gf_node_register((GF_Node *) priv->rec_box, n1);	priv->dlist = (M_Layer2D *) ttd_create_node(priv, TAG_MPEG4_Layer2D, NULL);	priv->dlist->size.x = priv->cfg->text_width;	priv->dlist->size.y = priv->cfg->text_height;	add_child((GF_Node *)priv->dlist, (GF_Node *)priv->tr_box);	priv->blink_nodes = gf_list_new();	priv->ts_blink = (M_TimeSensor *) ttd_create_node(priv, TAG_MPEG4_TimeSensor, "TimerBlink");	priv->ts_blink->cycleInterval = 0.25;	priv->ts_blink->startTime = 0.0;	priv->ts_blink->loop = 1;	priv->process_blink = (M_ScalarInterpolator *) ttd_create_node(priv, TAG_MPEG4_ScalarInterpolator, NULL);	/*override set_fraction*/	priv->process_blink->on_set_fraction = ttd_set_blink_fraction;	gf_node_set_private((GF_Node *) priv->process_blink, priv);	/*route from fraction_changed to set_fraction*/	gf_sg_route_new(priv->sg, (GF_Node *) priv->ts_blink, 6, (GF_Node *) priv->process_blink, 0);		priv->ts_scroll = (M_TimeSensor *) ttd_create_node(priv, TAG_MPEG4_TimeSensor, "TimerScroll");	priv->ts_scroll->cycleInterval = 0;	priv->ts_scroll->startTime = -1;	priv->ts_scroll->loop = 0;	priv->process_scroll = (M_ScalarInterpolator *) ttd_create_node(priv, TAG_MPEG4_ScalarInterpolator, NULL);	/*override set_fraction*/	priv->process_scroll->on_set_fraction = ttd_set_scroll_fraction;	gf_node_set_private((GF_Node *) priv->process_scroll, priv);	/*route from fraction_changed to set_fraction*/	gf_sg_route_new(priv->sg, (GF_Node *) priv->ts_scroll, 6, (GF_Node *) priv->process_scroll, 0);	gf_node_register((GF_Node *) priv->ts_blink, NULL);	gf_node_register((GF_Node *) priv->process_blink, NULL);	gf_node_register((GF_Node *) priv->ts_scroll, NULL);	gf_node_register((GF_Node *) priv->process_scroll, NULL);	/*option setup*/	opt = gf_modules_get_option((GF_BaseInterface *)plug, "StreamingText", "UseTexturing");	priv->use_texture = (opt && !strcmp(opt, "yes")) ? 1 : 0;	return e;}static GF_Err TTD_DetachStream(GF_BaseDecoder *plug, u16 ES_ID){	TTDPriv *priv = (TTDPriv *)plug->privateStack;	if (!priv->nb_streams) return GF_BAD_PARAM;	gf_is_register_extra_graph(priv->inlineScene, priv->sg, 1);	gf_node_unregister((GF_Node *) priv->ts_blink, NULL);	gf_node_unregister((GF_Node *) priv->process_blink, NULL);	gf_node_unregister((GF_Node *) priv->ts_scroll, NULL);	gf_node_unregister((GF_Node *) priv->process_scroll, NULL);	gf_sg_del(priv->sg);	priv->sg = NULL;	if (priv->cfg) gf_odf_desc_del((GF_Descriptor *) priv->cfg);	priv->cfg = NULL;	priv->nb_streams = 0;	gf_list_del(priv->blink_nodes);	return GF_OK;}static void ttd_set_blink_fraction(GF_Node *node){	M_Material2D *m;	u32 i;	TTDPriv *priv = (TTDPriv *)gf_node_get_private(node);		Bool blink_on = 1;	if (priv->process_blink->set_fraction>FIX_ONE/2) blink_on = 0;	i=0;	while ((m = (M_Material2D*)gf_list_enum(priv->blink_nodes, &i))) {		if (m->filled != blink_on) {			m->filled = blink_on;			gf_node_changed((GF_Node *) m, NULL);		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -