GF_EXPORT Bool gf_inline_is_default_viewpoint(GF_Node *node) { const char *nname, *seg_name; GF_SceneGraph *sg = gf_node_get_graph(node); GF_Scene *scene = sg ? (GF_Scene *) gf_sg_get_private(sg) : NULL; if (!scene) return 0; nname = gf_node_get_name(node); if (!nname) return 0; /*check any viewpoint*/ seg_name = strrchr(scene->root_od->net_service->url, '#'); /*check the URL of the parent*/ if (!seg_name && scene->current_url) { if (scene->current_url->count && scene->current_url->vals[0].url) seg_name = strrchr(scene->current_url->vals[0].url, '#'); } else if (!seg_name && scene->root_od->mo && scene->root_od->mo->URLs.count && scene->root_od->mo->URLs.vals[0].url) { seg_name = strrchr(scene->root_od->mo->URLs.vals[0].url, '#'); } if (!seg_name) return 0; seg_name += 1; /*look for a media segment with this name - if none found, this is a viewpoint name*/ if (gf_odm_find_segment(scene->root_od, (char *) seg_name) != NULL) return 0; return (!strcmp(nname, seg_name)); }
/* Creates a subscene from the xlink:href */ static GF_Scene *gf_svg_get_subscene(GF_Node *elt, XLinkAttributesPointers *xlinkp, SMILSyncAttributesPointers *syncp, Bool use_sync, Bool primary_resource) { MFURL url; Bool lock_timelines = 0; GF_MediaObject *mo; GF_SceneGraph *graph = gf_node_get_graph(elt); GF_Scene *scene = (GF_Scene *)gf_sg_get_private(graph); if (!scene) return NULL; if (use_sync && syncp) { switch ((syncp->syncBehavior?*syncp->syncBehavior:SMIL_SYNCBEHAVIOR_DEFAULT)) { case SMIL_SYNCBEHAVIOR_LOCKED: case SMIL_SYNCBEHAVIOR_CANSLIP: lock_timelines = 1; break; case SMIL_SYNCBEHAVIOR_DEFAULT: { #if 0 if (svg && syncp) { switch ((syncp->syncBehaviorDefault ? *syncp->syncBehaviorDefault : SMIL_SYNCBEHAVIOR_LOCKED)) { case SMIL_SYNCBEHAVIOR_LOCKED: case SMIL_SYNCBEHAVIOR_CANSLIP: lock_timelines = 1; break; default: break; } } #endif } default: break; } } memset(&url, 0, sizeof(MFURL)); if (!xlinkp->href) return NULL; gf_term_get_mfurl_from_xlink(elt, &url); while (scene->secondary_resource && scene->root_od->parentscene) scene = scene->root_od->parentscene; mo = gf_scene_get_media_object_ex(scene, &url, GF_MEDIA_OBJECT_SCENE, lock_timelines, NULL, primary_resource, elt); gf_sg_vrml_mf_reset(&url, GF_SG_VRML_MFURL); if (!mo || !mo->odm) return NULL; mo->odm->subscene->secondary_resource = primary_resource ? 0 : 1; return mo->odm->subscene; }
GF_Node *gf_scene_get_keynav(GF_SceneGraph *sg, GF_Node *sensor) { #ifndef GPAC_DISABLE_VRML u32 i, count; GF_Scene *scene = gf_sg_get_private(sg); if (!scene) return NULL; if (!sensor) return gf_list_get(scene->keynavigators, 0); count = gf_list_count(scene->keynavigators); for (i=0; i<count; i++) { M_KeyNavigator *kn = gf_list_get(scene->keynavigators, i); if (kn->sensor==sensor) return (GF_Node *) kn; } #endif return NULL; }
static void TraverseInputSensor(GF_Node *node, void *rs, Bool is_destroy) { ISStack *st = (ISStack*)gf_node_get_private(node); M_InputSensor *is = (M_InputSensor *)node; if (is_destroy) { GF_Scene *scene; if (st->registered) IS_Unregister(node, st); scene = (GF_Scene*)gf_sg_get_private(gf_node_get_graph(node)); gf_term_unqueue_node_traverse(scene->root_od->term, node); gf_free(st); } else { /*get decoder object */ if (!st->mo) st->mo = gf_mo_register(node, &is->url, 0, 0); /*register with decoder*/ if (st->mo && !st->registered) IS_Register(node); } }
static void RenderInputSensor(GF_Node *node, void *rs, Bool is_destroy) { ISStack *st = (ISStack*)gf_node_get_private(node); M_InputSensor *is = (M_InputSensor *)node; if (is_destroy) { GF_InlineScene *is; if (st->registered) IS_Unregister(st); is = (GF_InlineScene*)gf_sg_get_private(gf_node_get_graph(node)); gf_term_rem_render_node(is->root_od->term, node); free(st); } else { /*get decoder object */ if (!st->mo) st->mo = gf_mo_find(node, &is->url, 0); /*register with decoder*/ if (st->mo && !st->registered) IS_Register(node); } }
static Bool gf_inline_set_scene(M_Inline *root) { GF_MediaObject *mo; GF_Scene *parent; GF_SceneGraph *graph = gf_node_get_graph((GF_Node *) root); parent = (GF_Scene *)gf_sg_get_private(graph); if (!parent) return 0; mo = gf_scene_get_media_object_ex(parent, &root->url, GF_MEDIA_OBJECT_SCENE, 0, NULL, 0, (GF_Node*)root); if (!mo || !mo->odm) return 0; if (!mo->odm->subscene) { gf_term_invalidate_compositor(parent->root_od->term); return 0; } /*assign inline scene as private stack of inline node, and remember inline node for event propagation*/ gf_node_set_private((GF_Node *)root, mo->odm->subscene); /*play*/ gf_mo_play(mo, 0, -1, 0); return 1; }
GF_EXPORT GF_Err gf_term_get_mfurl_from_xlink(GF_Node *node, MFURL *mfurl) { u32 stream_id = 0; GF_Err e = GF_OK; SFURL *sfurl = NULL; GF_FieldInfo info; XMLRI *iri; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return GF_BAD_PARAM; gf_sg_vrml_mf_reset(mfurl, GF_SG_VRML_MFURL); e = gf_node_get_attribute_by_tag(node, TAG_XLINK_ATT_href, 0, 0, &info); if (e) return e; iri = (XMLRI*)info.far_ptr; if (iri->type==XMLRI_STREAMID) { stream_id = iri->lsr_stream_id; } else if (!iri->string) return GF_OK; mfurl->count = 1; GF_SAFEALLOC(mfurl->vals, SFURL) sfurl = mfurl->vals; sfurl->OD_ID = stream_id; if (stream_id) return GF_OK; if (!strncmp(iri->string, "data:", 5)) { const char *cache_dir = gf_cfg_get_key(scene->root_od->term->user->config, "General", "CacheDirectory"); e = gf_node_store_embedded_data(iri, cache_dir, "embedded_"); if (e) return e; sfurl->url = gf_strdup(iri->string); return GF_OK; } sfurl->url = gf_term_resolve_xlink(node, iri->string); return e; }
char *gf_term_resolve_xlink(GF_Node *node, char *the_url) { char *url; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return NULL; url = gf_strdup(the_url); /*apply XML:base*/ while (node) { GF_FieldInfo info; if (gf_node_get_attribute_by_tag(node, TAG_XML_ATT_base, 0, 0, &info)==GF_OK) { char *new_url = gf_url_concatenate( ((XMLRI*)info.far_ptr)->string, url); if (new_url) { gf_free(url); url = new_url; } } node = gf_node_get_parent(node, 0); } /*if this is a fragment and no XML:BASE was found, this is a fragment of the current document*/ if (url[0]=='#') return url; if (scene) { char *the_url; if (scene->redirect_xml_base) { the_url = gf_url_concatenate(scene->redirect_xml_base, url); } else { // the_url = gf_url_concatenate(is->root_od->net_service->url, url); /*the root url of a document should be "." if not specified, so that the final URL resolve happens only once at the service level*/ the_url = gf_strdup(url); } gf_free(url); return the_url; } return url; }
GF_MediaObject *gf_mo_load_xlink_resource(GF_Node *node, Bool primary_resource, Double clipBegin, Double clipEnd) { GF_Scene *new_resource; SVGAllAttributes all_atts; XLinkAttributesPointers xlinkp; SMILSyncAttributesPointers syncp; GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node)); if (!scene) return NULL; gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); xlinkp.actuate = all_atts.xlink_actuate; xlinkp.arcrole = all_atts.xlink_arcrole; xlinkp.href = all_atts.xlink_href; xlinkp.role = all_atts.xlink_role; xlinkp.show = all_atts.xlink_show; xlinkp.title = all_atts.xlink_title; xlinkp.type = all_atts.xlink_type; syncp.syncBehavior = all_atts.syncBehavior; syncp.syncBehaviorDefault = all_atts.syncBehaviorDefault; syncp.syncMaster = all_atts.syncMaster; syncp.syncReference = all_atts.syncReference; syncp.syncTolerance = all_atts.syncTolerance; syncp.syncToleranceDefault = all_atts.syncToleranceDefault; if (!xlinkp.href) return NULL; if (xlinkp.href->type == XMLRI_ELEMENTID) return NULL; // else if (xlinkp.href->string && (xlinkp.href->string[0]=='#')) return NULL; new_resource = gf_svg_get_subscene(node, &xlinkp, &syncp, primary_resource ? 1 : 0, primary_resource); if (!new_resource) return NULL; /*play*/ gf_mo_play(new_resource->root_od->mo, 0, -1, 0); return new_resource->root_od->mo; }
GF_EXPORT GF_MediaObject *gf_mo_register(GF_Node *node, MFURL *url, Bool lock_timelines, Bool force_new_res) { u32 obj_type; #ifndef GPAC_DISABLE_SVG Bool post_pone; GF_FieldInfo info; #endif GF_Scene *scene; GF_MediaObject *res, *syncRef; GF_SceneGraph *sg = gf_node_get_graph(node); if (!sg) return NULL; scene = (GF_Scene*)gf_sg_get_private(sg); if (!scene) return NULL; syncRef = NULL; /*keep track of the kind of object expected if URL is not using OD scheme*/ switch (gf_node_get_tag(node)) { #ifndef GPAC_DISABLE_VRML /*MPEG-4 / VRML / X3D only*/ case TAG_MPEG4_AudioClip: case TAG_MPEG4_AudioSource: #ifndef GPAC_DISABLE_X3D case TAG_X3D_AudioClip: #endif obj_type = GF_MEDIA_OBJECT_AUDIO; break; case TAG_MPEG4_SBVCAnimation: case TAG_MPEG4_AnimationStream: obj_type = GF_MEDIA_OBJECT_UPDATES; break; case TAG_MPEG4_BitWrapper: obj_type = GF_MEDIA_OBJECT_SCENE; break; case TAG_MPEG4_InputSensor: obj_type = GF_MEDIA_OBJECT_INTERACT; break; case TAG_MPEG4_Background2D: case TAG_MPEG4_Background: case TAG_MPEG4_ImageTexture: case TAG_MPEG4_CacheTexture: case TAG_MPEG4_MovieTexture: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Background: case TAG_X3D_ImageTexture: case TAG_X3D_MovieTexture: #endif obj_type = GF_MEDIA_OBJECT_VIDEO; break; case TAG_MPEG4_Inline: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: #endif obj_type = GF_MEDIA_OBJECT_SCENE; break; #endif /*GPAC_DISABLE_VRML*/ /*SVG*/ #ifndef GPAC_DISABLE_SVG case TAG_SVG_audio: obj_type = GF_MEDIA_OBJECT_AUDIO; if (gf_node_get_attribute_by_tag(node, TAG_SVG_ATT_syncReference, GF_FALSE, GF_FALSE, &info)==GF_OK) { syncRef = get_sync_reference(scene, (XMLRI *)info.far_ptr, GF_MEDIA_OBJECT_UNDEF, node, &post_pone); /*syncRef is specified but doesn't exist yet, post-pone*/ if (post_pone) return NULL; } break; case TAG_SVG_video: obj_type = GF_MEDIA_OBJECT_VIDEO; if (gf_node_get_attribute_by_tag(node, TAG_SVG_ATT_syncReference, GF_FALSE, GF_FALSE, &info)==GF_OK) { syncRef = get_sync_reference(scene, (XMLRI *)info.far_ptr, GF_MEDIA_OBJECT_UNDEF, node, &post_pone); /*syncRef is specified but doesn't exist yet, post-pone*/ if (post_pone) return NULL; } break; case TAG_SVG_image: obj_type = GF_MEDIA_OBJECT_VIDEO; break; case TAG_SVG_foreignObject: case TAG_SVG_animation: obj_type = GF_MEDIA_OBJECT_SCENE; break; case TAG_LSR_updates: obj_type = GF_MEDIA_OBJECT_UPDATES; break; #endif default: obj_type = GF_MEDIA_OBJECT_UNDEF; break; } /*move to primary resource handler*/ while (scene->secondary_resource && scene->root_od->parentscene) scene = scene->root_od->parentscene; res = gf_scene_get_media_object_ex(scene, url, obj_type, lock_timelines, syncRef, force_new_res, node); return res; }
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; }