Bool MC_URLChanged(MFURL *old_url, MFURL *new_url) { u32 i; if (gf_mo_get_od_id(old_url) != gf_mo_get_od_id(new_url)) return 1; if (old_url->count != new_url->count) return 1; for (i=0; i<old_url->count; i++) { if (old_url->vals[i].url || new_url->vals[i].url) { if (!old_url->vals[i].url || !new_url->vals[i].url) return 1; if (strcmp(old_url->vals[i].url, new_url->vals[i].url)) return 1; } } return 0; }
void gf_inline_on_modified(GF_Node *node) { u32 ODID; GF_MediaObject *mo; M_Inline *pInline = (M_Inline *) node; GF_Scene *scene = (GF_Scene *)gf_node_get_private(node); ODID = gf_mo_get_od_id(&pInline->url); if (scene) { mo = (scene->root_od) ? scene->root_od->mo : NULL; /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/ if (mo) { Bool changed = 1; if (ODID != GF_MEDIA_EXTERNAL_ID) { if (ODID && (ODID==scene->root_od->OD->objectDescriptorID)) changed = 0; } else { if (gf_mo_is_same_url(mo, &pInline->url, NULL, 0) ) changed = 0; } if (mo->num_open) { if (!changed) return; gf_scene_notify_event(scene, GF_EVENT_UNLOAD, node, NULL, GF_OK); gf_node_dirty_parents(node); gf_list_del_item(mo->nodes, node); /*reset the scene pointer as it may get destroyed*/ switch (gf_node_get_tag(node)) { case TAG_MPEG4_Inline: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: #endif gf_node_set_private(node, NULL); break; } mo->num_open --; if (!mo->num_open) { if (ODID == GF_MEDIA_EXTERNAL_ID) { GF_Scene *parent = scene->root_od->parentscene; /*!!! THIS WILL DESTROY THE INLINE SCENE OBJECT !!!*/ gf_odm_disconnect(scene->root_od, 1); /*and force removal of the media object*/ if (parent) { if (gf_list_del_item(parent->scene_objects, mo)>=0) { gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL); gf_list_del(mo->nodes); gf_free(mo); } } } else { gf_term_lock_media_queue(scene->root_od->term, 1); /*external media are completely unloaded*/ if (scene->root_od->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID) { scene->root_od->action_type = GF_ODM_ACTION_DELETE; } else { scene->root_od->action_type = GF_ODM_ACTION_STOP; } if (gf_list_find(scene->root_od->term->media_queue, scene->root_od)<0) gf_list_add(scene->root_od->term->media_queue, scene->root_od); gf_term_lock_media_queue(scene->root_od->term, 0); } } } } } else { gf_node_dirty_parents(node); } if (ODID) gf_inline_set_scene(pInline); }
GF_SceneGraph *gf_inline_get_proto_lib(void *_is, MFURL *lib_url) { GF_ProtoLink *pl; u32 i; GF_Scene *scene = (GF_Scene *) _is; if (!scene || !lib_url->count) return NULL; if (gf_inline_is_hardcoded_proto(lib_url, scene->root_od->term->user->config)) return GF_SG_INTERNAL_PROTO; i=0; while ((pl = (GF_ProtoLink*)gf_list_enum(scene->extern_protos, &i))) { if (!pl->mo) continue; if (gf_mo_get_od_id(pl->url) != GF_MEDIA_EXTERNAL_ID) { if (gf_mo_get_od_id(pl->url) == gf_mo_get_od_id(lib_url)) { if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL; return pl->mo->odm->subscene->graph; } } } /*for string URL based protos, recursively check until top if the proto lib is not already present*/ if (lib_url->vals[0].url) { GF_Scene *check_scene = scene; while (check_scene) { i=0; while ((pl = (GF_ProtoLink*)gf_list_enum(check_scene->extern_protos, &i))) { char *url1, *url2; Bool ok; if (!pl->mo) continue; if (gf_mo_get_od_id(pl->url) != GF_MEDIA_EXTERNAL_ID) continue; /*not the same url*/ if (!gf_mo_is_same_url(pl->mo, lib_url, NULL, 0)) continue; /*check the url path is the same*/ url1 = gf_url_concatenate(pl->mo->odm->net_service->url, lib_url->vals[0].url); url2 = gf_url_concatenate(scene->root_od->net_service->url, lib_url->vals[0].url); ok = 0; if (url1 && url2 && !strcmp(url1, url2)) ok=1; if (url1) gf_free(url1); if (url2) gf_free(url2); if (!ok) continue; if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL; return pl->mo->odm->subscene->graph; } check_scene = check_scene->root_od->parentscene; } } /*not found, let's try to load it*/ if (!lib_url || !lib_url->count) return NULL; /*internal, don't waste ressources*/ if (gf_inline_is_hardcoded_proto(lib_url, scene->root_od->term->user->config)) return NULL; i=0; while ((pl = (GF_ProtoLink*)gf_list_enum(scene->extern_protos, &i)) ) { if (pl->url == lib_url) return NULL; if (pl->url->vals[0].OD_ID && (pl->url->vals[0].OD_ID == lib_url->vals[0].OD_ID)) return NULL; if (pl->url->vals[0].url && lib_url->vals[0].url && !stricmp(pl->url->vals[0].url, lib_url->vals[0].url) ) return NULL; } pl = (GF_ProtoLink*)gf_malloc(sizeof(GF_ProtoLink)); pl->url = lib_url; gf_list_add(scene->extern_protos, pl); pl->mo = gf_scene_get_media_object(scene, lib_url, GF_MEDIA_OBJECT_SCENE, 0); /*this may already be destroyed*/ if (pl->mo) gf_mo_play(pl->mo, 0, -1, 0); /*and return NULL*/ return NULL; }
void gf_inline_on_modified(GF_Node *node) { u32 ODID; GF_MediaObject *mo; M_Inline *pInline = (M_Inline *) node; GF_Scene *scene = (GF_Scene *)gf_node_get_private(node); ODID = gf_mo_get_od_id(&pInline->url); if (scene) { mo = (scene->root_od) ? scene->root_od->mo : NULL; /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/ if (mo) { Bool changed = GF_TRUE; if (ODID != GF_MEDIA_EXTERNAL_ID) { if (ODID && (ODID==scene->root_od->OD->objectDescriptorID)) changed = GF_FALSE; } else { if (gf_mo_is_same_url(mo, &pInline->url, NULL, 0) ) changed = GF_FALSE; } if (mo->num_open) { if (!changed) return; gf_scene_notify_event(scene, GF_EVENT_UNLOAD, node, NULL, GF_OK, GF_TRUE); gf_node_dirty_parents(node); gf_mo_event_target_remove_by_node(mo, node); /*reset the scene pointer as it may get destroyed*/ switch (gf_node_get_tag(node)) { case TAG_MPEG4_Inline: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: #endif gf_node_set_private(node, NULL); break; } mo->num_open --; if (!mo->num_open) { if (ODID == GF_MEDIA_EXTERNAL_ID) { GF_Scene *parent = scene->root_od->parentscene; /*!!! THIS WILL DESTROY THE INLINE SCENE OBJECT !!!*/ gf_odm_disconnect(scene->root_od, GF_TRUE); /*and force removal of the media object*/ if (parent) { if (gf_list_del_item(parent->scene_objects, mo)>=0) { gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL); gf_mo_del(mo); } } } else { gf_term_lock_media_queue(scene->root_od->term, GF_TRUE); /*external media are completely unloaded, except addons which are only declared once */ if (!scene->root_od->addon && (scene->root_od->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID)) { scene->root_od->action_type = GF_ODM_ACTION_DELETE; } else { scene->root_od->action_type = GF_ODM_ACTION_STOP; } if (gf_list_find(scene->root_od->term->media_queue, scene->root_od)<0) gf_list_add(scene->root_od->term->media_queue, scene->root_od); gf_term_lock_media_queue(scene->root_od->term, GF_FALSE); } } } } } /*force a redraw and load scene at next pass - we cannot load the scene now because - we can be in a JS call (eg JS mutex blocked) - locating scene objects matching the new url needs exclusive access to the MediaObject list, achieved with the term net mutex - another service may already be setting up objects (eg exclusive access to the net mutex grabbed), which can trigger event forwarding - some event forwarders may request JS context (eg access to JS mutex) In such a case we would end up in a deadlock - this needs urgent fixing ... */ if (ODID) { /*if no parent we must process the url change as we may not be traversed later on (not in the scene tree)*/ if (gf_node_get_parent(node, 0)==NULL) { gf_inline_set_scene(pInline); } else { gf_node_dirty_parents(node); } } }