static void term_on_connect(void *user_priv, GF_ClientService *service, LPNETCHANNEL netch, GF_Err err) { GF_Channel *ch; GF_ObjectManager *root; GET_TERM(); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] %s connection ACK received from %s - %s\n", netch ? "Channel" : "Service", service->url, gf_error_to_string(err) )); root = service->owner; if (root && (root->net_service != service)) { gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR); return; } /*this is service connection*/ if (!netch) { gf_term_service_media_event(service->owner, GF_EVENT_MEDIA_SETUP_DONE); if (err) { char msg[5000]; snprintf(msg, sizeof(msg)-1, "Cannot open %s", service->url); gf_term_message(term, service->url, msg, err); gf_term_service_media_event(service->owner, GF_EVENT_ERROR); /*destroy service only if attached*/ if (root) { gf_term_lock_media_queue(term, 1); service->ifce->CloseService(service->ifce); root->net_service = NULL; if (service->owner && service->nb_odm_users) service->nb_odm_users--; service->owner = NULL; /*depends on module: some module could forget to call gf_term_on_disconnect */ if ( gf_list_del_item(term->net_services, service) >= 0) { /*and queue for destroy*/ gf_list_add(term->net_services_to_remove, service); } gf_term_lock_media_queue(term, 0); if (!root->parentscene) { GF_Event evt; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 0; gf_term_send_event(term, &evt); } else { if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err); /*try to reinsert OD for VRML/X3D with multiple URLs: 1- first remove from parent scene without destroying object, this will trigger a re-setup if other URLs are present 2- then destroy object*/ gf_scene_remove_object(root->parentscene, root, 0); gf_odm_disconnect(root, 1); } return; } } if (!root) { /*channel service connect*/ u32 i; GF_ChannelSetup *cs; GF_List *ODs; if (!gf_list_count(term->channels_pending)) { return; } ODs = gf_list_new(); gf_term_lock_net(term, 1); i=0; while ((cs = (GF_ChannelSetup*)gf_list_enum(term->channels_pending, &i))) { if (cs->ch->service != service) continue; gf_list_rem(term->channels_pending, i-1); i--; /*even if error do setup (channel needs to be deleted)*/ if (gf_odm_post_es_setup(cs->ch, cs->dec, err) == GF_OK) { if (cs->ch->odm && (gf_list_find(ODs, cs->ch->odm)==-1) ) gf_list_add(ODs, cs->ch->odm); } gf_free(cs); } gf_term_lock_net(term, 0); /*finally setup all ODs concerned (we do this later in case of scalability)*/ while (gf_list_count(ODs)) { GF_ObjectManager *odm = (GF_ObjectManager*)gf_list_get(ODs, 0); gf_list_rem(ODs, 0); /*force re-setup*/ gf_scene_setup_object(odm->parentscene, odm); } gf_list_del(ODs); } else { /*setup od*/ gf_odm_setup_entry_point(root, service->url); } /*load cache if requested*/ if (!err && term->enable_cache) { err = gf_term_service_cache_load(service); /*not a fatal error*/ if (err) gf_term_message(term, "GPAC Cache", "Cannot load cache", err); } return; } /*this is channel connection*/ ch = gf_term_get_channel(service, netch); if (!ch) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel connection ACK error: channel not found\n")); return; } /*confirm channel connection even if error - this allow playback of objects even if not all streams are setup*/ gf_term_lock_net(term, 1); gf_es_on_connect(ch); gf_term_lock_net(term, 0); if (err && ((err!=GF_STREAM_NOT_FOUND) || (ch->esd->decoderConfig->streamType!=GF_STREAM_INTERACT))) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel %d connection error: %s\n", ch->esd->ESID, gf_error_to_string(err) )); ch->es_state = GF_ESM_ES_UNAVAILABLE; /* return;*/ } if (ch->odm->mo) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - %d objects opened\n", ch->esd->ESID, ch->odm->mo->num_open )); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - not attached to the scene\n", ch->esd->ESID)); } /*Plays request are skiped until all channels are connected. We send a PLAY on the objecy in case 1-OD user has requested a play 2-this is a channel of the root OD */ if ( (ch->odm->mo && ch->odm->mo->num_open) || !ch->odm->parentscene ) { gf_odm_start(ch->odm, 0); } #if 0 else if (ch->odm->codec && ch->odm->codec->ck && ch->odm->codec->ck->no_time_ctrl) { gf_odm_play(ch->odm); } #endif }
static void term_on_media_add(void *user_priv, GF_ClientService *service, GF_Descriptor *media_desc, Bool no_scene_check) { u32 i, min_od_id; GF_MediaObject *the_mo; GF_Scene *scene; GF_ObjectManager *odm, *root; GF_ObjectDescriptor *od; GET_TERM(); root = service->owner; if (!root) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] has not root, aborting !\n", service->url)); return; } if (root->flags & GF_ODM_DESTROYED) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] root has been scheduled for destruction - aborting !\n", service->url)); return; } scene = root->subscene ? root->subscene : root->parentscene; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Service %s] %s\n", service->url, media_desc ? "Adding new media object" : "Regenerating scene graph")); if (!media_desc) { if (!no_scene_check) gf_scene_regenerate(scene); return; } switch (media_desc->tag) { case GF_ODF_OD_TAG: case GF_ODF_IOD_TAG: if (root && (root->net_service == service)) { od = (GF_ObjectDescriptor *) media_desc; break; } default: gf_odf_desc_del(media_desc); return; } gf_term_lock_net(term, 1); /*object declared this way are not part of an OD stream and are considered as dynamic*/ /* od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; */ /*check if we have a mediaObject in the scene not attached and matching this object*/ the_mo = NULL; odm = NULL; min_od_id = 0; for (i=0; i<gf_list_count(scene->scene_objects); i++) { char *frag, *ext; GF_ESD *esd; char *url; u32 match_esid = 0; GF_MediaObject *mo = gf_list_get(scene->scene_objects, i); if ((mo->OD_ID != GF_MEDIA_EXTERNAL_ID) && (min_od_id<mo->OD_ID)) min_od_id = mo->OD_ID; if (!mo->odm) continue; /*if object is attached to a service, don't bother looking in a different one*/ if (mo->odm->net_service && (mo->odm->net_service != service)) continue; /*already assigned object - this may happen since the compositor has no control on when objects are declared by the service, therefore opening file#video and file#audio may result in the objects being declared twice if the service doesn't keep track of declared objects*/ if (mo->odm->OD) { if (od->objectDescriptorID && is_same_od(mo->odm->OD, od)) { /*reassign OD ID*/ mo->OD_ID = od->objectDescriptorID; gf_odf_desc_del(media_desc); gf_term_lock_net(term, 0); return; } continue; } if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) { if (mo->OD_ID == od->objectDescriptorID) { the_mo = mo; odm = mo->odm; break; } continue; } if (!mo->URLs.count || !mo->URLs.vals[0].url) continue; frag = NULL; ext = strrchr(mo->URLs.vals[0].url, '#'); if (ext) { frag = strchr(ext, '='); ext[0] = 0; } url = mo->URLs.vals[0].url; if (!strnicmp(url, "file://localhost", 16)) url += 16; else if (!strnicmp(url, "file://", 7)) url += 7; else if (!strnicmp(url, "gpac://", 7)) url += 7; else if (!strnicmp(url, "pid://", 6)) match_esid = atoi(url+6); if (!match_esid && !strstr(service->url, url)) { if (ext) ext[0] = '#'; continue; } if (ext) ext[0] = '#'; esd = gf_list_get(od->ESDescriptors, 0); if (match_esid && (esd->ESID != match_esid)) continue; /*match type*/ switch (esd->decoderConfig->streamType) { case GF_STREAM_VISUAL: if (mo->type != GF_MEDIA_OBJECT_VIDEO) continue; break; case GF_STREAM_AUDIO: if (mo->type != GF_MEDIA_OBJECT_AUDIO) continue; break; case GF_STREAM_PRIVATE_MEDIA: if ((mo->type != GF_MEDIA_OBJECT_AUDIO) && (mo->type != GF_MEDIA_OBJECT_VIDEO)) continue; break; case GF_STREAM_SCENE: if (mo->type != GF_MEDIA_OBJECT_UPDATES) continue; break; default: continue; } if (frag) { u32 frag_id = 0; u32 ID = od->objectDescriptorID; if (ID==GF_MEDIA_EXTERNAL_ID) ID = esd->ESID; frag++; frag_id = atoi(frag); if (ID!=frag_id) continue; } the_mo = mo; odm = mo->odm; break; } /*add a pass on scene->resource to check for min_od_id, otherwise we may have another modules declaring an object with ID 0 from another thread, which will assert (only one object with a givne OD ID)*/ for (i=0; i<gf_list_count(scene->resources); i++) { GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); if (an_odm->OD && (an_odm->OD->objectDescriptorID != GF_MEDIA_EXTERNAL_ID) && (min_od_id < an_odm->OD->objectDescriptorID)) min_od_id = an_odm->OD->objectDescriptorID; } if (!odm) { odm = gf_odm_new(); odm->term = term; odm->parentscene = scene; gf_list_add(scene->resources, odm); } odm->OD = od; odm->mo = the_mo; odm->flags |= GF_ODM_NOT_IN_OD_STREAM; if (!od->objectDescriptorID) { od->objectDescriptorID = min_od_id + 1; } if (the_mo) the_mo->OD_ID = od->objectDescriptorID; if (!scene->selected_service_id) scene->selected_service_id = od->ServiceID; /*net is unlocked before seting up the object as this might trigger events going into JS and deadlocks with the compositor*/ gf_term_lock_net(term, 0); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] setup object - MO %08x\n", odm->OD->objectDescriptorID, odm->mo)); gf_odm_setup_object(odm, service); /*OD inserted by service: resetup scene*/ if (!no_scene_check && scene->is_dynamic_scene) gf_scene_regenerate(scene); }
static void term_on_command(void *user_priv, GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GET_TERM(); if (com->command_type==GF_NET_BUFFER_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) { com->buffer.occupancy = 0; return; } /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ gf_mx_p(term->mm_mx); if (!gf_list_count(od_list)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 j, count; if (!odm->codec) continue; count = gf_list_count(odm->channels); for (j=0; j<count; j++) { GF_Channel *ch = (GF_Channel *)gf_list_get(odm->channels, j); if (ch->service != service) continue; if (ch->es_state != GF_ESM_ES_RUNNING) continue; if (/*!ch->MaxBuffer || */ch->dispatch_after_db || ch->bypass_sl_and_db || ch->IsEndOfStream) continue; //perform buffer management only on base layer -this is because we don't signal which ESs are on/off in the underlying service ... if (ch->esd->dependsOnESID) continue; if (ch->MaxBuffer>com->buffer.max) com->buffer.max = ch->MaxBuffer; if (ch->MinBuffer<com->buffer.min) com->buffer.min = ch->MinBuffer; if (ch->IsClockInit && (u32) ch->BufferTime < com->buffer.occupancy) { /*if we don't have more units (compressed or not) than requested max for the composition memory, request more data*/ if (odm->codec->CB->UnitCount + ch->AU_Count <= odm->codec->CB->Capacity) { // com->buffer.occupancy = 0; com->buffer.occupancy = ch->BufferTime; } else { com->buffer.occupancy = ch->BufferTime; } } } } gf_mx_v(term->mm_mx); // fprintf(stderr, "Buffer occupancy %d\n", com->buffer.occupancy); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = ch->BufferTime; } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; default: return; } }
static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GF_Terminal *term = service->term; if (com->command_type==GF_NET_BUFFER_QUERY) { GF_Scene *scene; u32 i, max_buffer_time; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; com->buffer.buffering = GF_FALSE; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (!scene) { com->buffer.occupancy = 0; return; } /*get exclusive access to scene resources , to make sure ODs are not being inserted/remove*/ gf_mx_p(scene->mx_resources); max_buffer_time=0; if (!gf_list_count(scene->resources)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { gather_buffer_level(odm, service, com, &max_buffer_time); } gf_mx_v(scene->mx_resources); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; //in bench mode return the 1 if one of the buffer is full (eg sleep until all buffers are not full), 0 otherwise if (term->bench_mode) { com->buffer.occupancy = (max_buffer_time>com->buffer.max) ? 2 : 0; com->buffer.max = 1; com->buffer.min = 0; } return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (com->command_type==GF_NET_SERVICE_MEDIA_CAP_QUERY) { gf_sc_get_av_caps(term->compositor, &com->mcaps.width, &com->mcaps.height, &com->mcaps.display_bit_depth, &com->mcaps.audio_bpp, &com->mcaps.channels, &com->mcaps.sample_rate); return; } if (com->command_type==GF_NET_SERVICE_EVENT) { /*check for UDP timeout*/ if (com->send_event.evt.message.error == GF_IP_UDP_TIMEOUT) { const char *sOpt = gf_cfg_get_key(term->user->config, "Network", "AutoReconfigUDP"); if (sOpt && !stricmp(sOpt, "yes")) { char szMsg[1024]; sprintf(szMsg, "!! UDP down (%s) - Retrying with TCP !!\n", com->send_event.evt.message.message); gf_term_message(term, service->url, szMsg, GF_IP_NETWORK_FAILURE); /*reload scene - FIXME this shall work on inline nodes, not on the root !*/ if (term->reload_url) gf_free(term->reload_url); term->reload_state = 1; term->reload_url = gf_strdup(term->root_scene->root_od->net_service->url); gf_cfg_set_key(term->user->config, "Network", "UDPNotAvailable", "yes"); return; } } com->send_event.res = 0; gf_term_send_event(term, &com->send_event.evt); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_LOCATION) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_register_associated_media(scene, &com->addon_info); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_TIMING) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_notify_associated_media_timeline(scene, &com->addon_time); return; } if (com->command_type==GF_NET_SERVICE_SEEK) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene && scene->is_dynamic_scene) { gf_sc_lock(term->compositor, 1); gf_scene_restart_dynamic(scene, (u64) (com->play.start_range*1000), 0, 0); gf_sc_lock(term->compositor, 0); } return; } if (com->command_type == GF_NET_SERVICE_CODEC_STAT_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->codec_stat.avg_dec_time = 0; com->codec_stat.max_dec_time = 0; com->codec_stat.irap_avg_dec_time = 0; com->codec_stat.irap_max_dec_time = 0; if (!service->owner) return; /*browse all channels in the scene, running on this service, and get codec stat*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) return; /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 avg_dec_time; /*the decoder statistics are reliable only if we decoded at least 1s*/ if (!odm->codec || !odm->codec->nb_dec_frames || (odm->codec->ck->speed > 0 ? odm->codec->stat_start + 1000 > odm->codec->last_unit_dts : odm->codec->stat_start - 1000 < odm->codec->last_unit_dts)) continue; avg_dec_time = (u32) (odm->codec->total_dec_time / odm->codec->nb_dec_frames); if (avg_dec_time > com->codec_stat.avg_dec_time) { com->codec_stat.avg_dec_time = avg_dec_time; com->codec_stat.max_dec_time = odm->codec->max_dec_time; com->codec_stat.irap_avg_dec_time = odm->codec->nb_iframes ? (u32) (odm->codec->total_iframes_time / odm->codec->nb_iframes) : 0; com->codec_stat.irap_max_dec_time = odm->codec->max_iframes_time; } if (odm->codec->codec_reset) { com->codec_stat.codec_reset = GF_TRUE; odm->codec->codec_reset = GF_FALSE; } com->codec_stat.decode_only_rap = odm->codec->decode_only_rap ? GF_TRUE : GF_FALSE; } return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_SET_MEDIA_TIME: if (gf_es_owns_clock(ch) || !ch->clock->has_media_time_shift) { Double mtime = com->map_time.media_time; if (ch->clock->clock_init) { Double t = (Double) com->map_time.timestamp; t /= ch->esd->slConfig->timestampResolution; t -= ((Double) ch->clock->init_time) /1000; mtime += t; } ch->clock->media_time_at_init = (u32) (1000*mtime); ch->clock->has_media_time_shift = 1; } return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = (u32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; case GF_NET_CHAN_RESET: gf_es_reset_buffers(ch); break; case GF_NET_CHAN_PAUSE: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.max; gf_es_buffer_on(ch); break; case GF_NET_CHAN_RESUME: ch->BufferTime = ch->MaxBuffer; gf_es_update_buffering(ch, 1); gf_es_buffer_off(ch); break; case GF_NET_CHAN_BUFFER: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.occupancy; gf_es_update_buffering(ch, 1); break; default: return; } }