static GF_MediaObject *get_sync_reference(GF_Scene *scene, XMLRI *iri, u32 o_type, GF_Node *orig_ref, Bool *post_pone) { MFURL mfurl; SFURL sfurl; GF_MediaObject *res; GF_Node *ref = NULL; u32 stream_id = 0; if (iri->type==XMLRI_STREAMID) { stream_id = iri->lsr_stream_id; } else if (!iri->string) { return NULL; } else { if (iri->target) ref = iri->target; else if (iri->string[0]=='#') ref = gf_sg_find_node_by_name(scene->graph, iri->string+1); else ref = gf_sg_find_node_by_name(scene->graph, iri->string); if (ref) { #ifndef GPAC_DISABLE_SVG GF_FieldInfo info; #endif /*safety check, break cyclic references*/ if (ref==orig_ref) return NULL; switch (ref->sgprivate->tag) { #ifndef GPAC_DISABLE_SVG case TAG_SVG_audio: o_type = GF_MEDIA_OBJECT_AUDIO; if (gf_node_get_attribute_by_tag(ref, TAG_XLINK_ATT_href, 0, 0, &info)==GF_OK) { return get_sync_reference(scene, info.far_ptr, o_type, orig_ref ? orig_ref : ref, post_pone); } return NULL; case TAG_SVG_video: o_type = GF_MEDIA_OBJECT_VIDEO; if (gf_node_get_attribute_by_tag(ref, TAG_XLINK_ATT_href, 0, 0, &info)==GF_OK) { return get_sync_reference(scene, info.far_ptr, o_type, orig_ref ? orig_ref : ref, post_pone); } return NULL; #endif default: return NULL; } } } *post_pone = 0; mfurl.count = 1; mfurl.vals = &sfurl; mfurl.vals[0].OD_ID = stream_id; mfurl.vals[0].url = iri->string; res = gf_scene_get_media_object(scene, &mfurl, o_type, 0); if (!res) *post_pone = 1; return res; }
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 RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) { Bool shall_restart, need_restart; GF_MediaObject *prev; GF_ObjectManager *odm; GF_TraverseState *tr_state = (GF_TraverseState *)rs; MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node); if (is_destroy) { GF_ObjectManager *odm; MediaControlStack *stack = (MediaControlStack *) gf_node_get_private(node); /*reset ODM using this control*/ if (stack->stream) { if (stack->stream->odm) { odm = stack->stream->odm; gf_odm_remove_mediacontrol(odm, stack); } /*also removes the association ck<->MC if the object has been destroyed before the node*/ if (stack->ck) stack->ck->mc = NULL; } gf_list_del(stack->seg); gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL); gf_free(stack); return; } //we need to disable culling otherwise we may never be called back again ... tr_state->disable_cull = 1; /*not changed nothing to do - note we need to register with stream yet for control switching...*/ if (stack->stream && (!stack->changed || !stack->control->enabled)) return; need_restart = (stack->changed==2) ? 1 : 0; shall_restart = (stack->control->mediaStartTime>=0) ? 1 : 0; /*check url target*/ if (stack->stream) { if (MC_URLChanged(&stack->url, &stack->control->url)) { gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL); prev = stack->stream; if (gf_list_find(stack->parent->scene_objects, prev)<0) prev = NULL; stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0); if (stack->stream) { if (!stack->stream->odm) return; /*MediaControl on inline: if dynamic scene, make sure it is connected before attaching...*/ if (stack->stream->odm->subscene) { if (stack->stream->odm->subscene->is_dynamic_scene && !stack->stream->odm->subscene->dyn_ck) return; } gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL); /*remove from prev*/ if (prev && prev->odm && (prev != stack->stream)) gf_odm_remove_mediacontrol(prev->odm, stack); /*register with new*/ /*if we assigned the media control to an exiting object - force the state of the object*/ gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack); while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0); gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url); stack->current_seg = 0; //do not restart if no mediaStartTime and speed is 1 if ((stack->control->mediaStartTime>0) || gf_list_count(stack->seg) || (stack->control->mediaSpeed != FIX_ONE) ) { shall_restart = need_restart = 1; } else { shall_restart = need_restart = 0; //URL changed, we are by default in PLAY mode. stack->media_speed = 1; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); } /*control has been removed and we were paused, resume*/ else if (stack->paused) { mediacontrol_resume((GF_ObjectManager *) prev->odm, 0); stack->paused = 0; } /*MediaControl has been detached*/ else { if (prev) gf_odm_remove_mediacontrol(prev->odm, stack); return; } } } else { stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0); if (!stack->stream || !stack->stream->odm) { if (stack->control->url.count) gf_term_invalidate_compositor(stack->parent->root_od->term); stack->stream = NULL; stack->changed = 0; return; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); /*OD not ready yet*/ if (!stack->ck) { stack->stream = NULL; if (stack->control->url.count) { stack->is_init = 0; gf_term_invalidate_compositor(stack->parent->root_od->term); } return; } gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL); gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack); while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0); gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url); stack->current_seg = 0; /*we shouldn't have to restart unless start/stop times have been changed, which is tested below*/ need_restart = 0; } if (!stack->changed || !stack->control->enabled || !stack->stream) return; /*if not previously enabled and now enabled, switch all other controls off and reactivate*/ if (!stack->enabled) { stack->enabled = 1; need_restart = gf_odm_switch_mediacontrol(stack->stream->odm, stack); } stack->changed = 0; if (!stack->control->mediaSpeed) shall_restart = 0; odm = (GF_ObjectManager *)stack->stream->odm; /*check for changes*/ if (!stack->is_init) { /*not linked yet*/ if (!odm) return; stack->media_speed = stack->control->mediaSpeed; stack->enabled = stack->control->enabled; stack->media_start = stack->control->mediaStartTime; stack->media_stop = stack->control->mediaStopTime; stack->is_init = 1; stack->paused = 0; /*the object has already been started, and media start time is not 0, restart*/ if (stack->stream->num_open) { if ( (stack->media_start > 0) || (gf_list_count(stack->seg)>0 ) || (stack->media_speed!=FIX_ONE ) ) { mediacontrol_restart(odm); } else if (stack->media_speed == 0) { mediacontrol_pause(odm); stack->paused = 1; } } return; } if (stack->media_speed != stack->control->mediaSpeed) { /*if no speed pause*/ if (!stack->control->mediaSpeed && !stack->paused) { mediacontrol_pause(odm); stack->paused = 1; } /*else resume if paused*/ else if (stack->control->mediaSpeed && stack->paused) { mediacontrol_resume(odm, 0); stack->paused = 0; need_restart += shall_restart; } /*else set speed*/ else if (stack->media_speed && stack->control->mediaSpeed) { /*don't set speed if we have to restart the media ...*/ if (!shall_restart) MC_SetSpeed(odm, stack->control->mediaSpeed); need_restart += shall_restart; } /*init state was paused*/ else if (!stack->media_speed) { need_restart ++; } stack->media_speed = stack->control->mediaSpeed; } /*check start/stop changes*/ if (stack->media_start != stack->control->mediaStartTime) { stack->media_start = stack->control->mediaStartTime; need_restart += shall_restart; } /*stop change triggers restart no matter what (new range) if playing*/ if (stack->media_stop != stack->control->mediaStopTime) { stack->media_stop = stack->control->mediaStopTime; if (stack->control->mediaSpeed) need_restart = 1; } if (need_restart) { mediacontrol_restart(odm); } /*handle preroll*/ }