📄 object_manager.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. * */#include <gpac/internal/terminal_dev.h>#include <gpac/constants.h>#include "media_memory.h"#include "media_control.h"#include "input_sensor.h"/*removes the channel ressources and destroy it*/void ODM_DeleteChannel(GF_ObjectManager *odm, struct _es_channel *ch);GF_EXPORTGF_ObjectManager *gf_odm_new(){ GF_ObjectManager *tmp; GF_SAFEALLOC(tmp, GF_ObjectManager); if (!tmp) return NULL; tmp->channels = gf_list_new(); tmp->Audio_PL = (u8) -1; tmp->Graphics_PL = (u8) -1; tmp->OD_PL = (u8) -1; tmp->Scene_PL = (u8) -1; tmp->Visual_PL = (u8) -1; tmp->ms_stack = gf_list_new(); tmp->mc_stack = gf_list_new(); tmp->mx = gf_mx_new(); return tmp;}void gf_odm_del(GF_ObjectManager *odm){ u32 i; MediaSensorStack *media_sens; gf_mx_p(odm->mx); i=0; while ((media_sens = (MediaSensorStack *)gf_list_enum(odm->ms_stack, &i))) { MS_Stop(media_sens); /*and detach from stream object*/ media_sens->is_init = 0; } if (odm->mo) odm->mo->odm = NULL; gf_list_del(odm->channels); gf_list_del(odm->ms_stack); gf_list_del(odm->mc_stack); gf_odf_desc_del((GF_Descriptor *)odm->OD); assert (!odm->net_service); gf_mx_v(odm->mx); gf_mx_del(odm->mx); free(odm);}void gf_odm_lock(GF_ObjectManager *odm, u32 LockIt){ assert(odm); if (LockIt) gf_mx_p(odm->mx); else gf_mx_v(odm->mx);}Bool gf_odm_lock_mo(GF_MediaObject *mo){ if (!mo || !mo->odm) return 0; gf_odm_lock(mo->odm, 1); /*the ODM may have been destroyed here !!*/ if (!mo->odm) return 0; return 1;}GF_EXPORTvoid gf_odm_disconnect(GF_ObjectManager *odm, Bool do_remove){ GF_Channel *ch; gf_odm_stop(odm, 1); /*disconnect sub-scene*/ if (odm->subscene) gf_is_disconnect(odm->subscene, do_remove); /*no destroy*/ if (!do_remove) return; gf_odm_lock(odm, 1); /*unload the decoders before deleting the channels to prevent any access fault*/ if (odm->codec) gf_term_remove_codec(odm->term, odm->codec); if (odm->ocr_codec) gf_term_remove_codec(odm->term, odm->ocr_codec); if (odm->oci_codec) gf_term_remove_codec(odm->term, odm->oci_codec); /*then delete all the channels in this OD */ while (gf_list_count(odm->channels)) { ch = (GF_Channel*)gf_list_get(odm->channels, 0);#if 0 if (ch->clock->mc && ch->clock->mc->stream && ch->clock->mc->stream->odm==odm) { ch->clock->mc->stream = NULL; ch->clock->mc = NULL; }#endif ODM_DeleteChannel(odm, ch); } /*delete the decoders*/ if (odm->codec) { gf_codec_del(odm->codec); odm->codec = NULL; } if (odm->ocr_codec) { gf_codec_del(odm->ocr_codec); odm->ocr_codec = NULL; } if (odm->oci_codec) { gf_codec_del(odm->oci_codec); odm->oci_codec = NULL; } /*then detach from network service*/ if (odm->net_service) { if (odm->net_service->owner == odm) { if (odm->net_service->nb_odm_users) odm->net_service->nb_odm_users--; /*detach it!!*/ odm->net_service->owner = NULL; /*try to assign a new root in case this is not scene shutdown*/ if (odm->net_service->nb_odm_users && odm->parentscene) { GF_ObjectManager *new_root; u32 i = 0; while ((new_root = (GF_ObjectManager *)gf_list_enum(odm->parentscene->ODlist, &i)) ) { if (new_root == odm) continue; if (new_root->net_service != odm->net_service) continue; new_root->net_service->owner = new_root; break; } } } if (!odm->net_service->nb_odm_users) gf_term_close_services(odm->term, odm->net_service); odm->net_service = NULL; } gf_odm_lock(odm, 0); /*delete from the parent scene.*/ if (odm->parentscene) { gf_is_remove_object(odm->parentscene, odm, do_remove); if (odm->subscene) gf_is_del(odm->subscene); gf_odm_del(odm); return; } /*this is the scene root OD (may be a remote OD ..) */ if (odm->term->root_scene) { GF_Event evt; assert(odm->term->root_scene == odm->subscene); gf_is_del(odm->subscene); /*reset main pointer*/ odm->term->root_scene = NULL; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 0; GF_USER_SENDEVENT(odm->term->user, &evt); } /*delete the ODMan*/ gf_odm_del(odm);}/*setup service for OD (extract IOD and go)*/void gf_odm_setup_entry_point(GF_ObjectManager *odm, const char *service_sub_url){ u32 od_type; char *ext; char *sub_url = (char *) service_sub_url; GF_Terminal *term; GF_Descriptor *desc; GF_IPMP_ToolList *toolList; assert(odm->OD==NULL); odm->net_service->nb_odm_users++; if (odm->subscene) od_type = GF_MEDIA_OBJECT_SCENE; else if (odm->mo) { od_type = odm->mo->type; if (!sub_url && odm->mo->URLs.count && odm->mo->URLs.vals[0].url) { sub_url = odm->mo->URLs.vals[0].url; } } else od_type = GF_MEDIA_OBJECT_UNDEF; /*for remote ODs, get expected OD type in case the service needs to generate the IOD on the fly*/ if (odm->parentscene && odm->OD && odm->OD->URLString) { GF_MediaObject *mo; mo = gf_is_find_object(odm->parentscene, odm->OD->objectDescriptorID, odm->OD->URLString); if (mo) od_type = mo->type; ext = strchr(odm->OD->URLString, '#'); if (ext) sub_url = ext; } desc = odm->net_service->ifce->GetServiceDescriptor(odm->net_service->ifce, od_type, sub_url); /*create empty service descriptor, this will automatically create a dynamic scene*/ if (!desc) { if (od_type != GF_MEDIA_OBJECT_SCENE) return; desc = gf_odf_desc_new(GF_ODF_OD_TAG); } if (!gf_list_count( ((GF_ObjectDescriptor*)desc)->ESDescriptors)) { /*new subscene*/ if (!odm->subscene) { assert(odm->parentscene); odm->subscene = gf_is_new(odm->parentscene); odm->subscene->root_od = odm; } } toolList = NULL; switch (desc->tag) { case GF_ODF_IOD_TAG: { GF_InitialObjectDescriptor *the_iod = (GF_InitialObjectDescriptor *)desc; odm->OD = (GF_ObjectDescriptor*)malloc(sizeof(GF_ObjectDescriptor)); memcpy(odm->OD, the_iod, sizeof(GF_ObjectDescriptor)); odm->OD->tag = GF_ODF_OD_TAG; /*Check P&Ls of this IOD*/ odm->Audio_PL = the_iod->audio_profileAndLevel; odm->Graphics_PL = the_iod->graphics_profileAndLevel; odm->OD_PL = the_iod->OD_profileAndLevel; odm->Scene_PL = the_iod->scene_profileAndLevel; odm->Visual_PL = the_iod->visual_profileAndLevel; odm->flags |= GF_ODM_HAS_PROFILES; if (the_iod->inlineProfileFlag) odm->flags |= GF_ODM_INLINE_PROFILES; toolList = the_iod->IPMPToolList; free(the_iod); } break; case GF_ODF_OD_TAG: odm->Audio_PL = odm->Graphics_PL = odm->OD_PL = odm->Scene_PL = odm->Visual_PL = (u8) -1; odm->OD = (GF_ObjectDescriptor *)desc; break; default: gf_term_message(odm->term, odm->net_service->url, "MPEG4 Service Setup Failure", GF_ODF_INVALID_DESCRIPTOR); goto err_exit; } if (toolList) { Bool ipmp_failed = 0;/* GF_IPMP_Tool *ipmpt; i=0; while ((ipmpt = gf_list_enum(toolList->ipmp_tools, &i))) { if (!Term_CheckIPMPTool(odm->term, ipmpt)) { ipmp_failed = 1; break; } }*/ gf_odf_desc_del((GF_Descriptor *)toolList); if (ipmp_failed) { gf_term_message(odm->term, odm->net_service->url, "MPEG4 IPMP Setup Failure - cannot process content", GF_SERVICE_ERROR); goto err_exit; } } /*keep track of term since the setup may fail and the OD may be destroyed*/ term = odm->term; gf_term_lock_net(term, 1); gf_odm_setup_object(odm, odm->net_service); gf_term_lock_net(term, 0); return;err_exit: if (!odm->parentscene) { GF_Event evt; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 0; GF_USER_SENDEVENT(odm->term->user, &evt); }}/*locate ESD by ID*/static GF_ESD *od_get_esd(GF_ObjectDescriptor *OD, u16 ESID){ GF_ESD *esd; u32 i = 0; while ((esd = (GF_ESD *)gf_list_enum(OD->ESDescriptors, &i)) ) { if (esd->ESID==ESID) return esd; } return NULL;}static void ODM_SelectAlternateStream(GF_ObjectManager *odm, u32 lang_code, u8 stream_type){ u32 i; GF_ESD *esd; u16 def_id, es_id; def_id = 0; i=0; while ( (esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) { if (esd->decoderConfig->streamType != stream_type) continue; if (!esd->langDesc) { if (!def_id) def_id = esd->ESID; continue; } if (esd->langDesc->langCode==lang_code) { def_id = esd->ESID; break; } else if (!def_id) { def_id = esd->ESID; } } /*remove all other media streams*/ i=0; while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) { if (esd->decoderConfig->streamType != stream_type) continue; /*get base stream ID for this stream*/ es_id = esd->ESID; if (esd->dependsOnESID && (esd->dependsOnESID != es_id)) { es_id = esd->dependsOnESID; while (es_id) { GF_ESD *base = od_get_esd(odm->OD, es_id); if (!base) break; /*forbidden except for BIFS->OD*/ if (base->decoderConfig->streamType != stream_type) break; if (!base->dependsOnESID) break; es_id = base->dependsOnESID; } } /*not part of same object as base, remove*/ if (es_id != def_id) { gf_list_del_item(odm->OD->ESDescriptors, esd); gf_odf_desc_del((GF_Descriptor*) esd); i--; } }}/*Validate the streams in this OD, and check if we have to setup an inline scene*/GF_Err ODM_ValidateOD(GF_ObjectManager *odm, Bool *hasInline, Bool *externalClock){ u32 i; u16 es_id; GF_ESD *esd, *base_scene; const char *sOpt; u32 lang, nb_od, nb_ocr, nb_scene, nb_mp7, nb_ipmp, nb_oci, nb_mpj, nb_other, prev_st; nb_od = nb_ocr = nb_scene = nb_mp7 = nb_ipmp = nb_oci = nb_mpj = nb_other = 0; prev_st = 0; *hasInline = 0; *externalClock = 0; /*step 1: validate OD*/ i=0; while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i))) { /*check external clock refs*/ if (esd->OCRESID && (esd->OCRESID!=esd->ESID) && (od_get_esd(odm->OD, esd->OCRESID) == NULL) ) { *externalClock = 1; } switch (esd->decoderConfig->streamType) { case GF_STREAM_OD: nb_od++; break; case GF_STREAM_OCR: nb_ocr++; break; case GF_STREAM_SCENE: nb_scene++; break; case GF_STREAM_MPEG7: nb_mp7++; break; case GF_STREAM_IPMP: nb_ipmp++; break; case GF_STREAM_OCI: nb_oci++; break; case GF_STREAM_MPEGJ: nb_mpj++; break; case GF_STREAM_PRIVATE_SCENE: nb_scene++; break; /*all other streams shall not be mixed: text, video, audio, interaction, font*/ default: if (esd->decoderConfig->streamType!=prev_st) nb_other++; prev_st = esd->decoderConfig->streamType; break; } } /*cf spec on stream aggregation*/ if (nb_other>1) return GF_ODF_INVALID_DESCRIPTOR; /*no more than one base media type*/ if (nb_od && !nb_scene) return GF_ODF_INVALID_DESCRIPTOR; /*if OD we must have scene description*/ if (nb_other && nb_scene) return GF_ODF_INVALID_DESCRIPTOR; /*scene OR media*/ if (nb_ocr>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE OCR*/ if (nb_oci>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE OCI*/ if (nb_mp7>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE MPEG-7 - this is not in the spec, but since MPEG-7 = OCI++ this seems reasonable*/ if (nb_mpj>1) return GF_ODF_INVALID_DESCRIPTOR; /*only ONE MPEG-J - this is not in the spec but well...*/ /*the rest should be OK*/ /*select independant streams - check language and (TODO) bitrate & term caps*/ sOpt = gf_cfg_get_key(odm->term->user->config, "Systems", "Language3CC"); if (!sOpt) { gf_cfg_set_key(odm->term->user->config, "Systems", "Language3CC", "und"); sOpt = "und"; } lang = (sOpt[0]<<16) | (sOpt[1]<<8) | sOpt[2]; if (gf_list_count(odm->OD->ESDescriptors)>1) { ODM_SelectAlternateStream(odm, lang, GF_STREAM_SCENE); ODM_SelectAlternateStream(odm, lang, GF_STREAM_OD); ODM_SelectAlternateStream(odm, lang, GF_STREAM_VISUAL); ODM_SelectAlternateStream(odm, lang, GF_STREAM_AUDIO); ODM_SelectAlternateStream(odm, lang, GF_STREAM_IPMP); ODM_SelectAlternateStream(odm, lang, GF_STREAM_INTERACT); ODM_SelectAlternateStream(odm, lang, GF_STREAM_TEXT); } /*no scene, OK*/ if (!nb_scene) return GF_OK; /*check if inline or animation stream*/ *hasInline = 1; base_scene = NULL; i=0; while ( (esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -