Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2018
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/compositor_dev.h>
27 : #include <gpac/network.h>
28 :
29 :
30 0 : void scene_ns_on_setup_error(GF_Filter *failed_filter, void *udta, GF_Err err)
31 : {
32 : GF_SceneNamespace *scene_ns;
33 : GF_Scene *scene;
34 : GF_ObjectManager *root = (GF_ObjectManager *)udta;
35 : assert(root);
36 0 : scene_ns = root->scene_ns;
37 : assert(scene_ns);
38 0 : scene = root->subscene ? root->subscene : root->parentscene;
39 : assert(scene);
40 :
41 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Service connection failure received from %s - %s\n", scene_ns->url, gf_error_to_string(err) ));
42 :
43 0 : if (root->scene_ns->owner != root) {
44 0 : gf_scene_message(scene, scene_ns->url, "Incompatible module type", GF_SERVICE_ERROR);
45 0 : return;
46 : }
47 : /*this is service connection*/
48 0 : gf_odm_service_media_event(root, GF_EVENT_MEDIA_SETUP_DONE);
49 :
50 0 : scene_ns->connect_ack = GF_TRUE;
51 0 : if (err) {
52 : char msg[5000];
53 0 : snprintf(msg, sizeof(msg), "Cannot open %s", scene_ns->url);
54 0 : gf_scene_message(scene, scene_ns->url, msg, err);
55 :
56 0 : if (root->mo) root->mo->connect_failure = GF_TRUE;
57 0 : gf_odm_service_media_event(root, GF_EVENT_ERROR);
58 :
59 : /*destroy service only if attached*/
60 : if (root) {
61 : GF_Scene *top_scene;
62 : //notify before disconnecting
63 0 : if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err, GF_FALSE);
64 :
65 : //detach clocks before destroying namspace
66 0 : root->ck = NULL;
67 0 : if (root->subscene) {
68 0 : u32 i, count = gf_list_count(root->subscene->resources);
69 0 : for (i=0; i<count; i++) {
70 0 : GF_ObjectManager *anodm = gf_list_get(root->subscene->resources, i);
71 0 : anodm->ck = NULL;
72 0 : if (anodm->scene_ns==root->scene_ns)
73 0 : anodm->scene_ns = NULL;
74 : }
75 : }
76 :
77 0 : root->scene_ns = NULL;
78 0 : if (scene_ns->owner && scene_ns->nb_odm_users) scene_ns->nb_odm_users--;
79 0 : scene_ns->owner = NULL;
80 :
81 0 : top_scene = gf_scene_get_root_scene(scene);
82 :
83 : //source filter no longer exists
84 0 : scene_ns->source_filter = NULL;
85 0 : gf_scene_ns_del(scene_ns, top_scene);
86 :
87 0 : if (!root->parentscene) {
88 : GF_Event evt;
89 0 : evt.type = GF_EVENT_CONNECT;
90 0 : evt.connect.is_connected = 0;
91 0 : gf_filter_send_gf_event(scene->compositor->filter, &evt);
92 : } else {
93 : /*try to reinsert OD for VRML/X3D with multiple URLs:
94 : 1- first remove from parent scene without destroying object, this will trigger a re-setup
95 : if other URLs are present
96 : 2- then destroy object*/
97 0 : gf_scene_remove_object(root->parentscene, root, 0);
98 0 : gf_odm_disconnect(root, 1);
99 : }
100 0 : return;
101 : }
102 : }
103 : }
104 :
105 :
106 :
107 : #ifdef FILTER_FIXME
108 : static void term_on_disconnect(GF_ClientService *service, LPNETCHANNEL netch, GF_Err response)
109 : {
110 : GF_ObjectManager *root;
111 : GF_Channel *ch;
112 : GF_Terminal *term = service->term;
113 :
114 : /*may be null upon destroy*/
115 : root = service->owner;
116 : if (root && (root->net_service != service)) {
117 : if (root->net_service) gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR);
118 : return;
119 : }
120 : //reset global seek time
121 : if (term->root_scene && term->root_scene->root_od)
122 : term->root_scene->root_od->media_start_time = 0;
123 :
124 : /*this is service disconnect*/
125 : if (!netch) {
126 : if (service->subservice_disconnect) {
127 : if (service->owner && service->subservice_disconnect==1) {
128 : GF_Scene *scene = service->owner->subscene ? service->owner->subscene : service->owner->parentscene;
129 : /*destroy all media*/
130 : gf_scene_disconnect(scene, GF_TRUE);
131 : }
132 : return;
133 : }
134 : /*unregister from valid services*/
135 : if (gf_list_del_item(term->net_services, service)>=0) {
136 : /*and queue for destroy*/
137 : gf_list_add(term->net_services_to_remove, service);
138 : }
139 : return;
140 : }
141 : /*this is channel disconnect*/
142 :
143 : /*no notif in case of failure for disconnection*/
144 : ch = gf_term_get_channel(service, netch);
145 : if (!ch) return;
146 : /*signal channel state*/
147 : ch->es_state = GF_ESM_ES_DISCONNECTED;
148 : }
149 : #endif
150 :
151 887 : void gf_scene_insert_pid(GF_Scene *scene, GF_SceneNamespace *sns, GF_FilterPid *pid, Bool is_in_iod)
152 : {
153 : u32 i, min_od_id;
154 : GF_MediaObject *the_mo;
155 : GF_ObjectManager *odm, *root;
156 : const GF_PropertyValue *v;
157 : u32 mtype=0;
158 : u32 pid_odid=0;
159 : u32 pid_id=0;
160 : u32 ServiceID=0;
161 :
162 887 : root = sns->owner;
163 887 : if (!root) {
164 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] has no root, aborting !\n", sns->url));
165 : return;
166 : }
167 887 : if (root->flags & GF_ODM_DESTROYED) {
168 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] root has been scheduled for destruction - aborting !\n", sns->url));
169 : return;
170 : }
171 887 : scene = root->subscene ? root->subscene : root->parentscene;
172 887 : if (scene->root_od->addon && (scene->root_od->addon->addon_type == GF_ADDON_TYPE_MAIN)) {
173 0 : scene->root_od->flags |= GF_ODM_REGENERATE_SCENE;
174 : }
175 :
176 887 : if (scene->is_dynamic_scene) {
177 209 : if (!root->ID)
178 207 : root->ID = 1;
179 : }
180 :
181 887 : v = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
182 887 : if (!v) return;
183 887 : mtype = v->value.uint;
184 :
185 887 : v = gf_filter_pid_get_property(pid, GF_PROP_PID_SERVICE_ID);
186 887 : if (v) ServiceID = v->value.uint;
187 :
188 887 : v = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
189 887 : if (v) pid_id = v->value.uint;
190 :
191 887 : if (scene->compositor->autofps && (mtype==GF_STREAM_VISUAL) ) {
192 345 : v = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
193 345 : if (v && v->value.frac.den && v->value.frac.num && (v->value.frac.den!=v->value.frac.num)) {
194 180 : scene->compositor->autofps = GF_FALSE;
195 180 : gf_sc_set_fps(scene->compositor, v->value.frac);
196 : }
197 : }
198 :
199 887 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Service %s] Adding new media\n", sns->url));
200 :
201 : /*object declared this way are not part of an OD stream and are considered as dynamic*/
202 : /* od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; */
203 :
204 : /*check if we have a mediaObject in the scene not attached and matching this object*/
205 : the_mo = NULL;
206 : odm = NULL;
207 : min_od_id = 0;
208 139 : for (i=0; i<gf_list_count(scene->scene_objects); i++) {
209 : #if FILTER_FIXME
210 : char *frag = NULL;
211 : #endif
212 : char *ext, *url;
213 : u32 match_esid = 0;
214 : Bool type_matched = GF_FALSE;
215 310 : GF_MediaObject *mo = gf_list_get(scene->scene_objects, i);
216 :
217 310 : if ((mo->OD_ID != GF_MEDIA_EXTERNAL_ID) && (min_od_id<mo->OD_ID))
218 : min_od_id = mo->OD_ID;
219 :
220 : //got the service, check the type
221 : /*match type*/
222 310 : switch (mtype) {
223 256 : case GF_STREAM_VISUAL:
224 256 : if (mo->type == GF_MEDIA_OBJECT_VIDEO) type_matched = GF_TRUE;
225 : break;
226 21 : case GF_STREAM_AUDIO:
227 21 : if (mo->type == GF_MEDIA_OBJECT_AUDIO) type_matched = GF_TRUE;
228 : break;
229 29 : case GF_STREAM_SCENE:
230 29 : if (mo->type == GF_MEDIA_OBJECT_UPDATES) type_matched = GF_TRUE;
231 : break;
232 : default:
233 : break;
234 : }
235 310 : if (!mo->odm) {
236 : u32 j;
237 : //if not external OD, look for ODM with same ID
238 14 : if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) {
239 6 : for (j=0; j<gf_list_count(scene->resources); j++) {
240 20 : GF_ObjectManager *an_odm = gf_list_get(scene->resources, j);
241 20 : if (an_odm->ID == mo->OD_ID) {
242 14 : mo->odm = an_odm;
243 14 : break;
244 : }
245 : }
246 : }
247 14 : if (!mo->odm) {
248 0 : continue;
249 : }
250 : }
251 : /*if object is attached to a service, don't bother looking in a different one*/
252 310 : if (mo->odm->scene_ns && (mo->odm->scene_ns != sns)) {
253 : Bool mine = 0;
254 284 : if (mo->odm->scene_ns->source_filter) {
255 217 : mine = gf_filter_pid_is_filter_in_parents(pid, mo->odm->scene_ns->source_filter);
256 : }
257 : //passthrough ODM not yet assigned, consider it ours
258 67 : else if (!mo->odm->pid && (mo->odm->flags & GF_ODM_PASSTHROUGH)) {
259 : mine = GF_TRUE;
260 : }
261 327 : if (!mine) continue;
262 :
263 174 : if (type_matched) {
264 : the_mo = mo;
265 171 : odm = mo->odm;
266 171 : pid_odid = odm->ID = mo->OD_ID;
267 171 : break;
268 : }
269 : }
270 :
271 : /*already assigned object*/
272 29 : if (mo->odm->ID) continue;
273 :
274 : /*we cannot match yet the object, we need the OD command for that*/
275 0 : if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) {
276 0 : continue;
277 : }
278 0 : if (!mo->URLs.count || !mo->URLs.vals[0].url) continue;
279 :
280 0 : ext = strrchr(mo->URLs.vals[0].url, '#');
281 0 : if (ext) {
282 : #if FILTER_FIXME
283 : frag = strchr(ext, '=');
284 : #endif
285 0 : ext[0] = 0;
286 : }
287 0 : url = mo->URLs.vals[0].url;
288 0 : if (!strnicmp(url, "file://localhost", 16)) url += 16;
289 0 : else if (!strnicmp(url, "file://", 7)) url += 7;
290 0 : else if (!strnicmp(url, "gpac://", 7)) url += 7;
291 0 : else if (!strnicmp(url, "pid://", 6)) match_esid = atoi(url+6);
292 :
293 0 : if (!match_esid && mo->odm->scene_ns && !strstr(mo->odm->scene_ns->url, url)) {
294 0 : if (ext) ext[0] = '#';
295 0 : continue;
296 : }
297 0 : if (ext) ext[0] = '#';
298 :
299 0 : if (match_esid && (pid_id != match_esid))
300 0 : continue;
301 :
302 : /*match type*/
303 0 : switch (mtype) {
304 0 : case GF_STREAM_VISUAL:
305 0 : if (mo->type != GF_MEDIA_OBJECT_VIDEO) continue;
306 : break;
307 0 : case GF_STREAM_AUDIO:
308 0 : if (mo->type != GF_MEDIA_OBJECT_AUDIO) continue;
309 : break;
310 0 : case GF_STREAM_SCENE:
311 0 : if (mo->type != GF_MEDIA_OBJECT_UPDATES) continue;
312 : break;
313 0 : default:
314 0 : continue;
315 : }
316 : #if FILTER_FIXME
317 : if (frag) {
318 : u32 frag_id = 0;
319 : u32 ID = od->objectDescriptorID;
320 : if (ID==GF_MEDIA_EXTERNAL_ID) ID = esd->ESID;
321 : frag++;
322 : frag_id = atoi(frag);
323 : if (ID!=frag_id) continue;
324 : }
325 : #endif
326 : the_mo = mo;
327 0 : odm = mo->odm;
328 0 : pid_odid = odm->ID = mo->OD_ID;
329 0 : if (mo->OD_ID == GF_MEDIA_EXTERNAL_ID)
330 0 : odm->flags |= GF_ODM_NOT_IN_OD_STREAM;
331 : break;
332 : }
333 :
334 : /*add a pass on scene->resource to check for min_od_id,
335 : otherwise we may have another modules declaring an object with ID 0 from
336 : another thread, which will assert (only one object with a givne OD ID)*/
337 1241 : for (i=0; i<gf_list_count(scene->resources); i++) {
338 371 : GF_ObjectManager *an_odm = gf_list_get(scene->resources, i);
339 :
340 371 : if (an_odm->ID == GF_MEDIA_EXTERNAL_ID) continue;
341 :
342 274 : if (min_od_id < an_odm->ID)
343 : min_od_id = an_odm->ID;
344 :
345 274 : if (odm) continue;
346 : //check for OD replacement, look for ODMs with no PID assigned and a source filter origin for this pid
347 65 : if (an_odm->pid) continue;
348 :
349 24 : if (!an_odm->scene_ns->source_filter) continue;
350 17 : if (! gf_filter_pid_is_filter_in_parents(pid, an_odm->scene_ns->source_filter))
351 0 : continue;
352 :
353 : odm = an_odm;
354 17 : pid_odid = an_odm->ID;
355 17 : break;
356 : }
357 :
358 887 : if (is_in_iod) {
359 479 : odm = scene->root_od;
360 : //for inline cases, the media object may already be setup
361 479 : the_mo = odm->mo;
362 479 : if (the_mo) pid_odid = the_mo->OD_ID;
363 : }
364 :
365 887 : if (!odm) {
366 220 : odm = gf_odm_new();
367 220 : odm->parentscene = scene;
368 220 : gf_list_add(scene->resources, odm);
369 : }
370 887 : odm->flags |= GF_ODM_NOT_SETUP;
371 887 : if (!pid_odid) {
372 658 : pid_odid = min_od_id + 1;
373 : }
374 887 : odm->ID = pid_odid;
375 887 : odm->mo = the_mo;
376 887 : odm->ServiceID = ServiceID;
377 887 : if (!odm->pid) {
378 881 : odm->type = mtype;
379 881 : if (mtype == GF_STREAM_AUDIO) {
380 18 : scene->compositor->audio_renderer->nb_audio_objects++;
381 18 : scene->compositor->audio_renderer->scene_ready = GF_FALSE;
382 : }
383 : }
384 :
385 : //register PID with ODM, but don't call setup object
386 887 : gf_odm_register_pid(odm, pid, GF_TRUE);
387 :
388 887 : gf_filter_pid_set_udta(pid, odm);
389 :
390 887 : v = gf_filter_pid_get_property(pid, GF_PROP_PID_PLAYBACK_MODE);
391 887 : if (!v || !v->value.uint) odm->flags |= GF_ODM_NO_TIME_CTRL;
392 :
393 887 : if (the_mo) the_mo->OD_ID = odm->ID;
394 887 : if (!scene->selected_service_id)
395 887 : scene->selected_service_id = ServiceID;
396 :
397 887 : if (odm->parentscene && odm->parentscene->is_dynamic_scene)
398 209 : odm->flags |= GF_ODM_NOT_IN_OD_STREAM;
399 :
400 : //we insert right away the PID as a new object if the scene is dynamic
401 : //if the scene is not dynamic, we wait for the corresponding OD update
402 : //FILTER_FIXME: needs rework to enable attaching subtitle to a non-dynamic scene
403 : //otherwise if subscene, this is an IOD
404 887 : if (odm->subscene || (odm->flags & GF_ODM_NOT_IN_OD_STREAM) ) {
405 876 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] setup object - MO %08x\n", odm->ID, odm->mo));
406 876 : gf_odm_setup_object(odm, sns, pid);
407 : } else {
408 : //cannot setup until we get the associated OD_Update
409 11 : odm->ID = 0;
410 : }
411 :
412 887 : if (scene->is_dynamic_scene && !root->scene_ns->connect_ack) {
413 : /*othewise send a connect ack for top level*/
414 : GF_Event evt;
415 209 : root->scene_ns->connect_ack = GF_TRUE;
416 :
417 209 : GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM] Root object connected (%s) !\n", root->scene_ns->url));
418 :
419 209 : evt.type = GF_EVENT_CONNECT;
420 209 : evt.connect.is_connected = GF_TRUE;
421 209 : gf_sc_send_event(scene->compositor, &evt);
422 : }
423 : }
424 :
425 906 : GF_SceneNamespace *gf_scene_ns_new(GF_Scene *scene, GF_ObjectManager *owner, const char *url, const char *parent_url)
426 : {
427 : char *frag;
428 : GF_SceneNamespace *sns;
429 :
430 906 : GF_SAFEALLOC(sns, GF_SceneNamespace);
431 906 : if (!sns) {
432 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Compose] Failed to allocate namespace\n"));
433 : return NULL;
434 : }
435 906 : sns->owner = owner;
436 906 : sns->url = gf_url_concatenate(parent_url, url);
437 906 : sns->clocks = gf_list_new();
438 906 : frag = strchr(sns->url, '#');
439 906 : if (frag) {
440 0 : sns->url_frag = gf_strdup(frag+1);
441 0 : frag[0] = 0;
442 : }
443 :
444 : //move to top scene
445 906 : scene = gf_scene_get_root_scene(scene);
446 906 : gf_list_add(scene->namespaces, sns);
447 :
448 906 : return sns;
449 : }
450 :
451 :
452 :
453 906 : void gf_scene_ns_del(GF_SceneNamespace *sns, GF_Scene *root_scene)
454 : {
455 906 : gf_list_del_item(root_scene->namespaces, sns);
456 :
457 906 : if (sns->source_filter) {
458 230 : gf_filter_remove_src(root_scene->compositor->filter, sns->source_filter);
459 : }
460 906 : if (sns->clocks) {
461 1747 : while (gf_list_count(sns->clocks)) {
462 841 : GF_Clock *ck = gf_list_pop_back(sns->clocks);
463 841 : gf_clock_del(ck);
464 : }
465 906 : gf_list_del(sns->clocks);
466 : }
467 906 : if (sns->url) gf_free(sns->url);
468 906 : if (sns->url_frag) gf_free(sns->url_frag);
469 906 : gf_free(sns);
470 906 : }
471 :
472 :
473 3 : Bool scene_ns_remove_object(GF_Filter *filter, void *callback, u32 *reschedule_ms)
474 : {
475 : GF_ObjectManager *odm = (GF_ObjectManager *)callback;
476 3 : gf_odm_disconnect(odm, 2);
477 3 : return GF_FALSE;
478 : }
479 :
480 : /*connects given OD manager to its URL*/
481 274 : void gf_scene_ns_connect_object(GF_Scene *scene, GF_ObjectManager *odm, char *serviceURL, char *parent_url)
482 : {
483 : GF_Err e;
484 : char *frag;
485 : Bool reloc_result=GF_FALSE;
486 :
487 : /*check cache*/
488 274 : if (parent_url) {
489 : u32 i, count;
490 260 : count = gf_opts_get_section_count();
491 2454 : for (i=0; i<count; i++) {
492 : u32 exp, sec, frac;
493 : const char *opt, *service_cache;
494 2194 : const char *name = gf_opts_get_section_name(i);
495 4388 : if (strncmp(name, "@cache=", 7)) continue;
496 0 : opt = gf_opts_get_key(name, "serviceURL");
497 0 : if (!opt || stricmp(opt, parent_url)) continue;
498 0 : opt = gf_opts_get_key(name, "cacheName");
499 0 : if (!opt || stricmp(opt, serviceURL)) continue;
500 :
501 0 : service_cache = (char*)gf_opts_get_key(name, "cacheFile");
502 0 : opt = gf_opts_get_key(name, "expireAfterNTP");
503 0 : if (opt) {
504 0 : sscanf(opt, "%u", &exp);
505 0 : gf_net_get_ntp(&sec, &frac);
506 0 : if (exp && (exp<sec)) {
507 0 : opt = gf_opts_get_key(name, "cacheFile");
508 0 : if (opt) gf_file_delete((char*) opt);
509 0 : gf_opts_del_section(name);
510 : service_cache = NULL;
511 : }
512 : }
513 0 : if (service_cache) serviceURL = (char *)service_cache;
514 0 : break;
515 : }
516 : }
517 :
518 274 : frag = strchr(serviceURL, '#');
519 274 : if (frag) {
520 10 : frag[0] = 0;
521 10 : u32 i, count = gf_list_count(scene->compositor->root_scene->namespaces);
522 21 : for (i=0; i<count; i++) {
523 11 : GF_SceneNamespace *sns = gf_list_get(scene->compositor->root_scene->namespaces, i);
524 11 : if (sns->url && !strcmp(sns->url, serviceURL)) {
525 0 : frag[0] = '#';
526 0 : odm->scene_ns = sns;
527 0 : sns->nb_odm_users++;
528 3 : return;
529 : }
530 : }
531 : }
532 :
533 274 : odm->scene_ns = gf_scene_ns_new(scene->compositor->root_scene, odm, serviceURL, (odm->addon || reloc_result) ? NULL : parent_url);
534 :
535 274 : if (!odm->scene_ns) {
536 0 : gf_scene_message(scene, serviceURL, "Cannot create scene service", GF_OUT_OF_MEM);
537 0 : gf_odm_disconnect(odm, 1);
538 0 : if (frag) frag[0] = '#';
539 : return;
540 : }
541 274 : odm->scene_ns->nb_odm_users++;
542 : assert(odm->scene_ns->owner == odm);
543 :
544 274 : if (frag && !odm->scene_ns->url_frag) {
545 10 : odm->scene_ns->url_frag = gf_strdup(frag+1);
546 : }
547 :
548 274 : if (!strncmp(serviceURL, "gpid://", 7)) {
549 0 : gf_odm_service_media_event(odm, GF_EVENT_MEDIA_SETUP_BEGIN);
550 0 : gf_odm_service_media_event(odm, GF_EVENT_MEDIA_SETUP_DONE);
551 0 : odm->scene_ns->connect_ack = GF_TRUE;
552 0 : odm->flags |= GF_ODM_NOT_IN_OD_STREAM | GF_ODM_PASSTHROUGH;
553 0 : if (frag) frag[0] = '#';
554 : return;
555 : }
556 274 : if (!parent_url && odm->parentscene && odm->parentscene->root_od->scene_ns)
557 7 : parent_url = odm->parentscene->root_od->scene_ns->url;
558 :
559 274 : odm->scene_ns->source_filter = gf_filter_connect_source(scene->compositor->filter, serviceURL, parent_url, GF_FALSE, &e);
560 :
561 274 : if (frag) frag[0] = '#';
562 274 : if (!odm->scene_ns->source_filter) {
563 : Bool remove_scene=GF_FALSE;
564 3 : GF_Scene *target_scene = odm->subscene ? NULL : odm->parentscene;
565 3 : if (odm->mo) odm->mo->connect_failure = GF_TRUE;
566 3 : odm->skip_disconnect_state = 1;
567 : //prevent scene from being disconnected - this can happen if a script catches the event and triggers a disonnection of the parent scene
568 3 : if (target_scene) target_scene->root_od->skip_disconnect_state = 1;
569 3 : gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, e, GF_TRUE);
570 3 : gf_scene_message(scene, serviceURL, "Cannot find filter for service", e);
571 3 : odm->skip_disconnect_state = 0;
572 :
573 3 : if (target_scene) {
574 2 : if (target_scene->root_od->skip_disconnect_state==2) remove_scene = GF_TRUE;
575 2 : target_scene->root_od->skip_disconnect_state = 0;
576 : }
577 2 : if (remove_scene) {
578 0 : gf_filter_post_task(scene->compositor->filter, scene_ns_remove_object, target_scene->root_od, "remove_odm");
579 : } else {
580 3 : gf_filter_post_task(scene->compositor->filter, scene_ns_remove_object, odm, "remove_odm");
581 : }
582 : return;
583 : }
584 : //make sure we only connect this filter to ourselves
585 271 : gf_filter_set_source_restricted(scene->compositor->filter, odm->scene_ns->source_filter, NULL);
586 :
587 271 : gf_filter_set_setup_failure_callback(scene->compositor->filter, odm->scene_ns->source_filter, scene_ns_on_setup_error, odm);
588 :
589 : /*OK connect*/
590 271 : gf_odm_service_media_event(odm, GF_EVENT_MEDIA_SETUP_BEGIN);
591 : }
592 :
593 :
594 : GF_EXPORT
595 2 : Bool gf_term_is_supported_url(GF_Terminal *term, const char *fileName, Bool use_parent_url, Bool no_mime_check)
596 : {
597 : #ifdef FILTER_FIXME
598 : GF_InputService *ifce;
599 : GF_Err e;
600 : char *sURL;
601 : char *mime=NULL;
602 : char *parent_url = NULL;
603 : if (use_parent_url && term->root_scene) parent_url = term->root_scene->root_od->net_service->url;
604 :
605 : ifce = gf_term_can_handle_service(term, fileName, parent_url, no_mime_check, &sURL, &e, NULL, &mime);
606 : if (!ifce) return 0;
607 : gf_modules_close_interface((GF_BaseInterface *) ifce);
608 : gf_free(sURL);
609 : if (mime) gf_free(mime);
610 : #endif
611 2 : return 1;
612 : }
|