1 //This software module was originally developed by TelecomParisTech in the
2 //course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard.
3 //
4 //This software module is an implementation of a part of one or
5 //more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets
6 //(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets
7 //(ISO/IEC 23007-1) free license to this software module or modifications
8 //thereof for use in hardware or software products claiming conformance to
9 //the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software
10 //module in hardware or software products are advised that its use may
11 //infringe existing patents.
12 //The original developer of this software module and his/her company, the
13 //subsequent editors and their companies, and ISO/IEC have no liability
14 //for use of this software module or modifications thereof in an implementation.
15 //Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming
16 //products.
17 //Telecom ParisTech retains full right to use the code for his/her own purpose,
18 //assign or donate the code to a third party and to inhibit third parties from
19 //using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products.
20 //
21 //This copyright notice must be included in all copies or derivative works.
22 //
23 //Copyright (c) 2009 Telecom ParisTech.
24 //
25 // Alternatively, this software module may be redistributed and/or modified
26 // it under the terms of the GNU Lesser General Public License as published by
27 // the Free Software Foundation; either version 2, or (at your option)
28 // any later version.
29 //
30 /////////////////////////////////////////////////////////////////////////////////
31
32 /////////////////////////////////////////////////////////////////////////////////
33 //
34 // Authors:
35 // Cyril Concolato, Telecom ParisTech
36 // Jean Le Feuvre, Telecom ParisTech
37 //
38 /////////////////////////////////////////////////////////////////////////////////
39
40
41 #include <gpac/internal/terminal_dev.h>
42 #include <gpac/internal/scenegraph_dev.h>
43 #include <gpac/nodes_svg.h>
44 #include <gpac/constants.h>
45
46 #if defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG)
47
48 typedef struct
49 {
50 GF_Scene *scene;
51 u8 oti;
52 char *file_name;
53 u32 file_size;
54 Bool loaded;
55 } WgtLoad;
56
WGT_ProcessData(GF_SceneDecoder * plug,const char * inBuffer,u32 inBufferLength,u16 ES_ID,u32 stream_time,u32 mmlevel)57 static GF_Err WGT_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 inBufferLength,
58 u16 ES_ID, u32 stream_time, u32 mmlevel)
59 {
60 GF_Err e = GF_OK;
61 WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
62
63 if (stream_time==(u32)-1) {
64 gf_sg_reset(wgtload->scene->graph);
65 return GF_OK;
66 }
67
68 switch (wgtload->oti) {
69 case GPAC_OTI_PRIVATE_SCENE_WGT:
70 if (wgtload->file_name && !wgtload->loaded) {
71 const char *path, *wmpath;
72 char *tmp;
73 GF_Node *n, *root;
74 GF_FieldInfo info;
75 FILE *jsfile;
76 GF_ChildNodeItem *last;
77
78 wgtload->loaded = GF_TRUE;
79
80 gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2000/svg", NULL);
81 gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/1999/xlink", "xlink");
82 gf_sg_add_namespace(wgtload->scene->graph, "http://www.w3.org/2001/xml-events", "ev");
83 gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, GF_TRUE);
84
85 /* modify the scene with an Inline/Animation pointing to the widget start file URL */
86 n = root = gf_node_new(wgtload->scene->graph, TAG_SVG_svg);
87 gf_node_register(root, NULL);
88 gf_sg_set_root_node(wgtload->scene->graph, root);
89 gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_viewBox, GF_TRUE, GF_FALSE, &info);
90 gf_svg_parse_attribute(n, &info, "0 0 320 240", 0);
91 gf_node_get_attribute_by_name(n, "xmlns", 0, GF_TRUE, GF_FALSE, &info);
92 gf_svg_parse_attribute(n, &info, "http://www.w3.org/2000/svg", 0);
93 /*
94 gf_sg_set_scene_size_info(wgtload->scene->graph, 800, 600, 1);
95 gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, 1, 0, &info);
96 gf_svg_parse_attribute(n, &info, "800", 0);
97 gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, 1, 0, &info);
98 gf_svg_parse_attribute(n, &info, "600", 0);
99 */
100 gf_node_init(n);
101
102 n = gf_node_new(wgtload->scene->graph, TAG_SVG_animation);
103 gf_node_set_id(n, 1, "w_anim");
104 gf_node_register(n, root);
105 gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
106 gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_width, GF_TRUE, GF_FALSE, &info);
107 gf_svg_parse_attribute(n, &info, "320", 0);
108 gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_height, GF_TRUE, GF_FALSE, &info);
109 gf_svg_parse_attribute(n, &info, "240", 0);
110 gf_node_init(n);
111
112 tmp = wgtload->file_name;
113 while ((tmp = strchr(tmp, '\\'))) {
114 tmp[0] = '/';
115 tmp++;
116 }
117
118 n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
119 gf_node_register(n, root);
120 gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
121 path = gf_opts_get_key("Widgets", "WidgetLoadScript");
122 jsfile = path ? gf_fopen(path, "rt") : NULL;
123 if (jsfile) {
124 gf_fclose(jsfile);
125 gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
126 gf_svg_parse_attribute(n, &info, (char *) path, 0);
127 } else {
128 const char *load_fun = "function load_widget(wid_url) {\n"
129 " var wid = WidgetManager.load(wid_url);\n"
130 " var anim = document.getElementById('w_anim');\n"
131 " if (wid != null) {\n"
132 " wid.activate(anim);"
133 " anim.setAttributeNS('http://www.w3.org/1999/xlink', 'href', wid.main);\n"
134 " } else {\n"
135 " alert('Widget ' + wid_url + ' is not valid');\n"
136 " }\n"
137 "}\n";
138
139 gf_dom_add_text_node(n, gf_strdup(load_fun) );
140 }
141 gf_node_init(n);
142
143
144 wmpath = gf_opts_get_key("Widgets", "WidgetManagerScript");
145 jsfile = wmpath ? gf_fopen(wmpath, "rt") : NULL;
146 if (jsfile) {
147 gf_fclose(jsfile);
148 n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
149 gf_node_register(n, root);
150 gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
151 gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
152 gf_svg_parse_attribute(n, &info, (char *) wmpath, 0);
153 gf_node_init(n);
154
155 n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
156 gf_node_register(n, root);
157 gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
158 gf_dom_add_text_node(n, gf_strdup("widget_manager_init();") );
159 gf_node_init(n);
160 }
161
162 tmp = (char*)gf_malloc(sizeof(char) * (strlen(wgtload->file_name)+50) );
163 sprintf(tmp, "load_widget(\"%s\");\n", wgtload->file_name);
164
165 n = gf_node_new(wgtload->scene->graph, TAG_SVG_script);
166 gf_node_register(n, root);
167 gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last);
168 gf_dom_add_text_node(n, gf_strdup(tmp) );
169 gf_free(tmp);
170
171 gf_node_init(n);
172
173 if ((wgtload->scene->graph_attached!=1) && (gf_sg_get_root_node(wgtload->scene->graph)!=NULL) ) {
174 gf_scene_attach_to_compositor(wgtload->scene);
175 e = GF_EOS;
176 }
177 }
178 break;
179
180 default:
181 return GF_BAD_PARAM;
182 }
183 return e;
184 }
185
WGT_AttachScene(GF_SceneDecoder * plug,GF_Scene * scene,Bool is_scene_decoder)186 static GF_Err WGT_AttachScene(GF_SceneDecoder *plug, GF_Scene *scene, Bool is_scene_decoder)
187 {
188 WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
189 wgtload->scene = scene;
190 return GF_OK;
191 }
192
WGT_ReleaseScene(GF_SceneDecoder * plug)193 static GF_Err WGT_ReleaseScene(GF_SceneDecoder *plug)
194 {
195 WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
196 wgtload->scene = NULL;
197 return GF_OK;
198 }
199
WGT_AttachStream(GF_BaseDecoder * plug,GF_ESD * esd)200 static GF_Err WGT_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd)
201 {
202 GF_BitStream *bs;
203 WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
204 if (esd->decoderConfig->upstream) return GF_NOT_SUPPORTED;
205
206 /* decSpecInfo is not null only when reading from an WGT file (local or distant, cached or not) */
207 switch (esd->decoderConfig->objectTypeIndication) {
208 case GPAC_OTI_PRIVATE_SCENE_WGT:
209 default:
210 if (!esd->decoderConfig->decoderSpecificInfo) return GF_NON_COMPLIANT_BITSTREAM;
211 bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ);
212 wgtload->file_size = gf_bs_read_u32(bs);
213 gf_bs_del(bs);
214 wgtload->file_name = (char *) gf_malloc(sizeof(char)*(1 + esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32)) );
215 memcpy(wgtload->file_name, esd->decoderConfig->decoderSpecificInfo->data + sizeof(u32), esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) );
216 wgtload->file_name[esd->decoderConfig->decoderSpecificInfo->dataLength - sizeof(u32) ] = 0;
217 break;
218 }
219 wgtload->oti = esd->decoderConfig->objectTypeIndication;
220 return GF_OK;
221 }
222
WGT_DetachStream(GF_BaseDecoder * plug,u16 ES_ID)223 static GF_Err WGT_DetachStream(GF_BaseDecoder *plug, u16 ES_ID)
224 {
225 WgtLoad *wgtload = (WgtLoad *)plug->privateStack;
226 if (wgtload->file_name) gf_free(wgtload->file_name);
227 wgtload->file_name = NULL;
228 return GF_OK;
229 }
230
WGT_GetName(struct _basedecoder * plug)231 const char *WGT_GetName(struct _basedecoder *plug)
232 {
233 return "GPAC W3C Widget Loader";
234 }
235
WGT_CanHandleStream(GF_BaseDecoder * ifce,u32 StreamType,GF_ESD * esd,u8 PL)236 static u32 WGT_CanHandleStream(GF_BaseDecoder *ifce, u32 StreamType, GF_ESD *esd, u8 PL)
237 {
238 /*don't reply to media type query*/
239 if (!esd) return GF_CODEC_NOT_SUPPORTED;
240
241 if (StreamType==GF_STREAM_PRIVATE_SCENE) {
242 if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_PRIVATE_SCENE_WGT) return GF_CODEC_SUPPORTED;
243 return GF_CODEC_NOT_SUPPORTED;
244 }
245 return GF_CODEC_NOT_SUPPORTED;
246 }
247
WGT_GetCapabilities(GF_BaseDecoder * plug,GF_CodecCapability * cap)248 static GF_Err WGT_GetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability *cap)
249 {
250 cap->cap.valueInt = 0;
251 if (cap->CapCode==GF_CODEC_PADDING_BYTES) {
252 /* Adding one byte of padding for \r\n problems*/
253 cap->cap.valueInt = 1;
254 return GF_OK;
255 }
256 return GF_NOT_SUPPORTED;
257 }
258
WGT_SetCapabilities(GF_BaseDecoder * plug,const GF_CodecCapability capability)259 static GF_Err WGT_SetCapabilities(GF_BaseDecoder *plug, const GF_CodecCapability capability)
260 {
261 return GF_OK;
262 }
263
264 /*interface create*/
LoadWidgetReader()265 GF_BaseInterface *LoadWidgetReader()
266 {
267 WgtLoad *wgtload;
268 GF_SceneDecoder *sdec;
269
270 GF_SAFEALLOC(sdec, GF_SceneDecoder)
271 if (!sdec) return NULL;
272 GF_REGISTER_MODULE_INTERFACE(sdec, GF_SCENE_DECODER_INTERFACE, "GPAC W3C Widget Loader", "gpac distribution");
273
274 GF_SAFEALLOC(wgtload, WgtLoad);
275 if (!wgtload) {
276 gf_free(sdec);
277 return NULL;
278 }
279
280 sdec->privateStack = wgtload;
281 sdec->AttachStream = WGT_AttachStream;
282 sdec->CanHandleStream = WGT_CanHandleStream;
283 sdec->DetachStream = WGT_DetachStream;
284 sdec->AttachScene = WGT_AttachScene;
285 sdec->ReleaseScene = WGT_ReleaseScene;
286 sdec->ProcessData = WGT_ProcessData;
287 sdec->GetName = WGT_GetName;
288 sdec->SetCapabilities = WGT_SetCapabilities;
289 sdec->GetCapabilities = WGT_GetCapabilities;
290 return (GF_BaseInterface *)sdec;
291 }
292
293
294 /*interface destroy*/
ShutdownWidgetReader(GF_BaseInterface * ifce)295 void ShutdownWidgetReader(GF_BaseInterface *ifce)
296 {
297 GF_SceneDecoder *sdec = (GF_SceneDecoder *)ifce;
298 WgtLoad *wgtload;
299 if (!ifce)
300 return;
301 wgtload = (WgtLoad *) sdec->privateStack;
302 if (wgtload)
303 gf_free(wgtload);
304 sdec->privateStack = NULL;
305 gf_free(sdec);
306 }
307
308 #endif /* defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) */
309