void Channel_ReceiveSkipSL(GF_ClientService *serv, GF_Channel *ch, const char *StreamBuf, u32 StreamLength) { GF_DBUnit *au; if (!StreamLength) return; gf_es_lock(ch, 1); au = gf_db_unit_new(); au->flags = GF_DB_AU_RAP; au->DTS = gf_clock_time(ch->clock); au->data = (char*)gf_malloc(sizeof(char) * (ch->media_padding_bytes + StreamLength)); memcpy(au->data, StreamBuf, sizeof(char) * StreamLength); if (ch->media_padding_bytes) memset(au->data + StreamLength, 0, sizeof(char)*ch->media_padding_bytes); au->dataLength = StreamLength; au->next = NULL; /*if channel owns the clock, start it*/ if (ch->clock && !ch->IsClockInit) { if (gf_es_owns_clock(ch)) { gf_clock_set_time(ch->clock, 0); ch->IsClockInit = 1; ch->seed_ts = 0; } if (ch->clock->clock_init && !ch->IsClockInit) { ch->IsClockInit = 1; ch->seed_ts = gf_clock_time(ch->clock); } } if (!ch->AU_buffer_first) { ch->AU_buffer_first = au; ch->AU_buffer_last = au; ch->AU_Count = 1; } else { ch->AU_buffer_last->next = au; ch->AU_buffer_last = ch->AU_buffer_last->next; ch->AU_Count += 1; } Channel_UpdateBufferTime(ch); if (ch->BufferOn) { ch->last_au_time = gf_term_get_time(ch->odm->term); Channel_UpdateBuffering(ch, 1); } gf_es_lock(ch, 0); }
GF_Err gf_es_start(GF_Channel *ch) { if (!ch) return GF_BAD_PARAM; switch (ch->es_state) { case GF_ESM_ES_UNAVAILABLE: case GF_ESM_ES_SETUP: return GF_BAD_PARAM; /*if the channel is already running, don't reset its settings. This only happens in the case of broadcast objects started several times by the scene but not stopped at the ODManager level (cf gf_odm_stop)*/ case GF_ESM_ES_RUNNING: return GF_OK; default: break; } GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] Starting ES %d\n", ch->esd->ESID)); /*reset clock if we own it*/ if (gf_es_owns_clock(ch) && !ch->clock->no_time_ctrl) gf_clock_reset(ch->clock); /*reset channel*/ Channel_Reset(ch, 1); /*create pull buffer if needed*/ if (ch->is_pulling && !ch->AU_buffer_pull) ch->AU_buffer_pull = gf_db_unit_new(); /*and start buffering - pull channels always turn off buffering immediately, otherwise buffering size is setup by the network service - except InputSensor*/ if ((ch->esd->decoderConfig->streamType != GF_STREAM_INTERACT) || ch->esd->URLString) { /*don't trigger rebuffer*/ //if (ch->MinBuffer || (ch->clock->clock_init && ch->clock->Paused)) ch_buffer_on(ch); } ch->last_au_time = gf_term_get_time(ch->odm->term); ch->es_state = GF_ESM_ES_RUNNING; ch->resync_drift = 0; if (ch->clock->clockID==ch->esd->ESID) { const char *opt = gf_cfg_get_key(ch->clock->term->user->config, "Systems", "ResyncLateClock"); if (opt) ch->resync_drift = atoi(opt); } return GF_OK; }
static void gf_es_check_timing(GF_Channel *ch) { /*the first data received inits the clock - this is needed to handle clock dependencies on non-initialized streams (eg, bifs/od depends on audio/video clock)*/ if (!ch->clock->clock_init) { if (!ch->clock->use_ocr) { gf_clock_set_time(ch->clock, ch->CTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Forcing clock initialization at STB %d - AU DTS %d\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS)); ch->IsClockInit = 1; } } /*channel is the OCR, force a re-init of the clock since we cannot assume the AU used to init the clock was not sent ahead of time*/ else if (gf_es_owns_clock(ch)) { if (!ch->clock->use_ocr) { ch->clock->clock_init = 0; gf_clock_set_time(ch->clock, ch->DTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: initializing clock at STB %d - AU DTS %d - %d buffering - OTB %d\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS, ch->clock->Buffering, gf_clock_time(ch->clock) )); ch->IsClockInit = 1; } } /*if channel is not the OCR, shift all time stamps to match the current time at clock init*/ else if (!ch->IsClockInit ) { // ch->ts_offset += gf_clock_real_time(ch->clock); if (ch->clock->clock_init) { ch->IsClockInit = 1; if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { // ch->ts_offset += gf_clock_real_time(ch->clock) - ch->CTS; } } } /*deal with some broken DMB streams were the timestamps on BIFS/OD are not set (0) or completely out of sync of the OCR clock (usually audio). If the audio codec (BSAC ...) is not found, we force re-initializing of the clock so that video can play back correctly*/ else if (gf_clock_time(ch->clock) * 1000 < ch->DTS) { ch->clock->clock_init = 0; gf_clock_set_time(ch->clock, ch->DTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: re-initializing clock at STB %d - AU DTS %d - %d buffering\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS, ch->clock->Buffering)); ch->IsClockInit = 1; } }
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; } }
/*handles reception of an SL-PDU, logical or physical*/ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *payload, u32 payload_size, GF_SLHeader *header, GF_Err reception_status) { GF_SLHeader hdr; u32 nbAU, OldLength, size, AUSeqNum; Bool EndAU, NewAU; if (ch->bypass_sl_and_db) { GF_SceneDecoder *sdec; ch->IsClockInit = 1; if (ch->odm->subscene) { sdec = (GF_SceneDecoder *)ch->odm->subscene->scene_codec->decio; } else { sdec = (GF_SceneDecoder *)ch->odm->codec->decio; } gf_mx_p(ch->mx); sdec->ProcessData(sdec, payload, payload_size, ch->esd->ESID, 0, 0); gf_mx_v(ch->mx); return; } if (ch->es_state != GF_ESM_ES_RUNNING) return; if (ch->skip_sl) { Channel_ReceiveSkipSL(serv, ch, payload, payload_size); return; } if (ch->is_raw_channel) { ch->CTS = ch->DTS = (u32) (ch->ts_offset + (header->compositionTimeStamp - ch->seed_ts) * 1000 / ch->ts_res); if (!ch->IsClockInit) { gf_es_check_timing(ch); } if (payload) gf_es_dispatch_raw_media_au(ch, payload, payload_size, ch->CTS); return; } /*physical SL-PDU - depacketize*/ if (!header) { u32 SLHdrLen; if (!payload_size) return; gf_sl_depacketize(ch->esd->slConfig, &hdr, payload, payload_size, &SLHdrLen); payload_size -= SLHdrLen; payload += SLHdrLen; } else { hdr = *header; } /*we ignore OCRs for the moment*/ if (hdr.OCRflag) { if (!ch->IsClockInit) { /*channel is the OCR, re-initialize the clock with the proper OCR*/ if (gf_es_owns_clock(ch)) { u32 OCR_TS; /*timestamps of PCR stream haven been shifted - shift the OCR as well*/ if (ch->seed_ts) { u64 diff_ts; Double scale = hdr.m2ts_pcr ? 27000000 : ch->esd->slConfig->OCRResolution; scale /= ch->ts_res; diff_ts = (u64) (ch->seed_ts * scale); hdr.objectClockReference -= diff_ts; } /*if SL is mapped from network module(eg not coded), OCR=PCR shall be given in 27Mhz units*/ if (hdr.m2ts_pcr) { OCR_TS = (u32) ( hdr.objectClockReference / 27000); } else { OCR_TS = (u32) ( (s64) (hdr.objectClockReference) * ch->ocr_scale); } OCR_TS += ch->ts_offset; ch->clock->clock_init = 0; gf_clock_set_time(ch->clock, OCR_TS); /*many TS streams deployed with HLS have broken PCRs - we will check their consistency when receiving the first AU with DTS/CTS on this channel*/ ch->clock->probe_ocr = 1; GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: initializing clock at STB %d from OCR TS %d (original TS "LLD") - %d buffering - OTB %d\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), OCR_TS, hdr.objectClockReference, ch->clock->Buffering, gf_clock_time(ch->clock) )); if (ch->clock->clock_init) ch->IsClockInit = 1; } } #if 0 /*adjust clock if M2TS PCR discontinuity*/ else if (hdr.m2ts_pcr==2) { u32 ck; u32 OCR_TS = (u32) ( hdr.objectClockReference / 27000); ck = gf_clock_time(ch->clock); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %d - OCR Discontinuity OCR: adjusting to %d (original TS "LLD") - original clock %d\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, ck)); // gf_clock_set_time(ch->clock, (u32) OCR_TS); } /*compute clock drift*/ else { u32 ck; u32 OCR_TS; if (hdr.m2ts_pcr) { OCR_TS = (u32) ( hdr.objectClockReference / 27000); } else { OCR_TS = (u32) ( (s64) (hdr.objectClockReference) * ch->ocr_scale); } ck = gf_clock_time(ch->clock); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %d adjusting OCR to %d (original TS "LLD") - diff %d\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, (s32) OCR_TS - (s32) ck)); // gf_clock_set_time(ch->clock, (u32) OCR_TS); } #else { u32 ck; u32 OCR_TS; if (hdr.m2ts_pcr) { OCR_TS = (u32) ( hdr.objectClockReference / 27000); } else { OCR_TS = (u32) ( (s64) (hdr.objectClockReference) * ch->ocr_scale); } ck = gf_clock_time(ch->clock); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %d got OCR %d (original TS "LLD") - diff %d%s\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, (s32) OCR_TS - (s32) ck, (hdr.m2ts_pcr==2) ? " - PCR Discontinuity flag" : "" )); } #endif if (!payload_size) return; } /*check state*/ if (!ch->codec_resilient && (reception_status==GF_CORRUPTED_DATA)) { Channel_WaitRAP(ch); return; } if (!ch->esd->slConfig->useAccessUnitStartFlag) { /*no AU signaling - each packet is an AU*/ if (!ch->esd->slConfig->useAccessUnitEndFlag) hdr.accessUnitEndFlag = hdr.accessUnitStartFlag = 1; /*otherwise AU are signaled by end of previous packet*/ else hdr.accessUnitStartFlag = ch->NextIsAUStart; } /*get RAP*/ if (ch->esd->slConfig->hasRandomAccessUnitsOnlyFlag) { hdr.randomAccessPointFlag = 1; } else if ((ch->carousel_type!=GF_ESM_CAROUSEL_MPEG2) && (!ch->esd->slConfig->useRandomAccessPointFlag || ch->codec_resilient) ) { ch->stream_state = 0; } if (ch->esd->slConfig->packetSeqNumLength) { if (ch->pck_sn && hdr.packetSequenceNumber) { /*repeated -> drop*/ if (ch->pck_sn == hdr.packetSequenceNumber) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: repeated packet, droping\n", ch->esd->ESID)); return; } /*if codec has no resiliency check packet drops*/ if (!ch->codec_resilient && !hdr.accessUnitStartFlag) { if (ch->pck_sn == (u32) (1<<ch->esd->slConfig->packetSeqNumLength) ) { if (hdr.packetSequenceNumber) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: packet loss, droping & wait RAP\n", ch->esd->ESID)); Channel_WaitRAP(ch); return; } } else if (ch->pck_sn + 1 != hdr.packetSequenceNumber) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: packet loss, droping & wait RAP\n", ch->esd->ESID)); Channel_WaitRAP(ch); return; } } } ch->pck_sn = hdr.packetSequenceNumber; } /*if empty, skip the packet*/ if (hdr.paddingFlag && !hdr.paddingBits) { GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: Empty packet - skipping\n", ch->esd->ESID)); return; } /*IDLE stream shall be processed*/ NewAU = 0; if (hdr.accessUnitStartFlag) { NewAU = 1; ch->NextIsAUStart = 0; ch->skip_carousel_au = 0; /*if we have a pending AU, add it*/ if (ch->buffer) { if (ch->esd->slConfig->useAccessUnitEndFlag) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: missed end of AU (DTS %d)\n", ch->esd->ESID, ch->DTS)); } if (ch->codec_resilient) { if (!ch->IsClockInit && !ch->skip_time_check_for_pending) gf_es_check_timing(ch); Channel_DispatchAU(ch, 0); } else { gf_free(ch->buffer); ch->buffer = NULL; ch->AULength = 0; ch->len = ch->allocSize = 0; } } ch->skip_time_check_for_pending = 0; AUSeqNum = hdr.AU_sequenceNumber; /*Get CTS */ if (ch->esd->slConfig->useTimestampsFlag) { if (hdr.compositionTimeStampFlag) { ch->net_dts = ch->net_cts = hdr.compositionTimeStamp; /*get DTS */ if (hdr.decodingTimeStampFlag) ch->net_dts = hdr.decodingTimeStamp; #if 0 /*until clock is not init check seed ts*/ if (!ch->IsClockInit && (ch->net_dts < ch->seed_ts)) ch->seed_ts = ch->net_dts; #endif if (ch->net_cts<ch->seed_ts) { u64 diff = ch->seed_ts - ch->net_cts; ch->CTS_past_offset = (u32) (diff * 1000 / ch->ts_res) + ch->ts_offset; ch->net_dts = ch->net_cts = 0; ch->CTS = ch->DTS = gf_clock_time(ch->clock); } else { if (ch->net_dts>ch->seed_ts) ch->net_dts -= ch->seed_ts; else ch->net_dts=0; ch->net_cts -= ch->seed_ts; ch->CTS_past_offset = 0; /*TS Wraping not tested*/ ch->CTS = (u32) (ch->ts_offset + (s64) (ch->net_cts) * 1000 / ch->ts_res); ch->DTS = (u32) (ch->ts_offset + (s64) (ch->net_dts) * 1000 / ch->ts_res); } if (ch->clock->probe_ocr && gf_es_owns_clock(ch)) { s32 diff_ts = ch->DTS; diff_ts -= ch->clock->init_time; if (ABS(diff_ts) > 10000) { GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d: invalid clock reference detected - DTS %d but OCR %d - using DTS as OCR\n", ch->esd->ESID, ch->DTS, ch->clock->init_time)); ch->clock->clock_init = 0; gf_clock_set_time(ch->clock, ch->DTS-1000); } ch->clock->probe_ocr = 0; } ch->no_timestamps = 0; } else { ch->no_timestamps = 1; } } else { /*use CU duration*/ if (!ch->IsClockInit) ch->DTS = ch->CTS = ch->ts_offset; if (!ch->esd->slConfig->AUSeqNumLength) { if (!ch->au_sn) { ch->CTS = ch->ts_offset; ch->au_sn = 1; } else { ch->CTS += ch->esd->slConfig->CUDuration; } } else { //use the sequence number to get the TS if (AUSeqNum < ch->au_sn) { nbAU = ( (1<<ch->esd->slConfig->AUSeqNumLength) - ch->au_sn) + AUSeqNum; } else { nbAU = AUSeqNum - ch->au_sn; } ch->CTS += nbAU * ch->esd->slConfig->CUDuration; } } /*if the AU Length is carried in SL, get its size*/ if (ch->esd->slConfig->AULength > 0) { ch->AULength = hdr.accessUnitLength; } else { ch->AULength = 0; } /*carousel for repeated AUs.*/ if (ch->carousel_type) { /* not used : Bool use_rap = hdr.randomAccessPointFlag; */ if (ch->carousel_type==GF_ESM_CAROUSEL_MPEG2) { AUSeqNum = hdr.m2ts_version_number_plus_one-1; /*mpeg-2 section carrouseling does not take into account the RAP nature of the tables*/ if (AUSeqNum==ch->au_sn) { if (ch->stream_state) { ch->stream_state=0; GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: MPEG-2 Carousel: tuning in\n", ch->esd->ESID)); } else { ch->skip_carousel_au = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: MPEG-2 Carousel: repeated AU (TS %d) - skipping\n", ch->esd->ESID, ch->CTS)); return; } } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: MPEG-2 Carousel: updated AU (TS %d)\n", ch->esd->ESID, ch->CTS)); ch->stream_state=0; ch->au_sn = AUSeqNum; } } else { if (hdr.randomAccessPointFlag) { /*initial tune-in*/ if (ch->stream_state==1) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP Carousel found (TS %d) - tuning in\n", ch->esd->ESID, ch->CTS)); ch->au_sn = AUSeqNum; ch->stream_state = 0; } /*carousel RAP*/ else if (AUSeqNum == ch->au_sn) { /*error recovery*/ if (ch->stream_state==2) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP Carousel found (TS %d) - recovering\n", ch->esd->ESID, ch->CTS)); ch->stream_state = 0; } else { ch->skip_carousel_au = 1; GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP Carousel found (TS %d) - skipping\n", ch->esd->ESID, ch->CTS)); return; } } /*regular RAP*/ else { if (ch->stream_state==2) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP Carousel found (TS %d) - recovering from previous errors\n", ch->esd->ESID, ch->CTS)); } ch->au_sn = AUSeqNum; ch->stream_state = 0; } } /*regular AU but waiting for RAP*/ else if (ch->stream_state) { #if 0 ch->skip_carousel_au = 1; GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Waiting for RAP Carousel - skipping\n", ch->esd->ESID)); return; #else GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Tuning in before RAP\n", ch->esd->ESID)); #endif } /*previous packet(s) loss: check for critical or non-critical AUs*/ else if (reception_status == GF_REMOTE_SERVICE_ERROR) { if (ch->au_sn == AUSeqNum) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Lost a non critical packet\n", ch->esd->ESID)); } /*Packet lost are critical*/ else { ch->stream_state = 2; GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Lost a critical packet - skipping\n", ch->esd->ESID)); return; } } else { ch->au_sn = AUSeqNum; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: NON-RAP AU received (TS %d)\n", ch->esd->ESID, ch->DTS)); } } } /*no carousel signaling, tune-in at first RAP*/ else if (hdr.randomAccessPointFlag) { ch->stream_state = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP AU received\n", ch->esd->ESID)); } /*waiting for RAP, return*/ else if (ch->stream_state) { GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Waiting for RAP - skipping AU (DTS %d)\n", ch->esd->ESID, ch->DTS)); return; } } /*update the RAP marker on a packet base (to cope with AVC/H264 NALU->AU reconstruction)*/ if (hdr.randomAccessPointFlag) ch->IsRap = 1; /*get AU end state*/ OldLength = ch->buffer ? ch->len : 0; EndAU = hdr.accessUnitEndFlag; if (ch->AULength == OldLength + payload_size) EndAU = 1; if (EndAU) ch->NextIsAUStart = 1; if (EndAU && !ch->IsClockInit) gf_es_check_timing(ch); /* we need to skip all the packets of the current AU in the carousel scenario */ if (ch->skip_carousel_au == 1) return; if (!payload_size && EndAU && ch->buffer) { GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: Empty packet, flushing buffer\n", ch->esd->ESID)); Channel_DispatchAU(ch, 0); return; } if (!payload_size) return; /*missed begining, unusable*/ if (!ch->buffer && !NewAU) { if (ch->esd->slConfig->useAccessUnitStartFlag) { GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d: missed begin of AU\n", ch->esd->ESID)); } if (ch->codec_resilient) NewAU = 1; else return; } /*Write the Packet payload to the buffer*/ if (NewAU) { /*we should NEVER have a bitstream at this stage*/ assert(!ch->buffer); /*ignore length fields*/ size = payload_size + ch->media_padding_bytes; ch->buffer = (char*)gf_malloc(sizeof(char) * size); if (!ch->buffer) { assert(0); return; } ch->allocSize = size; memset(ch->buffer, 0, sizeof(char) * size); ch->len = 0; } if (!ch->esd->slConfig->usePaddingFlag) hdr.paddingFlag = 0; if (ch->ipmp_tool) { GF_Err e; GF_IPMPEvent evt; memset(&evt, 0, sizeof(evt)); evt.event_type=GF_IPMP_TOOL_PROCESS_DATA; evt.channel = ch; evt.data = payload; evt.data_size = payload_size; evt.is_encrypted = hdr.isma_encrypted; evt.isma_BSO = hdr.isma_BSO; e = ch->ipmp_tool->process(ch->ipmp_tool, &evt); /*we discard undecrypted AU*/ if (e) { if (e==GF_EOS) { gf_es_on_eos(ch); /*restart*/ if (evt.restart_requested) { if (ch->odm->parentscene->is_dynamic_scene) { gf_scene_restart_dynamic(ch->odm->parentscene, 0); } else { mediacontrol_restart(ch->odm); } } } return; } } gf_es_lock(ch, 1); if (hdr.paddingFlag && !EndAU) { /*to do - this shouldn't happen anyway */ } else { /*check if enough space*/ size = ch->allocSize; if (size && (payload_size + ch->len <= size)) { memcpy(ch->buffer+ch->len, payload, payload_size); ch->len += payload_size; } else { size = payload_size + ch->len + ch->media_padding_bytes; ch->buffer = (char*)gf_realloc(ch->buffer, sizeof(char) * size); memcpy(ch->buffer+ch->len, payload, payload_size); ch->allocSize = size; ch->len += payload_size; } if (hdr.paddingFlag) ch->padingBits = hdr.paddingBits; } if (EndAU) Channel_DispatchAU(ch, hdr.au_duration); gf_es_lock(ch, 0); }
GF_Err gf_codec_add_channel(GF_Codec *codec, GF_Channel *ch) { GF_Err e; GF_NetworkCommand com; GF_Channel *a_ch; u32 CUsize, i; GF_CodecCapability cap; u32 min, max; /*only for valid codecs (eg not OCR)*/ if (codec->decio) { com.get_dsi.dsi = NULL; if (ch->esd->decoderConfig->upstream) codec->flags |= GF_ESM_CODEC_HAS_UPSTREAM; /*For objects declared in OD stream, override with network DSI if any*/ if (ch->service && !(ch->odm->flags & GF_ODM_NOT_IN_OD_STREAM) ) { com.command_type = GF_NET_CHAN_GET_DSI; com.base.on_channel = ch; e = gf_term_service_command(ch->service, &com); if (!e && com.get_dsi.dsi) { if (ch->esd->decoderConfig->decoderSpecificInfo->data) gf_free(ch->esd->decoderConfig->decoderSpecificInfo->data); ch->esd->decoderConfig->decoderSpecificInfo->data = com.get_dsi.dsi; ch->esd->decoderConfig->decoderSpecificInfo->dataLength = com.get_dsi.dsi_len; } } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attaching stream %d to codec %s\n", ch->esd->ESID, codec->decio->module_name)); /*lock the channel before setup in case we are using direct_decode */ gf_mx_p(ch->mx); e = codec->decio->AttachStream(codec->decio, ch->esd); gf_mx_v(ch->mx); if (ch->esd->decoderConfig && ch->esd->decoderConfig->rvc_config) { gf_odf_desc_del((GF_Descriptor *)ch->esd->decoderConfig->rvc_config); ch->esd->decoderConfig->rvc_config = NULL; } if (e) { GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attach Stream failed %s\n", gf_error_to_string(e) )); return e; } /*ask codec for desired output capacity - note this may be 0 if stream is not yet configured*/ cap.CapCode = GF_CODEC_OUTPUT_SIZE; gf_codec_get_capability(codec, &cap); if (codec->CB && (cap.cap.valueInt != codec->CB->UnitSize)) { gf_cm_del(codec->CB); codec->CB = NULL; } CUsize = cap.cap.valueInt; /*get desired amount of units and minimal fullness (used for scheduling)*/ switch(codec->type) { case GF_STREAM_VISUAL: case GF_STREAM_AUDIO: cap.CapCode = GF_CODEC_BUFFER_MIN; cap.cap.valueInt = 1; gf_codec_get_capability(codec, &cap); min = cap.cap.valueInt; cap.CapCode = GF_CODEC_BUFFER_MAX; cap.cap.valueInt = 1; gf_codec_get_capability(codec, &cap); max = cap.cap.valueInt; break; case GF_STREAM_ND_SUBPIC: max = 1; min = 0; break; default: min = max = 0; break; } if ((codec->type==GF_STREAM_AUDIO) && (max<2)) max = 2; /*setup CB*/ if (!codec->CB && max) { if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) { max = 1; /*create a semaphore in non-notified stage*/ codec->odm->raw_frame_sema = gf_sema_new(1, 0); } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODM] Creating composition buffer for codec %s - %d units %d bytes each\n", codec->decio->module_name, max, CUsize)); codec->CB = gf_cm_new(CUsize, max, (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) ? 1 : 0); codec->CB->Min = min; codec->CB->odm = codec->odm; } if (codec->CB) { /*check re-ordering - set by default on all codecs*/ codec->is_reordering = 1; cap.CapCode = GF_CODEC_REORDER; if (gf_codec_get_capability(codec, &cap) == GF_OK) codec->is_reordering = cap.cap.valueInt; } if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) { ch->is_raw_channel = 1; } /*setup net channel config*/ if (ch->service) { memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_CHAN_CONFIG; com.base.on_channel = ch; com.cfg.priority = ch->esd->streamPriority; assert( ch->clock ); com.cfg.sync_id = ch->clock->clockID; memcpy(&com.cfg.sl_config, ch->esd->slConfig, sizeof(GF_SLConfig)); /*get the frame duration if audio (used by some network stack)*/ if (ch->odm->codec && (ch->odm->codec->type==GF_STREAM_AUDIO) ) { cap.CapCode = GF_CODEC_SAMPLERATE; gf_codec_get_capability(ch->odm->codec, &cap); com.cfg.sample_rate = cap.cap.valueInt; cap.CapCode = GF_CODEC_CU_DURATION; gf_codec_get_capability(ch->odm->codec, &cap); com.cfg.frame_duration = cap.cap.valueInt; } gf_term_service_command(ch->service, &com); ch->carousel_type = GF_ESM_CAROUSEL_NONE; if (com.cfg.use_m2ts_sections) { ch->carousel_type = GF_ESM_CAROUSEL_MPEG2; } else { switch (ch->esd->decoderConfig->streamType) { case GF_STREAM_OD: case GF_STREAM_SCENE: ch->carousel_type = ch->esd->slConfig->AUSeqNumLength ? GF_ESM_CAROUSEL_MPEG4 : GF_ESM_CAROUSEL_NONE; break; } } } } else if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) { cap.CapCode = GF_CODEC_OUTPUT_SIZE; gf_codec_get_capability(codec, &cap); if (codec->CB && (cap.cap.valueInt != codec->CB->UnitSize)) { gf_cm_del(codec->CB); codec->CB = NULL; } CUsize = cap.cap.valueInt; /*create a semaphore in non-notified stage*/ codec->odm->raw_frame_sema = gf_sema_new(1, 0); codec->CB = gf_cm_new(CUsize, 1, 1); codec->CB->Min = 0; codec->CB->odm = codec->odm; ch->is_raw_channel = 1; if (gf_es_owns_clock(ch)) ch->is_raw_channel = 2; if (ch->is_pulling) { codec->process = gf_codec_process_raw_media_pull; } } /*assign the first base layer as the codec clock by default, or current channel clock if no clock set Also assign codec priority here*/ if (!ch->esd->dependsOnESID || !codec->ck) { codec->ck = ch->clock; /*insert base layer first - note we are sure this is a stream of the same type as the codec (other streams - OCI, MPEG7, MPEGJ - are not added that way)*/ return gf_list_insert(codec->inChannels, ch, 0); } else { /*make sure all channels are in order*/ i=0; while ((a_ch = (GF_Channel*)gf_list_enum(codec->inChannels, &i))) { if (ch->esd->dependsOnESID == a_ch->esd->ESID) { return gf_list_insert(codec->inChannels, ch, i); } if (a_ch->esd->dependsOnESID == ch->esd->ESID) { return gf_list_insert(codec->inChannels, ch, i-1); } } /*by default append*/ return gf_list_add(codec->inChannels, ch); } }