📄 inline.c
字号:
} /*check on full URL without removing fragment IDs*/ if (include_sub_url) { for (i=0; i<an_url->count; i++) { if (!stricmp(szURL1, an_url->vals[i].url)) return 1; } return 0; } ext = strrchr(szURL1, '#'); if (ext) ext[0] = 0; for (i=0; i<an_url->count; i++) { strcpy(szURL2, an_url->vals[i].url); ext = strrchr(szURL2, '#'); if (ext) ext[0] = 0; if (!stricmp(szURL1, szURL2)) return 1; } return 0;}void gf_is_on_modified(GF_Node *node){ u32 ODID; GF_MediaObject *mo; M_Inline *pInline = (M_Inline *) node; GF_InlineScene *pIS = (GF_InlineScene *)gf_node_get_private(node); ODID = URL_GetODID(&pInline->url); if (pIS) { mo = (pIS->root_od) ? pIS->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_ESM_DYNAMIC_OD_ID) { if (ODID && (ODID==pIS->root_od->OD->objectDescriptorID)) changed = 0; } else { if (gf_mo_is_same_url(mo, &pInline->url) ) changed = 0; } if (mo->num_open) { if (!changed) return; mo->num_open --; if (!mo->num_open) { gf_odm_stop(pIS->root_od, 1); gf_is_disconnect(pIS, 1); assert(gf_list_count(pIS->ODlist) == 0); } } } } if (ODID) Inline_SetScene(pInline);}static void IS_CheckMediaRestart(GF_InlineScene *is){ /*no ctrl if no duration*/ if (!is->duration) return; if (!is->needs_restart) gf_odm_check_segment_switch(is->root_od); if (is->needs_restart) return; if (is->root_od->media_ctrl && is->root_od->media_ctrl->control->loop) { GF_Clock *ck = gf_odm_get_media_clock(is->root_od); if (ck->has_seen_eos) { u32 now = gf_clock_time(ck); u64 dur = is->duration; if (is->root_od->media_ctrl->current_seg) { /*only process when all segments are played*/ if (gf_list_count(is->root_od->media_ctrl->seg) <= is->root_od->media_ctrl->current_seg) { is->needs_restart = 1; is->root_od->media_ctrl->current_seg = 0; } } else { Double s, e; s = now; s/=1000; e = -1; MC_GetRange(is->root_od->media_ctrl, &s, &e); if ((e>=0) && (e<GF_MAX_FLOAT)) dur = (u32) (e*1000); if (dur<now) { is->needs_restart = 1; is->root_od->media_ctrl->current_seg = 0; } } } else { /*trigger render until to watch for restart...*/ gf_term_invalidate_renderer(is->root_od->term); } }}void gf_is_render(GF_Node *n, void *render_stack, Bool is_destroy){ GF_Node *root; GF_InlineScene *is = (GF_InlineScene *)gf_node_get_private(n); if (is_destroy) { GF_MediaObject *mo = (is && is->root_od) ? is->root_od->mo : NULL; if (!mo) return; /*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) { /*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_ESM_DYNAMIC_OD_ID) { gf_odm_disconnect(is->root_od, 1); } else { gf_odm_stop(is->root_od, 1); gf_is_disconnect(is, 1); assert(gf_list_count(is->ODlist) == 0); } } } return; } //if no private scene is associated get the node parent graph, retrieve the IS and find the OD if (!is) { Inline_SetScene((M_Inline *) n); is = (GF_InlineScene *)gf_node_get_private(n); if (!is) { /*just like protos, we must invalidate parent graph until attached*/ gf_node_dirty_set(n, 0, 1); return; } } IS_CheckMediaRestart(is); /*if we need to restart, shutdown graph and do it*/ if (is->needs_restart) { u32 current_seg = 0; /*special case: scene change*/ if (is->needs_restart==2) { is->needs_restart = 0; gf_is_on_modified(n); return; } if (is->root_od->media_ctrl) current_seg = is->root_od->media_ctrl->current_seg; is->needs_restart = 0; if (is->is_dynamic_scene) { if (is->root_od->media_ctrl) is->root_od->media_ctrl->current_seg = current_seg; gf_is_restart_dynamic(is, 0); } else { /*we cannot use gf_mo_restart since it only sets the needs_restart for inline scenes. The rational is that gf_mo_restart can be called from the parent scene (OK) or from the scene itself, in which case shutting down the graph would crash the renderer. We therefore need two render passes to safely restart an inline scene*/ /*1- stop main object from playing but don't disconnect channels*/ gf_odm_stop(is->root_od, 1); /*2- close all ODs inside the scene and reset the graph*/ gf_is_disconnect(is, 0); if (is->root_od->media_ctrl) is->root_od->media_ctrl->current_seg = current_seg; /*3- restart the scene*/ gf_odm_start(is->root_od); } 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 (!is->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); root = gf_sg_get_root_node(is->graph); if (root) { gf_sr_render_inline(is->root_od->term->renderer, n, root, render_stack); }}GF_EXPORTvoid gf_is_attach_to_renderer(GF_InlineScene *is){ if ((is->graph_attached==1) || (gf_sg_get_root_node(is->graph)==NULL) ) { gf_term_invalidate_renderer(is->root_od->term); return; } is->graph_attached = 1; /*main display scene, setup renderer*/ if (is->root_od->term->root_scene == is) { gf_sr_set_scene(is->root_od->term->renderer, is->graph); } else { gf_term_invalidate_renderer(is->root_od->term); }}static GF_MediaObject *IS_CheckExistingObject(GF_InlineScene *is, MFURL *urls){ GF_MediaObject *obj; u32 i = 0; while ((obj = (GF_MediaObject *)gf_list_enum(is->media_objects, &i))) { if ((obj->OD_ID == GF_ESM_DYNAMIC_OD_ID) && gf_mo_is_same_url(obj, urls)) return obj; else if ((obj->OD_ID != GF_ESM_DYNAMIC_OD_ID) && (obj->OD_ID == urls->vals[0].OD_ID)) return obj; } return NULL;}static GFINLINE Bool is_match_obj_type(u32 type, u32 hint_type){ if (!hint_type) return 1; if (type==hint_type) return 1; /*TEXT are used by animation stream*/ if ((type==GF_MEDIA_OBJECT_TEXT) && (hint_type==GF_MEDIA_OBJECT_BIFS)) return 1; return 0;}GF_MediaObject *gf_is_get_media_object_ex(GF_InlineScene *is, MFURL *url, u32 obj_type_hint, Bool lock_timelines, GF_MediaObject *sync_ref){ GF_MediaObject *obj; u32 i, OD_ID; OD_ID = URL_GetODID(url); if (!OD_ID) return NULL; obj = NULL; i=0; while ((obj = (GF_MediaObject *)gf_list_enum(is->media_objects, &i))) { /*regular OD scheme*/ if (OD_ID != GF_ESM_DYNAMIC_OD_ID && (obj->OD_ID==OD_ID)) return obj; /*dynamic OD scheme*/ if ((OD_ID == GF_ESM_DYNAMIC_OD_ID) && (obj->OD_ID==GF_ESM_DYNAMIC_OD_ID) /*if object type unknown (media control, media sensor), return first obj matching URL otherwise check types*/ && is_match_obj_type(obj->type, obj_type_hint) /*locate sub-url in given one (handles viewpoint/segments)*/ && gf_mo_is_same_url(obj, url) ) return obj; } /*we cannot create an OD manager at this point*/ if (obj_type_hint==GF_MEDIA_OBJECT_UNDEF) return NULL; /*create a new object identification*/ obj = gf_mo_new(); obj->OD_ID = OD_ID; obj->type = obj_type_hint; gf_list_add(is->media_objects, obj); if (OD_ID == GF_ESM_DYNAMIC_OD_ID) { gf_sg_vrml_field_copy(&obj->URLs, url, GF_SG_VRML_MFURL); IS_InsertObject(is, obj, lock_timelines, sync_ref); /*safety check!!!*/ if (gf_list_find(is->media_objects, obj)<0) return NULL; } return obj;}GF_MediaObject *gf_is_get_media_object(GF_InlineScene *is, MFURL *url, u32 obj_type_hint, Bool lock_timelines){ return gf_is_get_media_object_ex(is, url, obj_type_hint, lock_timelines, NULL);}GF_EXPORTvoid gf_is_setup_object(GF_InlineScene *is, GF_ObjectManager *odm){ GF_MediaObject *obj; u32 i; /*an object may already be assigned (when using ESD URLs, setup is performed twice)*/ if (odm->mo != NULL) goto existing; i=0; while ((obj = (GF_MediaObject*)gf_list_enum(is->media_objects, &i))) { if (obj->OD_ID==GF_ESM_DYNAMIC_OD_ID) { //assert(obj->odm); if (obj->odm == odm) { /*assign FINAL OD, not parent*/ obj->odm = odm; odm->mo = obj; goto existing; } } else if (obj->OD_ID == odm->OD->objectDescriptorID) { assert(obj->odm==NULL); obj->odm = odm; odm->mo = obj; goto existing; } } /*newly created OD*/ odm->mo = gf_mo_new(); gf_list_add(is->media_objects, odm->mo); odm->mo->odm = odm; odm->mo->OD_ID = odm->OD->objectDescriptorID;existing: /*setup object type*/ if (!odm->codec) odm->mo->type = GF_MEDIA_OBJECT_SCENE; else if (odm->codec->type == GF_STREAM_VISUAL) odm->mo->type = GF_MEDIA_OBJECT_VIDEO; else if (odm->codec->type == GF_STREAM_AUDIO) odm->mo->type = GF_MEDIA_OBJECT_AUDIO; else if (odm->codec->type == GF_STREAM_TEXT) odm->mo->type = GF_MEDIA_OBJECT_TEXT; else if (odm->codec->type == GF_STREAM_SCENE) odm->mo->type = GF_MEDIA_OBJECT_BIFS; /*update info*/ MO_UpdateCaps(odm->mo); /*media object playback has already been requested by the scene, trigger media start*/ if (odm->mo->num_open && !odm->state) { gf_odm_start(odm); if (odm->mo->speed != FIX_ONE) gf_odm_set_speed(odm, odm->mo->speed); } /*invalidate scene for all nodes using the OD*/ gf_term_invalidate_renderer(odm->term);}void gf_is_restart(GF_InlineScene *is){ is->needs_restart = 1; gf_term_invalidate_renderer(is->root_od->term);}GF_EXPORTvoid gf_is_set_duration(GF_InlineScene *is){ Double dur; u32 i; u64 max_dur; GF_ObjectManager *odm; MediaSensorStack *media_sens; GF_Clock *ck; /*this is not normative but works in so many cases... set the duration to the max duration of all streams sharing the clock*/ ck = gf_odm_get_media_clock(is->root_od); max_dur = is->root_od->duration; i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(is->ODlist, &i))) { if (!odm->codec) continue; if (!ck || gf_odm_shares_clock(odm, ck)) { if (odm->duration>max_dur) max_dur = odm->duration; } } if (is->duration == max_dur) return; is->duration = max_dur; dur = (Double) (s64) is->duration; dur /= 1000; i=0; while ((media_sens = (MediaSensorStack*)gf_list_enum(is->root_od->ms_stack, &i))) { if (media_sens->sensor->isActive) { media_sens->sensor->mediaDuration = dur; gf_node_event_out_str((GF_Node *) media_sens->sensor, "mediaDuration"); } } if ((is == is->root_od->term->root_scene) && is->root_od->term->user->EventProc) { GF_Event evt; evt.type = GF_EVENT_DURATION; evt.duration.duration = dur; evt.duration.can_seek = !(is->root_od->flags & GF_ODM_NO_TIME_CTRL); if (dur<2.0) evt.duration.can_seek = 0; GF_USER_SENDEVENT(is->root_od->term->user,&evt); }}static Bool IS_IsHardcodedProto(MFURL *url, GF_Config *cfg){ u32 i; const char *sOpt = gf_cfg_get_key(cfg, "Systems", "hardcoded_protos"); for (i=0; i<url->count; i++) { if (!url->vals[i].url) continue; if (strstr(url->vals[i].url, "urn:inet:gpac:builtin")) return 1; if (sOpt && strstr(sOpt, url->vals[i].url)) return 1; } return 0;}void IS_LoadExternProto(GF_InlineScene *is, MFURL *url){ u32 i; ProtoLink *pl; if (!url || !url->count) return; /*internal, don't waste ressources*/ if (IS_IsHardcodedProto(url, is->root_od->term->user->config)) return; i=0; while ((pl = (ProtoLink*)gf_list_enum(is->extern_protos, &i)) ) { if (pl->url == url) return; if (pl->url->vals[0].OD_ID && (pl->url->vals[0].OD_ID == url->vals[0].OD_ID)) return; if (pl->url->vals[0].url && url->vals[0].url && !stricmp(pl->url->vals[0].url, url->vals[0].url) ) return; } pl = (ProtoLink*)malloc(sizeof(ProtoLink)); pl->url = url; gf_list_add(is->extern_protos, pl); pl->mo = gf_is_get_media_object(is, url, GF_MEDIA_OBJECT_SCENE, 0); /*this may already be destroyed*/ if (pl->mo) gf_mo_play(pl->mo, 0, -1, 0);}GF_EXPORTGF_SceneGraph *gf_is_get_proto_lib(void *_is, MFURL *lib_url){ ProtoLink *pl; u32 i; GF_InlineScene *is = (GF_InlineScene *) _is; if (!is || !lib_url->count) return NULL; if (IS_IsHardcodedProto(lib_url, is->root_od->term->user->config)) return GF_SG_INTERNAL_PROTO; i=0; while ((pl = (ProtoLink*)gf_list_enum(is->extern_protos, &i))) { if (!pl->mo) continue; if (URL_GetODID(pl->url) != GF_ESM_DYNAMIC_OD_ID) { if (URL_GetODID(pl->url) == URL_GetODID(lib_url)) { if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL; return pl->mo->odm->subscene->graph; } } else if (lib_url->vals[0].url) { if (gf_mo_is_same_url(pl->mo, lib_url)) { if (!pl->mo->odm || !pl->mo->odm->subscene) return NULL; return pl->mo->odm->subscene->graph; } } } /*not found, create loader*/ IS_LoadExternProto(is, lib_url); /*and return NULL*/ return NULL;}GF_ObjectManager *IS_GetProtoSceneByGraph(void *_is, GF_SceneGraph *sg){ u32 i; ProtoLink *pl; GF_InlineScene *is = (GF_InlineScene *) _is; if (!is) return NULL; i=0; while ((pl = (ProtoLink*)gf_list_enum(is->extern_protos, &i))) { if (pl->mo->odm && pl->mo->odm->subscene && (pl->mo->odm->subscene->graph==sg)) return pl->mo->odm; } return NULL;}Bool IS_IsProtoLibObject(GF_InlineScene *is, GF_ObjectManager *odm){ u32 i; ProtoLink *pl; i=0; while ((pl = (ProtoLink*)gf_list_enum(is->extern_protos, &i))) { if (pl->mo->odm == odm) return 1; } return 0;}GF_MediaObject *gf_is_find_object(GF_InlineScene *is, u16 ODID, char *url){ u32 i; GF_MediaObject *mo; if (!url && !ODID) return NULL; i=0; while ((mo = (GF_MediaObject *)gf_list_enum(is->media_objects, &i))) { if (ODID==GF_ESM_DYNAMIC_OD_ID) { if (mo->URLs.count && !stricmp(mo->URLs.vals[0].url, url)) return mo; } else if (mo->OD_ID==ODID) return mo; } return NULL;}const char *IS_GetSceneViewName(GF_InlineScene *is) { char *seg_name; /*check any viewpoint*/ seg_name = strrchr(is->root_od->net_service->url, '#'); if (!seg_name) return NULL; seg_name += 1; /*look for a media segment with this name - if none found, this is a viewpoint name*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -