📄 object_manager.c
字号:
switch (esd->decoderConfig->streamType) { case GF_STREAM_PRIVATE_SCENE: case GF_STREAM_SCENE: base_scene = esd; break; default: break; } if (base_scene) break; } /*we have a scene stream without dependancies, this is an inline*/ if (!base_scene || !base_scene->dependsOnESID) return GF_OK; /*if the stream the base scene depends on is in this OD, this is in inline*/ es_id = base_scene->dependsOnESID; while (es_id) { esd = od_get_esd(odm->OD, es_id); /*the stream this stream depends on is not in this OD, this is some anim stream*/ if (!esd) { *hasInline = 0; return GF_OK; } es_id = esd->dependsOnESID; /*should be forbidden (circular reference), we assume this describes inline (usually wrong BIFS->OD setup)*/ if (es_id==base_scene->ESID) break; } /*no dependency to external stream, this is an inline*/ return GF_OK;}/*connection of OD and setup of streams. The streams are not requested if the ODis in an unexecuted statethe ODM is created either because of IOD / remoteOD, or by the OD codec. In the latercase, the GF_InlineScene pointer will be set by the OD codec.*/GF_EXPORTvoid gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv){ Bool hasInline, externalClock; u32 i, numOK; GF_Err e; GF_ESD *esd; GF_MediaObject *syncRef; if (!odm->net_service) odm->net_service = serv; /*if this is a remote OD, we need a new manager and a new service...*/ if (odm->OD->URLString) { GF_ClientService *parent = odm->net_service; char *url = odm->OD->URLString; odm->OD->URLString = NULL; /*store original OD ID */ if (!odm->current_time) odm->current_time = odm->OD->objectDescriptorID; gf_odf_desc_del((GF_Descriptor *)odm->OD); odm->OD = NULL; odm->net_service = NULL; gf_term_connect_object(odm->term, odm, url, parent); free(url); return; } /*restore OD ID */ if (odm->current_time) { odm->OD->objectDescriptorID = odm->current_time; odm->current_time = 0; odm->flags |= GF_ODM_REMOTE_OD; } /*HACK - temp storage of sync ref*/ syncRef = (GF_MediaObject*)odm->ocr_codec; odm->ocr_codec = NULL; e = ODM_ValidateOD(odm, &hasInline, &externalClock); if (e) { gf_term_message(odm->term, odm->net_service->url, "MPEG-4 Service Error", e); gf_odm_disconnect(odm, 1); return; } /*if there is a BIFS stream in the OD, we need an GF_InlineScene (except if we already have one, which means this is the first IOD)*/ if (hasInline && !odm->subscene) { odm->subscene = gf_is_new(odm->parentscene); odm->subscene->root_od = odm; } /*this is an inline OD using clocks in its subnamespace - this is NOT supported by gpac since it breaks all buffering logics (and may not be compliant, spec is unclear here) -> force single clock for these streams (many ISMA files use this...)*/ if (hasInline && externalClock) { GF_ESD *esd = (GF_ESD *)gf_list_get(odm->OD->ESDescriptors, 0); odm->subscene->force_sub_clock_id = esd->ESID; } numOK = odm->pending_channels = 0; /*empty IOD, use a dynamic scene*/ if (!gf_list_count(odm->OD->ESDescriptors) && odm->subscene) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] No streams in object - taking over scene graph generation\n",odm->OD->objectDescriptorID)); assert(odm->subscene->root_od==odm); odm->subscene->is_dynamic_scene = 1; } else { /*avoid channels PLAY request when confirming connection (sync network service)*/ odm->state = GF_ODM_STATE_IN_SETUP; i=0; while ((esd = (GF_ESD *)gf_list_enum(odm->OD->ESDescriptors, &i)) ) { e = gf_odm_setup_es(odm, esd, serv, syncRef); /*notify error but still go on, all streams are not so usefull*/ if (e==GF_OK) { numOK++; } else { gf_term_message(odm->term, odm->net_service->url, "Stream Setup Failure", e); } } odm->state = GF_ODM_STATE_STOP; } /*special case for ODs only having OCRs: force a START since they're never refered to by media nodes*/ if (odm->ocr_codec) gf_odm_start(odm);#if 0 /*clean up - note that this will not be performed if one of the stream is using ESD URL*/ if (!numOK) { gf_odm_disconnect(odm, 1); return; }#endif /*setup mediaobject info except for top-level OD*/ if (odm->parentscene) { gf_is_setup_object(odm->parentscene, odm); } else { /*othewise send a connect ack for top level*/ GF_Event evt; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 1; GF_USER_SENDEVENT(odm->term->user, &evt); } /* and connect ONLY if main scene - inlines are connected when attached to Inline nodes*/ if (!odm->parentscene) { assert(odm->subscene == odm->term->root_scene); assert(odm->subscene->root_od==odm); gf_odm_start(odm); } /*for objects inserted by user (subs & co), auto select*/ if (odm->term->root_scene->is_dynamic_scene && (odm->OD->objectDescriptorID==GF_ESM_DYNAMIC_OD_ID) && (odm->flags & GF_ODM_REMOTE_OD)) { GF_Event evt; if (odm->OD_PL) { gf_is_select_object(odm->term->root_scene, odm); odm->OD_PL = 0; } evt.type = GF_EVENT_STREAMLIST; GF_USER_SENDEVENT(odm->term->user,&evt); }}/*refresh all ODs when an non-interactive stream is found*/void gf_odm_refresh_uninteractives(GF_ObjectManager *odm){ u32 i, j; GF_Channel *ch; GF_ObjectManager *test_od; GF_InlineScene *in_scene; /*check for inline*/ in_scene = odm->parentscene; if (odm->subscene) { assert(odm->subscene->root_od == odm); in_scene = odm->subscene; i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) { if (ch->clock->no_time_ctrl) { odm->flags |= GF_ODM_NO_TIME_CTRL; break; } } } i=0; while ((test_od = (GF_ObjectManager *)gf_list_enum(in_scene->ODlist, &i)) ) { if (odm==test_od) continue; j=0; while ((ch = (GF_Channel*)gf_list_enum(test_od->channels, &j)) ) { if (ch->clock->no_time_ctrl) { test_od->flags |= GF_ODM_NO_TIME_CTRL; break; } } }}void ODM_CheckChannelService(GF_Channel *ch){ if (ch->service == ch->odm->net_service) return; /*if the stream has created a service check if close is needed or not*/ if (ch->esd->URLString && !ch->service->nb_ch_users) gf_term_close_services(ch->odm->term, ch->service);}/*setup channel, clock and query caps*/GF_EXPORTGF_Err gf_odm_setup_es(GF_ObjectManager *odm, GF_ESD *esd, GF_ClientService *serv, GF_MediaObject *sync_ref){ GF_CodecCapability cap; GF_Channel *ch; GF_Clock *ck; GF_List *ck_namespace; GF_Codec *dec; s8 flag; u16 clockID; Bool emulated_od = 0; GF_Err e; GF_InlineScene *is; /*find the clock for this new channel*/ ck = NULL; flag = (s8) -1; /*sync reference*/ if (sync_ref && sync_ref->odm && sync_ref->odm->codec) { ck = sync_ref->odm->codec->ck; goto clock_setup; } /*timeline override*/ if (odm->flags & GF_ODM_INHERIT_TIMELINE) { if (odm->parentscene->root_od->subscene->scene_codec) ck = odm->parentscene->root_od->subscene->scene_codec->ck; else ck = odm->parentscene->root_od->subscene->dyn_ck; goto clock_setup; } /*get clocks namespace (eg, parent scene)*/ is = odm->subscene ? odm->subscene : odm->parentscene; if (is->force_sub_clock_id) esd->OCRESID = is->force_sub_clock_id; ck_namespace = odm->net_service->Clocks; /*little trick for non-OD addressing: if object is a remote one, and service owner already has clocks, override OCR. This will solve addressing like file.avi#audio and file.avi#video*/ if (!esd->OCRESID && (odm->flags & GF_ODM_REMOTE_OD) && (gf_list_count(ck_namespace)==1) ) { ck = (GF_Clock*)gf_list_get(ck_namespace, 0); esd->OCRESID = ck->clockID; } /*for dynamic scene, force all streams to be sync on main OD stream (one timeline, no need to reload ressources)*/ else if (odm->term->root_scene->is_dynamic_scene) { GF_ObjectManager *root_od = odm->term->root_scene->root_od; if (gf_list_count(root_od->net_service->Clocks)==1) { ck = (GF_Clock*)gf_list_get(root_od->net_service->Clocks, 0); esd->OCRESID = ck->clockID; goto clock_setup; } } /*do we have an OCR specified*/ clockID = esd->OCRESID; /*if OCR stream force self-synchro !!*/ if (esd->decoderConfig->streamType==GF_STREAM_OCR) clockID = esd->ESID; if (!clockID) { /*if no clock ID but depandancy, force the clock to be the base layer for AV but not systems (animation streams, ..)*/ if ((esd->decoderConfig->streamType==GF_STREAM_VISUAL) || (esd->decoderConfig->streamType==GF_STREAM_AUDIO)) clockID = esd->dependsOnESID; if (!clockID) clockID = esd->ESID; } /*override clock dependencies if specified*/ if (odm->term->flags & GF_TERM_SINGLE_CLOCK) { if (is->scene_codec) { clockID = is->scene_codec->ck->clockID; } else if (is->od_codec) { clockID = is->od_codec->ck->clockID; } ck_namespace = odm->term->root_scene->root_od->net_service->Clocks; } /*if the GF_Clock is the stream, check if we have embedded OCR in the stream...*/ if (clockID == esd->ESID) { flag = (esd->slConfig && esd->slConfig->OCRLength > 0); } if (!esd->slConfig) { esd->slConfig = (GF_SLConfig *)gf_odf_desc_new(GF_ODF_SLC_TAG); esd->slConfig->timestampResolution = 1000; } /*attach clock in namespace*/ ck = gf_clock_attach(ck_namespace, is, clockID, esd->ESID, flag); if (!ck) return GF_OUT_OF_MEM; esd->OCRESID = ck->clockID;clock_setup: /*create a channel for this stream*/ ch = gf_es_new(esd); if (!ch) return GF_OUT_OF_MEM; ch->clock = ck; ch->service = serv; /*setup the decoder for this stream or find the existing one.*/ e = GF_OK; dec = NULL; switch (esd->decoderConfig->streamType) { case GF_STREAM_OD: //OD - MUST be in inline if (!odm->subscene) { e = GF_NON_COMPLIANT_BITSTREAM; break; } /*OD codec acts as main scene codec when used to generate scene graph*/ if (! odm->subscene->od_codec) { odm->subscene->od_codec = gf_codec_new(odm, esd, odm->OD_PL, &e); gf_term_add_codec(odm->term, odm->subscene->od_codec); } dec = odm->subscene->od_codec; break; case GF_STREAM_OCR: /*OD codec acts as main scene codec when used to generate scene graph*/ dec = odm->ocr_codec = gf_codec_new(odm, esd, odm->OD_PL, &e); gf_term_add_codec(odm->term, odm->ocr_codec); break; case GF_STREAM_SCENE: /*animationStream */ if (!odm->subscene) { if (!odm->codec) { odm->codec = gf_codec_new(odm, esd, odm->Scene_PL, &e); gf_term_add_codec(odm->term, odm->codec); } dec = odm->codec; } /*inline scene*/ else { if (! odm->subscene->scene_codec) { odm->subscene->scene_codec = gf_codec_new(odm, esd, odm->Scene_PL, &e); if (!e) gf_term_add_codec(odm->term, odm->subscene->scene_codec); } dec = odm->subscene->scene_codec; } break; case GF_STREAM_OCI: /*OCI - only one per OD */ if (odm->oci_codec) { e = GF_NON_COMPLIANT_BITSTREAM; } else { odm->oci_codec = gf_codec_new(odm, esd, odm->OD_PL, &e); odm->oci_codec->odm = odm; gf_term_add_codec(odm->term, odm->oci_codec); } break; case GF_STREAM_AUDIO: case GF_STREAM_VISUAL: /*we have a media or user-specific codec...*/ if (!odm->codec) { odm->codec = gf_codec_new(odm, esd, (esd->decoderConfig->streamType==GF_STREAM_VISUAL) ? odm->Visual_PL : odm->Audio_PL, &e); if (!e) gf_term_add_codec(odm->term, odm->codec); } dec = odm->codec; break; /*interaction stream*/ case GF_STREAM_INTERACT: if (!odm->codec) { odm->codec = gf_codec_new(odm, esd, odm->OD_PL, &e); if (!e) { IS_Configure(odm->codec->decio, odm->parentscene, esd->URLString ? 1 : 0); gf_term_add_codec(odm->term, odm->codec); /*register it*/ gf_list_add(odm->term->input_streams, odm->codec); } } dec = odm->codec; if ((esd->ESID==esd->OCRESID) &&(esd->ESID>=65530)) { emulated_od = 1; } break; case GF_STREAM_PRIVATE_SCENE: if (odm->subscene) { assert(!odm->subscene->scene_codec); odm->subscene->scene_codec = gf_codec_new(odm, esd, odm->Scene_PL, &e); if (odm->subscene->scene_codec) { gf_term_add_codec(odm->term, odm->subscene->scene_codec); } dec = odm->subscene->scene_codec; } else { /*this is a bit tricky: the scene decoder needs to ba called with the dummy streams of this object, so we associate the main decoder to this object*/ odm->codec = dec = gf_codec_use_codec(odm->parentscene->scene_codec, odm); gf_term_add_codec(odm->term, odm->codec); } break; /*all other cases*/ default: if (!odm->codec) { odm->codec = gf_codec_new(odm, esd, odm->OD_PL, &e); if (!e) gf_term_add_codec(odm->term, odm->codec); } dec = odm->codec; break; } /*if we have a decoder, set up the channel and co.*/ if (!dec) { if (e) { gf_es_del(ch); return e; } } /*setup scene decoder*/ if (dec->decio && (dec->decio->InterfaceType==GF_SCENE_DECODER_INTERFACE) ) { GF_SceneDecoder *sdec = (GF_SceneDecoder *) dec->decio; is = odm->subscene ? odm->subscene : odm->parentscene; if (sdec->AttachScene) sdec->AttachScene(sdec, is, (is->scene_codec==dec) ? 1: 0); } ch->es_state = GF_ESM_ES_SETUP; ch->odm = odm; /*get media padding BEFORE channel setup, since we use it on channel connect ack*/ if (dec) { cap.CapCode = GF_CODEC_PADDING_BYTES; gf_codec_get_capability(dec, &cap); ch->media_padding_bytes = cap.cap.valueInt; cap.CapCode = GF_CODEC_RESILIENT; gf_codec_get_capability(dec, &cap); ch->codec_resilient = cap.cap.valueInt; } if (emulated_od) { ch->service = NULL; } /*one more channel to wait for*/ odm->pending_channels++; /*service redirection*/ if (esd->URLString) { GF_ChannelSetup *cs; /*here we have a pb with the MPEG4 model: streams are supposed to be attachable as soon as the OD update is recieved, but this is not true with ESD URLs, where service setup may take some time (file downloading, authentification, etc...). We therefore need to wait for the service connect response before
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -