static void gf_inline_traverse(GF_Node *n, void *rs, Bool is_destroy) { MFURL *current_url; GF_Scene *scene = (GF_Scene *)gf_node_get_private(n); if (is_destroy) { GF_MediaObject *mo; if (!scene) return; mo = scene->root_od ? scene->root_od->mo : NULL; gf_scene_notify_event(scene, GF_EVENT_UNLOAD, n, NULL, GF_OK); if (!mo) return; gf_list_del_item(mo->nodes, n); /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/ if (mo->num_open) { mo->num_open --; if (!mo->num_open) { gf_term_lock_media_queue(scene->root_od->term, 1); /*this is unspecified in the spec: whenever an inline not using the OD framework is destroyed, destroy the associated resource*/ if (mo->OD_ID == GF_MEDIA_EXTERNAL_ID) { /*get parent scene and remove MediaObject in case the ressource gets re-requested later on*/ GF_Scene *parent_scene = (GF_Scene *)gf_sg_get_private(gf_node_get_graph((GF_Node *) n) ); if (gf_list_del_item(parent_scene->scene_objects, mo)>=0) { gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL); gf_list_del(mo->nodes); if (mo->odm) mo->odm->mo = NULL; gf_free(mo); } scene->root_od->action_type = GF_ODM_ACTION_DELETE; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } else { scene->root_od->action_type = GF_ODM_ACTION_SCENE_DISCONNECT; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } gf_term_lock_media_queue(scene->root_od->term, 0); } } return; } //if no private scene is associated get the node parent graph, retrieve the IS and find the OD if (!scene) { M_Inline *inl = (M_Inline *)n; gf_inline_set_scene(inl); scene = (GF_Scene *)gf_node_get_private(n); if (!scene) { /*just like protos, we must invalidate parent graph until attached*/ if (inl->url.count) { if (!inl->url.vals[0].OD_ID && (!inl->url.vals[0].url || !strlen(inl->url.vals[0].url) ) ) { gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL); } else { gf_node_dirty_set(n, 0, 1); } } return; } } gf_inline_check_restart(scene); /*if we need to restart, shutdown graph and do it*/ if (scene->needs_restart) { /*special case: scene change*/ if (scene->needs_restart==2) { scene->needs_restart = 0; gf_inline_on_modified(n); return; } scene->needs_restart = 0; gf_term_lock_media_queue(scene->root_od->term, 1); scene->root_od->action_type = GF_ODM_ACTION_SCENE_INLINE_RESTART; gf_list_add(scene->root_od->term->media_queue, scene->root_od); gf_term_lock_media_queue(scene->root_od->term, 0); gf_node_dirty_set(n, 0, 1); return; } /*if not attached return (attaching the graph cannot be done in render since render is not called while unattached :) */ if (!scene->graph_attached) { /*just like protos, we must invalidate parent graph until attached*/ gf_node_dirty_set(n, 0, 1); return; } /*clear dirty flags for any sub-inlines, bitmaps or protos*/ gf_node_dirty_clear(n, 0); current_url = scene->current_url; scene->current_url = & ((M_Inline*)n)->url; gf_sc_traverse_subscene(scene->root_od->term->compositor, n, scene->graph, rs); scene->current_url = current_url; }
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); }
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); } } }