📄 inline.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Media terminal sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * *//*for OD service types*/#include <gpac/constants.h>#include <gpac/internal/terminal_dev.h>#include "media_control.h"/*for inline scene rendering*/#include <gpac/renderer.h>void MO_UpdateCaps(GF_MediaObject *mo);/*extern proto fetcher*/typedef struct{ MFURL *url; GF_MediaObject *mo;} ProtoLink;GF_EXPORTDouble gf_is_get_time(void *_is){ u32 ret; GF_Clock *ck; GF_InlineScene *is = (GF_InlineScene *)_is; assert(is); ck = is->scene_codec ? is->scene_codec->ck : is->dyn_ck; if (!ck) return 0.0; ret = gf_clock_time(ck); if (is->root_od->media_stop_time && (is->root_od->media_stop_time<ret)) ret = (u32) is->root_od->media_stop_time; return ret/1000.0;}GF_InlineScene *gf_is_new(GF_InlineScene *parentScene){ GF_InlineScene *tmp; GF_SAFEALLOC(tmp, GF_InlineScene); if (! tmp) return NULL; tmp->ODlist = gf_list_new(); tmp->media_objects = gf_list_new(); tmp->extern_protos = gf_list_new(); tmp->inline_nodes = gf_list_new(); tmp->extra_scenes = gf_list_new(); /*init inline scene*/ if (parentScene) { tmp->graph = gf_sg_new_subscene(parentScene->graph); } else { tmp->graph = gf_sg_new(); } gf_sg_set_private(tmp->graph, tmp); gf_sg_set_node_callback(tmp->graph, gf_term_node_callback); gf_sg_set_scene_time_callback(tmp->graph, gf_is_get_time); gf_sg_set_proto_loader(tmp->graph, gf_is_get_proto_lib); return tmp;}void gf_is_del(GF_InlineScene *is){ gf_list_del(is->ODlist); gf_list_del(is->inline_nodes); assert(!gf_list_count(is->extra_scenes) ); gf_list_del(is->extra_scenes); while (gf_list_count(is->extern_protos)) { ProtoLink *pl = (ProtoLink *)gf_list_get(is->extern_protos, 0); gf_list_rem(is->extern_protos, 0); free(pl); } gf_list_del(is->extern_protos); /*delete scene decoder */ if (is->scene_codec) { GF_SceneDecoder *dec = (GF_SceneDecoder *)is->scene_codec->decio; /*make sure the scene codec doesn't have anything left in the scene graph*/ if (dec->ReleaseScene) dec->ReleaseScene(dec); gf_term_remove_codec(is->root_od->term, is->scene_codec); gf_codec_del(is->scene_codec); /*reset pointer to NULL in case nodes try to access scene time*/ is->scene_codec = NULL; } /*delete the scene graph*/ gf_sg_del(is->graph); if (is->od_codec) { gf_term_remove_codec(is->root_od->term, is->od_codec); gf_codec_del(is->od_codec); is->od_codec = NULL; } /*don't touch the root_od, will be deleted by the parent scene*/ /*clean all remaining associations*/ while (gf_list_count(is->media_objects)) { GF_MediaObject *obj = (GF_MediaObject *)gf_list_get(is->media_objects, 0); if (obj->odm) obj->odm->mo = NULL; gf_list_rem(is->media_objects, 0); gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL); free(obj); } gf_list_del(is->media_objects); if (is->audio_url.url) free(is->audio_url.url); if (is->visual_url.url) free(is->visual_url.url); if (is->text_url.url) free(is->text_url.url); free(is);}GF_EXPORTGF_ObjectManager *gf_is_find_odm(GF_InlineScene *is, u16 OD_ID){ GF_ObjectManager *odm; u32 i=0; while ((odm = (GF_ObjectManager *)gf_list_enum(is->ODlist, &i))) { if (odm->OD->objectDescriptorID == OD_ID) return odm; } return NULL;}void gf_is_disconnect(GF_InlineScene *is, Bool for_shutdown){ GF_MediaObject *obj; GF_Node *root_node; GF_ObjectManager *odm; GF_SceneDecoder *dec = NULL; if (is->scene_codec) dec = (GF_SceneDecoder *)is->scene_codec->decio; gf_term_lock_renderer(is->root_od->term, 1); /*disconnect / kill all objects BEFORE reseting the scene graph since we have potentially registered Inline nodes of the graph with the sub-scene*/ if (!for_shutdown && is->static_media_ressources) { u32 i=0; /*stop all objects but DON'T DESTROY THEM*/ while ((odm = (GF_ObjectManager *)gf_list_enum(is->ODlist, &i))) { if (odm->state) gf_odm_disconnect(odm, 0); } /*reset all stream associations*/ i=0; while ((obj = (GF_MediaObject*)gf_list_enum(is->media_objects, &i))) { gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL); } } else { while (gf_list_count(is->ODlist)) { odm = (GF_ObjectManager *)gf_list_get(is->ODlist, 0); gf_odm_disconnect(odm, (for_shutdown || !is->static_media_ressources) ? 1 : 0); } } root_node = gf_sg_get_root_node(is->graph); while (gf_list_count(is->inline_nodes)) { GF_Node *n = (GF_Node *)gf_list_get(is->inline_nodes, 0); gf_list_rem(is->inline_nodes, 0); gf_node_set_private(n, NULL); } if (is->graph_attached && (is->root_od->term->root_scene == is)) { gf_sr_set_scene(is->root_od->term->renderer, NULL); } /*release the scene*/ if (dec && dec->ReleaseScene) dec->ReleaseScene(dec); gf_sg_reset(is->graph); is->graph_attached = 0; gf_term_lock_renderer(is->root_od->term, 0); assert(!gf_list_count(is->extra_scenes) ); /*reset statc ressource flag since we destroyed scene objects*/ is->static_media_ressources = 0; /*remove stream associations*/ while (gf_list_count(is->media_objects)) { obj = (GF_MediaObject*)gf_list_get(is->media_objects, 0); gf_list_rem(is->media_objects, 0); if (obj->odm) obj->odm->mo = NULL; gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL); free(obj); }}static void IS_InsertObject(GF_InlineScene *is, GF_MediaObject *mo, Bool lock_timelines, GF_MediaObject *sync_ref){ GF_ObjectManager *root_od; GF_ObjectManager *odm; char *url; if (!mo || !is) return; odm = gf_odm_new(); /*remember OD*/ odm->mo = mo; mo->odm = odm; odm->parentscene = is; odm->OD = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); odm->OD->objectDescriptorID = GF_ESM_DYNAMIC_OD_ID; odm->parentscene = is; odm->term = is->root_od->term; root_od = is->root_od; url = mo->URLs.vals[0].url; if (!stricmp(url, "KeySensor")) { GF_ESD *esd = gf_odf_desc_esd_new(0); esd->decoderConfig->streamType = GF_STREAM_INTERACT; esd->decoderConfig->objectTypeIndication = 1; free(esd->decoderConfig->decoderSpecificInfo->data); esd->decoderConfig->decoderSpecificInfo->data = strdup(" KeySensor"); esd->decoderConfig->decoderSpecificInfo->data[0] = 9; esd->decoderConfig->decoderSpecificInfo->dataLength = 10; esd->ESID = esd->OCRESID = 65534; gf_list_add(odm->OD->ESDescriptors, esd); } else if (!stricmp(url, "StringSensor")) { GF_ESD *esd = gf_odf_desc_esd_new(0); esd->decoderConfig->streamType = GF_STREAM_INTERACT; esd->decoderConfig->objectTypeIndication = 1; free(esd->decoderConfig->decoderSpecificInfo->data); esd->decoderConfig->decoderSpecificInfo->data = strdup(" StringSensor"); esd->decoderConfig->decoderSpecificInfo->data[0] = 12; esd->decoderConfig->decoderSpecificInfo->dataLength = 13; esd->ESID = esd->OCRESID = 65534; gf_list_add(odm->OD->ESDescriptors, esd); } else if (!stricmp(url, "Mouse")) { GF_ESD *esd = gf_odf_desc_esd_new(0); esd->decoderConfig->streamType = GF_STREAM_INTERACT; esd->decoderConfig->objectTypeIndication = 1; free(esd->decoderConfig->decoderSpecificInfo->data); esd->decoderConfig->decoderSpecificInfo->data = strdup(" Mouse"); esd->decoderConfig->decoderSpecificInfo->data[0] = 5; esd->decoderConfig->decoderSpecificInfo->dataLength = 6; esd->ESID = esd->OCRESID = 65534; gf_list_add(odm->OD->ESDescriptors, esd); } else { if (mo->type==GF_MEDIA_OBJECT_SCENE) { char *frag = strrchr(mo->URLs.vals[0].url, '#'); if (frag) frag[0] = 0; odm->OD->URLString = strdup(mo->URLs.vals[0].url); if (frag) frag[0] = '#'; } else { odm->OD->URLString = strdup(mo->URLs.vals[0].url); } if (lock_timelines) odm->flags |= GF_ODM_INHERIT_TIMELINE; } /*HACK - temp storage of sync ref*/ if (sync_ref) odm->ocr_codec = (struct _generic_codec *)sync_ref; gf_list_add(is->ODlist, odm); gf_odm_setup_object(odm, root_od->net_service);}static void IS_ReinsertObject(GF_InlineScene *is, GF_MediaObject *mo){ u32 i; free(mo->URLs.vals[0].url); mo->URLs.vals[0].url = NULL; for (i=0; i<mo->URLs.count-1; i++) mo->URLs.vals[i].url = mo->URLs.vals[i+1].url; mo->URLs.vals[mo->URLs.count-1].url = NULL; mo->URLs.count-=1; IS_InsertObject(is, mo, 0, NULL);}void gf_is_remove_object(GF_InlineScene *is, GF_ObjectManager *odm, Bool for_shutdown){ u32 i; GF_MediaObject *obj; gf_list_del_item(is->ODlist, odm); i=0; while ((obj = (GF_MediaObject*)gf_list_enum(is->media_objects, &i))) { if ( /*assigned object*/ (obj->odm==odm) || /*remote OD*/ ((obj->OD_ID!=GF_ESM_DYNAMIC_OD_ID) && odm->OD && (obj->OD_ID == odm->OD->objectDescriptorID) ) || /*dynamic OD*/ (obj->URLs.count && odm->OD && odm->OD->URLString && !stricmp(obj->URLs.vals[0].url, odm->OD->URLString)) ) { gf_odm_lock(odm, 1); obj->flags = 0; if (obj->odm) obj->odm->mo = NULL; odm->mo = NULL; obj->odm = NULL; obj->frame = NULL; obj->framesize = obj->timestamp = 0; gf_odm_lock(odm, 0); /*if graph not attached we can remove the link (this is likely scene shutdown for some error)*/ if (!is->graph_attached) { ProtoLink *pl; u32 j=0; while ((pl = (ProtoLink *)gf_list_enum(is->extern_protos, &j))) { if (pl->mo==obj) { pl->mo = NULL; break; } } gf_list_rem(is->media_objects, i-1); gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL); free(obj); } else if (!for_shutdown) { /*if dynamic OD and more than 1 URLs resetup*/ if ((obj->OD_ID==GF_ESM_DYNAMIC_OD_ID) && (obj->URLs.count>1)) IS_ReinsertObject(is, obj); } return; } }}u32 URL_GetODID(MFURL *url){ u32 i, j, tmpid; char *str, *s_url; u32 id = 0; if (!url) return 0; for (i=0; i<url->count; i++) { if (url->vals[i].OD_ID) { /*works because OD ID 0 is forbidden in MPEG4*/ if (!id) { id = url->vals[i].OD_ID; } /*bad url, only one object can be described in MPEG4 urls*/ else if (id != url->vals[i].OD_ID) return 0; } else if (url->vals[i].url && strlen(url->vals[i].url)) { /*format: od:ID or od:ID#segment - also check for "ID" in case...*/ str = url->vals[i].url; if (!strnicmp(str, "od:", 3)) str += 3; /*remove segment info*/ s_url = strdup(str); j = 0; while (j<strlen(s_url)) { if (s_url[j]=='#') { s_url[j] = 0; break; } j++; } j = sscanf(s_url, "%d", &tmpid); /*be carefull, an url like "11-regression-test.mp4" will return 1 on sscanf :)*/ if (j==1) { char szURL[20]; sprintf(szURL, "%d", tmpid); if (stricmp(szURL, s_url)) j = 0; } free(s_url); if (j!= 1) { /*dynamic OD if only one URL specified*/ if (!i) return GF_ESM_DYNAMIC_OD_ID; /*otherwise ignore*/ continue; } if (!id) { id = tmpid; continue; } /*bad url, only one object can be described in MPEG4 urls*/ else if (id != tmpid) return 0; } } return id;}//browse all channels and update buffering infovoid gf_is_buffering_info(GF_InlineScene *is){ u32 i, j, max_buffer, cur_buffer; GF_Channel *ch; GF_Event evt; GF_ObjectManager *odm; if (!is) return; max_buffer = cur_buffer = 0; /*get buffering on root OD*/ j=0; while ((ch = (GF_Channel*)gf_list_enum(is->root_od->channels, &j))) { /*count only re-buffering channels*/ if (!ch->BufferOn) continue; max_buffer += ch->MaxBuffer; cur_buffer += (ch->BufferTime>0) ? ch->BufferTime : 1; } /*get buffering on all ODs*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(is->ODlist, &i))) { if (!odm->codec) continue; j=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &j))) { /*count only re-buffering channels*/ if (!ch->BufferOn) continue; max_buffer += ch->MaxBuffer; cur_buffer += (ch->BufferTime>0) ? ch->BufferTime : 1; } } evt.type = GF_EVENT_PROGRESS; evt.progress.progress_type = 0; evt.progress.service = is->root_od->net_service->url; if (!max_buffer || !cur_buffer || (max_buffer <= cur_buffer)) { evt.progress.done = evt.progress.total = max_buffer; } else { evt.progress.done = cur_buffer; evt.progress.total = max_buffer; } GF_USER_SENDEVENT(is->root_od->term->user, &evt);}static Bool Inline_SetScene(M_Inline *root){ GF_MediaObject *mo; GF_InlineScene *parent; GF_SceneGraph *graph = gf_node_get_graph((GF_Node *) root); parent = (GF_InlineScene *)gf_sg_get_private(graph); if (!parent) return 0; mo = gf_is_get_media_object(parent, &root->url, GF_MEDIA_OBJECT_SCENE, 0); if (!mo || !mo->odm) return 0; if (!mo->odm->subscene) { gf_term_invalidate_renderer(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); gf_list_add(mo->odm->subscene->inline_nodes, root); /*play*/ gf_mo_play(mo, 0, -1, 0); return 1;}Bool gf_mo_is_same_url(GF_MediaObject *obj, MFURL *an_url){ Bool include_sub_url = 0; u32 i; char szURL1[GF_MAX_PATH], szURL2[GF_MAX_PATH], *ext; /*don't analyse audio/video to locate segments or viewports*/ if (obj->type==GF_MEDIA_OBJECT_AUDIO) include_sub_url = 1; if (obj->type==GF_MEDIA_OBJECT_VIDEO) include_sub_url = 1; if (obj->OD_ID==GF_ESM_DYNAMIC_OD_ID) { if (!obj->URLs.count) { if (!obj->odm) return 0; strcpy(szURL1, obj->odm->net_service->url); } else { strcpy(szURL1, obj->URLs.vals[0].url); } } else { if (!obj->URLs.count) return 0; strcpy(szURL1, obj->URLs.vals[0].url);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -