in src/terminal/channel.c [877:1415]
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;
Bool EndAU, NewAU;
Bool init_ts = 0;
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) {
gf_es_receive_skip_sl(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;
}
//if PCR is not trusted and this is not a PCR discontinuity, ignore it
if (ch->clock->broken_pcr && (hdr.m2ts_pcr == 1)) {
hdr.OCRflag = 0;
}
if (ch->odm->parentscene && ch->odm->parentscene->root_od->addon)
hdr.OCRflag = 0;
/*we ignore OCRs for the moment*/
if (hdr.OCRflag==1) {
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;
ch->prev_pcr_diff = 0;
gf_es_init_clock(ch, 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;
}
} else if (hdr.OCRflag==2) {
GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u clock disctontinuity was signaled\n", ch->esd->ESID, gf_clock_real_time(ch->clock) ));
gf_clock_discontinuity(ch->clock, ch->odm->parentscene, (hdr.m2ts_pcr==2) ? GF_TRUE : GF_FALSE);
//and re-init timing
gf_es_receive_sl_packet(serv, ch, payload, payload_size, header, reception_status);
return;
} else {
Bool discontinuity = (hdr.m2ts_pcr==2) ? GF_TRUE : GF_FALSE;
u32 ck;
u32 OCR_TS;
s32 pcr_diff, pcr_pcrprev_diff;
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);
pcr_diff = (s32) OCR_TS - (s32) ck;
pcr_pcrprev_diff = pcr_diff - ch->prev_pcr_diff;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u got OCR %u (original TS "LLU") - diff %d%s (diff with prev OCR %d)\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, pcr_diff, discontinuity ? " - PCR Discontinuity flag" : "", pcr_pcrprev_diff));
//PCR loop or disc - use 10 sec as a threshold - it may happen that video is sent up to 4 or 5 seconds ahead of the PCR in some systems
//1- check the PCR diff is greater than 10 seconds
//2- check the diff between this PCR diff and last PCR diff is greater than 10 seconds
//the first test is used to avoid disc detecting when the TS is sent in burst (eg DASH):
if (ch->IsClockInit && (ABS(pcr_diff) > 10000) && (ABS(pcr_pcrprev_diff) > 10000) ) {
discontinuity = GF_TRUE;
}
if (discontinuity) {
GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u detected PCR %s (PCR diff %d - last PCR diff %d)\n", ch->esd->ESID, gf_clock_real_time(ch->clock), (hdr.m2ts_pcr==2) ? "discontinuity" : "looping", pcr_diff, ch->prev_pcr_diff));
gf_clock_discontinuity(ch->clock, ch->odm->parentscene, (hdr.m2ts_pcr==2) ? GF_TRUE : GF_FALSE);
//and re-init timing
gf_es_receive_sl_packet(serv, ch, payload, payload_size, header, reception_status);
//do not probe OCR after a discontinuity
ch->clock->probe_ocr = (hdr.m2ts_pcr==2) ? 0 : 1;
ch->last_pcr = hdr.objectClockReference;
return;
} else {
ch->prev_pcr_diff = pcr_diff;
ch->last_pcr = hdr.objectClockReference;
}
}
if (!payload_size) return;
}
/*check state*/
if (!ch->codec_resilient && (reception_status==GF_CORRUPTED_DATA)) {
gf_es_wait_rap(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==GF_CODEC_RESILIENT_ALWAYS) ) ) {
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));
gf_es_wait_rap(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));
gf_es_wait_rap(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;
ch->skip_time_check_for_pending = 0;
init_ts = 1;
}
/*if not first packet but about to force a clock init, do init timestamps*/
else if (!ch->IsClockInit) {
/*don't process anything until the clock is initialized*/
if (ch->esd->dependsOnESID && !gf_es_owns_clock(ch))
return;
if (hdr.compositionTimeStampFlag)
init_ts = 1;
}
/*if we had a previous buffer, add or discard it, depending on codec resilience*/
if (hdr.accessUnitStartFlag && 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);
gf_es_dispatch_au(ch, 0);
} else {
gf_free(ch->buffer);
ch->buffer = NULL;
ch->AULength = 0;
ch->len = ch->allocSize = 0;
}
}
if (init_ts) {
if (hdr.sender_ntp) ch->sender_ntp = hdr.sender_ntp;
/*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->odm->parentscene && ch->odm->parentscene->root_od->addon) {
s64 res = gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene->root_od->addon, ch->CTS);
if (res<0) return;
ch->CTS = (u32) res;
res = gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene->root_od->addon, ch->DTS);
if (res<0) res=0;
ch->DTS = (u32) 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_WARNING, 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));
gf_es_init_clock(ch, ch->DTS-1000);
ch->clock->broken_pcr = 1;
}
ch->clock->probe_ocr = 0;
}
ch->no_timestamps = 0;
} else {
ch->no_timestamps = 1;
}
} else {
u32 AUSeqNum = hdr.AU_sequenceNumber;
/*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 (hdr.accessUnitStartFlag) {
u32 AUSeqNum = hdr.AU_sequenceNumber;
/*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;
}
//temp hack
if (ch->odm->lower_layer_odm)
hdr.randomAccessPointFlag = 1;
/*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) {
if (ch->stream_state) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): RAP AU received\n", ch->esd->ESID, ch->odm->net_service->url));
ch->stream_state = 0;
}
}
/*waiting for RAP, return*/
else if (ch->stream_state) {
if (ch->esd->dependsOnESID || ch->odm->lower_layer_odm) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Considering AU is RAP on enhancement layer\n", ch->esd->ESID, ch->odm->net_service->url));
ch->stream_state = 0;
} else {
GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Waiting for RAP - skipping AU (DTS %d)\n", ch->esd->ESID, ch->odm->net_service->url, 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;
if (hdr.seekFlag) ch->SeekFlag = 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;
/*init clock if end of AU or if header is valid*/
if ((EndAU || init_ts) && !ch->IsClockInit && !ch->skip_time_check_for_pending) {
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));
gf_es_dispatch_au(ch, 0);
return;
}
if (!payload_size) return;
/*missed beginning, 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 = GF_TRUE;
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 || hdr.cenc_encrypted) ? 1 : 0;
if (hdr.isma_encrypted) {
evt.isma_BSO = hdr.isma_BSO;
} else if (hdr.cenc_encrypted) {
evt.sai = hdr.sai;
evt.saiz = hdr.saiz;
evt.IV_size = hdr.IV_size;
}
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, 0, 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) gf_es_dispatch_au(ch, hdr.au_duration);
gf_es_lock(ch, 0);
}