in src/media_tools/media_import.c [7509:8345]
void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par)
{
GF_Err e;
GF_ISOSample *samp;
Bool is_au_start;
u32 i, count, idx;
GF_M2TS_Program *prog;
GF_TSImport *tsimp = (GF_TSImport *) ts->user;
GF_MediaImporter *import= (GF_MediaImporter *)tsimp->import;
GF_M2TS_ES *es = NULL;
GF_M2TS_PES *pes = NULL;
switch (evt_type) {
case GF_M2TS_EVT_PAT_FOUND:
break;
// case GF_M2TS_EVT_PAT_REPEAT:
// case GF_M2TS_EVT_SDT_REPEAT:
case GF_M2TS_EVT_PMT_REPEAT:
/*abort upon first PMT repeat if not using 4on2. Otherwise we must parse the entire
bitstream to locate ODs sent in OD updates in order to get their stream types...*/
/* if (!ts->has_4on2 && (import->flags & GF_IMPORT_PROBE_ONLY) && !import->trackID)
import->flags |= GF_IMPORT_DO_ABORT;
*/
break;
case GF_M2TS_EVT_PMT_UPDATE:
gf_import_message(import, GF_OK, "[MPEG-2 TS] PMT Update found - cannot import any further");
import->flags |= GF_IMPORT_DO_ABORT;
break;
case GF_M2TS_EVT_DURATION_ESTIMATED:
prog = (GF_M2TS_Program*)par;
if (import->flags & GF_IMPORT_PROBE_ONLY) {
import->probe_duration = ((GF_M2TS_PES_PCK *) par)->PTS;
}
break;
/*case GF_M2TS_EVT_SDT_FOUND:
import->nb_progs = gf_list_count(ts->SDTs);
for (i=0; i<import->nb_progs; i++) {
GF_M2TS_SDT *sdt = (GF_M2TS_SDT *)gf_list_get(ts->SDTs, i);
strcpy(import->pg_info[i].name, sdt->service);
import->pg_info[i].number = sdt->service_id;
}
if (!ts->has_4on2 && import->flags & GF_IMPORT_PROBE_ONLY)
//import->flags |= GF_IMPORT_DO_ABORT;
break;*/
case GF_M2TS_EVT_PMT_FOUND:
prog = (GF_M2TS_Program*)par;
if (import->flags & GF_IMPORT_PROBE_ONLY) {
/*
we scan all the streams declared in this PMT to fill the tk_info structures
NOTE: in the T-DMB case, we also need to decode ObjectDescriptor Updates see "case GF_M2TS_EVT_SL_PCK"
*/
count = gf_list_count(prog->streams);
for (i=0; i<count; i++) {
es = (GF_M2TS_ES *)gf_list_get(prog->streams, i);
if (es->pid == prog->pmt_pid) continue;
if (es->flags & GF_M2TS_ES_IS_SECTION) {
//ses = (GF_M2TS_SECTION_ES *)es;
} else {
pes = (GF_M2TS_PES *)es;
gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_DEFAULT);
}
idx = import->nb_tracks;
import->tk_info[idx].track_num = es->pid;
import->tk_info[idx].prog_num = prog->number;
import->tk_info[idx].mpeg4_es_id = es->mpeg4_es_id;
switch (es->stream_type) {
case GF_M2TS_VIDEO_MPEG1:
import->tk_info[idx].media_type = GF_4CC('M','P','G','1');
import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_video++;
break;
case GF_M2TS_VIDEO_MPEG2:
import->tk_info[idx].media_type = GF_4CC('M','P','G','2');
import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_video++;
break;
case GF_M2TS_VIDEO_MPEG4:
import->tk_info[idx].media_type = GF_4CC('M','P','4','V');
import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_video++;
break;
case GF_M2TS_VIDEO_H264:
case GF_M2TS_VIDEO_SVC:
import->tk_info[idx].media_type = (es->stream_type==GF_M2TS_VIDEO_SVC) ? GF_4CC('S','V','C',' ') : GF_4CC('H','2','6','4');
import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_video++;
break;
case GF_M2TS_VIDEO_HEVC:
case GF_M2TS_VIDEO_SHVC:
import->tk_info[idx].media_type = (es->stream_type==GF_M2TS_VIDEO_SHVC) ? GF_4CC('S','H','V','C') : GF_4CC('H','E','V','C');
import->tk_info[idx].type = GF_ISOM_MEDIA_VISUAL;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_video++;
break;
case GF_M2TS_AUDIO_MPEG1:
import->tk_info[idx].media_type = GF_4CC('M','P','G','1');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_AUDIO_MPEG2:
import->tk_info[idx].media_type = GF_4CC('M','P','G','2');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_AUDIO_AAC:
case GF_M2TS_AUDIO_LATM_AAC:
import->tk_info[idx].media_type = GF_4CC('M','P','4','A');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_AUDIO_AC3:
import->tk_info[idx].media_type = GF_4CC('D','A','C','3');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_AUDIO_EC3:
import->tk_info[idx].media_type = GF_4CC('D','E','C','3');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_AUDIO_DTS:
import->tk_info[idx].media_type = GF_4CC('D','T','S',' ');
import->tk_info[idx].type = GF_ISOM_MEDIA_AUDIO;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
tsimp->nb_audio++;
break;
case GF_M2TS_SYSTEMS_MPEG4_PES:
case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
if (es->stream_type == GF_M2TS_SYSTEMS_MPEG4_PES) {
import->tk_info[idx].media_type = GF_4CC('M','4','S','P');
} else {
import->tk_info[idx].media_type = GF_4CC('M','4','S','S');
}
if (prog->pmt_iod) {
GF_ESD *esd = gf_m2ts_get_esd(es);
m2ts_set_track_mpeg4_probe_info(es, esd, &import->tk_info[idx]);
if (esd && esd->decoderConfig->streamType == GF_STREAM_OD) {
es->flags |= GF_M2TS_ES_IS_MPEG4_OD;
}
} else {
import->tk_info[idx].type = GF_ISOM_MEDIA_ESM;
}
import->nb_tracks++;
break;
case GF_M2TS_METADATA_ID3_HLS:
import->tk_info[idx].media_type = GF_4CC('I','D','3',' ');
import->tk_info[idx].type = GF_ISOM_MEDIA_META;
import->tk_info[idx].lang = pes->lang;
import->nb_tracks++;
break;
default:
gf_import_message(import, GF_OK, "[MPEG-2 TS] Ignoring stream of type %d", es->stream_type);
}
}
} else {
/* We are not in PROBE mode, we are importing only one stream and don't care about the other streams */
u32 mtype, stype, oti;
Bool is_in_iod, found;
/* Since the GF_M2TS_ES_IS_MPEG4_OD flag is stored at the ES level and ES are reset after probe,
we need to set it again as in probe mode */
found = GF_FALSE;
count = gf_list_count(prog->streams);
for (i=0; i<count; i++) {
GF_ESD *esd;
es = (GF_M2TS_ES *)gf_list_get(prog->streams, i);
if (es->pid == prog->pmt_pid) continue;
if (es->pid == import->trackID) found = GF_TRUE;
if (es->flags & GF_M2TS_ES_IS_SECTION) {
//ses = (GF_M2TS_SECTION_ES *)es;
} else {
pes = (GF_M2TS_PES *)es;
}
esd = gf_m2ts_get_esd(es);
if (esd && esd->decoderConfig->streamType == GF_STREAM_OD) {
es->flags |= GF_M2TS_ES_IS_MPEG4_OD;
}
}
/*this PMT is not the one of our stream*/
if (!found || !ts->ess[import->trackID]) return;
/*make sure all the streams in this programe are in RAW pes framing mode, so that we get notified of the
DTS/PTS*/
for (i=0; i<count; i++) {
es = (GF_M2TS_ES *)gf_list_get(prog->streams, i);
if (!(es->flags & GF_M2TS_ES_IS_SECTION)) {
gf_m2ts_set_pes_framing((GF_M2TS_PES *)es, GF_M2TS_PES_FRAMING_RAW);
}
}
es = ts->ess[import->trackID]; /* import->trackID == pid */
if (es->flags & GF_M2TS_ES_IS_SECTION) {
//ses = (GF_M2TS_SECTION_ES *)es;
} else {
pes = (GF_M2TS_PES *)es;
gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_DEFAULT_NAL);
}
mtype = stype = oti = 0;
is_in_iod = GF_FALSE;
switch (es->stream_type) {
case GF_M2TS_VIDEO_MPEG1:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_MPEG1;
break;
case GF_M2TS_VIDEO_MPEG2:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_MPEG2_422;
break;
case GF_M2TS_VIDEO_MPEG4:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_MPEG4_PART2;
break;
case GF_M2TS_VIDEO_H264:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_AVC;
tsimp->avccfg = gf_odf_avc_cfg_new();
break;
case GF_M2TS_VIDEO_HEVC:
case GF_M2TS_VIDEO_SHVC:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_HEVC;
#ifndef GPAC_DISABLE_HEVC
tsimp->hevccfg = gf_odf_hevc_cfg_new();
#endif //GPAC_DISABLE_HEVC
break;
case GF_M2TS_VIDEO_SVC:
mtype = GF_ISOM_MEDIA_VISUAL;
stype = GF_STREAM_VISUAL;
oti = GPAC_OTI_VIDEO_SVC;
tsimp->avccfg = gf_odf_avc_cfg_new();
break;
case GF_M2TS_AUDIO_MPEG1:
mtype = GF_ISOM_MEDIA_AUDIO;
stype = GF_STREAM_AUDIO;
oti = GPAC_OTI_AUDIO_MPEG1;
break;
case GF_M2TS_AUDIO_MPEG2:
mtype = GF_ISOM_MEDIA_AUDIO;
stype = GF_STREAM_AUDIO;
oti = GPAC_OTI_AUDIO_MPEG2_PART3;
break;
case GF_M2TS_AUDIO_LATM_AAC:
case GF_M2TS_AUDIO_AAC:
mtype = GF_ISOM_MEDIA_AUDIO;
stype = GF_STREAM_AUDIO;
oti = GPAC_OTI_AUDIO_AAC_MPEG4;
break;
case GF_M2TS_AUDIO_AC3:
mtype = GF_ISOM_MEDIA_AUDIO;
stype = GF_STREAM_AUDIO;
oti = GPAC_OTI_AUDIO_AC3;
break;
case GF_M2TS_SYSTEMS_MPEG4_PES:
case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
if (prog->pmt_iod && !import->esd) {
import->esd = gf_m2ts_get_esd(es);
m2ts_set_track_mpeg4_creation_info(import, &mtype, &stype, &oti);
is_in_iod = GF_TRUE;
}
break;
}
m2ts_create_track(tsimp, mtype, stype, oti, es->mpeg4_es_id, is_in_iod);
}
break;
case GF_M2TS_EVT_AAC_CFG:
if (!(import->flags & GF_IMPORT_PROBE_ONLY) && !tsimp->stream_setup) {
GF_ESD *esd = gf_isom_get_esd(import->dest, tsimp->track, 1);
if (esd) {
if (!esd->decoderConfig->decoderSpecificInfo) esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
if (esd->decoderConfig->decoderSpecificInfo->data) gf_free(esd->decoderConfig->decoderSpecificInfo->data);
esd->decoderConfig->decoderSpecificInfo->data = ((GF_M2TS_PES_PCK*)par)->data;
esd->decoderConfig->decoderSpecificInfo->dataLength = ((GF_M2TS_PES_PCK*)par)->data_len;
gf_isom_change_mpeg4_description(import->dest, tsimp->track, 1, esd);
esd->decoderConfig->decoderSpecificInfo->data = NULL;
gf_odf_desc_del((GF_Descriptor *)esd);
tsimp->stream_setup = GF_TRUE;
gf_isom_set_audio_info(import->dest, tsimp->track, 1, ((GF_M2TS_PES_PCK*)par)->stream->aud_sr, ((GF_M2TS_PES_PCK*)par)->stream->aud_nb_ch, 8);
}
}
break;
case GF_M2TS_EVT_PES_PCK:
{
GF_M2TS_PES_PCK *pck = (GF_M2TS_PES_PCK *)par;
is_au_start = (pck->flags & GF_M2TS_PES_PCK_AU_START);
if (import->flags & GF_IMPORT_PROBE_ONLY) {
for (i=0; i<import->nb_tracks; i++) {
if (import->tk_info[i].track_num == pck->stream->pid) {
if (pck->stream->aud_sr && ! import->tk_info[i].audio_info.sample_rate) {
import->tk_info[i].audio_info.sample_rate = pck->stream->aud_sr;
import->tk_info[i].audio_info.nb_channels = pck->stream->aud_nb_ch;
if ((pck->stream->stream_type==GF_M2TS_AUDIO_AAC) || (pck->stream->stream_type==GF_M2TS_AUDIO_LATM_AAC)) {
sprintf(import->tk_info[i].szCodecProfile, "mp4a.40.%02x", (u8) pck->stream->aud_aac_obj_type);
}
import->tk_info[i].audio_info.sample_rate = pck->stream->aud_sr;
import->tk_info[i].audio_info.nb_channels = pck->stream->aud_nb_ch;
tsimp->nb_audio_configured++;
}
/*unpack AVC config*/
else if (((pck->stream->stream_type==GF_M2TS_VIDEO_H264) || (pck->stream->stream_type==GF_M2TS_VIDEO_SVC)) && !pck->data[0] && !pck->data[1]) {
u32 nal_type = pck->data[4] & 0x1F;
if (nal_type == GF_AVC_NALU_SEQ_PARAM) {
sprintf(import->tk_info[i].szCodecProfile, "avc1.%02x%02x%02x", (u8) pck->data[5], (u8) pck->data[6], (u8) pck->data[7]);
}
}
else if (pck->stream->stream_type==GF_M2TS_VIDEO_HEVC) {
u32 nal_type = (pck->data[4] & 0x7E) >> 1;
if (nal_type == GF_HEVC_NALU_SEQ_PARAM) {
//todo ..;
sprintf(import->tk_info[i].szCodecProfile, "hvc1");
}
}
else if ((pck->stream->stream_type==GF_M2TS_AUDIO_EC3) || (pck->stream->stream_type==GF_M2TS_AUDIO_AC3) || (pck->stream->stream_type==GF_M2TS_AUDIO_DTS)) {
if (!import->tk_info[i].audio_info.sample_rate) {
//todo ...
import->tk_info[i].audio_info.sample_rate = 44100;
import->tk_info[i].audio_info.nb_channels = 2;
tsimp->nb_audio_configured++;
}
}
if (pck->stream->vid_w && ! import->tk_info[i].video_info.width ) {
import->tk_info[i].video_info.width = pck->stream->vid_w;
import->tk_info[i].video_info.height = pck->stream->vid_h;
tsimp->nb_video_configured++;
}
/*consider we are done if not using 4 on 2*/
if (!ts->has_4on2
&& (tsimp->nb_video_configured == tsimp->nb_video)
&& (tsimp->nb_audio_configured == tsimp->nb_audio)
&& import->probe_duration
) {
import->flags |= GF_IMPORT_DO_ABORT;
}
break;
}
}
if (!ts->has_4on2 && (import->trackID==pck->stream->pid) && (pck->stream->vid_h || pck->stream->aud_sr) )
import->flags |= GF_IMPORT_DO_ABORT;
return;
}
/* Even if we don't import this stream we need to check the first dts of the program */
if (!(pck->stream->flags & GF_M2TS_ES_FIRST_DTS) && is_au_start) {
pck->stream->flags |= GF_M2TS_ES_FIRST_DTS;
pck->stream->first_dts = (pck->PTS!=pck->DTS) ? pck->DTS : pck->PTS;
if (!pck->stream->program->first_dts || pck->stream->program->first_dts > pck->stream->first_dts) {
pck->stream->program->first_dts = pck->stream->first_dts;
if (pck->stream->pid != import->trackID) {
gf_m2ts_set_pes_framing((GF_M2TS_PES *)pck->stream, GF_M2TS_PES_FRAMING_SKIP);
}
}
}
if (pck->stream->pid != import->trackID) return;
/*avc data for the current sample is stored in annex-B, as we don't know the size of each nal
when called back (depending on PES packetization, the end of the nal could be in following pes)*/
if (tsimp->avccfg && !pck->data[0] && !pck->data[1]) {
GF_AVCConfigSlot *slc;
s32 idx;
Bool add_sps, is_subseq = GF_FALSE;
u32 nal_type = pck->data[4] & 0x1F;
switch (nal_type) {
case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
is_subseq = GF_TRUE;
case GF_AVC_NALU_SEQ_PARAM:
idx = gf_media_avc_read_sps(pck->data+4, pck->data_len-4, &tsimp->avc, is_subseq, NULL);
add_sps = GF_FALSE;
if (idx>=0) {
if (is_subseq) {
if ((tsimp->avc.sps[idx].state & AVC_SUBSPS_PARSED) && !(tsimp->avc.sps[idx].state & AVC_SUBSPS_DECLARED)) {
tsimp->avc.sps[idx].state |= AVC_SUBSPS_DECLARED;
add_sps = GF_TRUE;
}
} else {
if ((tsimp->avc.sps[idx].state & AVC_SPS_PARSED) && !(tsimp->avc.sps[idx].state & AVC_SPS_DECLARED)) {
tsimp->avc.sps[idx].state |= AVC_SPS_DECLARED;
add_sps = GF_TRUE;
}
}
if (add_sps) {
/*always store nalu size on 4 bytes*/
tsimp->avccfg->nal_unit_size = 4;
tsimp->avccfg->configurationVersion = 1;
tsimp->avccfg->profile_compatibility = tsimp->avc.sps[idx].prof_compat;
tsimp->avccfg->AVCProfileIndication = tsimp->avc.sps[idx].profile_idc;
tsimp->avccfg->AVCLevelIndication = tsimp->avc.sps[idx].level_idc;
if (pck->stream->vid_w < tsimp->avc.sps[idx].width)
pck->stream->vid_w = tsimp->avc.sps[idx].width;
if (pck->stream->vid_h < tsimp->avc.sps[idx].height)
pck->stream->vid_h = tsimp->avc.sps[idx].height;
if (!(import->flags & GF_IMPORT_FORCE_XPS_INBAND)) {
slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
slc->size = pck->data_len-4;
slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
memcpy(slc->data, pck->data+4, sizeof(char)*slc->size);
gf_list_add(tsimp->avccfg->sequenceParameterSets, slc);
}
}
}
if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) {
break;
}
return;
case GF_AVC_NALU_PIC_PARAM:
idx = gf_media_avc_read_pps(pck->data+4, pck->data_len-4, &tsimp->avc);
if ((idx>=0) && (tsimp->avc.pps[idx].status==1)) {
tsimp->avc.pps[idx].status = 2;
if (!(import->flags & GF_IMPORT_FORCE_XPS_INBAND)) {
slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
slc->size = pck->data_len-4;
slc->data = (char*)gf_malloc(sizeof(char)*slc->size);
memcpy(slc->data, pck->data+4, sizeof(char)*slc->size);
gf_list_add(tsimp->avccfg->pictureParameterSets, slc);
}
}
if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) {
break;
}
/*else discard because of invalid PPS*/
return;
/*remove*/
case GF_AVC_NALU_ACCESS_UNIT:
tsimp->force_next_au_start = GF_TRUE;
return;
case GF_AVC_NALU_FILLER_DATA:
case GF_AVC_NALU_END_OF_SEQ:
case GF_AVC_NALU_END_OF_STREAM:
return;
case GF_AVC_NALU_SEI:
break;
}
if (tsimp->force_next_au_start) {
is_au_start = GF_TRUE;
tsimp->force_next_au_start = GF_FALSE;
}
}
/*avc data for the current sample is stored in annex-B, as we don't know the size of each nal
when called back (depending on PES packetization, the end of the nal could be in following pes)*/
#ifndef GPAC_DISABLE_HEVC
else if (tsimp->hevccfg && !pck->data[0] && !pck->data[1]) {
s32 idx;
Bool add_sps, is_subseq = GF_FALSE;
u32 nal_type = (pck->data[4] & 0x7E) >> 1;
switch (nal_type) {
case GF_HEVC_NALU_SEQ_PARAM:
idx = gf_media_hevc_read_sps(pck->data+4, pck->data_len-4, &tsimp->hevc);
add_sps = GF_FALSE;
if (idx>=0) {
if (is_subseq) {
if ((tsimp->hevc.sps[idx].state & AVC_SUBSPS_PARSED) && !(tsimp->hevc.sps[idx].state & AVC_SUBSPS_DECLARED)) {
tsimp->hevc.sps[idx].state |= AVC_SUBSPS_DECLARED;
add_sps = GF_TRUE;
}
} else {
if ((tsimp->hevc.sps[idx].state & AVC_SPS_PARSED) && !(tsimp->hevc.sps[idx].state & AVC_SPS_DECLARED)) {
tsimp->hevc.sps[idx].state |= AVC_SPS_DECLARED;
add_sps = GF_TRUE;
}
}
if (add_sps) {
/*always store nalu size on 4 bytes*/
tsimp->hevccfg->nal_unit_size = 4;
tsimp->hevccfg->configurationVersion = 1;
tsimp->hevccfg->configurationVersion = 1;
tsimp->hevccfg->profile_space = tsimp->hevc.sps[idx].ptl.profile_space;
tsimp->hevccfg->profile_idc = tsimp->hevc.sps[idx].ptl.profile_idc;
tsimp->hevccfg->constraint_indicator_flags = 0;
tsimp->hevccfg->level_idc = tsimp->hevc.sps[idx].ptl.level_idc;
tsimp->hevccfg->general_profile_compatibility_flags = tsimp->hevc.sps[idx].ptl.profile_compatibility_flag;
tsimp->hevccfg->chromaFormat = tsimp->hevc.sps[idx].chroma_format_idc;
tsimp->hevccfg->luma_bit_depth = tsimp->hevc.sps[idx].bit_depth_luma;
tsimp->hevccfg->chroma_bit_depth = tsimp->hevc.sps[idx].bit_depth_chroma;
hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
if (pck->stream->vid_w < tsimp->avc.sps[idx].width)
pck->stream->vid_w = tsimp->avc.sps[idx].width;
if (pck->stream->vid_h < tsimp->avc.sps[idx].height)
pck->stream->vid_h = tsimp->avc.sps[idx].height;
}
}
if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) {
is_au_start = GF_TRUE;
break;
}
return;
case GF_HEVC_NALU_PIC_PARAM:
idx = gf_media_hevc_read_pps(pck->data+4, pck->data_len-4, &tsimp->hevc);
if ((idx>=0) && (tsimp->hevc.pps[idx].state==1)) {
tsimp->hevc.pps[idx].state = 2;
hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
}
if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) {
is_au_start = GF_TRUE;
break;
}
return;
case GF_HEVC_NALU_VID_PARAM:
idx = gf_media_hevc_read_vps(pck->data+4, pck->data_len-4, &tsimp->hevc);
if ((idx>=0) && (tsimp->hevc.vps[idx].state==1)) {
tsimp->hevc.vps[idx].state = 2;
tsimp->hevccfg->avgFrameRate = tsimp->hevc.vps[idx].rates[0].avg_pic_rate;
tsimp->hevccfg->constantFrameRate = tsimp->hevc.vps[idx].rates[0].constand_pic_rate_idc;
tsimp->hevccfg->numTemporalLayers = tsimp->hevc.vps[idx].max_sub_layers;
hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4);
}
if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) {
is_au_start = GF_TRUE;
break;
}
return;
/*remove*/
case GF_HEVC_NALU_ACCESS_UNIT:
tsimp->force_next_au_start = GF_TRUE;
return;
case GF_HEVC_NALU_FILLER_DATA:
case GF_HEVC_NALU_END_OF_SEQ:
case GF_HEVC_NALU_END_OF_STREAM:
return;
case GF_HEVC_NALU_SEI_PREFIX:
is_au_start = GF_TRUE;
break;
}
if (tsimp->force_next_au_start) {
is_au_start = GF_TRUE;
tsimp->force_next_au_start = GF_FALSE;
}
}
#endif //GPAC_DISABLE_HEVC
if (!is_au_start) {
e = gf_isom_append_sample_data(import->dest, tsimp->track, (char*)pck->data, pck->data_len);
if (e) {
if (!gf_isom_get_sample_count(import->dest, tsimp->track)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] missed beginning of sample data\n"));
e = GF_OK;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] Error appending sample data\n"));
}
}
if (pck->flags & GF_M2TS_PES_PCK_I_FRAME) tsimp->nb_i++;
if (pck->flags & GF_M2TS_PES_PCK_P_FRAME) tsimp->nb_p++;
if (pck->flags & GF_M2TS_PES_PCK_B_FRAME) tsimp->nb_b++;
if (pck->flags & GF_M2TS_PES_PCK_RAP) {
e = gf_isom_set_sample_rap(import->dest, tsimp->track);
}
return;
}
samp = gf_isom_sample_new();
samp->DTS = pck->DTS;
samp->CTS_Offset = (u32) (pck->PTS - samp->DTS);
if (pck->stream->first_dts==samp->DTS) {
switch (pck->stream->stream_type) {
case GF_M2TS_VIDEO_MPEG1:
gf_import_message(import, GF_OK, "MPEG-1 Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_VIDEO_MPEG2:
gf_import_message(import, GF_OK, "MPEG-2 Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_VIDEO_MPEG4:
gf_import_message(import, GF_OK, "MPEG-4 Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_VIDEO_H264:
gf_import_message(import, GF_OK, "MPEG-4 AVC/H264 Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_VIDEO_HEVC:
gf_import_message(import, GF_OK, "MPEG-H HEVC Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_VIDEO_SVC:
gf_import_message(import, GF_OK, "H264-SVC Video import (TS PID %d)", pck->stream->pid);
break;
case GF_M2TS_AUDIO_MPEG1:
gf_import_message(import, GF_OK, "MPEG-1 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid);
break;
case GF_M2TS_AUDIO_MPEG2:
gf_import_message(import, GF_OK, "MPEG-2 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid);
break;
case GF_M2TS_AUDIO_AAC:
gf_import_message(import, GF_OK, "MPEG-4 AAC Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid);
break;
case GF_M2TS_AUDIO_AC3:
gf_import_message(import, GF_OK, "Dolby AC3 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid);
break;
case GF_M2TS_AUDIO_EC3:
gf_import_message(import, GF_OK, "Dolby E-AC3 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid);
break;
}
if (pck->stream->lang)
gf_isom_set_media_language(import->dest, tsimp->track, (char *) gf_4cc_to_str(pck->stream->lang)+1);
}
if (!tsimp->stream_setup) {
if (pck->stream->aud_sr) {
gf_isom_set_audio_info(import->dest, tsimp->track, 1, pck->stream->aud_sr, pck->stream->aud_nb_ch, 16);
tsimp->stream_setup = GF_TRUE;
}
else if (pck->stream->vid_w) {
u32 w = pck->stream->vid_w;
if (pck->stream->vid_par) w = w * (pck->stream->vid_par>>16) / (pck->stream->vid_par&0xffff);
gf_isom_set_visual_info(import->dest, tsimp->track, 1, pck->stream->vid_w, pck->stream->vid_h);
gf_isom_set_track_layout_info(import->dest, tsimp->track, w<<16, pck->stream->vid_h<<16, 0, 0, 0);
if (w != pck->stream->vid_w)
e = gf_isom_set_pixel_aspect_ratio(import->dest, tsimp->track, 1, pck->stream->vid_par>>16, pck->stream->vid_par&0xff);
tsimp->stream_setup = GF_TRUE;
}
}
if (samp->DTS >= pck->stream->first_dts) {
samp->DTS -= pck->stream->first_dts;
samp->IsRAP = (pck->flags & GF_M2TS_PES_PCK_RAP) ? RAP : RAP_NO;
samp->data = pck->data;
samp->dataLength = pck->data_len;
if (samp->DTS && (samp->DTS==tsimp->last_dts)) {
e = gf_isom_append_sample_data(import->dest, tsimp->track, (char*)pck->data, pck->data_len);
} else {
if (tsimp->avccfg || tsimp->hevccfg) m2ts_rewrite_nalu_sample(import, tsimp);
e = gf_isom_add_sample(import->dest, tsimp->track, 1, samp);
}
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] PID %d: Error adding sample: %s\n", pck->stream->pid, gf_error_to_string(e)));
//import->flags |= GF_IMPORT_DO_ABORT;
import->last_error = e;
}
if (import->duration && (import->duration<=(samp->DTS+samp->CTS_Offset)/90))
//import->flags |= GF_IMPORT_DO_ABORT;
if (pck->flags & GF_M2TS_PES_PCK_I_FRAME) tsimp->nb_i++;
if (pck->flags & GF_M2TS_PES_PCK_P_FRAME) tsimp->nb_p++;
if (pck->flags & GF_M2TS_PES_PCK_B_FRAME) tsimp->nb_b++;
tsimp->last_dts = samp->DTS;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] negative time sample - skipping\n"));
}
samp->data = NULL;
gf_isom_sample_del(&samp);
}
break;
case GF_M2TS_EVT_SL_PCK:
{
GF_M2TS_SL_PCK *sl_pck = (GF_M2TS_SL_PCK *)par;
/* if there is no IOD for this program we cannot handle SL packets */
if (!sl_pck->stream->program->pmt_iod) return;
if (sl_pck->stream->flags & GF_M2TS_ES_IS_SECTION) {
//ses = (GF_M2TS_SECTION_ES *)sl_pck->stream;
} else {
pes = (GF_M2TS_PES *)sl_pck->stream;
}
if (sl_pck->stream->flags & GF_M2TS_ES_IS_MPEG4_OD) {
/* We need to handle OD streams even if this is not the stream we are importing */
GF_ESD *esd = gf_m2ts_get_esd(sl_pck->stream);
if (esd) {
GF_SLHeader hdr;
u32 hdr_len;
GF_ODCodec *od_codec = gf_odf_codec_new();
GF_ODCom *com;
GF_ODUpdate* odU;
u32 com_count, com_index, od_count, od_index;
gf_sl_depacketize(esd->slConfig, &hdr, sl_pck->data, sl_pck->data_len, &hdr_len);
gf_odf_codec_set_au(od_codec, sl_pck->data+hdr_len, sl_pck->data_len - hdr_len);
gf_odf_codec_decode(od_codec);
com_count = gf_list_count(od_codec->CommandList);
for (com_index = 0; com_index < com_count; com_index++) {
com = (GF_ODCom *)gf_list_get(od_codec->CommandList, com_index);
switch (com->tag) {
case GF_ODF_OD_UPDATE_TAG:
odU = (GF_ODUpdate*)com;
od_count = gf_list_count(odU->objectDescriptors);
for (od_index=0; od_index<od_count; od_index++) {
GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(odU->objectDescriptors, od_index);
gf_list_add(sl_pck->stream->program->additional_ods, od);
/* We need to set the remaining unset track info for the streams declared in this OD */
m2ts_set_tracks_mpeg4_probe_info(import, sl_pck->stream->program, od->ESDescriptors);
}
gf_list_reset(odU->objectDescriptors);
}
}
gf_odf_codec_del(od_codec);
}
}
if (import->flags & GF_IMPORT_PROBE_ONLY) {
if (pes) {
for (i=0; i<import->nb_tracks; i++) {
if (import->tk_info[i].track_num == sl_pck->stream->pid) {
if (pes->aud_sr) {
import->tk_info[i].audio_info.sample_rate = pes->aud_sr;
import->tk_info[i].audio_info.nb_channels = pes->aud_nb_ch;
} else {
import->tk_info[i].video_info.width = pes->vid_w;
import->tk_info[i].video_info.height = pes->vid_h;
}
break;
}
}
// if (pes->vid_h || pes->aud_sr) import->flags |= GF_IMPORT_DO_ABORT;
}
return;
}
if (sl_pck->stream->pid != import->trackID) return;
/* we create a track for the stream to import only if it was not created */
if (!gf_isom_get_track_by_id(import->dest, (import->esd?import->esd->ESID:import->trackID))) {
u32 mtype, stype, oti;
mtype = stype = oti = 0;
import->esd = gf_m2ts_get_esd(sl_pck->stream);
m2ts_set_track_mpeg4_creation_info(import, &mtype, &stype, &oti);
m2ts_create_track(tsimp, mtype, stype, oti, sl_pck->stream->mpeg4_es_id, GF_FALSE);
}
if (import->esd) {
GF_SLHeader hdr;
u32 hdr_len;
gf_sl_depacketize(import->esd->slConfig, &hdr, sl_pck->data, sl_pck->data_len, &hdr_len);
if (!hdr.accessUnitStartFlag) {
e = gf_isom_append_sample_data(import->dest, tsimp->track, sl_pck->data + hdr_len, sl_pck->data_len - hdr_len);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] Error appending sample data\n"));
}
} else {
if (!(sl_pck->stream->flags & GF_M2TS_ES_FIRST_DTS)) {
sl_pck->stream->flags |= GF_M2TS_ES_FIRST_DTS;
if (!hdr.compositionTimeStampFlag) {
hdr.compositionTimeStamp = sl_pck->stream->program->first_dts;
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] PID %d First SL Access unit start flag set without any composition time stamp - defaulting to last CTS seen on program\n", sl_pck->stream->pid));
}
sl_pck->stream->first_dts = (hdr.decodingTimeStamp?hdr.decodingTimeStamp:hdr.compositionTimeStamp);
if (!sl_pck->stream->program->first_dts ||
sl_pck->stream->program->first_dts > sl_pck->stream->first_dts) {
sl_pck->stream->program->first_dts = sl_pck->stream->first_dts;
}
} else {
if (!hdr.compositionTimeStampFlag) {
hdr.compositionTimeStamp = sl_pck->stream->first_dts + tsimp->last_dts+1;
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] PID %d SL Access unit start flag set without any composition time stamp - defaulting to last CTS seen on stream + 1\n", sl_pck->stream->pid));
}
}
samp = gf_isom_sample_new();
samp->DTS = (hdr.decodingTimeStamp?hdr.decodingTimeStamp:hdr.compositionTimeStamp);
samp->CTS_Offset = (u32) (hdr.compositionTimeStamp - samp->DTS);
if (samp->DTS >= sl_pck->stream->first_dts) {
samp->DTS -= sl_pck->stream->first_dts;
samp->IsRAP = import->esd->slConfig->useRandomAccessPointFlag ? hdr.randomAccessPointFlag : RAP;
/*fix for some DMB streams where TSs are not coded*/
if ((tsimp->last_dts == samp->DTS) && gf_isom_get_sample_count(import->dest, tsimp->track))
samp->DTS += gf_isom_get_media_timescale(import->dest, tsimp->track);
samp->data = sl_pck->data + hdr_len;
samp->dataLength = sl_pck->data_len - hdr_len;
e = gf_isom_add_sample(import->dest, tsimp->track, 1, samp);
/*if CTS was not specified, samples will simply be skipped*/
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] PID %d Error adding sample\n", sl_pck->stream->pid));
}
if (import->duration && (import->duration<=(samp->DTS+samp->CTS_Offset)/90)) {
//import->flags |= GF_IMPORT_DO_ABORT;
}
tsimp->last_dts = samp->DTS;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] negative time sample - skipping\n"));
sl_pck->stream->first_dts = samp->DTS;
if (!sl_pck->stream->program->first_dts ||
sl_pck->stream->program->first_dts > sl_pck->stream->first_dts) {
sl_pck->stream->program->first_dts = sl_pck->stream->first_dts;
}
}
samp->data = NULL;
gf_isom_sample_del(&samp);
}
}
}
break;
}
}