This source file includes following definitions.
- gf_m2ts_get_stream_name
- gf_m2ts_estimate_duration
- gf_m2ts_reframe_default
- gf_m2ts_reframe_reset
- gf_m2ts_reframe_nalu_video
- gf_m2ts_reframe_avc_h264
- gf_m2ts_reframe_hevc
- gf_m2ts_reframe_mpeg_video
- gf_m2ts_reframe_aac_adts
- gf_m2ts_reframe_aac_latm
- gf_m2ts_reframe_mpeg_audio
- gf_m2ts_reframe_ac3
- gf_m2ts_reframe_ec3
- add_text
- id3_parse_tag
- gf_m2ts_reframe_id3_pes
- gf_m2ts_sync
- gf_m2ts_crc32_check
- gf_m2ts_section_filter_new
- gf_m2ts_reset_sections
- gf_m2ts_section_filter_reset
- gf_m2ts_section_filter_del
- gf_m2ts_es_del
- gf_m2ts_reset_sdt
- gf_m2ts_get_sdt_info
- gf_m2ts_section_complete
- gf_m2ts_is_long_section
- gf_m2ts_get_section_length
- gf_m2ts_gather_section
- gf_m2ts_process_sdt
- gf_m2ts_process_mpeg4section
- gf_m2ts_process_nit
- dvb_decode_mjd_date
- gf_m2ts_process_tdt_tot
- gf_m2ts_read_metadata_pointer_descriptor
- gf_m2ts_metadata_pointer_descriptor_del
- gf_m2ts_read_metadata_descriptor
- gf_m2ts_metadata_descriptor_del
- gf_m2ts_process_pmt
- gf_m2ts_process_pat
- gf_m2ts_process_cat
- gf_m2ts_get_pts
- gf_m2ts_pes_header
- gf_m2ts_store_temi
- gf_m2ts_flush_pes
- gf_m2ts_process_pes
- gf_m2ts_get_adaptation_field
- gf_m2ts_process_packet
- gf_m2ts_process_data
- gf_m2ts_get_esd
- gf_m2ts_set_segment_switch
- gf_m2ts_reset_parsers_for_program
- gf_m2ts_reset_parsers
- gf_m2ts_process_section_discard
- gf_m2ts_pes_get_framing_mode
- gf_m2ts_set_pes_framing
- gf_m2ts_demux_new
- gf_m2ts_abort_parsing
- gf_m2ts_demux_dmscc_init
- gf_m2ts_demux_del
- gf_m2ts_print_info
- gf_m2ts_pause_demux
- gf_m2ts_demux_file
- gf_m2ts_demuxer_run
- gf_m2ts_get_socket
- gf_m2ts_demuxer_setup_live
- gf_dvb_tune
- gf_dvb_get_freq_from_url
- gf_m2ts_demuxer_setup_dvb
- gf_m2ts_demuxer_setup_file
- gf_m2ts_demuxer_setup
- gf_m2ts_demuxer_close
- gf_m2ts_demuxer_play
- gf_m2ts_probe_file
- rewrite_pts_dts
- gf_m2ts_restamp
#include <gpac/mpegts.h>
#ifndef GPAC_DISABLE_MPEG2TS
#include <string.h>
#include <gpac/constants.h>
#include <gpac/internal/media_dev.h>
#include <gpac/download.h>
#ifndef GPAC_DISABLE_STREAMING
#include <gpac/internal/ietf_dev.h>
#endif
#ifdef GPAC_CONFIG_LINUX
#include <unistd.h>
#endif
#ifdef GPAC_ENABLE_MPE
#include <gpac/dvb_mpe.h>
#endif
#ifdef GPAC_ENABLE_DSMCC
#include <gpac/ait.h>
#endif
#define DEBUG_TS_PACKET 0
GF_EXPORT
const char *gf_m2ts_get_stream_name(u32 streamType)
{
switch (streamType) {
case GF_M2TS_VIDEO_MPEG1:
return "MPEG-1 Video";
case GF_M2TS_VIDEO_MPEG2:
return "MPEG-2 Video";
case GF_M2TS_AUDIO_MPEG1:
return "MPEG-1 Audio";
case GF_M2TS_AUDIO_MPEG2:
return "MPEG-2 Audio";
case GF_M2TS_PRIVATE_SECTION:
return "Private Section";
case GF_M2TS_PRIVATE_DATA:
return "Private Data";
case GF_M2TS_AUDIO_AAC:
return "AAC Audio";
case GF_M2TS_VIDEO_MPEG4:
return "MPEG-4 Video";
case GF_M2TS_VIDEO_H264:
return "MPEG-4/H264 Video";
case GF_M2TS_VIDEO_SVC:
return "H264-SVC Video";
case GF_M2TS_VIDEO_HEVC:
return "HEVC Video";
case GF_M2TS_VIDEO_SHVC:
return "SHVC Video";
case GF_M2TS_VIDEO_SHVC_TEMPORAL:
return "SHVC Video Temporal Sublayer";
case GF_M2TS_VIDEO_MHVC:
return "MHVC Video";
case GF_M2TS_VIDEO_MHVC_TEMPORAL:
return "MHVC Video Temporal Sublayer";
case GF_M2TS_AUDIO_AC3:
return "Dolby AC3 Audio";
case GF_M2TS_AUDIO_DTS:
return "Dolby DTS Audio";
case GF_M2TS_SUBTITLE_DVB:
return "DVB Subtitle";
case GF_M2TS_SYSTEMS_MPEG4_PES:
return "MPEG-4 SL (PES)";
case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
return "MPEG-4 SL (Section)";
case GF_M2TS_MPE_SECTIONS:
return "MPE (Section)";
case GF_M2TS_METADATA_PES:
return "Metadata (PES)";
case GF_M2TS_METADATA_ID3_HLS:
return "ID3/HLS Metadata (PES)";
default:
return "Unknown";
}
}
static void gf_m2ts_estimate_duration(GF_M2TS_Demuxer *ts, u64 PCR, u16 pcr_pid)
{
u64 file_size = 0;
if (ts->file || ts->file_size) {
file_size = ts->file_size;
} else if (ts->dnload) {
u32 size;
gf_dm_sess_get_stats(ts->dnload, NULL, NULL, &size, NULL, NULL, NULL);
file_size = size;
} else {
return;
}
if (!ts->first_pcr_found) {
ts->first_pcr_found = PCR;
ts->pcr_pid = pcr_pid;
ts->nb_pck_at_pcr = ts->nb_pck;
} else if (ts->pcr_pid == pcr_pid) {
if (PCR < ts->first_pcr_found) {
ts->first_pcr_found = PCR;
ts->pcr_pid = pcr_pid;
ts->nb_pck_at_pcr = ts->nb_pck;
} else if (PCR - ts->first_pcr_found > 2*27000000) {
Bool changed = GF_FALSE;
Double pck_dur = (Double) (PCR-ts->first_pcr_found);
pck_dur /= (ts->nb_pck - ts->nb_pck_at_pcr);
pck_dur /= 27000000;
pck_dur *= file_size;
pck_dur /= 188.0;
if ((u32) ts->duration != (u32) pck_dur) {
ts->duration = pck_dur;
changed = GF_TRUE;
}
ts->first_pcr_found = PCR;
ts->pcr_pid = pcr_pid;
ts->nb_pck_at_pcr = ts->nb_pck;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Estimated duration based on instant bitrate: %g sec\n", ts->duration));
if (ts->on_event && changed) {
GF_M2TS_PES_PCK pck;
memset(&pck, 0, sizeof(GF_M2TS_PES_PCK));
pck.PTS = (u64) (ts->duration*1000);
ts->on_event(ts, GF_M2TS_EVT_DURATION_ESTIMATED, &pck);
}
}
}
}
static u32 gf_m2ts_reframe_default(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
GF_M2TS_PES_PCK pck;
pck.flags = 0;
if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP;
if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
pck.data = (char *)data;
pck.data_len = data_len;
pck.stream = pes;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
return 0;
}
static u32 gf_m2ts_reframe_reset(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
if (pes->pck_data) {
gf_free(pes->pck_data);
pes->pck_data = NULL;
}
pes->pck_data_len = pes->pck_alloc_len = 0;
if (pes->prev_data) {
gf_free(pes->prev_data);
pes->prev_data = NULL;
}
pes->prev_data_len = 0;
pes->pes_len = 0;
pes->prev_PTS = 0;
pes->reframe = NULL;
pes->cc = -1;
pes->temi_tc_desc_len = 0;
return 0;
}
static u32 gf_m2ts_reframe_nalu_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr, Bool is_hevc)
{
Bool au_start_in_pes=0;
Bool prev_is_au_delim=0;
Bool force_new_au=0;
u32 start_code_found = 0;
Bool short_start_code = 0;
Bool esc_code_found = 0;
u32 nal_type, sc_pos = 0;
u32 first_nal_offset_in_pck = 0;
Bool full_au_pes_mode = 0;
u8 *au_start = NULL;
GF_M2TS_PES_PCK pck;
if (!same_pts)
force_new_au = 1;
pck.stream = pes;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
pck.flags = 0;
while (sc_pos<data_len) {
unsigned char *start = (unsigned char *)memchr(data+sc_pos, 0, data_len-sc_pos);
if (!start) break;
sc_pos = (u32) (start - data);
if (data_len - sc_pos < 5)
break;
if (!start[1] && !start[2] && (start[3]==1)) {
short_start_code = 0;
}
else if (!start[1] && (start[2]==1) && sc_pos && (data[sc_pos-1]!=0) ) {
short_start_code = 1;
}
else if (!start[1] && !start[2]) {
esc_code_found=1;
if (!start_code_found) {
sc_pos ++;
continue;
}
} else {
esc_code_found=0;
sc_pos ++;
continue;
}
if (!start_code_found) {
if (sc_pos) {
if (!esc_code_found) {
pck.data = (char *)data;
pck.data_len = sc_pos;
pck.flags = 0;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
data += sc_pos;
first_nal_offset_in_pck += sc_pos;
data_len -= sc_pos;
}
start_code_found = short_start_code ? 2 : 1;
sc_pos=1;
} else {
Bool is_short_start_code = (start_code_found==2) ? GF_TRUE : GF_FALSE;
if (!full_au_pes_mode && (start_code_found==2)) {
pck.data = (char *)data-1;
pck.data[0]=0;
pck.data_len = sc_pos+1;
} else {
pck.data = (char *)data;
pck.data_len = sc_pos;
}
start_code_found = short_start_code ? 2 : 1;
if (is_hevc) {
#ifndef GPAC_DISABLE_HEVC
nal_type = (pck.data[ is_short_start_code ? 3 : 4 ] & 0x7E) >> 1;
#ifndef GPAC_DISABLE_AV_PARSERS
if (!pes->vid_w && (nal_type==GF_HEVC_NALU_SEQ_PARAM)) {
HEVCState hevc;
s32 idx;
memset(&hevc, 0, sizeof(HEVCState));
hevc.sps_active_idx = -1;
idx = gf_media_hevc_read_sps((char *)data+4, sc_pos-4, &hevc);
if (idx>=0) {
pes->vid_w = hevc.sps[idx].width;
pes->vid_h = hevc.sps[idx].height;
}
}
#endif
if ((nal_type==GF_HEVC_NALU_ACCESS_UNIT) || (pes->depends_on_pid && !first_nal_offset_in_pck)) {
if (!prev_is_au_delim) {
if (au_start) {
pck.data = (char *)au_start;
pck.data_len = (u32) (data - au_start);
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
au_start = NULL;
full_au_pes_mode = 0;
if (is_short_start_code) {
pck.data = (char *)data-1;
pck.data[0]=0;
pck.data_len = sc_pos+1;
} else {
pck.data = (char *)data;
pck.data_len = sc_pos;
}
}
if (au_start_in_pes) {
pck.DTS += 3000;
pck.PTS += 3000;
}
pck.flags = GF_M2TS_PES_PCK_AU_START;
force_new_au = 0;
au_start_in_pes = 1;
if (pes_hdr->data_alignment && !first_nal_offset_in_pck && !pes->single_nal_mode) {
full_au_pes_mode = GF_TRUE;
au_start = (u8 *) pck.data;
} else {
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
prev_is_au_delim=1;
}
} else if ((nal_type>=GF_HEVC_NALU_SLICE_BLA_W_LP) && (nal_type<=GF_HEVC_NALU_SLICE_CRA)) {
if (!full_au_pes_mode) {
pck.flags = GF_M2TS_PES_PCK_RAP;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
} else {
pck.flags |= GF_M2TS_PES_PCK_RAP;
}
prev_is_au_delim=0;
}
else
#endif
{
if (!full_au_pes_mode) {
pck.flags = 0;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
prev_is_au_delim=0;
}
} else {
nal_type = pck.data[is_short_start_code ? 3 : 4] & 0x1F;
#ifndef GPAC_DISABLE_AV_PARSERS
if ((nal_type==GF_AVC_NALU_SEQ_PARAM) || (nal_type==GF_AVC_NALU_SVC_SUBSEQ_PARAM)) {
AVCState avc;
s32 idx;
memset(&avc, 0, sizeof(AVCState));
avc.sps_active_idx = -1;
idx = gf_media_avc_read_sps((char *)data+4, sc_pos-4, &avc, 0, NULL);
if ((idx>=0) && (pes->vid_w < avc.sps[idx].width) && (pes->vid_h < avc.sps[idx].height)) {
pes->vid_w = avc.sps[idx].width;
pes->vid_h = avc.sps[idx].height;
}
}
#endif
if ((nal_type==GF_AVC_NALU_ACCESS_UNIT) || (nal_type==GF_AVC_NALU_VDRD) ) {
if (!prev_is_au_delim) {
if (au_start) {
pck.data = (char *)au_start;
pck.data_len = (u32) (data - au_start);
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
au_start = NULL;
full_au_pes_mode = 0;
if (is_short_start_code) {
pck.data = (char *)data-1;
pck.data[0]=0;
pck.data_len = sc_pos+1;
} else {
pck.data = (char *)data;
pck.data_len = sc_pos;
}
}
if (au_start_in_pes) {
pck.DTS += 3000;
pck.PTS += 3000;
}
pck.flags = GF_M2TS_PES_PCK_AU_START;
force_new_au = 0;
au_start_in_pes = 1;
if (pes_hdr->data_alignment && !first_nal_offset_in_pck && !pes->single_nal_mode) {
full_au_pes_mode = GF_TRUE;
au_start = (u8 *) pck.data;
} else {
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
prev_is_au_delim=1;
}
} else {
if (!full_au_pes_mode) {
pck.flags = (nal_type==GF_AVC_NALU_IDR_SLICE) ? GF_M2TS_PES_PCK_RAP : 0;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
} else {
if (nal_type==GF_AVC_NALU_IDR_SLICE) pck.flags |= GF_M2TS_PES_PCK_RAP;
}
prev_is_au_delim=0;
}
}
data += sc_pos;
data_len -= sc_pos;
first_nal_offset_in_pck += sc_pos;
sc_pos = 0;
if (esc_code_found) {
esc_code_found=0;
start_code_found=0;
} else {
sc_pos = 1;
}
}
}
if (!start_code_found) {
u32 min_size = is_hevc ? 6 : 5;
if (au_start) {
pck.data = (char *)au_start;
pck.data_len = (u32) (data - au_start);
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
au_start = NULL;
}
if (data_len < min_size )
return data_len;
}
if (au_start) {
u8 sc_end = ((data[0]==0) && (data[1]==0) && (data[2]==1)) ? 3 : 4;
if (is_hevc) {
#ifndef GPAC_DISABLE_HEVC
nal_type = (data[sc_end] & 0x7E) >> 1;
if ((nal_type>=GF_HEVC_NALU_SLICE_BLA_W_LP) && (nal_type<=GF_HEVC_NALU_SLICE_CRA)) {
pck.flags |= GF_M2TS_PES_PCK_RAP;
}
#endif
} else {
nal_type = data[sc_end] & 0x1F;
if (nal_type==GF_AVC_NALU_IDR_SLICE) pck.flags |= GF_M2TS_PES_PCK_RAP;
}
pck.data = (char *)au_start;
pck.data_len = (u32) (data - au_start) + data_len;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
return 0;
}
if (data_len) {
pck.flags = 0;
pck.data = (char *)data;
pck.data_len = data_len;
if (start_code_found) {
if (start_code_found==2) {
pck.data = (char *)data-1;
pck.data[0]=0;
pck.data_len = data_len+1;
}
if (is_hevc) {
#ifndef GPAC_DISABLE_HEVC
nal_type = (pck.data[4] & 0x7E) >> 1;
if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) {
pck.flags = GF_M2TS_PES_PCK_AU_START;
} else if ((nal_type==GF_HEVC_NALU_SLICE_IDR_W_DLP) || (nal_type==GF_HEVC_NALU_SLICE_IDR_N_LP)) {
pck.flags = GF_M2TS_PES_PCK_RAP;
} else if (nal_type==GF_HEVC_NALU_FILLER_DATA) {
return 0;
}
#endif
} else {
nal_type = pck.data[4] & 0x1F;
if (nal_type==GF_AVC_NALU_ACCESS_UNIT) {
pck.flags = GF_M2TS_PES_PCK_AU_START;
} else if (nal_type==GF_AVC_NALU_IDR_SLICE) {
pck.flags = GF_M2TS_PES_PCK_RAP;
}
}
}
if (force_new_au) {
pck.flags |= GF_M2TS_PES_PCK_AU_START;
}
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
return 0;
}
static u32 gf_m2ts_reframe_avc_h264(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
return gf_m2ts_reframe_nalu_video(ts, pes, same_pts, data, data_len, pes_hdr, 0);
}
static u32 gf_m2ts_reframe_hevc(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
return gf_m2ts_reframe_nalu_video(ts, pes, same_pts, data, data_len, pes_hdr, 1);
}
static u32 gf_m2ts_reframe_mpeg_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
u32 sc_pos = 0;
u32 to_send = data_len;
GF_M2TS_PES_PCK pck;
pck.stream = pes;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
pck.flags = 0;
while (sc_pos+4<data_len) {
unsigned char *start = (unsigned char*)memchr(data+sc_pos, 0, data_len-sc_pos);
if (!start) break;
sc_pos = (u32) (start - (unsigned char*)data);
if (!start[1] && (start[2]==0x01)) {
if (!start[3] || (start[3]==0xb3) || (start[3]==0xb8)) {
Bool new_au;
if (sc_pos) {
pck.data = (char *)data;
pck.data_len = sc_pos;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
pck.flags = 0;
data += sc_pos;
data_len -= sc_pos;
to_send -= sc_pos;
sc_pos = 0;
}
new_au = 1;
if (pes->frame_state)
new_au = 0;
pes->frame_state = data[3];
if (new_au) {
pck.flags = GF_M2TS_PES_PCK_AU_START;
if (pes->rap)
pck.flags |= GF_M2TS_PES_PCK_RAP;
}
if (!pes->vid_h && (pes->frame_state==0xb3)) {
u32 den, num;
unsigned char *p = data+4;
pes->vid_w = (p[0] << 4) | ((p[1] >> 4) & 0xf);
pes->vid_h = ((p[1] & 0xf) << 8) | p[2];
pes->vid_par = (p[3] >> 4) & 0xf;
switch (pes->vid_par) {
case 2:
num = 4;
den = 3;
break;
case 3:
num = 16;
den = 9;
break;
case 4:
num = 221;
den = 100;
break;
default:
pes->vid_par = 0;
den = num = 0;
break;
}
if (den)
pes->vid_par = ((pes->vid_h/den)<<16) | (pes->vid_w/num);
break;
}
if (pes->frame_state==0x00) {
switch ((data[5] >> 3) & 0x7) {
case 1:
pck.flags |= GF_M2TS_PES_PCK_I_FRAME;
break;
case 2:
pck.flags |= GF_M2TS_PES_PCK_P_FRAME;
break;
case 3:
pck.flags |= GF_M2TS_PES_PCK_B_FRAME;
break;
}
}
}
sc_pos+=3;
}
sc_pos++;
}
pck.data = (char *)data;
pck.data_len = data_len;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
return 0;
}
#ifndef GPAC_DISABLE_AV_PARSERS
typedef struct
{
Bool is_mp2, no_crc;
u32 profile, sr_idx, nb_ch, frame_size;
} ADTSHeader;
static u32 gf_m2ts_reframe_aac_adts(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
ADTSHeader hdr;
u32 sc_pos = 0;
u32 start = 0;
u32 hdr_size = 0;
u64 PTS;
Bool first = 1;
Bool garbage_bytes = 0;
GF_M2TS_PES_PCK pck;
PTS = pes->PTS;
pck.stream = pes;
pck.DTS = pes->DTS;
pck.PTS = PTS;
pck.flags = 0;
if (pes->frame_state && ((pes->frame_state==data_len) || (((pes->frame_state+1<data_len)) && (data[pes->frame_state]==0xFF) && ((data[pes->frame_state+1] & 0xF0) == 0xF0)))) {
assert(pes->frame_state<=data_len);
pck.stream = pes;
pck.DTS = PTS;
pck.PTS = PTS;
pck.flags = 0;
pck.data = (char *)data;
pck.data_len = pes->frame_state;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
first = 0;
start = sc_pos = pes->frame_state;
}
pes->frame_state = 0;
while (sc_pos+2<data_len) {
u32 size;
GF_BitStream *bs;
if ((data[sc_pos]!=0xFF) || ((data[sc_pos+1] & 0xF0) != 0xF0)) {
sc_pos++;
continue;
}
if (garbage_bytes) {
garbage_bytes = 0;
}
else if (start < sc_pos) {
pck.stream = pes;
pck.DTS = PTS;
pck.PTS = PTS;
pck.flags = 0;
pck.data = (char *)data+start;
pck.data_len = sc_pos-start;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
if (pes->frame_state == pck.data_len) {
first = 0;
} else {
first = 1;
}
pes->frame_state = 0;
}
if (sc_pos + 7 >= data_len) {
pes->frame_state = 0;
pes->prev_PTS = PTS;
return data_len-sc_pos;
}
bs = gf_bs_new((char *)data + sc_pos + 1, 9, GF_BITSTREAM_READ);
gf_bs_read_int(bs, 4);
hdr.is_mp2 = gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 2);
hdr.no_crc = gf_bs_read_int(bs, 1);
hdr.profile = 1 + gf_bs_read_int(bs, 2);
hdr.sr_idx = gf_bs_read_int(bs, 4);
gf_bs_read_int(bs, 1);
hdr.nb_ch = gf_bs_read_int(bs, 3);
gf_bs_read_int(bs, 4);
hdr.frame_size = gf_bs_read_int(bs, 13);
gf_bs_read_int(bs, 11);
gf_bs_read_int(bs, 2);
if (!hdr.no_crc) gf_bs_read_int(bs, 16);
hdr_size = hdr.no_crc ? 7 : 9;
gf_bs_del(bs);
if (sc_pos + hdr.frame_size < data_len) {
if ((hdr.frame_size < hdr_size) || (data[sc_pos + hdr.frame_size]!=0xFF) || ((data[sc_pos+hdr.frame_size+1] & 0xF0) != 0xF0)) {
sc_pos++;
continue;
}
} else if (first && (hdr.frame_size + sc_pos > data_len)) {
sc_pos++;
continue;
}
if (pes->aud_sr != GF_M4ASampleRates[hdr.sr_idx]) {
GF_M4ADecSpecInfo cfg;
pck.stream = pes;
memset(&cfg, 0, sizeof(GF_M4ADecSpecInfo));
cfg.base_object_type = hdr.profile;
cfg.base_sr = GF_M4ASampleRates[hdr.sr_idx];
if (!cfg.base_sr) {
sc_pos++;
garbage_bytes = 1;
continue;
}
pes->aud_sr = cfg.base_sr;
pes->aud_nb_ch = cfg.nb_chan = hdr.nb_ch;
cfg.sbr_object_type = 0;
gf_m4a_write_config(&cfg, &pck.data, &pck.data_len);
ts->on_event(ts, GF_M2TS_EVT_AAC_CFG, &pck);
gf_free(pck.data);
pes->aud_aac_sr_idx = cfg.base_sr_index;
pes->aud_sr = cfg.base_sr;
pes->aud_nb_ch = cfg.nb_chan;
pes->aud_aac_obj_type = hdr.profile;
}
pck.stream = pes;
if (first && pes->prev_PTS) {
pck.DTS = pck.PTS = pes->prev_PTS;
} else {
pck.DTS = pck.PTS = PTS;
}
pck.flags = GF_M2TS_PES_PCK_AU_START | GF_M2TS_PES_PCK_RAP;
pck.data = (char *)data + sc_pos + hdr_size;
pck.data_len = hdr.frame_size - hdr_size;
if (pck.data_len > data_len - sc_pos - hdr_size) {
assert(pck.data_len - (data_len - sc_pos - hdr_size) > 0);
pes->frame_state = pck.data_len - (data_len - sc_pos - hdr_size);
assert((s32) pes->frame_state > 0);
pck.data_len = data_len - sc_pos - hdr_size;
}
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
sc_pos += pck.data_len + hdr_size;
start = sc_pos;
if (first && pes->prev_PTS) {
pes->prev_PTS = 0;
}
else if (pes->aud_sr) {
size = 1024*90000/pes->aud_sr;
PTS += size;
}
first = 0;
}
if (data_len==sc_pos) return 0;
pes->prev_PTS = PTS;
return data_len - sc_pos;
}
static u32 gf_m2ts_reframe_aac_latm(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
u32 sc_pos = 0;
u32 start = 0;
GF_M2TS_PES_PCK pck;
pck.stream = pes;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
pck.flags = 0;
if (data_len + pes->reassemble_len > pes->reassemble_alloc) {
pes->reassemble_alloc = data_len + pes->reassemble_len;
pes->reassemble_buf = gf_realloc(pes->reassemble_buf, sizeof(char)*pes->reassemble_alloc);
}
memcpy(pes->reassemble_buf + pes->reassemble_len, data, data_len);
pes->reassemble_len += data_len;
data_len = pes->reassemble_len;
data = pes->reassemble_buf;
while (sc_pos+2<data_len) {
u32 size;
u32 amux_len;
GF_BitStream *bs;
if ((data[sc_pos]!=0x56) || ((data[sc_pos+1] & 0xE0) != 0xE0)) {
sc_pos++;
continue;
}
if (start < sc_pos) {
assert(data_len >= sc_pos);
memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos);
pes->reassemble_len -= sc_pos;
sc_pos = 0;
data_len = pes->reassemble_len;
data = pes->reassemble_buf;
}
amux_len = data[sc_pos+1] & 0x1F;
amux_len <<= 8;
amux_len |= data[sc_pos+2];
if (!amux_len) {
sc_pos+=3;
assert(data_len >= sc_pos);
memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos);
pes->reassemble_len -= sc_pos;
sc_pos = 0;
data_len = pes->reassemble_len;
data = pes->reassemble_buf;
continue;
}
if (data_len < sc_pos+4+amux_len) {
if (pes->aud_sr) {
u32 tsinc = 1024*90000/pes->aud_sr;
pes->PTS += tsinc;
}
return 0;
}
if ((data[sc_pos+3+amux_len] != 0x56) || ((data[sc_pos+3+amux_len + 1] & 0xE0) != 0xE0)) {
sc_pos+=2;
assert(data_len >= sc_pos);
memmove(pes->reassemble_buf , pes->reassemble_buf+ sc_pos, data_len - sc_pos);
pes->reassemble_len -= sc_pos;
sc_pos = 0;
data_len = pes->reassemble_len;
data = pes->reassemble_buf;
continue;
}
bs = gf_bs_new((char *)data+sc_pos+3, amux_len, GF_BITSTREAM_READ);
if (!gf_bs_read_int(bs, 1)) {
Bool amux_version, amux_versionA;
amux_version = gf_bs_read_int(bs, 1);
amux_versionA = 0;
if (amux_version) amux_versionA = gf_bs_read_int(bs, 1);
if (!amux_versionA) {
u32 i, allStreamsSameTimeFraming, numProgram;
if (amux_version) gf_latm_get_value(bs);
allStreamsSameTimeFraming = gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 6);
numProgram = gf_bs_read_int(bs, 4);
for (i=0; i<=numProgram; i++) {
u32 j, num_lay;
num_lay = gf_bs_read_int(bs, 3);
for (j=0; j<=num_lay; j++) {
GF_M4ADecSpecInfo cfg;
u32 frameLengthType;
Bool same_cfg = 0;
if (i || j) same_cfg = gf_bs_read_int(bs, 1);
if (!same_cfg) {
if (amux_version==1) gf_latm_get_value(bs);
gf_m4a_parse_config(bs, &cfg, 0);
if (!pes->aud_sr) {
pck.stream = pes;
pes->aud_aac_sr_idx = cfg.base_sr_index;
pes->aud_sr = cfg.base_sr;
pes->aud_nb_ch = cfg.nb_chan;
pes->aud_aac_obj_type = cfg.base_object_type;
gf_m4a_write_config(&cfg, &pck.data, &pck.data_len);
ts->on_event(ts, GF_M2TS_EVT_AAC_CFG, &pck);
gf_free(pck.data);
}
}
frameLengthType = gf_bs_read_int(bs, 3);
if (!frameLengthType) {
gf_bs_read_int(bs, 8);
if (!allStreamsSameTimeFraming) {
}
} else {
}
}
}
if (gf_bs_read_int(bs, 1)) {
}
if (gf_bs_read_int(bs, 1)) {
}
}
}
if (pes->aud_sr) {
size = 0;
while (1) {
u32 tmp = gf_bs_read_int(bs, 8);
size += tmp;
if (tmp!=255) break;
}
if (size>pes->buf_len) {
pes->buf_len = size;
pes->buf = gf_realloc(pes->buf, sizeof(char)*pes->buf_len);
}
gf_bs_read_data(bs, (char *)pes->buf, size);
pck.stream = pes;
pck.DTS = pes->PTS;
pck.PTS = pes->PTS;
pck.flags = GF_M2TS_PES_PCK_AU_START | GF_M2TS_PES_PCK_RAP;
pck.data = (char *)pes->buf;
pck.data_len = size;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
}
gf_bs_del(bs);
sc_pos += amux_len+3;
assert(data_len >= sc_pos);
memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos);
pes->reassemble_len -= sc_pos;
sc_pos = 0;
data_len = pes->reassemble_len;
data = pes->reassemble_buf;
if ((data_len>3) && pes->aud_sr) {
size = 1024*90000/pes->aud_sr;
pes->PTS += size;
}
}
return 0;
}
#endif
#ifndef GPAC_DISABLE_AV_PARSERS
static u32 gf_m2ts_reframe_mpeg_audio(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
GF_M2TS_PES_PCK pck;
u32 pos, frame_size, remain;
u64 PTS;
u32 next_hdr = 0;
pck.flags = GF_M2TS_PES_PCK_RAP;
pck.stream = pes;
remain = pes->frame_state;
PTS = pes->PTS;
next_hdr = gf_mp3_get_next_header_mem((char *)data, data_len, &pos);
if (next_hdr && remain && (pos<remain) ) {
if ((pes->aud_sr == gf_mp3_sampling_rate(pes->frame_state) )
&& (pes->aud_nb_ch == gf_mp3_num_channels(pes->frame_state))
) {
remain = pos;
}
}
if (remain) {
pck.DTS = pck.PTS = PTS;
pck.data = (char *)data;
pck.data_len = (remain>data_len) ? data_len : remain;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
if (remain>data_len) {
pes->frame_state = remain - data_len;
return 0;
}
data += remain;
data_len -= remain;
}
pes->frame_state = gf_mp3_get_next_header_mem((char *)data, data_len, &pos);
if (!pes->frame_state) {
return data_len;
}
assert((pes->frame_state & 0xffe00000) == 0xffe00000);
if (!pes->aud_sr || !pes->aud_nb_ch) {
pes->aud_sr = gf_mp3_sampling_rate(pes->frame_state);
pes->aud_nb_ch = gf_mp3_num_channels(pes->frame_state);
}
pck.flags = GF_M2TS_PES_PCK_RAP | GF_M2TS_PES_PCK_AU_START;
frame_size = gf_mp3_frame_size(pes->frame_state);
while (frame_size <= data_len) {
pck.DTS = pck.PTS = PTS;
pck.data = (char *)data;
pck.data_len = frame_size;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
PTS += gf_mp3_window_size(pes->frame_state)*90000/gf_mp3_sampling_rate(pes->frame_state);
data += frame_size;
data_len -= frame_size;
if (!data_len) break;
pes->frame_state = gf_mp3_get_next_header_mem((char *)data, data_len, &pos);
if (!pes->frame_state) {
return data_len;
}
if (pos) {
data_len -= pos;
data += pos;
}
frame_size = gf_mp3_frame_size(pes->frame_state);
}
if (data_len) {
pck.DTS = pck.PTS = PTS;
pck.data = (char *)data;
pck.data_len = data_len;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
pes->PTS += gf_mp3_window_size(pes->frame_state)*90000/gf_mp3_sampling_rate(pes->frame_state);
pes->frame_state = frame_size - data_len;
} else {
pes->frame_state = 0;
}
return 0;
}
#endif
#ifndef GPAC_DISABLE_AV_PARSERS
static u32 gf_m2ts_reframe_ac3(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
GF_M2TS_PES_PCK pck;
pck.flags = 0;
if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP;
if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
if (!pes->aud_sr) {
GF_AC3Header hdr;
u32 pos;
if (gf_ac3_parser(data, data_len, &pos, &hdr, GF_TRUE)) {
pes->aud_sr = hdr.sample_rate;
pes->aud_nb_ch = hdr.channels;
}
}
pck.data = (char *)data;
pck.data_len = data_len;
pck.stream = pes;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
return 0;
}
static u32 gf_m2ts_reframe_ec3(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
GF_M2TS_PES_PCK pck;
pck.flags = 0;
if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP;
if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
if (!pes->aud_sr) {
GF_AC3Header hdr;
GF_BitStream *bs = gf_bs_new((const char *) data, data_len, GF_BITSTREAM_READ);
if (gf_eac3_parser_bs(bs, &hdr, GF_TRUE)) {
pes->aud_sr = hdr.sample_rate;
pes->aud_nb_ch = hdr.channels;
}
gf_bs_del(bs);
}
pck.data = (char *)data;
pck.data_len = data_len;
pck.stream = pes;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
return 0;
}
#endif
typedef enum {
ID3V2_FRAME_AENC = GF_4CC('A','E','N','C'),
ID3V2_FRAME_APIC = GF_4CC('A','P','I','C'),
ID3V2_FRAME_COMM = GF_4CC('C','O','M','M'),
ID3V2_FRAME_COMR = GF_4CC('C','O','M','R'),
ID3V2_FRAME_ENCR = GF_4CC('E','N','C','R'),
ID3V2_FRAME_EQUA = GF_4CC('E','Q','U','A'),
ID3V2_FRAME_ETCO = GF_4CC('E','T','C','O'),
ID3V2_FRAME_GEOB = GF_4CC('G','E','O','B'),
ID3V2_FRAME_GRID = GF_4CC('G','R','I','D'),
ID3V2_FRAME_IPLS = GF_4CC('I','P','L','S'),
ID3V2_FRAME_LINK = GF_4CC('L','I','N','K'),
ID3V2_FRAME_MCDI = GF_4CC('M','C','D','I'),
ID3V2_FRAME_MLLT = GF_4CC('M','L','L','T'),
ID3V2_FRAME_OWNE = GF_4CC('O','W','N','E'),
ID3V2_FRAME_PRIV = GF_4CC('P','R','I','V'),
ID3V2_FRAME_PCNT = GF_4CC('P','C','N','T'),
ID3V2_FRAME_POPM = GF_4CC('P','O','P','M'),
ID3V2_FRAME_POSS = GF_4CC('P','O','S','S'),
ID3V2_FRAME_RBUF = GF_4CC('R','B','U','F'),
ID3V2_FRAME_RVAD = GF_4CC('R','V','A','D'),
ID3V2_FRAME_RVRB = GF_4CC('R','V','R','B'),
ID3V2_FRAME_SYLT = GF_4CC('S','Y','L','T'),
ID3V2_FRAME_SYTC = GF_4CC('S','Y','T','C'),
ID3V2_FRAME_TALB = GF_4CC('T','E','N','C'),
ID3V2_FRAME_TBPM = GF_4CC('T','B','P','M'),
ID3V2_FRAME_TCOM = GF_4CC('T','C','O','M'),
ID3V2_FRAME_TCON = GF_4CC('T','C','O','N'),
ID3V2_FRAME_TCOP = GF_4CC('T','C','O','P'),
ID3V2_FRAME_TDAT = GF_4CC('T','D','A','T'),
ID3V2_FRAME_TDLY = GF_4CC('T','D','L','Y'),
ID3V2_FRAME_TENC = GF_4CC('T','E','N','C'),
ID3V2_FRAME_TEXT = GF_4CC('T','E','X','T'),
ID3V2_FRAME_TFLT = GF_4CC('T','F','L','T'),
ID3V2_FRAME_TIME = GF_4CC('T','I','M','E'),
ID3V2_FRAME_TIT1 = GF_4CC('T','I','T','1'),
ID3V2_FRAME_TIT2 = GF_4CC('T','I','T','2'),
ID3V2_FRAME_TIT3 = GF_4CC('T','I','T','3'),
ID3V2_FRAME_TKEY = GF_4CC('T','K','E','Y'),
ID3V2_FRAME_TLAN = GF_4CC('T','L','A','N'),
ID3V2_FRAME_TLEN = GF_4CC('T','L','E','N'),
ID3V2_FRAME_TMED = GF_4CC('T','M','E','D'),
ID3V2_FRAME_TOAL = GF_4CC('T','O','A','L'),
ID3V2_FRAME_TOFN = GF_4CC('T','O','F','N'),
ID3V2_FRAME_TOLY = GF_4CC('T','O','L','Y'),
ID3V2_FRAME_TOPE = GF_4CC('T','O','P','E'),
ID3V2_FRAME_TORY = GF_4CC('T','O','R','Y'),
ID3V2_FRAME_TOWN = GF_4CC('T','O','W','N'),
ID3V2_FRAME_TPE1 = GF_4CC('T','P','E','1'),
ID3V2_FRAME_TPE2 = GF_4CC('T','P','E','2'),
ID3V2_FRAME_TPE3 = GF_4CC('T','P','E','3'),
ID3V2_FRAME_TPE4 = GF_4CC('T','P','E','4'),
ID3V2_FRAME_TPOS = GF_4CC('T','P','E','5'),
ID3V2_FRAME_TPUB = GF_4CC('T','P','U','B'),
ID3V2_FRAME_TRCK = GF_4CC('T','R','C','K'),
ID3V2_FRAME_TRDA = GF_4CC('T','R','D','A'),
ID3V2_FRAME_TRSN = GF_4CC('T','R','S','N'),
ID3V2_FRAME_TRSO = GF_4CC('T','R','S','O'),
ID3V2_FRAME_TSIZ = GF_4CC('T','S','I','Z'),
ID3V2_FRAME_TSRC = GF_4CC('T','S','R','C'),
ID3V2_FRAME_TSSE = GF_4CC('T','S','S','E'),
ID3V2_FRAME_TYER = GF_4CC('T','Y','E','R'),
ID3V2_FRAME_TXXX = GF_4CC('T','X','X','X'),
ID3V2_FRAME_UFID = GF_4CC('U','F','I','D'),
ID3V2_FRAME_USER = GF_4CC('U','S','E','R'),
ID3V2_FRAME_USLT = GF_4CC('U','S','L','T'),
ID3V2_FRAME_WCOM = GF_4CC('W','C','O','M'),
ID3V2_FRAME_WCOP = GF_4CC('W','C','O','P'),
ID3V2_FRAME_WOAF = GF_4CC('W','O','A','F'),
ID3V2_FRAME_WOAR = GF_4CC('W','O','A','R'),
ID3V2_FRAME_WOAS = GF_4CC('W','O','A','S'),
ID3V2_FRAME_WORS = GF_4CC('W','O','R','S'),
ID3V2_FRAME_WPAY = GF_4CC('W','P','A','Y'),
ID3V2_FRAME_WPUB = GF_4CC('W','P','U','B'),
ID3V2_FRAME_WXXX = GF_4CC('W','X','X','X')
} GF_ID3v2FrameType;
static void add_text(char **buffer, u32 *size, u32 *pos, char *msg, u32 msg_len)
{
if (!msg || !buffer || ! *buffer) return;
if (*pos+msg_len>*size) {
*size = *pos+msg_len-*size+256;
*buffer = (char *)gf_realloc(*buffer, *size);
}
strncpy((*buffer)+(*pos), msg, msg_len);
*pos += msg_len;
}
static GF_Err id3_parse_tag(char *data, u32 length, char **output, u32 *output_size, u32 *output_pos)
{
u32 size;
u32 pos = 0;
if (data[pos] == 'I' && data[pos+1] == 'D' && data[pos+2] == '3') {
Bool extended_header_flag = ((data[pos+5]>>6 & 0x1) ? GF_TRUE: GF_FALSE);
if (data[pos+5] & 0x1F) {
return GF_NOT_SUPPORTED;
} else {
size = 10 + ((data[pos+9] & 0x7f) + ((data[pos+8] & 0x7f) << 7) + ((data[pos+7] & 0x7f) << 14) + ((data[pos+6] & 0x7f) << 21));
}
pos += 10;
if (extended_header_flag) {
u32 extended_size = 4 + ((data[pos]) + ((data[pos+1]) << 8) + ((data[pos+2]) << 16) + ((data[pos+3]) << 24));
pos += extended_size;
}
while (pos < size) {
GF_ID3v2FrameType type;
u32 frame_size, frame_pos;
Bool compression_flag, encryption_flag;
frame_pos = pos;
type = (GF_ID3v2FrameType)(((data[pos+3]) + ((data[pos+2]) << 8) + ((data[pos+1]) << 16) + ((data[pos]) << 24)));
pos+=4;
frame_size = 10 + ((data[pos+3] & 0x7f) + ((data[pos+2] & 0x7f) << 7) + ((data[pos+1] & 0x7f) << 14) + ((data[pos] & 0x7f) << 21));
pos+=4;
pos++;
compression_flag = ((data[pos]>>7 & 0x1) ? GF_TRUE: GF_FALSE);
encryption_flag = ((data[pos]>>6 & 0x1) ? GF_TRUE: GF_FALSE);
if (compression_flag || encryption_flag) {
pos = frame_pos + frame_size;
} else {
switch (type) {
case ID3V2_FRAME_TXXX:
add_text(output, output_size, output_pos, data+pos+3, frame_size-10-3);
pos = frame_pos + frame_size;
break;
default:
pos = frame_pos + frame_size;
}
}
}
return GF_OK;
} else {
return GF_NOT_SUPPORTED;
}
}
static u32 gf_m2ts_reframe_id3_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr)
{
char frame_header[256];
char *output_text = NULL;
u32 output_len = 0;
u32 pos = 0;
GF_M2TS_PES_PCK pck;
pck.flags = 0;
if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP;
if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START;
pck.DTS = pes->DTS;
pck.PTS = pes->PTS;
sprintf(frame_header, LLU" --> NEXT\n", pes->PTS);
add_text(&output_text, &output_len, &pos, frame_header, (u32)strlen(frame_header));
id3_parse_tag((char *)data, data_len, &output_text, &output_len, &pos);
add_text(&output_text, &output_len, &pos, "\n\n", 2);
pck.data = (char *)output_text;
pck.data_len = pos;
pck.stream = pes;
ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck);
gf_free(output_text);
return 0;
}
static u32 gf_m2ts_sync(GF_M2TS_Demuxer *ts, Bool simple_check)
{
u32 i=0;
if (simple_check && (ts->buffer[i]==0x47)) return 0;
while (i<ts->buffer_size) {
if (i+188>ts->buffer_size) return ts->buffer_size;
if ((ts->buffer[i]==0x47) && (ts->buffer[i+188]==0x47))
break;
if ((ts->buffer[i]==0x47) && (ts->buffer[i+192]==0x47)) {
ts->prefix_present = 1;
break;
}
i++;
}
if (i) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] re-sync skipped %d bytes\n", i) );
}
return i;
}
Bool gf_m2ts_crc32_check(char *data, u32 len)
{
u32 crc = gf_crc_32(data, len);
u32 crc_val = GF_4CC((u8) data[len], (u8) data[len+1], (u8) data[len+2], (u8) data[len+3]);
return (crc==crc_val) ? GF_TRUE : GF_FALSE;
}
static GF_M2TS_SectionFilter *gf_m2ts_section_filter_new(gf_m2ts_section_callback process_section_callback, Bool process_individual)
{
GF_M2TS_SectionFilter *sec;
GF_SAFEALLOC(sec, GF_M2TS_SectionFilter);
if (!sec) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] gf_m2ts_section_filter_new : OUT OF MEMORY\n"));
return NULL;
}
sec->cc = -1;
sec->process_section = process_section_callback;
sec->process_individual = process_individual;
return sec;
}
static void gf_m2ts_reset_sections(GF_List *sections)
{
u32 count;
GF_M2TS_Section *section;
count = gf_list_count(sections);
while (count) {
section = gf_list_get(sections, 0);
gf_list_rem(sections, 0);
if (section->data) gf_free(section->data);
gf_free(section);
count--;
}
}
static void gf_m2ts_section_filter_reset(GF_M2TS_SectionFilter *sf)
{
if (sf->section) {
gf_free(sf->section);
sf->section = NULL;
}
while (sf->table) {
GF_M2TS_Table *t = sf->table;
sf->table = t->next;
gf_m2ts_reset_sections(t->sections);
gf_list_del(t->sections);
gf_free(t);
}
sf->cc = -1;
sf->length = sf->received = 0;
sf->demux_restarted = 1;
}
static void gf_m2ts_section_filter_del(GF_M2TS_SectionFilter *sf)
{
gf_m2ts_section_filter_reset(sf);
gf_free(sf);
}
GF_EXPORT
void gf_m2ts_es_del(GF_M2TS_ES *es, GF_M2TS_Demuxer *ts)
{
gf_list_del_item(es->program->streams, es);
if (es->flags & GF_M2TS_ES_IS_SECTION) {
GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es;
if (ses->sec) gf_m2ts_section_filter_del(ses->sec);
#ifdef GPAC_ENABLE_MPE
if (es->flags & GF_M2TS_ES_IS_MPE)
gf_dvb_mpe_section_del(es);
#endif
} else if (es->pid!=es->program->pmt_pid) {
GF_M2TS_PES *pes = (GF_M2TS_PES *)es;
if ((pes->flags & GF_M2TS_INHERIT_PCR) && ts->ess[es->program->pcr_pid]==es)
ts->ess[es->program->pcr_pid] = NULL;
if (pes->pck_data) gf_free(pes->pck_data);
if (pes->prev_data) gf_free(pes->prev_data);
if (pes->buf) gf_free(pes->buf);
if (pes->reassemble_buf) gf_free(pes->reassemble_buf);
if (pes->temi_tc_desc) gf_free(pes->temi_tc_desc);
}
if (es->slcfg) gf_free(es->slcfg);
gf_free(es);
}
static void gf_m2ts_reset_sdt(GF_M2TS_Demuxer *ts)
{
while (gf_list_count(ts->SDTs)) {
GF_M2TS_SDT *sdt = (GF_M2TS_SDT *)gf_list_last(ts->SDTs);
gf_list_rem_last(ts->SDTs);
if (sdt->provider) gf_free(sdt->provider);
if (sdt->service) gf_free(sdt->service);
gf_free(sdt);
}
}
GF_EXPORT
GF_M2TS_SDT *gf_m2ts_get_sdt_info(GF_M2TS_Demuxer *ts, u32 program_id)
{
u32 i;
for (i=0; i<gf_list_count(ts->SDTs); i++) {
GF_M2TS_SDT *sdt = (GF_M2TS_SDT *)gf_list_get(ts->SDTs, i);
if (sdt->service_id==program_id) return sdt;
}
return NULL;
}
static void gf_m2ts_section_complete(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter *sec, GF_M2TS_SECTION_ES *ses)
{
if (ts->start_range && (sec->section[0] != GF_M2TS_TABLE_ID_PAT) && (sec->section[0] != GF_M2TS_TABLE_ID_PMT)) {
if (sec->section) gf_free(sec->section);
sec->section = NULL;
sec->length = sec->received = 0;
return;
}
if (!sec->process_section) {
if ((ts->on_event && (sec->section[0]==GF_M2TS_TABLE_ID_AIT)) ) {
#ifdef GPAC_ENABLE_DSMCC
GF_M2TS_SL_PCK pck;
pck.data_len = sec->length;
pck.data = sec->section;
pck.stream = (GF_M2TS_ES *)ses;
on_ait_section(ts, GF_M2TS_EVT_AIT_FOUND, &pck);
#endif
} else if ((ts->on_event && (sec->section[0]==GF_M2TS_TABLE_ID_DSM_CC_ENCAPSULATED_DATA || sec->section[0]==GF_M2TS_TABLE_ID_DSM_CC_UN_MESSAGE ||
sec->section[0]==GF_M2TS_TABLE_ID_DSM_CC_DOWNLOAD_DATA_MESSAGE || sec->section[0]==GF_M2TS_TABLE_ID_DSM_CC_STREAM_DESCRIPTION || sec->section[0]==GF_M2TS_TABLE_ID_DSM_CC_PRIVATE)) ) {
#ifdef GPAC_ENABLE_DSMCC
GF_M2TS_SL_PCK pck;
pck.data_len = sec->length;
pck.data = sec->section;
pck.stream = (GF_M2TS_ES *)ses;
on_dsmcc_section(ts,GF_M2TS_EVT_DSMCC_FOUND,&pck);
#endif
}
#ifdef GPAC_ENABLE_MPE
else if (ts->on_mpe_event && ((ses && (ses->flags & GF_M2TS_EVT_DVB_MPE)) || (sec->section[0]==GF_M2TS_TABLE_ID_INT)) ) {
GF_M2TS_SL_PCK pck;
pck.data_len = sec->length;
pck.data = sec->section;
pck.stream = (GF_M2TS_ES *)ses;
ts->on_mpe_event(ts, GF_M2TS_EVT_DVB_MPE, &pck);
}
#endif
else if (ts->on_event) {
GF_M2TS_SL_PCK pck;
pck.data_len = sec->length;
pck.data = sec->section;
pck.stream = (GF_M2TS_ES *)ses;
ts->on_event(ts, GF_M2TS_EVT_DVB_GENERAL, &pck);
}
} else {
Bool has_syntax_indicator;
u8 table_id;
u16 extended_table_id;
u32 status, section_start, i;
GF_M2TS_Table *t, *prev_t;
unsigned char *data;
Bool section_valid = 0;
status = 0;
data = (u8 *)sec->section;
table_id = data[0];
if (ts->on_event) {
switch (table_id) {
case GF_M2TS_TABLE_ID_PAT:
case GF_M2TS_TABLE_ID_SDT_ACTUAL:
case GF_M2TS_TABLE_ID_PMT:
case GF_M2TS_TABLE_ID_NIT_ACTUAL:
case GF_M2TS_TABLE_ID_TDT:
case GF_M2TS_TABLE_ID_TOT:
{
GF_M2TS_SL_PCK pck;
pck.data_len = sec->length;
pck.data = sec->section;
pck.stream = (GF_M2TS_ES *)ses;
ts->on_event(ts, GF_M2TS_EVT_DVB_GENERAL, &pck);
}
}
}
has_syntax_indicator = (data[1] & 0x80) ? 1 : 0;
if (has_syntax_indicator) {
extended_table_id = (data[3]<<8) | data[4];
} else {
extended_table_id = 0;
}
prev_t = NULL;
t = sec->table;
while (t) {
if ((t->table_id==table_id) && (t->ex_table_id == extended_table_id)) break;
prev_t = t;
t = t->next;
}
if (!t) {
GF_SAFEALLOC(t, GF_M2TS_Table);
if (!t) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Fail to alloc table %d %d\n", table_id, extended_table_id));
return;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Creating table %d %d\n", table_id, extended_table_id));
t->table_id = table_id;
t->ex_table_id = extended_table_id;
t->last_version_number = 0xFF;
t->sections = gf_list_new();
if (prev_t) prev_t->next = t;
else sec->table = t;
}
if (has_syntax_indicator) {
if (sec->length < 4) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted section length %d less than CRC \n", sec->length));
} else {
sec->length -= 4;
if (gf_m2ts_crc32_check((char *)data, sec->length)) {
s32 cur_sec_num;
t->version_number = (data[5] >> 1) & 0x1f;
if (t->last_section_number && t->section_number && (t->version_number != t->last_version_number)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] table transmission interrupted: previous table (v=%d) %d/%d sections - new table (v=%d) %d/%d sections\n", t->last_version_number, t->section_number, t->last_section_number, t->version_number, data[6] + 1, data[7] + 1) );
gf_m2ts_reset_sections(t->sections);
t->section_number = 0;
}
t->current_next_indicator = (data[5] & 0x1) ? 1 : 0;
cur_sec_num = data[6] + 1;
t->last_section_number = data[7] + 1;
section_start = 8;
if (!sec->process_individual && t->section_number + 1 != cur_sec_num) {
section_valid = 0;
if (t->is_init) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted table (lost section %d)\n", cur_sec_num ? cur_sec_num-1 : 31) );
}
} else {
section_valid = 1;
t->section_number = cur_sec_num;
}
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted section (CRC32 failed)\n"));
}
}
} else {
section_valid = 1;
section_start = 3;
}
if (section_valid) {
GF_M2TS_Section *section;
GF_SAFEALLOC(section, GF_M2TS_Section);
if (!section) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Fail to create section\n"));
return;
}
section->data_size = sec->length - section_start;
section->data = (unsigned char*)gf_malloc(sizeof(unsigned char)*section->data_size);
memcpy(section->data, sec->section + section_start, sizeof(unsigned char)*section->data_size);
gf_list_add(t->sections, section);
if (t->section_number == 1) {
status |= GF_M2TS_TABLE_START;
if (t->last_version_number == t->version_number) {
t->is_repeat = 1;
} else {
t->is_repeat = 0;
}
t->last_version_number = t->version_number;
}
if (t->is_init) {
if (t->is_repeat) {
status |= GF_M2TS_TABLE_REPEAT;
} else {
status |= GF_M2TS_TABLE_UPDATE;
}
} else {
status |= GF_M2TS_TABLE_FOUND;
}
if (t->last_section_number == t->section_number) {
u32 table_size;
status |= GF_M2TS_TABLE_END;
table_size = 0;
for (i=0; i<gf_list_count(t->sections); i++) {
GF_M2TS_Section *section = gf_list_get(t->sections, i);
table_size += section->data_size;
}
if (t->is_repeat) {
if (t->table_size != table_size) {
status |= GF_M2TS_TABLE_UPDATE;
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Repeated section found with different sizes (old table %d bytes, new table %d bytes)\n", t->table_size, table_size) );
t->table_size = table_size;
}
} else {
t->table_size = table_size;
}
t->is_init = 1;
t->section_number = 0;
t->is_repeat = 0;
}
if (sec->process_individual) {
sec->process_section(ts, ses, t->sections, t->table_id, t->ex_table_id, t->version_number, (u8) (t->last_section_number - 1), status);
gf_m2ts_reset_sections(t->sections);
} else {
if (status&GF_M2TS_TABLE_END) {
sec->process_section(ts, ses, t->sections, t->table_id, t->ex_table_id, t->version_number, (u8) (t->last_section_number - 1), status);
gf_m2ts_reset_sections(t->sections);
}
}
} else {
sec->cc = -1;
t->section_number = 0;
}
}
if (sec->section) gf_free(sec->section);
sec->section = NULL;
sec->length = sec->received = 0;
}
static Bool gf_m2ts_is_long_section(u8 table_id)
{
switch (table_id) {
case GF_M2TS_TABLE_ID_MPEG4_BIFS:
case GF_M2TS_TABLE_ID_MPEG4_OD:
case GF_M2TS_TABLE_ID_INT:
case GF_M2TS_TABLE_ID_EIT_ACTUAL_PF:
case GF_M2TS_TABLE_ID_EIT_OTHER_PF:
case GF_M2TS_TABLE_ID_ST:
case GF_M2TS_TABLE_ID_SIT:
case GF_M2TS_TABLE_ID_DSM_CC_PRIVATE:
case GF_M2TS_TABLE_ID_MPE_FEC:
case GF_M2TS_TABLE_ID_DSM_CC_DOWNLOAD_DATA_MESSAGE:
case GF_M2TS_TABLE_ID_DSM_CC_UN_MESSAGE:
return 1;
default:
if (table_id >= GF_M2TS_TABLE_ID_EIT_SCHEDULE_MIN && table_id <= GF_M2TS_TABLE_ID_EIT_SCHEDULE_MAX)
return 1;
else
return 0;
}
}
static u32 gf_m2ts_get_section_length(char byte0, char byte1, char byte2)
{
u32 length;
if (gf_m2ts_is_long_section(byte0)) {
length = 3 + ( ((byte1<<8) | (byte2&0xff)) & 0xfff );
} else {
length = 3 + ( ((byte1<<8) | (byte2&0xff)) & 0x3ff );
}
return length;
}
static void gf_m2ts_gather_section(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter *sec, GF_M2TS_SECTION_ES *ses, GF_M2TS_Header *hdr, unsigned char *data, u32 data_size)
{
u32 payload_size = data_size;
u8 expect_cc = (sec->cc<0) ? hdr->continuity_counter : (sec->cc + 1) & 0xf;
Bool disc = (expect_cc == hdr->continuity_counter) ? 0 : 1;
sec->cc = expect_cc;
if (!data_size) return;
if (hdr->payload_start) {
u32 ptr_field;
ptr_field = data[0];
if (ptr_field+1>data_size) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Invalid section start (@ptr_field=%d, @data_size=%d)\n", ptr_field, data_size) );
return;
}
if (!sec->length && sec->received) {
if (sec->received == 1)
sec->length = gf_m2ts_get_section_length(sec->section[0], data[1], data[2]);
else
sec->length = gf_m2ts_get_section_length(sec->section[0], sec->section[1], data[1]);
sec->section = (char*)gf_realloc(sec->section, sizeof(char)*sec->length);
}
if (sec->length && sec->received + ptr_field >= sec->length) {
u32 len = sec->length - sec->received;
memcpy(sec->section + sec->received, data+1, sizeof(char)*len);
sec->received += len;
if (ptr_field > len)
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Invalid pointer field (@ptr_field=%d, @remaining=%d)\n", ptr_field, len) );
gf_m2ts_section_complete(ts, sec, ses);
}
data += ptr_field+1;
data_size -= ptr_field+1;
payload_size -= ptr_field+1;
aggregated_section:
if (sec->section) gf_free(sec->section);
sec->length = sec->received = 0;
sec->section = (char*)gf_malloc(sizeof(char)*data_size);
memcpy(sec->section, data, sizeof(char)*data_size);
sec->received = data_size;
} else if (disc) {
if (sec->section) gf_free(sec->section);
sec->section = NULL;
sec->received = sec->length = 0;
return;
} else if (!sec->section) {
return;
} else {
if (sec->length && sec->received+data_size > sec->length)
data_size = sec->length - sec->received;
if (sec->length) {
memcpy(sec->section + sec->received, data, sizeof(char)*data_size);
} else {
sec->section = (char*)gf_realloc(sec->section, sizeof(char)*(sec->received+data_size));
memcpy(sec->section + sec->received, data, sizeof(char)*data_size);
}
sec->received += data_size;
}
if (!sec->length && (sec->received >= 3)) {
sec->length = gf_m2ts_get_section_length(sec->section[0], sec->section[1], sec->section[2]);
sec->section = (char*)gf_realloc(sec->section, sizeof(char)*sec->length);
if (sec->received > sec->length) {
data_size -= sec->received - sec->length;
sec->received = sec->length;
}
}
if (!sec->length || sec->received < sec->length) return;
gf_m2ts_section_complete(ts, sec, ses);
if (payload_size > data_size) {
data += data_size;
if (data[0] != 0xFF) {
data_size = payload_size - data_size;
payload_size = data_size;
goto aggregated_section;
}
}
}
static void gf_m2ts_process_sdt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
u32 pos, evt_type;
u32 nb_sections;
u32 data_size;
unsigned char *data;
GF_M2TS_Section *section;
if (!(status&GF_M2TS_TABLE_END)) return;
if (status&GF_M2TS_TABLE_REPEAT) {
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SDT_REPEAT, NULL);
return;
}
if (table_id != GF_M2TS_TABLE_ID_SDT_ACTUAL) {
return;
}
gf_m2ts_reset_sdt(ts);
nb_sections = gf_list_count(sections);
if (nb_sections > 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] SDT on multiple sections not supported\n"));
}
section = (GF_M2TS_Section *)gf_list_get(sections, 0);
data = section->data;
data_size = section->data_size;
pos = 3;
while (pos < data_size) {
GF_M2TS_SDT *sdt;
u32 descs_size, d_pos, ulen;
GF_SAFEALLOC(sdt, GF_M2TS_SDT);
if (!sdt) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Fail to create SDT\n"));
return;
}
gf_list_add(ts->SDTs, sdt);
sdt->service_id = (data[pos]<<8) + data[pos+1];
sdt->EIT_schedule = (data[pos+2] & 0x2) ? 1 : 0;
sdt->EIT_present_following = (data[pos+2] & 0x1);
sdt->running_status = (data[pos+3]>>5) & 0x7;
sdt->free_CA_mode = (data[pos+3]>>4) & 0x1;
descs_size = ((data[pos+3]&0xf)<<8) | data[pos+4];
pos += 5;
d_pos = 0;
while (d_pos < descs_size) {
u8 d_tag = data[pos+d_pos];
u8 d_len = data[pos+d_pos+1];
switch (d_tag) {
case GF_M2TS_DVB_SERVICE_DESCRIPTOR:
if (sdt->provider) gf_free(sdt->provider);
sdt->provider = NULL;
if (sdt->service) gf_free(sdt->service);
sdt->service = NULL;
d_pos+=2;
sdt->service_type = data[pos+d_pos];
ulen = data[pos+d_pos+1];
d_pos += 2;
sdt->provider = (char*)gf_malloc(sizeof(char)*(ulen+1));
memcpy(sdt->provider, data+pos+d_pos, sizeof(char)*ulen);
sdt->provider[ulen] = 0;
d_pos += ulen;
ulen = data[pos+d_pos];
d_pos += 1;
sdt->service = (char*)gf_malloc(sizeof(char)*(ulen+1));
memcpy(sdt->service, data+pos+d_pos, sizeof(char)*ulen);
sdt->service[ulen] = 0;
d_pos += ulen;
break;
default:
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) not supported\n", d_tag));
d_pos += d_len;
if (d_len == 0) d_pos = descs_size;
break;
}
}
pos += descs_size;
}
evt_type = GF_M2TS_EVT_SDT_FOUND;
if (ts->on_event) ts->on_event(ts, evt_type, NULL);
}
static void gf_m2ts_process_mpeg4section(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *es, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
GF_M2TS_SL_PCK sl_pck;
u32 nb_sections, i;
GF_M2TS_Section *section;
if (status & GF_M2TS_TABLE_REPEAT)
if (!(es->flags & GF_M2TS_ES_SEND_REPEATED_SECTIONS))
return;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Sections for PID %d\n", es->pid) );
nb_sections = gf_list_count(sections);
for (i=0; i<nb_sections; i++) {
section = (GF_M2TS_Section *)gf_list_get(sections, i);
sl_pck.data = (char *)section->data;
sl_pck.data_len = section->data_size;
sl_pck.stream = (GF_M2TS_ES *)es;
sl_pck.version_number = version_number;
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SL_PCK, &sl_pck);
}
}
static void gf_m2ts_process_nit(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *nit_es, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] NIT table processing (not yet implemented)"));
}
static void dvb_decode_mjd_date(u32 date, u16 *year, u8 *month, u8 *day)
{
u32 yp, mp, k;
yp = (u32)((date - 15078.2)/365.25);
mp = (u32)((date - 14956.1 - (u32)(yp * 365.25))/30.6001);
if (day) *day = (u32)(date - 14956 - (u32)(yp * 365.25) - (u32)(mp * 30.6001));
if (mp == 14 || mp == 15) k = 1;
else k = 0;
if (year) *year = yp + k + 1900;
if (month) *month = mp - 1 - k*12;
}
static void gf_m2ts_process_tdt_tot(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *tdt_tot_es, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
unsigned char *data;
u32 data_size, nb_sections;
GF_M2TS_Section *section;
GF_M2TS_TDT_TOT *time_table;
const char *table_name;
if ( !(status & GF_M2TS_TABLE_END) )
return;
switch (table_id) {
case GF_M2TS_TABLE_ID_TDT:
table_name = "TDT";
break;
case GF_M2TS_TABLE_ID_TOT:
table_name = "TOT";
break;
default:
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Unimplemented table_id %u for PID %u\n", table_id, GF_M2TS_PID_TDT_TOT_ST));
return;
}
nb_sections = gf_list_count(sections);
if (nb_sections > 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] %s on multiple sections not supported\n", table_name));
}
section = (GF_M2TS_Section *)gf_list_get(sections, 0);
data = section->data;
data_size = section->data_size;
if ((table_id==GF_M2TS_TABLE_ID_TDT) && (data_size != 5)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Corrupted TDT size\n", table_name));
}
GF_SAFEALLOC(time_table, GF_M2TS_TDT_TOT);
if (!time_table) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Fail to alloc DVB time table\n"));
return;
}
dvb_decode_mjd_date(data[0]*256 + data[1], &(time_table->year), &(time_table->month), &(time_table->day));
time_table->hour = 10*((data[2]&0xf0)>>4) + (data[2]&0x0f);
time_table->minute = 10*((data[3]&0xf0)>>4) + (data[3]&0x0f);
time_table->second = 10*((data[4]&0xf0)>>4) + (data[4]&0x0f);
assert(time_table->hour<24 && time_table->minute<60 && time_table->second<60);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Stream UTC time is %u/%02u/%02u %02u:%02u:%02u\n", time_table->year, time_table->month, time_table->day, time_table->hour, time_table->minute, time_table->second));
switch (table_id) {
case GF_M2TS_TABLE_ID_TDT:
if (ts->TDT_time) gf_free(ts->TDT_time);
ts->TDT_time = time_table;
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_TDT, time_table);
break;
case GF_M2TS_TABLE_ID_TOT:
#if 0
{
u32 pos, loop_len;
loop_len = ((data[5]&0x0f) << 8) | (data[6] & 0xff);
data += 7;
pos = 0;
while (pos < loop_len) {
u8 tag = data[pos];
pos += 2;
if (tag == GF_M2TS_DVB_LOCAL_TIME_OFFSET_DESCRIPTOR) {
char tmp_time[10];
u16 offset_hours, offset_minutes;
now->country_code[0] = data[pos];
now->country_code[1] = data[pos+1];
now->country_code[2] = data[pos+2];
now->country_region_id = data[pos+3]>>2;
sprintf(tmp_time, "%02x", data[pos+4]);
offset_hours = atoi(tmp_time);
sprintf(tmp_time, "%02x", data[pos+5]);
offset_minutes = atoi(tmp_time);
now->local_time_offset_seconds = (offset_hours * 60 + offset_minutes) * 60;
if (data[pos+3] & 1) now->local_time_offset_seconds *= -1;
dvb_decode_mjd_to_unix_time(data+pos+6, &now->unix_next_toc);
sprintf(tmp_time, "%02x", data[pos+11]);
offset_hours = atoi(tmp_time);
sprintf(tmp_time, "%02x", data[pos+12]);
offset_minutes = atoi(tmp_time);
now->next_time_offset_seconds = (offset_hours * 60 + offset_minutes) * 60;
if (data[pos+3] & 1) now->next_time_offset_seconds *= -1;
pos+= 13;
}
}
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_TOT, time_table);
}
#endif
if (ts->tdt_tot->length<4) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted %s table (less than 4 bytes but CRC32 should be present\n", table_name));
goto error_exit;
}
if (!gf_m2ts_crc32_check(ts->tdt_tot->section, ts->tdt_tot->length-4)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted %s table (CRC32 failed)\n", table_name));
goto error_exit;
}
if (ts->TDT_time) gf_free(ts->TDT_time);
ts->TDT_time = time_table;
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_TOT, time_table);
break;
default:
assert(0);
goto error_exit;
}
return;
error_exit:
gf_free(time_table);
return;
}
static GF_M2TS_MetadataPointerDescriptor *gf_m2ts_read_metadata_pointer_descriptor(GF_BitStream *bs, u32 length)
{
u32 size;
GF_M2TS_MetadataPointerDescriptor *d;
GF_SAFEALLOC(d, GF_M2TS_MetadataPointerDescriptor);
if (!d) return NULL;
d->application_format = gf_bs_read_u16(bs);
size = 2;
if (d->application_format == 0xFFFF) {
d->application_format_identifier = gf_bs_read_u32(bs);
size += 4;
}
d->format = gf_bs_read_u8(bs);
size += 1;
if (d->format == 0xFF) {
d->format_identifier = gf_bs_read_u32(bs);
size += 4;
}
d->service_id = gf_bs_read_u8(bs);
d->locator_record_flag = (gf_bs_read_int(bs, 1) ? GF_TRUE : GF_FALSE);
d->carriage_flag = (enum metadata_carriage)gf_bs_read_int(bs, 2);
gf_bs_read_int(bs, 5);
size += 2;
if (d->locator_record_flag) {
d->locator_length = gf_bs_read_u8(bs);
d->locator_data = (char *)gf_malloc(d->locator_length);
size += 1 + d->locator_length;
gf_bs_read_data(bs, d->locator_data, d->locator_length);
}
if (d->carriage_flag != 3) {
d->program_number = gf_bs_read_u16(bs);
size += 2;
}
if (d->carriage_flag == 1) {
d->ts_location = gf_bs_read_u16(bs);
d->ts_id = gf_bs_read_u16(bs);
size += 4;
}
if (length-size > 0) {
d->data_size = length-size;
d->data = (char *)gf_malloc(d->data_size);
gf_bs_read_data(bs, d->data, d->data_size);
}
return d;
}
void gf_m2ts_metadata_pointer_descriptor_del(GF_M2TS_MetadataPointerDescriptor *metapd)
{
if (metapd) {
if (metapd->locator_data) gf_free(metapd->locator_data);
if (metapd->data) gf_free(metapd->data);
gf_free(metapd);
}
}
static GF_M2TS_MetadataDescriptor *gf_m2ts_read_metadata_descriptor(GF_BitStream *bs, u32 length)
{
u32 size;
GF_M2TS_MetadataDescriptor *d;
GF_SAFEALLOC(d, GF_M2TS_MetadataDescriptor);
if (!d) return NULL;
d->application_format = gf_bs_read_u16(bs);
size = 2;
if (d->application_format == 0xFFFF) {
d->application_format_identifier = gf_bs_read_u32(bs);
size += 4;
}
d->format = gf_bs_read_u8(bs);
size += 1;
if (d->format == 0xFF) {
d->format_identifier = gf_bs_read_u32(bs);
size += 4;
}
d->service_id = gf_bs_read_u8(bs);
d->decoder_config_flags = gf_bs_read_int(bs, 3);
d->dsmcc_flag = (gf_bs_read_int(bs, 1) ? GF_TRUE : GF_FALSE);
gf_bs_read_int(bs, 4);
size += 2;
if (d->dsmcc_flag) {
d->service_id_record_length = gf_bs_read_u8(bs);
d->service_id_record = (char *)gf_malloc(d->service_id_record_length);
size += 1 + d->service_id_record_length;
gf_bs_read_data(bs, d->service_id_record, d->service_id_record_length);
}
if (d->decoder_config_flags == 1) {
d->decoder_config_length = gf_bs_read_u8(bs);
d->decoder_config = (char *)gf_malloc(d->decoder_config_length);
size += 1 + d->decoder_config_length;
gf_bs_read_data(bs, d->decoder_config, d->decoder_config_length);
}
if (d->decoder_config_flags == 3) {
d->decoder_config_id_length = gf_bs_read_u8(bs);
d->decoder_config_id = (char *)gf_malloc(d->decoder_config_id_length);
size += 1 + d->decoder_config_id_length;
gf_bs_read_data(bs, d->decoder_config_id, d->decoder_config_id_length);
}
if (d->decoder_config_flags == 4) {
d->decoder_config_service_id = gf_bs_read_u8(bs);
size++;
}
return d;
}
void gf_m2ts_metadata_descriptor_del(GF_M2TS_MetadataDescriptor *metad)
{
if (metad) {
if (metad->service_id_record) gf_free(metad->service_id_record);
if (metad->decoder_config) gf_free(metad->decoder_config);
if (metad->decoder_config_id) gf_free(metad->decoder_config_id);
gf_free(metad);
}
}
static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
u32 info_length, pos, desc_len, evt_type, nb_es,i;
u32 nb_sections;
u32 data_size;
unsigned char *data;
GF_M2TS_Section *section;
GF_Err e = GF_OK;
if (!(status&GF_M2TS_TABLE_END)) return;
nb_es = 0;
if ((status&GF_M2TS_TABLE_REPEAT) && !(status&GF_M2TS_TABLE_UPDATE)) {
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PMT_REPEAT, pmt->program);
return;
}
if (pmt->sec->demux_restarted) {
pmt->sec->demux_restarted = 0;
return;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PMT Found or updated\n"));
nb_sections = gf_list_count(sections);
if (nb_sections > 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("PMT on multiple sections not supported\n"));
}
section = (GF_M2TS_Section *)gf_list_get(sections, 0);
data = section->data;
data_size = section->data_size;
pmt->program->pcr_pid = ((data[0] & 0x1f) << 8) | data[1];
info_length = ((data[2]&0xf)<<8) | data[3];
if (info_length != 0) {
u8 tag, len;
u32 first_loop_len = 0;
tag = data[4];
len = data[5];
while (info_length > first_loop_len) {
#ifndef FORCE_DISABLE_MPEG4SL_OVER_MPEG2TS
if (tag == GF_M2TS_MPEG4_IOD_DESCRIPTOR) {
u32 size;
GF_BitStream *iod_bs;
iod_bs = gf_bs_new((char *)data+8, len-2, GF_BITSTREAM_READ);
if (pmt->program->pmt_iod) gf_odf_desc_del((GF_Descriptor *)pmt->program->pmt_iod);
e = gf_odf_parse_descriptor(iod_bs , (GF_Descriptor **) &pmt->program->pmt_iod, &size);
gf_bs_del(iod_bs );
if (e==GF_OK) {
if (pmt->program->pmt_iod) pmt->program->pmt_iod->ServiceID = pmt->program->number;
if (!gf_list_count(pmt->program->pmt_iod->ESDescriptors)) {
gf_odf_desc_del((GF_Descriptor *)pmt->program->pmt_iod);
pmt->program->pmt_iod = NULL;
}
}
} else if (tag == GF_M2TS_METADATA_POINTER_DESCRIPTOR) {
GF_BitStream *metadatapd_bs;
GF_M2TS_MetadataPointerDescriptor *metapd;
metadatapd_bs = gf_bs_new((char *)data+6, len, GF_BITSTREAM_READ);
metapd = gf_m2ts_read_metadata_pointer_descriptor(metadatapd_bs, len);
gf_bs_del(metadatapd_bs);
if (metapd->application_format_identifier == GF_4CC('I', 'D', '3', ' ') &&
metapd->format_identifier == GF_4CC('I', 'D', '3', ' ') &&
metapd->carriage_flag == METADATA_CARRIAGE_SAME_TS) {
pmt->program->metadata_pointer_descriptor = metapd;
} else {
gf_m2ts_metadata_pointer_descriptor_del(metapd);
}
} else {
#else
{
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) and others not supported\n", tag));
}
first_loop_len += 2 + len;
}
}
if (data_size <= 4 + info_length) return;
data += 4 + info_length;
data_size -= 4 + info_length;
pos = 0;
for(i=0; i<gf_list_count(ts->programs); i++) {
GF_M2TS_Program *prog = (GF_M2TS_Program *)gf_list_get(ts->programs,i);
if(prog->pmt_pid == pmt->pid) {
break;
}
}
while (pos<data_size) {
GF_M2TS_PES *pes = NULL;
GF_M2TS_SECTION_ES *ses = NULL;
GF_M2TS_ES *es = NULL;
Bool inherit_pcr = 0;
u32 pid, stream_type, reg_desc_format;
stream_type = data[0];
pid = ((data[1] & 0x1f) << 8) | data[2];
desc_len = ((data[3] & 0xf) << 8) | data[4];
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("stream_type :%d \n",stream_type));
switch (stream_type) {
case GF_M2TS_VIDEO_MPEG1:
case GF_M2TS_VIDEO_MPEG2:
case GF_M2TS_VIDEO_DCII:
case GF_M2TS_VIDEO_MPEG4:
case GF_M2TS_SYSTEMS_MPEG4_PES:
case GF_M2TS_VIDEO_H264:
case GF_M2TS_VIDEO_SVC:
case GF_M2TS_VIDEO_HEVC:
case GF_M2TS_VIDEO_SHVC:
case GF_M2TS_VIDEO_SHVC_TEMPORAL:
case GF_M2TS_VIDEO_MHVC:
case GF_M2TS_VIDEO_MHVC_TEMPORAL:
inherit_pcr = 1;
case GF_M2TS_AUDIO_MPEG1:
case GF_M2TS_AUDIO_MPEG2:
case GF_M2TS_AUDIO_AAC:
case GF_M2TS_AUDIO_LATM_AAC:
case GF_M2TS_AUDIO_AC3:
case GF_M2TS_AUDIO_DTS:
case GF_M2TS_SUBTITLE_DVB:
case GF_M2TS_METADATA_PES:
GF_SAFEALLOC(pes, GF_M2TS_PES);
if (!pes) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG2TS] Failed to allocate ES for pid %d\n", pid));
return;
}
pes->cc = -1;
pes->flags = GF_M2TS_ES_IS_PES;
if (inherit_pcr)
pes->flags |= GF_M2TS_INHERIT_PCR;
es = (GF_M2TS_ES *)pes;
break;
case GF_M2TS_PRIVATE_DATA:
GF_SAFEALLOC(pes, GF_M2TS_PES);
if (!pes) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG2TS] Failed to allocate ES for pid %d\n", pid));
return;
}
pes->cc = -1;
pes->flags = GF_M2TS_ES_IS_PES;
es = (GF_M2TS_ES *)pes;
break;
case GF_M2TS_SYSTEMS_MPEG4_SECTIONS:
GF_SAFEALLOC(ses, GF_M2TS_SECTION_ES);
if (!ses) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG2TS] Failed to allocate ES for pid %d\n", pid));
return;
}
es = (GF_M2TS_ES *)ses;
es->flags |= GF_M2TS_ES_IS_SECTION;
if (stream_type == GF_M2TS_SYSTEMS_MPEG4_SECTIONS) {
ses->sec = gf_m2ts_section_filter_new(gf_m2ts_process_mpeg4section, 0);
if (!pmt->program->additional_ods) {
pmt->program->additional_ods = gf_list_new();
ts->has_4on2 = 1;
}
}
break;
case GF_M2TS_13818_6_ANNEX_A:
case GF_M2TS_13818_6_ANNEX_B:
case GF_M2TS_13818_6_ANNEX_C:
case GF_M2TS_13818_6_ANNEX_D:
case GF_M2TS_PRIVATE_SECTION:
GF_SAFEALLOC(ses, GF_M2TS_SECTION_ES);
if (!ses) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG2TS] Failed to allocate ES for pid %d\n", pid));
return;
}
es = (GF_M2TS_ES *)ses;
es->flags |= GF_M2TS_ES_IS_SECTION;
es->pid = pid;
es->service_id = pmt->program->number;
if(stream_type == GF_M2TS_PRIVATE_SECTION) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("AIT section found on pid %d\n", pid));
} else {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("stream type DSM CC user private section: pid = %d \n", pid));
}
ses->sec = gf_m2ts_section_filter_new(NULL, 1);
break;
case GF_M2TS_MPE_SECTIONS:
if (! ts->prefix_present) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("stream type MPE found : pid = %d \n", pid));
#ifdef GPAC_ENABLE_MPE
es = gf_dvb_mpe_section_new();
if (es->flags & GF_M2TS_ES_IS_SECTION) {
((GF_M2TS_SECTION_ES*)es)->sec = gf_m2ts_section_filter_new(NULL, 1);
}
#endif
break;
}
default:
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Stream type (0x%x) for PID %d not supported\n", stream_type, pid ) );
break;
}
if (es) {
es->stream_type = (stream_type==GF_M2TS_PRIVATE_DATA) ? 0 : stream_type;
es->program = pmt->program;
es->pid = pid;
es->component_tag = -1;
}
pos += 5;
data += 5;
while (desc_len) {
u8 tag = data[0];
u32 len = data[1];
if (es) {
switch (tag) {
case GF_M2TS_ISO_639_LANGUAGE_DESCRIPTOR:
pes->lang = GF_4CC(' ', data[2], data[3], data[4]);
break;
case GF_M2TS_MPEG4_SL_DESCRIPTOR:
#ifdef FORCE_DISABLE_MPEG4SL_OVER_MPEG2TS
es->mpeg4_es_id = es->pid;
#else
es->mpeg4_es_id = ((data[2] & 0x1f) << 8) | data[3];
#endif
es->flags |= GF_M2TS_ES_IS_SL;
break;
case GF_M2TS_REGISTRATION_DESCRIPTOR:
reg_desc_format = GF_4CC(data[2], data[3], data[4], data[5]);
switch (reg_desc_format) {
case GF_4CC('A', 'C', '-', '3'):
es->stream_type = GF_M2TS_AUDIO_AC3;
break;
case GF_4CC('V', 'C', '-', '1'):
es->stream_type = GF_M2TS_VIDEO_VC1;
break;
default:
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Unknown registration descriptor %s\n", gf_4cc_to_str(reg_desc_format) ));
break;
}
break;
case GF_M2TS_DVB_EAC3_DESCRIPTOR:
es->stream_type = GF_M2TS_AUDIO_EC3;
break;
case GF_M2TS_DVB_DATA_BROADCAST_ID_DESCRIPTOR:
{
u32 id = data[2]<<8 | data[3];
if ((id == 0xB) && ses && !ses->sec) {
ses->sec = gf_m2ts_section_filter_new(NULL, 1);
}
}
break;
case GF_M2TS_DVB_SUBTITLING_DESCRIPTOR:
pes->sub.language[0] = data[2];
pes->sub.language[1] = data[3];
pes->sub.language[2] = data[4];
pes->sub.type = data[5];
pes->sub.composition_page_id = (data[6]<<8) | data[7];
pes->sub.ancillary_page_id = (data[8]<<8) | data[9];
es->stream_type = GF_M2TS_DVB_SUBTITLE;
break;
case GF_M2TS_DVB_STREAM_IDENTIFIER_DESCRIPTOR:
{
es->component_tag = data[2];
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Component Tag: %d on Program %d\n", es->component_tag, es->program->number));
}
break;
case GF_M2TS_DVB_TELETEXT_DESCRIPTOR:
es->stream_type = GF_M2TS_DVB_TELETEXT;
break;
case GF_M2TS_DVB_VBI_DATA_DESCRIPTOR:
es->stream_type = GF_M2TS_DVB_VBI;
break;
case GF_M2TS_HIERARCHY_DESCRIPTOR:
if (pes) {
u8 hierarchy_embedded_layer_index;
GF_BitStream *hbs = gf_bs_new((const char *)data, data_size, GF_BITSTREAM_READ);
gf_bs_read_int(hbs, 16);
gf_bs_read_int(hbs, 1);
gf_bs_read_int(hbs, 1);
gf_bs_read_int(hbs, 1);
gf_bs_read_int(hbs, 1);
gf_bs_read_int(hbs, 4);
gf_bs_read_int(hbs, 2);
gf_bs_read_int(hbs, 6);
gf_bs_read_int(hbs, 1);
gf_bs_read_int(hbs, 1);
hierarchy_embedded_layer_index = gf_bs_read_int(hbs, 6);
gf_bs_read_int(hbs, 2);
gf_bs_read_int(hbs, 6);
gf_bs_del(hbs);
pes->depends_on_pid = 1+hierarchy_embedded_layer_index;
}
break;
case GF_M2TS_METADATA_DESCRIPTOR:
{
GF_BitStream *metadatad_bs;
GF_M2TS_MetadataDescriptor *metad;
metadatad_bs = gf_bs_new((char *)data+2, len, GF_BITSTREAM_READ);
metad = gf_m2ts_read_metadata_descriptor(metadatad_bs, len);
gf_bs_del(metadatad_bs);
if (metad->application_format_identifier == GF_4CC('I', 'D', '3', ' ') &&
metad->format_identifier == GF_4CC('I', 'D', '3', ' ')) {
if (pes) {
pes->metadata_descriptor = metad;
pes->stream_type = GF_M2TS_METADATA_ID3_HLS;
}
} else {
gf_m2ts_metadata_descriptor_del(metad);
}
}
break;
default:
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] skipping descriptor (0x%x) not supported\n", tag));
break;
}
}
data += len+2;
pos += len+2;
if (desc_len < len+2) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Invalid PMT es descriptor size for PID %d\n", pid ) );
break;
}
desc_len-=len+2;
}
if (es && !es->stream_type) {
gf_free(es);
es = NULL;
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Private Stream type (0x%x) for PID %d not supported\n", stream_type, pid ) );
}
if (!es) continue;
if (ts->ess[pid]) {
if (status & GF_M2TS_TABLE_FOUND) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d reused across programs %d and %d, not completely supported\n", pid, ts->ess[pid]->program->number, es->program->number ) );
gf_list_add(pmt->program->streams, es);
if (!(es->flags & GF_M2TS_ES_IS_SECTION) ) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP);
nb_es++;
es = NULL;
}
else {
GF_M2TS_ES *o_es = ts->ess[es->pid];
if ((o_es->stream_type == es->stream_type)
&& ((o_es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK) == (es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK))
&& (o_es->mpeg4_es_id == es->mpeg4_es_id)
&& ((o_es->flags & GF_M2TS_ES_IS_SECTION) || ((GF_M2TS_PES *)o_es)->lang == ((GF_M2TS_PES *)es)->lang)
) {
gf_free(es);
es = NULL;
} else {
gf_m2ts_es_del(o_es, ts);
ts->ess[es->pid] = NULL;
}
}
}
if (es) {
ts->ess[es->pid] = es;
gf_list_add(pmt->program->streams, es);
if (!(es->flags & GF_M2TS_ES_IS_SECTION) ) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP);
nb_es++;
}
}
if (nb_es) {
u32 i;
for (i=0; i<gf_list_count(pmt->program->streams); i++) {
GF_M2TS_PES *an_es = NULL;
GF_M2TS_PES *es = (GF_M2TS_PES *)gf_list_get(pmt->program->streams, i);
if ( !(es->flags & GF_M2TS_ES_IS_PES)) continue;
if (!es->depends_on_pid) continue;
an_es = (GF_M2TS_PES *)gf_list_get(pmt->program->streams, es->depends_on_pid);
if (an_es)
es->depends_on_pid = an_es->pid;
}
evt_type = (status&GF_M2TS_TABLE_FOUND) ? GF_M2TS_EVT_PMT_FOUND : GF_M2TS_EVT_PMT_UPDATE;
if (ts->on_event) ts->on_event(ts, evt_type, pmt->program);
} else {
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PMT_REPEAT, pmt->program);
}
}
static void gf_m2ts_process_pat(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
GF_M2TS_Program *prog;
GF_M2TS_SECTION_ES *pmt;
u32 i, nb_progs, evt_type;
u32 nb_sections;
u32 data_size;
unsigned char *data;
GF_M2TS_Section *section;
if (!(status&GF_M2TS_TABLE_END)) return;
if (status&GF_M2TS_TABLE_REPEAT) {
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PAT_REPEAT, NULL);
return;
}
nb_sections = gf_list_count(sections);
if (nb_sections > 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("PAT on multiple sections not supported\n"));
}
section = (GF_M2TS_Section *)gf_list_get(sections, 0);
data = section->data;
data_size = section->data_size;
if (!(status&GF_M2TS_TABLE_UPDATE) && gf_list_count(ts->programs)) {
if (ts->pat->demux_restarted) {
ts->pat->demux_restarted = 0;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Multiple different PAT on single TS found, ignoring new PAT declaration (table id %d - extended table id %d)\n", table_id, ex_table_id));
}
return;
}
nb_progs = data_size / 4;
for (i=0; i<nb_progs; i++) {
u16 number, pid;
number = (data[0]<<8) | data[1];
pid = (data[2]&0x1f)<<8 | data[3];
data += 4;
if (number==0) {
if (!ts->nit) {
ts->nit = gf_m2ts_section_filter_new(gf_m2ts_process_nit, 0);
}
} else {
GF_SAFEALLOC(prog, GF_M2TS_Program);
if (!prog) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Fail to allocate program for pid %d\n", pid));
return;
}
prog->streams = gf_list_new();
prog->pmt_pid = pid;
prog->number = number;
prog->ts = ts;
gf_list_add(ts->programs, prog);
GF_SAFEALLOC(pmt, GF_M2TS_SECTION_ES);
if (!pmt) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Fail to allocate pmt filter for pid %d\n", pid));
return;
}
pmt->flags = GF_M2TS_ES_IS_SECTION;
gf_list_add(prog->streams, pmt);
pmt->pid = prog->pmt_pid;
pmt->program = prog;
ts->ess[pmt->pid] = (GF_M2TS_ES *)pmt;
pmt->sec = gf_m2ts_section_filter_new(gf_m2ts_process_pmt, 0);
}
}
evt_type = (status&GF_M2TS_TABLE_UPDATE) ? GF_M2TS_EVT_PAT_UPDATE : GF_M2TS_EVT_PAT_FOUND;
if (ts->on_event) ts->on_event(ts, evt_type, NULL);
}
static void gf_m2ts_process_cat(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
u32 evt_type;
if (!(status&GF_M2TS_TABLE_END)) return;
if (status&GF_M2TS_TABLE_REPEAT) {
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_CAT_REPEAT, NULL);
return;
}
evt_type = (status&GF_M2TS_TABLE_UPDATE) ? GF_M2TS_EVT_CAT_UPDATE : GF_M2TS_EVT_CAT_FOUND;
if (ts->on_event) ts->on_event(ts, evt_type, NULL);
}
u64 gf_m2ts_get_pts(unsigned char *data)
{
u64 pts;
u32 val;
pts = (u64)((data[0] >> 1) & 0x07) << 30;
val = (data[1] << 8) | data[2];
pts |= (u64)(val >> 1) << 15;
val = (data[3] << 8) | data[4];
pts |= (u64)(val >> 1);
return pts;
}
void gf_m2ts_pes_header(GF_M2TS_PES *pes, unsigned char *data, u32 data_size, GF_M2TS_PESHeader *pesh)
{
u32 has_pts, has_dts;
u32 len_check;
memset(pesh, 0, sizeof(GF_M2TS_PESHeader));
len_check = 0;
pesh->id = data[0];
pesh->pck_len = (data[1]<<8) | data[2];
pesh->data_alignment = (data[3] & 0x4) ? 1 : 0;
has_pts = (data[4]&0x80);
has_dts = has_pts ? (data[4]&0x40) : 0;
pesh->hdr_data_len = data[5];
data += 6;
if (has_pts) {
pesh->PTS = gf_m2ts_get_pts(data);
data+=5;
len_check += 5;
}
if (has_dts) {
pesh->DTS = gf_m2ts_get_pts(data);
len_check += 5;
} else {
pesh->DTS = pesh->PTS;
}
if (len_check < pesh->hdr_data_len) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Skipping %d bytes in pes header\n", pes->pid, pesh->hdr_data_len - len_check));
} else if (len_check > pesh->hdr_data_len) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Wrong pes_header_data_length field %d bytes - read %d\n", pes->pid, pesh->hdr_data_len, len_check));
}
if ((pesh->PTS<90000) && ((s32)pesh->DTS<0)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Wrong DTS %d negative for PTS %d - forcing to 0\n", pes->pid, pesh->DTS, pesh->PTS));
pesh->DTS=0;
}
}
static void gf_m2ts_store_temi(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes)
{
GF_BitStream *bs = gf_bs_new(pes->temi_tc_desc, pes->temi_tc_desc_len, GF_BITSTREAM_READ);
u32 has_timestamp = gf_bs_read_int(bs, 2);
Bool has_ntp = (Bool) gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 2);
memset(&pes->temi_tc, 0, sizeof(GF_M2TS_TemiTimecodeDescriptor));
pes->temi_tc.force_reload = gf_bs_read_int(bs, 1);
pes->temi_tc.is_paused = gf_bs_read_int(bs, 1);
pes->temi_tc.is_discontinuity = gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 7);
pes->temi_tc.timeline_id = gf_bs_read_int(bs, 8);
if (has_timestamp) {
pes->temi_tc.media_timescale = gf_bs_read_u32(bs);
if (has_timestamp==2)
pes->temi_tc.media_timestamp = gf_bs_read_u64(bs);
else
pes->temi_tc.media_timestamp = gf_bs_read_u32(bs);
}
if (has_ntp) {
pes->temi_tc.ntp = gf_bs_read_u64(bs);
}
gf_bs_del(bs);
pes->temi_tc_desc_len = 0;
pes->temi_pending = 1;
}
void gf_m2ts_flush_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes)
{
GF_M2TS_PESHeader pesh;
if (!ts) return;
if ((pes->pck_data_len >= 4) && !pes->pck_data[0] && !pes->pck_data[1] && (pes->pck_data[2] == 0x1)) {
u32 len;
u32 stream_id = pes->pck_data[3] | 0x100;
Bool same_pts = GF_FALSE;
if ((stream_id >= 0x1c0 && stream_id <= 0x1df) ||
(stream_id >= 0x1e0 && stream_id <= 0x1ef) ||
(stream_id == 0x1bd) ||
(stream_id == 0x10d) ||
((u8)pes->pck_data[3] == 0xfa)
) {
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: unknown stream ID %08X\n", pes->pid, stream_id));
}
gf_m2ts_pes_header(pes, pes->pck_data + 3, pes->pck_data_len - 3, &pesh);
if (ts->notify_pes_timing) {
GF_M2TS_PES_PCK pck;
memset(&pck, 0, sizeof(GF_M2TS_PES_PCK));
pck.PTS = pesh.PTS;
pck.DTS = pesh.DTS;
pck.stream = pes;
if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP;
pes->pes_end_packet_number = ts->pck_number;
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PES_TIMING, &pck);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Got PES header DTS %d PTS %d\n", pes->pid, pesh.DTS, pesh.PTS));
if (pesh.PTS) {
if (pesh.PTS == pes->PTS) {
same_pts = GF_TRUE;
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same PTS "LLU" for two consecutive PES packets \n", pes->pid, pes->PTS));
}
#ifndef GPAC_DISABLE_LOG
#endif
pes->PTS = pesh.PTS;
#ifndef GPAC_DISABLE_LOG
{
if (pes->DTS && (pesh.DTS == pes->DTS)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same DTS "LLU" for two consecutive PES packets \n", pes->pid, pes->DTS));
}
if (pesh.DTS < pes->DTS) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - DTS "LLU" less than previous DTS "LLU"\n", pes->pid, pesh.DTS, pes->DTS));
}
}
#endif
pes->DTS = pesh.DTS;
}
else if (!pesh.hdr_data_len) {
same_pts = GF_TRUE;
}
len = 9 + pesh.hdr_data_len;
if ((u8) pes->pck_data[3]==0xfa) {
GF_M2TS_SL_PCK sl_pck;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] SL Packet in PES for %d - ES ID %d\n", pes->pid, pes->mpeg4_es_id));
if (pes->pck_data_len > len) {
sl_pck.data = (char *)pes->pck_data + len;
sl_pck.data_len = pes->pck_data_len - len;
sl_pck.stream = (GF_M2TS_ES *)pes;
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SL_PCK, &sl_pck);
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Bad SL Packet size: (%d indicated < %d header)\n", pes->pid, pes->pck_data_len, len));
}
} else if (pes->reframe) {
u32 remain = 0;
u32 offset = len;
if (pesh.pck_len && (pesh.pck_len-3-pesh.hdr_data_len != pes->pck_data_len-len)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES payload size %d but received %d bytes\n", pes->pid, (u32) ( pesh.pck_len-3-pesh.hdr_data_len), pes->pck_data_len-len));
}
if (pes->prev_data_len) {
if (pes->prev_data_len < len) {
offset = len - pes->prev_data_len;
memcpy(pes->pck_data + offset, pes->prev_data, pes->prev_data_len);
} else {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES reassembly buffer overflow (%d bytes not processed from previous PES) - discarding prev data\n", pes->pid, pes->prev_data_len ));
}
}
if (!pes->temi_pending && pes->temi_tc_desc_len) {
gf_m2ts_store_temi(ts, pes);
}
if (pes->temi_pending) {
pes->temi_pending = 0;
pes->temi_tc.pes_pts = pes->PTS;
if (ts->on_event)
ts->on_event(ts, GF_M2TS_EVT_TEMI_TIMECODE, &pes->temi_tc);
}
if (! ts->start_range)
remain = pes->reframe(ts, pes, same_pts, pes->pck_data+offset, pes->pck_data_len-offset, &pesh);
if (pes->prev_data) gf_free(pes->prev_data);
pes->prev_data = NULL;
pes->prev_data_len = 0;
if (remain) {
pes->prev_data = gf_malloc(sizeof(char)*remain);
assert(pes->pck_data_len >= remain);
memcpy(pes->prev_data, pes->pck_data + pes->pck_data_len - remain, remain);
pes->prev_data_len = remain;
}
}
} else if (pes->pck_data_len) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Bad PES Header, discarding packet (maybe stream is encrypted ?)\n", pes->pid));
}
pes->pck_data_len = 0;
pes->pes_len = 0;
pes->rap = 0;
}
static void gf_m2ts_process_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, GF_M2TS_Header *hdr, unsigned char *data, u32 data_size, GF_M2TS_AdaptationField *paf)
{
u8 expect_cc;
Bool disc=0;
Bool flush_pes = 0;
if (hdr->continuity_counter==pes->cc) {
if (!hdr->payload_start || (hdr->adaptation_field!=3) ) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Duplicated Packet found (CC %d) - skipping\n", pes->pid, pes->cc));
return;
}
} else {
expect_cc = (pes->cc<0) ? hdr->continuity_counter : (pes->cc + 1) & 0xf;
if (expect_cc != hdr->continuity_counter)
disc = 1;
}
pes->cc = hdr->continuity_counter;
if (disc) {
if (pes->flags & GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY) {
pes->flags &= ~GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY;
disc = 0;
}
if (disc) {
if (hdr->payload_start) {
if (pes->pck_data_len) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Packet discontinuity (%d expected - got %d) - may have lost end of previous PES\n", pes->pid, expect_cc, hdr->continuity_counter));
}
} else {
if (pes->pck_data_len) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Packet discontinuity (%d expected - got %d) - trashing PES packet\n", pes->pid, expect_cc, hdr->continuity_counter));
}
pes->pck_data_len = 0;
pes->pes_len = 0;
pes->cc = -1;
return;
}
}
}
if (!pes->reframe) return;
if (hdr->payload_start) {
flush_pes = 1;
pes->pes_start_packet_number = ts->pck_number;
pes->before_last_pcr_value = pes->program->before_last_pcr_value;
pes->before_last_pcr_value_pck_number = pes->program->before_last_pcr_value_pck_number;
pes->last_pcr_value = pes->program->last_pcr_value;
pes->last_pcr_value_pck_number = pes->program->last_pcr_value_pck_number;
} else if (pes->pes_len && (pes->pck_data_len + data_size == pes->pes_len + 6)) {
if (pes->pck_data_len + data_size > pes->pck_alloc_len) {
pes->pck_alloc_len = pes->pck_data_len + data_size;
pes->pck_data = (u8*)gf_realloc(pes->pck_data, pes->pck_alloc_len);
}
memcpy(pes->pck_data+pes->pck_data_len, data, data_size);
pes->pck_data_len += data_size;
data_size = 0;
flush_pes = 1;
}
if (flush_pes && pes->pck_data_len) {
gf_m2ts_flush_pes(ts, pes);
if (!data_size) return;
}
if (!pes->pck_data_len && !hdr->payload_start) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Waiting for PES header, trashing data\n", hdr->pid));
return;
}
if (pes->pck_data_len + data_size > pes->pck_alloc_len ) {
pes->pck_alloc_len = pes->pck_data_len + data_size;
pes->pck_data = (u8*)gf_realloc(pes->pck_data, pes->pck_alloc_len);
}
memcpy(pes->pck_data + pes->pck_data_len, data, data_size);
pes->pck_data_len += data_size;
if (paf && paf->random_access_indicator) pes->rap = 1;
if (hdr->payload_start && !pes->pes_len && (pes->pck_data_len>=6)) {
pes->pes_len = (pes->pck_data[4]<<8) | pes->pck_data[5];
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Got PES packet len %d\n", pes->pid, pes->pes_len));
if (pes->pes_len + 6 == pes->pck_data_len) {
gf_m2ts_flush_pes(ts, pes);
}
}
}
static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_AdaptationField *paf, unsigned char *data, u32 size, u32 pid)
{
unsigned char *af_extension;
paf->discontinuity_indicator = (data[0] & 0x80) ? 1 : 0;
paf->random_access_indicator = (data[0] & 0x40) ? 1 : 0;
paf->priority_indicator = (data[0] & 0x20) ? 1 : 0;
paf->PCR_flag = (data[0] & 0x10) ? 1 : 0;
paf->OPCR_flag = (data[0] & 0x8) ? 1 : 0;
paf->splicing_point_flag = (data[0] & 0x4) ? 1 : 0;
paf->transport_private_data_flag = (data[0] & 0x2) ? 1 : 0;
paf->adaptation_field_extension_flag = (data[0] & 0x1) ? 1 : 0;
af_extension = data + 1;
if (paf->PCR_flag == 1) {
u32 base = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
u64 PCR = (u64) base;
paf->PCR_base = (PCR << 1) | (data[5] >> 7);
paf->PCR_ext = ((data[5] & 1) << 8) | data[6];
af_extension += 6;
}
if (paf->adaptation_field_extension_flag) {
u32 afext_bytes;
Bool ltw_flag, pwr_flag, seamless_flag, af_desc_not_present;
if (paf->OPCR_flag) {
af_extension += 6;
}
if (paf->splicing_point_flag) {
af_extension += 1;
}
if (paf->transport_private_data_flag) {
u32 priv_bytes = af_extension[0];
af_extension += 1 + priv_bytes;
}
afext_bytes = af_extension[0];
ltw_flag = af_extension[1] & 0x80 ? 1 : 0;
pwr_flag = af_extension[1] & 0x40 ? 1 : 0;
seamless_flag = af_extension[1] & 0x20 ? 1 : 0;
af_desc_not_present = af_extension[1] & 0x10 ? 1 : 0;
af_extension += 2;
if (!afext_bytes) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid));
return;
}
afext_bytes-=1;
if (ltw_flag) {
af_extension += 2;
if (afext_bytes<2) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid));
return;
}
afext_bytes-=2;
}
if (pwr_flag) {
af_extension += 3;
if (afext_bytes<3) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid));
return;
}
afext_bytes-=3;
}
if (seamless_flag) {
af_extension += 3;
if (afext_bytes<3) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid));
return;
}
afext_bytes-=3;
}
if (! af_desc_not_present) {
while (afext_bytes) {
GF_BitStream *bs;
char *desc;
u8 desc_tag = af_extension[0];
u8 desc_len = af_extension[1];
if (!desc_len || (u32) desc_len+2 > afext_bytes) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Descriptor found (tag %d) size is %d but only %d bytes available\n", pid, desc_tag, desc_len, afext_bytes));
break;
}
desc = (char *) af_extension+2;
bs = gf_bs_new(desc, desc_len, GF_BITSTREAM_READ);
switch (desc_tag) {
case GF_M2TS_AFDESC_LOCATION_DESCRIPTOR:
{
Bool use_base_temi_url;
char URL[255];
GF_M2TS_TemiLocationDescriptor temi_loc;
memset(&temi_loc, 0, sizeof(GF_M2TS_TemiLocationDescriptor) );
temi_loc.reload_external = gf_bs_read_int(bs, 1);
temi_loc.is_announce = gf_bs_read_int(bs, 1);
temi_loc.is_splicing = gf_bs_read_int(bs, 1);
use_base_temi_url = gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 5);
temi_loc.timeline_id = gf_bs_read_int(bs, 7);
if (!use_base_temi_url) {
char *_url = URL;
u8 scheme = gf_bs_read_int(bs, 8);
u8 url_len = gf_bs_read_int(bs, 8);
switch (scheme) {
case 1:
strcpy(URL, "http://");
_url = URL+7;
break;
case 2:
strcpy(URL, "https://");
_url = URL+8;
break;
}
gf_bs_read_data(bs, _url, url_len);
_url[url_len] = 0;
}
temi_loc.external_URL = URL;
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d AF Location descriptor found - URL %s\n", pid, URL));
if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_TEMI_LOCATION, &temi_loc);
}
break;
case GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR:
if (ts->ess[pid] && (ts->ess[pid]->flags & GF_M2TS_ES_IS_PES)) {
GF_M2TS_PES *pes = (GF_M2TS_PES *) ts->ess[pid];
if (pes->temi_tc_desc_len)
gf_m2ts_store_temi(ts, pes);
if (pes->temi_tc_desc_alloc_size < desc_len) {
pes->temi_tc_desc = gf_realloc(pes->temi_tc_desc, desc_len);
pes->temi_tc_desc_alloc_size = desc_len;
}
memcpy(pes->temi_tc_desc, desc, desc_len);
pes->temi_tc_desc_len = desc_len;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d AF Timeline descriptor found\n", pid));
}
break;
}
gf_bs_del(bs);
af_extension += 2+desc_len;
afext_bytes -= 2+desc_len;
}
}
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Adaptation Field found: Discontinuity %d - RAP %d - PCR: "LLD"\n", pid, paf->discontinuity_indicator, paf->random_access_indicator, paf->PCR_flag ? paf->PCR_base * 300 + paf->PCR_ext : 0));
}
static GF_Err gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data)
{
GF_M2TS_ES *es;
GF_M2TS_Header hdr;
GF_M2TS_AdaptationField af, *paf;
u32 payload_size, af_size;
u32 pos = 0;
ts->pck_number++;
hdr.sync = data[0];
if (hdr.sync != 0x47) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d does not start with sync marker\n", ts->pck_number));
return GF_CORRUPTED_DATA;
}
hdr.error = (data[1] & 0x80) ? 1 : 0;
hdr.payload_start = (data[1] & 0x40) ? 1 : 0;
hdr.priority = (data[1] & 0x20) ? 1 : 0;
hdr.pid = ( (data[1]&0x1f) << 8) | data[2];
hdr.scrambling_ctrl = (data[3] >> 6) & 0x3;
hdr.adaptation_field = (data[3] >> 4) & 0x3;
hdr.continuity_counter = data[3] & 0xf;
if (hdr.error) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d has error (PID could be %d)\n", ts->pck_number, hdr.pid));
return GF_CORRUPTED_DATA;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d PID %d CC %d Encrypted %d\n", ts->pck_number, hdr.pid, hdr.continuity_counter, hdr.scrambling_ctrl));
if (hdr.scrambling_ctrl) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d is scrambled - not supported\n", ts->pck_number, hdr.pid));
return GF_NOT_SUPPORTED;
}
paf = NULL;
payload_size = 184;
pos = 4;
switch (hdr.adaptation_field) {
case 3:
af_size = data[4];
if (af_size>183) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d AF field larger than 183 !\n", ts->pck_number));
return GF_CORRUPTED_DATA;
}
paf = ⁡
memset(paf, 0, sizeof(GF_M2TS_AdaptationField));
assert( af_size<=182);
if (af_size>182)
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d Detected wrong adaption field size %u when control value is 3\n", ts->pck_number, af_size));
if (af_size) gf_m2ts_get_adaptation_field(ts, paf, data+5, af_size, hdr.pid);
pos += 1+af_size;
payload_size = 183 - af_size;
break;
case 2:
af_size = data[4];
if (af_size != 183) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d AF size is %d when it must be 183 for AF type 2\n", ts->pck_number, af_size));
return GF_CORRUPTED_DATA;
}
paf = ⁡
memset(paf, 0, sizeof(GF_M2TS_AdaptationField));
gf_m2ts_get_adaptation_field(ts, paf, data+5, af_size, hdr.pid);
payload_size = 0;
if (!paf->PCR_flag)
return GF_OK;
break;
case 0:
return GF_OK;
default:
break;
}
data += pos;
if (hdr.pid == GF_M2TS_PID_PAT) {
gf_m2ts_gather_section(ts, ts->pat, NULL, &hdr, data, payload_size);
return GF_OK;
} else if (hdr.pid == GF_M2TS_PID_CAT) {
gf_m2ts_gather_section(ts, ts->cat, NULL, &hdr, data, payload_size);
return GF_OK;
}
es = ts->ess[hdr.pid];
if (paf && paf->PCR_flag) {
if (!es) {
u32 i, j;
for(i=0; i<gf_list_count(ts->programs); i++) {
GF_M2TS_PES *first_pes = NULL;
GF_M2TS_Program *program = (GF_M2TS_Program *)gf_list_get(ts->programs,i);
if(program->pcr_pid != hdr.pid) continue;
for (j=0; j<gf_list_count(program->streams); j++) {
GF_M2TS_PES *pes = (GF_M2TS_PES *) gf_list_get(program->streams, j);
if (pes->flags & GF_M2TS_INHERIT_PCR) {
ts->ess[hdr.pid] = (GF_M2TS_ES *) pes;
pes->flags |= GF_M2TS_FAKE_PCR;
break;
}
if (pes->flags & GF_M2TS_ES_IS_PES) {
first_pes = pes;
}
}
if (!es && first_pes) {
es = (GF_M2TS_ES *) first_pes;
first_pes->flags |= GF_M2TS_FAKE_PCR;
}
break;
}
if (!es)
es = ts->ess[hdr.pid];
}
if (es) {
GF_M2TS_PES_PCK pck;
s64 prev_diff_in_us;
Bool discontinuity;
s32 cc = -1;
if (es->flags & GF_M2TS_FAKE_PCR) {
cc = es->program->pcr_cc;
es->program->pcr_cc = hdr.continuity_counter;
}
else if (es->flags & GF_M2TS_ES_IS_PES) cc = ((GF_M2TS_PES*)es)->cc;
else if (((GF_M2TS_SECTION_ES*)es)->sec) cc = ((GF_M2TS_SECTION_ES*)es)->sec->cc;
discontinuity = paf->discontinuity_indicator;
if ((cc>=0) && es->program->before_last_pcr_value) {
if (hdr.adaptation_field == 2) {
if (hdr.continuity_counter != cc) {
discontinuity = GF_TRUE;
}
} else if (hdr.continuity_counter != ((cc + 1) & 0xF)) {
discontinuity = GF_TRUE;
}
}
memset(&pck, 0, sizeof(GF_M2TS_PES_PCK));
prev_diff_in_us = (s64) (es->program->last_pcr_value /27- es->program->before_last_pcr_value/27);
es->program->before_last_pcr_value = es->program->last_pcr_value;
es->program->before_last_pcr_value_pck_number = es->program->last_pcr_value_pck_number;
es->program->last_pcr_value_pck_number = ts->pck_number;
es->program->last_pcr_value = paf->PCR_base * 300 + paf->PCR_ext;
if (!es->program->last_pcr_value) es->program->last_pcr_value = 1;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR found "LLU" ("LLU" at 90kHz) - PCR diff is %d us\n", hdr.pid, es->program->last_pcr_value, es->program->last_pcr_value/300, (s32) (es->program->last_pcr_value - es->program->before_last_pcr_value)/27 ));
pck.PTS = es->program->last_pcr_value;
pck.stream = (GF_M2TS_PES *)es;
if (discontinuity) {
s64 diff_in_us = (s64) (es->program->last_pcr_value - es->program->before_last_pcr_value) / 27;
u64 diff = ABS(diff_in_us - prev_diff_in_us);
if ((diff_in_us<0) && (diff_in_us >= -200000)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d new PCR, with discontinuity signaled, is less than previously received PCR (diff %d us) but not too large, trying to ignore discontinuity\n", hdr.pid, diff_in_us));
}
else if ((diff_in_us > 0) && (diff < 200000)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR discontinuity signaled but diff is small (diff %d us - PCR diff %d vs prev PCR diff %d) - ignore it\n", hdr.pid, diff, diff_in_us, prev_diff_in_us));
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR discontinuity signaled (diff %d us - PCR diff %d vs prev PCR diff %d)\n", hdr.pid, diff, diff_in_us, prev_diff_in_us));
pck.flags = GF_M2TS_PES_PCK_DISCONTINUITY;
}
}
else if ( (es->program->last_pcr_value < es->program->before_last_pcr_value) ) {
s64 diff_in_us = (s64) (es->program->last_pcr_value - es->program->before_last_pcr_value) / 27;
if (GF_M2TS_MAX_PCR - es->program->before_last_pcr_value < 5400000 ) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR loop found from "LLU" to "LLU" \n", hdr.pid, es->program->before_last_pcr_value, es->program->last_pcr_value));
} else if ((diff_in_us<0) && (diff_in_us >= -200000)) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d new PCR, without discontinuity signaled, is less than previously received PCR (diff %d us) but not too large, trying to ignore discontinuity\n", hdr.pid, diff_in_us));
} else {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR found "LLU" is less than previously received PCR "LLU" (PCR diff %g sec) but no discontinuity signaled\n", hdr.pid, es->program->last_pcr_value, es->program->before_last_pcr_value, (GF_M2TS_MAX_PCR - es->program->before_last_pcr_value + es->program->last_pcr_value) / 27000000.0));
pck.flags = GF_M2TS_PES_PCK_DISCONTINUITY;
}
}
if (pck.flags & GF_M2TS_PES_PCK_DISCONTINUITY) {
gf_m2ts_reset_parsers_for_program(ts, es->program);
}
if (ts->on_event) {
gf_m2ts_estimate_duration(ts, es->program->last_pcr_value, hdr.pid);
ts->on_event(ts, GF_M2TS_EVT_PES_PCR, &pck);
}
}
}
if (!es) {
if (hdr.pid == GF_M2TS_PID_SDT_BAT_ST) {
gf_m2ts_gather_section(ts, ts->sdt, NULL, &hdr, data, payload_size);
return GF_OK;
} else if (hdr.pid == GF_M2TS_PID_NIT_ST) {
gf_m2ts_gather_section(ts, ts->nit, NULL, &hdr, data, payload_size);
return GF_OK;
} else if (hdr.pid == GF_M2TS_PID_EIT_ST_CIT) {
gf_m2ts_gather_section(ts, ts->eit, NULL, &hdr, data, payload_size);
return GF_OK;
} else if (hdr.pid == GF_M2TS_PID_TDT_TOT_ST) {
gf_m2ts_gather_section(ts, ts->tdt_tot, NULL, &hdr, data, payload_size);
} else {
}
} else if (es->flags & GF_M2TS_ES_IS_SECTION) {
GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es;
if (ses->sec) gf_m2ts_gather_section(ts, ses->sec, ses, &hdr, data, payload_size);
} else {
GF_M2TS_PES *pes = (GF_M2TS_PES *)es;
if (pes->reframe && payload_size) gf_m2ts_process_pes(ts, pes, &hdr, data, payload_size, paf);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_m2ts_process_data(GF_M2TS_Demuxer *ts, char *data, u32 data_size)
{
GF_Err e;
u32 pos, pck_size;
Bool is_align = 1;
if (ts->buffer) {
if (ts->alloc_size < ts->buffer_size+data_size) {
ts->alloc_size = ts->buffer_size+data_size;
ts->buffer = (char*)gf_realloc(ts->buffer, sizeof(char)*ts->alloc_size);
}
memcpy(ts->buffer + ts->buffer_size, data, sizeof(char)*data_size);
ts->buffer_size += data_size;
is_align = 0;
} else {
ts->buffer = data;
ts->buffer_size = data_size;
}
pos = gf_m2ts_sync(ts, is_align);
if (pos==ts->buffer_size) {
if (is_align) {
ts->buffer = (char*)gf_malloc(sizeof(char)*data_size);
memcpy(ts->buffer, data, sizeof(char)*data_size);
ts->alloc_size = ts->buffer_size = data_size;
}
return GF_OK;
}
pck_size = ts->prefix_present ? 192 : 188;
e=GF_OK;
for (;;) {
if (ts->buffer_size < pos + pck_size) {
ts->buffer_size -= pos;
if (!ts->buffer_size) {
if (!is_align) gf_free(ts->buffer);
ts->buffer = NULL;
return e;
}
if (is_align) {
data = ts->buffer+pos;
ts->buffer = (char*)gf_malloc(sizeof(char)*ts->buffer_size);
memcpy(ts->buffer, data, sizeof(char)*ts->buffer_size);
ts->alloc_size = ts->buffer_size;
} else {
memmove(ts->buffer, ts->buffer + pos, sizeof(char)*ts->buffer_size);
}
return e;
}
e |= gf_m2ts_process_packet(ts, (unsigned char *)ts->buffer+pos);
pos += pck_size;
if (ts->abort_parsing) {
if (!is_align) gf_free(ts->buffer);
ts->buffer = NULL;
return e;
}
}
return e;
}
GF_ESD *gf_m2ts_get_esd(GF_M2TS_ES *es)
{
GF_ESD *esd;
u32 k, esd_count;
esd = NULL;
if (es->program->pmt_iod && es->program->pmt_iod->ESDescriptors) {
esd_count = gf_list_count(es->program->pmt_iod->ESDescriptors);
for (k = 0; k < esd_count; k++) {
GF_ESD *esd_tmp = (GF_ESD *)gf_list_get(es->program->pmt_iod->ESDescriptors, k);
if (esd_tmp->ESID != es->mpeg4_es_id) continue;
esd = esd_tmp;
break;
}
}
if (!esd && es->program->additional_ods) {
u32 od_count, od_index;
od_count = gf_list_count(es->program->additional_ods);
for (od_index = 0; od_index < od_count; od_index++) {
GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(es->program->additional_ods, od_index);
esd_count = gf_list_count(od->ESDescriptors);
for (k = 0; k < esd_count; k++) {
GF_ESD *esd_tmp = (GF_ESD *)gf_list_get(od->ESDescriptors, k);
if (esd_tmp->ESID != es->mpeg4_es_id) continue;
esd = esd_tmp;
break;
}
}
}
return esd;
}
void gf_m2ts_set_segment_switch(GF_M2TS_Demuxer *ts)
{
u32 i;
for (i=0; i<GF_M2TS_MAX_STREAMS; i++) {
GF_M2TS_ES *es = (GF_M2TS_ES *) ts->ess[i];
if (!es) continue;
es->flags |= GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY;
}
}
GF_EXPORT
void gf_m2ts_reset_parsers_for_program(GF_M2TS_Demuxer *ts, GF_M2TS_Program *prog)
{
u32 i;
for (i=0; i<GF_M2TS_MAX_STREAMS; i++) {
GF_M2TS_ES *es = (GF_M2TS_ES *) ts->ess[i];
if (!es) continue;
if (prog && (es->program != prog) ) continue;
if (es->flags & GF_M2TS_ES_IS_SECTION) {
GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es;
gf_m2ts_section_filter_reset(ses->sec);
} else {
GF_M2TS_PES *pes = (GF_M2TS_PES *)es;
if (!pes || (pes->pid==pes->program->pmt_pid)) continue;
pes->cc = -1;
pes->frame_state = 0;
pes->pck_data_len = 0;
if (pes->prev_data) gf_free(pes->prev_data);
pes->prev_data = NULL;
pes->prev_data_len = 0;
pes->PTS = pes->DTS = 0;
pes->pes_len = pes->pes_end_packet_number = pes->pes_start_packet_number = 0;
if (pes->buf) gf_free(pes->buf);
pes->buf = NULL;
if (pes->temi_tc_desc) gf_free(pes->temi_tc_desc);
pes->temi_tc_desc = NULL;
pes->temi_tc_desc_len = pes->temi_tc_desc_alloc_size = 0;
pes->before_last_pcr_value = pes->before_last_pcr_value_pck_number = 0;
pes->last_pcr_value = pes->last_pcr_value_pck_number = 0;
if (pes->program->pcr_pid==pes->pid) {
pes->program->last_pcr_value = pes->program->last_pcr_value_pck_number = 0;
pes->program->before_last_pcr_value = pes->program->before_last_pcr_value_pck_number = 0;
}
}
}
}
GF_EXPORT
void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts)
{
gf_m2ts_reset_parsers_for_program(ts, NULL);
ts->pck_number = 0;
gf_m2ts_section_filter_reset(ts->cat);
gf_m2ts_section_filter_reset(ts->pat);
gf_m2ts_section_filter_reset(ts->sdt);
gf_m2ts_section_filter_reset(ts->nit);
gf_m2ts_section_filter_reset(ts->eit);
gf_m2ts_section_filter_reset(ts->tdt_tot);
}
static void gf_m2ts_process_section_discard(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *es, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status)
{
}
GF_EXPORT
u32 gf_m2ts_pes_get_framing_mode(GF_M2TS_PES *pes)
{
if (pes->flags & GF_M2TS_ES_IS_SECTION) {
if (pes->flags & GF_M2TS_ES_IS_SL) {
if ( ((GF_M2TS_SECTION_ES *)pes)->sec->process_section == gf_m2ts_process_section_discard)
return GF_M2TS_PES_FRAMING_DEFAULT;
}
return GF_M2TS_PES_FRAMING_SKIP_NO_RESET;
}
if (!pes->reframe ) return GF_M2TS_PES_FRAMING_SKIP_NO_RESET;
if (pes->reframe == gf_m2ts_reframe_default) return GF_M2TS_PES_FRAMING_RAW;
if (pes->reframe == gf_m2ts_reframe_reset) return GF_M2TS_PES_FRAMING_SKIP;
if (pes->single_nal_mode) return GF_M2TS_PES_FRAMING_DEFAULT_NAL;
return GF_M2TS_PES_FRAMING_DEFAULT;
}
GF_EXPORT
GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, u32 mode)
{
if (!pes) return GF_BAD_PARAM;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Setting pes framing mode of PID %d to %d\n", pes->pid, mode) );
if (pes->flags & GF_M2TS_ES_IS_SECTION) {
if (pes->flags & GF_M2TS_ES_IS_SL) {
if (mode==GF_M2TS_PES_FRAMING_DEFAULT) {
((GF_M2TS_SECTION_ES *)pes)->sec->process_section = gf_m2ts_process_mpeg4section;
} else {
((GF_M2TS_SECTION_ES *)pes)->sec->process_section = gf_m2ts_process_section_discard;
}
}
return GF_OK;
}
if (pes->pid==pes->program->pmt_pid) return GF_BAD_PARAM;
if ((mode > GF_M2TS_PES_FRAMING_SKIP) && (pes->program->ts->ess[pes->pid] != (GF_M2TS_ES *) pes)) {
GF_M2TS_PES *o_pes = (GF_M2TS_PES *) pes->program->ts->ess[pes->pid];
if (o_pes->flags & GF_M2TS_ES_IS_PES)
gf_m2ts_set_pes_framing(o_pes, GF_M2TS_PES_FRAMING_SKIP);
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] Reassinging PID %d from program %d to program %d\n", pes->pid, o_pes->program->number, pes->program->number) );
pes->program->ts->ess[pes->pid] = (GF_M2TS_ES *) pes;
}
switch (mode) {
case GF_M2TS_PES_FRAMING_RAW:
pes->reframe = gf_m2ts_reframe_default;
break;
case GF_M2TS_PES_FRAMING_SKIP:
pes->reframe = gf_m2ts_reframe_reset;
break;
case GF_M2TS_PES_FRAMING_SKIP_NO_RESET:
pes->reframe = NULL;
break;
case GF_M2TS_PES_FRAMING_DEFAULT_NAL:
case GF_M2TS_PES_FRAMING_DEFAULT:
default:
switch (pes->stream_type) {
case GF_M2TS_VIDEO_MPEG1:
case GF_M2TS_VIDEO_MPEG2:
pes->reframe = gf_m2ts_reframe_mpeg_video;
break;
case GF_M2TS_VIDEO_H264:
case GF_M2TS_VIDEO_SVC:
pes->reframe = gf_m2ts_reframe_avc_h264;
pes->single_nal_mode = (mode==GF_M2TS_PES_FRAMING_DEFAULT_NAL) ? 1 : 0;
break;
case GF_M2TS_VIDEO_HEVC:
case GF_M2TS_VIDEO_SHVC:
case GF_M2TS_VIDEO_SHVC_TEMPORAL:
case GF_M2TS_VIDEO_MHVC:
case GF_M2TS_VIDEO_MHVC_TEMPORAL:
pes->reframe = gf_m2ts_reframe_hevc;
pes->single_nal_mode = (mode==GF_M2TS_PES_FRAMING_DEFAULT_NAL) ? 1 : 0;
break;
#ifndef GPAC_DISABLE_AV_PARSERS
case GF_M2TS_AUDIO_MPEG1:
case GF_M2TS_AUDIO_MPEG2:
pes->reframe = gf_m2ts_reframe_mpeg_audio;
break;
case GF_M2TS_AUDIO_AAC:
pes->reframe = gf_m2ts_reframe_aac_adts;
break;
case GF_M2TS_AUDIO_LATM_AAC:
pes->reframe = gf_m2ts_reframe_aac_latm;
break;
case GF_M2TS_AUDIO_AC3:
pes->reframe = gf_m2ts_reframe_ac3;
break;
case GF_M2TS_AUDIO_EC3:
pes->reframe = gf_m2ts_reframe_ec3;
break;
#endif
case GF_M2TS_PRIVATE_DATA:
break;
case GF_M2TS_METADATA_ID3_HLS:
pes->reframe = gf_m2ts_reframe_id3_pes;
break;
default:
pes->reframe = gf_m2ts_reframe_default;
break;
}
break;
}
return GF_OK;
}
GF_EXPORT
GF_M2TS_Demuxer *gf_m2ts_demux_new()
{
GF_M2TS_Demuxer *ts;
GF_SAFEALLOC(ts, GF_M2TS_Demuxer);
if (!ts) return NULL;
ts->programs = gf_list_new();
ts->SDTs = gf_list_new();
ts->pat = gf_m2ts_section_filter_new(gf_m2ts_process_pat, 0);
ts->cat = gf_m2ts_section_filter_new(gf_m2ts_process_cat, 0);
ts->sdt = gf_m2ts_section_filter_new(gf_m2ts_process_sdt, 1);
ts->nit = gf_m2ts_section_filter_new(gf_m2ts_process_nit, 0);
ts->eit = gf_m2ts_section_filter_new(NULL, 1);
ts->tdt_tot = gf_m2ts_section_filter_new(gf_m2ts_process_tdt_tot, 1);
#ifdef GPAC_ENABLE_MPE
gf_dvb_mpe_init(ts);
#endif
ts->requested_progs = gf_list_new();
ts->requested_pids = gf_list_new();
ts->demux_and_play = 0;
ts->nb_prog_pmt_received = 0;
ts->ChannelAppList = gf_list_new();
return ts;
}
GF_EXPORT
void gf_m2ts_abort_parsing(GF_M2TS_Demuxer *ts, Bool force_reset_pes)
{
u32 i, j, count, count2;
if (force_reset_pes) {
count = gf_list_count(ts->programs);
for (i=0; i<count; i++) {
GF_M2TS_Program *prog = (GF_M2TS_Program *)gf_list_get(ts->programs, i);
count2 = gf_list_count(prog->streams);
for (j=0; j<count2; j++) {
GF_M2TS_PES *pes = (GF_M2TS_PES *)gf_list_get(prog->streams, j);
if (pes)
pes->pck_data_len = 0;
}
}
}
ts->abort_parsing = GF_TRUE;
}
GF_EXPORT
void gf_m2ts_demux_dmscc_init(GF_M2TS_Demuxer *ts) {
char* temp_dir;
u32 length;
GF_Err e;
ts->dsmcc_controler = gf_list_new();
ts->process_dmscc = 1;
temp_dir = gf_get_default_cache_directory();
length = (u32) strlen(temp_dir);
if(temp_dir[length-1] == GF_PATH_SEPARATOR) {
temp_dir[length-1] = 0;
}
ts->dsmcc_root_dir = (char*)gf_calloc(strlen(temp_dir)+strlen("CarouselData")+2,sizeof(char));
sprintf(ts->dsmcc_root_dir,"%s%cCarouselData",temp_dir,GF_PATH_SEPARATOR);
e = gf_mkdir(ts->dsmcc_root_dir);
if(e) {
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[Process DSMCC] Error during the creation of the directory %s \n",ts->dsmcc_root_dir));
}
}
GF_EXPORT
void gf_m2ts_demux_del(GF_M2TS_Demuxer *ts)
{
u32 i;
if (ts->pat) gf_m2ts_section_filter_del(ts->pat);
if (ts->cat) gf_m2ts_section_filter_del(ts->cat);
if (ts->sdt) gf_m2ts_section_filter_del(ts->sdt);
if (ts->nit) gf_m2ts_section_filter_del(ts->nit);
if (ts->eit) gf_m2ts_section_filter_del(ts->eit);
if (ts->tdt_tot) gf_m2ts_section_filter_del(ts->tdt_tot);
for (i=0; i<GF_M2TS_MAX_STREAMS; i++) {
if (ts->ess[i] && (ts->ess[i]->pid==i)) gf_m2ts_es_del(ts->ess[i], ts);
}
if (ts->buffer) gf_free(ts->buffer);
while (gf_list_count(ts->programs)) {
GF_M2TS_Program *p = (GF_M2TS_Program *)gf_list_last(ts->programs);
gf_list_rem_last(ts->programs);
gf_list_del(p->streams);
if (p->additional_ods) {
gf_odf_desc_list_del(p->additional_ods);
gf_list_del(p->additional_ods);
}
if (p->pmt_iod) gf_odf_desc_del((GF_Descriptor *)p->pmt_iod);
gf_free(p);
}
gf_list_del(ts->programs);
if (ts->TDT_time) gf_free(ts->TDT_time);
gf_m2ts_reset_sdt(ts);
if (ts->tdt_tot)
gf_list_del(ts->SDTs);
#ifdef GPAC_ENABLE_MPE
gf_dvb_mpe_shutdown(ts);
#endif
if(gf_list_count(ts->dsmcc_controler)) {
#ifdef GPAC_ENABLE_DSMCC
GF_M2TS_DSMCC_OVERLORD* dsmcc_overlord = (GF_M2TS_DSMCC_OVERLORD*)gf_list_get(ts->dsmcc_controler,0);
gf_cleanup_dir(dsmcc_overlord->root_dir);
gf_rmdir(dsmcc_overlord->root_dir);
gf_m2ts_delete_dsmcc_overlord(dsmcc_overlord);
if(ts->dsmcc_root_dir) {
gf_free(ts->dsmcc_root_dir);
}
#endif
}
while(gf_list_count(ts->ChannelAppList)) {
#ifdef GPAC_ENABLE_DSMCC
GF_M2TS_CHANNEL_APPLICATION_INFO* ChanAppInfo = (GF_M2TS_CHANNEL_APPLICATION_INFO*)gf_list_get(ts->ChannelAppList,0);
gf_m2ts_delete_channel_application_info(ChanAppInfo);
gf_list_rem(ts->ChannelAppList,0);
#endif
}
gf_list_del(ts->ChannelAppList);
if (ts->requested_progs) {
assert(!gf_list_count(ts->requested_progs));
gf_list_del(ts->requested_progs);
}
if (ts->requested_pids) {
assert(!gf_list_count(ts->requested_pids));
gf_list_del(ts->requested_pids);
}
if (ts->th)
gf_th_del(ts->th);
if (ts->socket_url) gf_free(ts->socket_url);
gf_free(ts);
}
void gf_m2ts_print_info(GF_M2TS_Demuxer *ts)
{
#ifdef GPAC_ENABLE_MPE
gf_m2ts_print_mpe_info(ts);
#endif
}
GF_EXPORT
void gf_m2ts_pause_demux(GF_M2TS_Demuxer *ts, Bool do_pause)
{
if (ts) ts->paused = do_pause;
}
GF_EXPORT
GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_byterange, u64 end_byterange, u32 refresh_type, Bool signal_end_of_stream)
{
u32 i;
GF_Err e;
u32 size;
u64 read;
GF_BitStream *bs = NULL;
FILE *f = NULL;
if (!fileName) {
if (!signal_end_of_stream) return GF_BAD_PARAM;
ts->pos_in_stream = 0;
}
else if (fileName && !strnicmp(fileName, "gmem://", 7)) {
void *mem_address;
u32 remain;
if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", fileName));
return GF_URL_ERROR;
}
if (refresh_type==0)
ts->pos_in_stream = 0;
mem_address = (u8 *) mem_address + ts->pos_in_stream;
size -= (u32) ts->pos_in_stream;
remain = (size % 188);
size -= remain;
ts->abort_parsing = GF_FALSE;
gf_m2ts_process_data(ts, mem_address, size);
if (refresh_type==2)
ts->pos_in_stream = 0;
else
ts->pos_in_stream += size;
} else if (fileName) {
char data[188000];
f = gf_fopen(fileName, "rb");
if (!f) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", fileName));
return GF_URL_ERROR;
}
bs = gf_bs_from_file(f, GF_BITSTREAM_READ);
if (refresh_type) {
if (ts->pos_in_stream) {
gf_bs_seek(bs, ts->pos_in_stream);
}
} else {
if (start_byterange) {
gf_bs_seek(bs, start_byterange);
}
}
read = 0;
ts->abort_parsing = GF_FALSE;
while (1) {
u32 to_read = 188000;
Bool done = 0;
u64 avail = gf_bs_available(bs);
if (avail < 188)
break;
if (end_byterange && (read + to_read > end_byterange)) {
to_read = (u32) (end_byterange - read);
done = 1;
}
if (to_read > avail) {
u32 skip = avail % 188;
to_read = (u32) (avail - skip);
done = 1;
}
size = gf_bs_read_data(bs, data, to_read);
if (size) {
e = gf_m2ts_process_data(ts, data, size);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Error %s while demuxing %s\n", gf_error_to_string(e), fileName));
}
}
read += size;
if (done) break;
if (ts->abort_parsing)
break;
}
if ((refresh_type==2) || !gf_bs_available(bs)) {
ts->pos_in_stream = 0;
} else {
ts->pos_in_stream = gf_bs_get_position(bs);
}
gf_bs_del(bs);
gf_fclose(f);
ts->abort_parsing = GF_FALSE;
}
if (signal_end_of_stream && !ts->pos_in_stream) {
for (i=0; i<GF_M2TS_MAX_STREAMS; i++) {
if (ts->ess[i]) {
if (ts->ess[i]->flags & GF_M2TS_ES_IS_PES) {
gf_m2ts_flush_pes(ts, (GF_M2TS_PES *) ts->ess[i]);
ts->on_event(ts, GF_M2TS_EVT_EOS, (GF_M2TS_PES *) ts->ess[i]);
}
}
}
}
return GF_OK;
}
static u32 gf_m2ts_demuxer_run(void *_p)
{
u32 i;
GF_Err e;
char data[GF_M2TS_UDP_BUFFER_SIZE];
u32 size;
GF_M2TS_Demuxer *ts = _p;
gf_m2ts_reset_parsers(ts);
ts->abort_parsing = GF_FALSE;
if (ts->socket_url && !ts->sock) {
gf_m2ts_get_socket(ts->socket_url, ts->network_type, GF_M2TS_UDP_BUFFER_SIZE, &ts->sock);
}
#ifdef GPAC_HAS_LINUX_DVB
if (ts->tuner) {
s32 ts_size;
while (ts->run_state) {
if (ts->paused) {
gf_sleep(1);
continue;
}
ts_size = read(ts->tuner->ts_fd, data, GF_M2TS_UDP_BUFFER_SIZE);
if (ts_size>0) gf_m2ts_process_data(ts, data, (u32) ts_size);
}
} else
#endif
if (ts->sock) {
#ifndef GPAC_DISABLE_STREAMING
u16 seq_num;
GF_RTPReorder *ch = NULL;
#endif
u32 nb_empty=0;
Bool first_run, is_rtp;
FILE *record_to = NULL;
if (ts->record_to)
record_to = gf_fopen(ts->record_to, "wb");
first_run = 1;
is_rtp = 0;
while (ts->run_state) {
if (ts->paused) {
gf_sleep(1);
continue;
}
size = 0;
e = gf_sk_receive(ts->sock, data, GF_M2TS_UDP_BUFFER_SIZE, 0, &size);
if (!size || e) {
nb_empty++;
if (nb_empty==1000) {
gf_sleep(1);
nb_empty=0;
}
continue;
}
if (first_run) {
first_run = 0;
if ((data[0] != 0x47) && ((data[1] & 0x7F) == 33) ) {
is_rtp = 1;
#ifndef GPAC_DISABLE_STREAMING
ch = gf_rtp_reorderer_new(100, 500);
#endif
}
}
if (is_rtp) {
#ifndef GPAC_DISABLE_STREAMING
char *pck;
seq_num = ((data[2] << 8) & 0xFF00) | (data[3] & 0xFF);
gf_rtp_reorderer_add(ch, (void *) data, size, seq_num);
pck = (char *) gf_rtp_reorderer_get(ch, &size);
if (pck) {
gf_m2ts_process_data(ts, pck+12, size-12);
if (record_to)
fwrite(data+12, size-12, 1, record_to);
gf_free(pck);
}
#else
gf_m2ts_process_data(ts, data+12, size-12);
if (record_to)
fwrite(data+12, size-12, 1, record_to);
#endif
} else {
gf_m2ts_process_data(ts, data, size);
if (record_to)
fwrite(data, size, 1, record_to);
}
}
if (record_to)
gf_fclose(record_to);
#ifndef GPAC_DISABLE_STREAMING
if (ch)
gf_rtp_reorderer_del(ch);
#endif
if (ts->sock && !ts->sock_is_delegate) gf_sk_del(ts->sock);
ts->sock = NULL;
} else if (ts->dnload) {
while (ts->run_state) {
gf_dm_sess_process(ts->dnload);
gf_sleep(1);
}
} else {
u32 pos = 0;
GF_BitStream *ts_bs = NULL;
if (ts->file)
ts_bs = gf_bs_from_file(ts->file, GF_BITSTREAM_READ);
else
ts_bs = gf_bs_new(ts->ts_data_chunk, ts->ts_data_chunk_size, GF_BITSTREAM_READ);
gf_bs_seek(ts_bs, 0);
while (ts->run_state && gf_bs_available(ts_bs) && !ts->force_file_refresh) {
if (ts->paused) {
gf_sleep(1);
continue;
}
if (ts->start_range && ts->duration) {
Double perc = ts->start_range / (1000 * ts->duration);
pos = (u32) (s64) (perc * ts->file_size);
pos/=188;
pos*=188;
if (pos>=ts->file_size) {
pos = 0;
}
ts->start_range = 0;
gf_bs_seek(ts_bs, pos);
}
size = gf_bs_read_data(ts_bs, data, 188);
if (!size && (ts->loop_demux == 1)) {
gf_bs_seek(ts_bs, pos);
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] Loop \n"));
size = gf_bs_read_data(ts_bs, data, 188);
}
if (!size) break;
if (size != 188) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] %u bytes read from file instead of 188.\n", size));
}
gf_m2ts_process_data(ts, data, size);
ts->nb_pck++;
if (!gf_bs_available(ts_bs) && ts->loop_demux == 1) {
gf_bs_seek(ts_bs, pos);
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] Loop \n"));
gf_sleep(3000);
}
}
ts->force_file_refresh = 0;
if (ts_bs) {
gf_bs_del(ts_bs);
ts_bs = NULL;
}
}
for (i=0; i<GF_M2TS_MAX_STREAMS; i++) {
if (ts->ess[i]) {
if (ts->ess[i]->flags & GF_M2TS_ES_IS_PES) {
gf_m2ts_flush_pes(ts, (GF_M2TS_PES *) ts->ess[i]);
ts->on_event(ts, GF_M2TS_EVT_EOS, (GF_M2TS_PES *) ts->ess[i]);
}
}
}
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] EOS reached\n"));
ts->run_state = 2;
return 0;
}
GF_EXPORT
GF_Err gf_m2ts_get_socket(const char *url, const char *mcast_ifce_or_mobileip, u32 buf_size, GF_Socket **out_socket)
{
char *str;
u16 port;
GF_Err e;
u32 sock_type = 0;
*out_socket=NULL;
if (!strnicmp(url, "udp://", 6) || !strnicmp(url, "mpegts-udp://", 13)) {
sock_type = GF_SOCK_TYPE_UDP;
} else if (!strnicmp(url, "mpegts-tcp://", 13) ) {
sock_type = GF_SOCK_TYPE_TCP;
} else {
return GF_NOT_SUPPORTED;
}
url = strchr(url, ':');
url += 3;
*out_socket = gf_sk_new(sock_type);
if (! (*out_socket) ) {
return GF_IO_ERR;
}
port = 1234;
str = strrchr(url, ':');
if (str && strchr(str, ']')) str = strchr(url, ':');
if (str) {
port = atoi(str+1);
str[0] = 0;
}
if (strlen(url) && strcmp(url, "localhost") ) {
if (gf_sk_is_multicast_address(url)) {
e = gf_sk_setup_multicast(*out_socket, url, port, 0, 0, (char*)mcast_ifce_or_mobileip);
} else {
e = gf_sk_bind(*out_socket, (char*)mcast_ifce_or_mobileip, port, url, 0, GF_SOCK_REUSE_PORT);
}
if (e) {
gf_sk_del(*out_socket);
*out_socket = NULL;
return e;
}
}
if (str) str[0] = ':';
gf_sk_set_buffer_size(*out_socket, 0, buf_size);
gf_sk_set_block_mode(*out_socket, 0);
return GF_OK;
}
static GF_Err gf_m2ts_demuxer_setup_live(GF_M2TS_Demuxer *ts, char *url)
{
if (!strnicmp(url, "mpegts-sk://", 12)) {
sscanf(url, "mpegts-sk://%p", &ts->sock);
ts->sock_is_delegate = GF_TRUE;
} else {
GF_Err e;
e = gf_m2ts_get_socket(url, ts->network_type, GF_M2TS_UDP_BUFFER_SIZE, &ts->sock);
if (e) return e;
}
if (ts->socket_url) gf_free(ts->socket_url);
ts->socket_url = gf_strdup(url);
return gf_m2ts_demuxer_play(ts);
}
#ifdef GPAC_HAS_LINUX_DVB
static GF_Err gf_dvb_tune(GF_Tuner *tuner, const char *url, const char *chan_path) {
struct dmx_pes_filter_params pesFilterParams;
struct dvb_frontend_parameters frp;
int demux1, front1;
FILE *chanfile;
char line[255], chan_name_t[255];
char freq_str[255], inv[255], bw[255], lcr[255], hier[255], cr[255],
mod[255], transm[255], gi[255], apid_str[255], vpid_str[255];
const char *chan_conf = ":%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:";
char *chan_name;
char *tmp;
char frontend_name[100], demux_name[100], dvr_name[100];
u32 adapter_num;
chanfile = gf_fopen(chan_path, "r");
if (!chanfile) return GF_BAD_PARAM;
chan_name = (char *) url+6;
tmp = strchr(chan_name, '@');
if (tmp) {
adapter_num = atoi(tmp+1);
tmp[0] = 0;
} else {
adapter_num = 0;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Channel name %s\n", chan_name));
while(!feof(chanfile)) {
if ( fgets(line, 255, chanfile) != NULL) {
if (line[0]=='#') continue;
if (line[0]=='\r') continue;
if (line[0]=='\n') continue;
strncpy(chan_name_t, line, index(line, ':')-line);
if (strncmp(chan_name,chan_name_t,strlen(chan_name))==0) {
sscanf(strstr(line,":"), chan_conf, freq_str, inv, bw, lcr, cr, mod, transm, gi, hier, apid_str, vpid_str);
tuner->freq = (uint32_t) atoi(freq_str);
tuner->apid = (uint16_t) atoi(apid_str);
tuner->vpid = (uint16_t) atoi(vpid_str);
if(! strcmp(inv, "INVERSION_ON")) tuner->specInv = INVERSION_ON;
else if(! strcmp(inv, "INVERSION_OFF")) tuner->specInv = INVERSION_OFF;
else tuner->specInv = INVERSION_AUTO;
if(! strcmp(lcr, "FEC_1_2")) tuner->LP_CodeRate =FEC_1_2;
else if(! strcmp(lcr, "FEC_2_3")) tuner->LP_CodeRate =FEC_2_3;
else if(! strcmp(lcr, "FEC_3_4")) tuner->LP_CodeRate =FEC_3_4;
else if(! strcmp(lcr, "FEC_4_5")) tuner->LP_CodeRate =FEC_4_5;
else if(! strcmp(lcr, "FEC_6_7")) tuner->LP_CodeRate =FEC_6_7;
else if(! strcmp(lcr, "FEC_8_9")) tuner->LP_CodeRate =FEC_8_9;
else if(! strcmp(lcr, "FEC_5_6")) tuner->LP_CodeRate =FEC_5_6;
else if(! strcmp(lcr, "FEC_7_8")) tuner->LP_CodeRate =FEC_7_8;
else if(! strcmp(lcr, "FEC_NONE")) tuner->LP_CodeRate =FEC_NONE;
else tuner->LP_CodeRate =FEC_AUTO;
if(! strcmp(cr, "FEC_1_2")) tuner->HP_CodeRate =FEC_1_2;
else if(! strcmp(cr, "FEC_2_3")) tuner->HP_CodeRate =FEC_2_3;
else if(! strcmp(cr, "FEC_3_4")) tuner->HP_CodeRate =FEC_3_4;
else if(! strcmp(cr, "FEC_4_5")) tuner->HP_CodeRate =FEC_4_5;
else if(! strcmp(cr, "FEC_6_7")) tuner->HP_CodeRate =FEC_6_7;
else if(! strcmp(cr, "FEC_8_9")) tuner->HP_CodeRate =FEC_8_9;
else if(! strcmp(cr, "FEC_5_6")) tuner->HP_CodeRate =FEC_5_6;
else if(! strcmp(cr, "FEC_7_8")) tuner->HP_CodeRate =FEC_7_8;
else if(! strcmp(cr, "FEC_NONE")) tuner->HP_CodeRate =FEC_NONE;
else tuner->HP_CodeRate =FEC_AUTO;
if(! strcmp(mod, "QAM_128")) tuner->modulation = QAM_128;
else if(! strcmp(mod, "QAM_256")) tuner->modulation = QAM_256;
else if(! strcmp(mod, "QAM_64")) tuner->modulation = QAM_64;
else if(! strcmp(mod, "QAM_32")) tuner->modulation = QAM_32;
else if(! strcmp(mod, "QAM_16")) tuner->modulation = QAM_16;
if(! strcmp(bw, "BANDWIDTH_6_MHZ")) tuner->bandwidth = BANDWIDTH_6_MHZ;
else if(! strcmp(bw, "BANDWIDTH_7_MHZ")) tuner->bandwidth = BANDWIDTH_7_MHZ;
else if(! strcmp(bw, "BANDWIDTH_8_MHZ")) tuner->bandwidth = BANDWIDTH_8_MHZ;
if(! strcmp(transm, "TRANSMISSION_MODE_2K")) tuner->TransmissionMode = TRANSMISSION_MODE_2K;
else if(! strcmp(transm, "TRANSMISSION_MODE_8K")) tuner->TransmissionMode = TRANSMISSION_MODE_8K;
if(! strcmp(gi, "GUARD_INTERVAL_1_32")) tuner->guardInterval = GUARD_INTERVAL_1_32;
else if(! strcmp(gi, "GUARD_INTERVAL_1_16")) tuner->guardInterval = GUARD_INTERVAL_1_16;
else if(! strcmp(gi, "GUARD_INTERVAL_1_8")) tuner->guardInterval = GUARD_INTERVAL_1_8;
else tuner->guardInterval = GUARD_INTERVAL_1_4;
if(! strcmp(hier, "HIERARCHY_1")) tuner->hierarchy = HIERARCHY_1;
else if(! strcmp(hier, "HIERARCHY_2")) tuner->hierarchy = HIERARCHY_2;
else if(! strcmp(hier, "HIERARCHY_4")) tuner->hierarchy = HIERARCHY_4;
else if(! strcmp(hier, "HIERARCHY_AUTO")) tuner->hierarchy = HIERARCHY_AUTO;
else tuner->hierarchy = HIERARCHY_NONE;
break;
}
}
}
gf_fclose(chanfile);
sprintf(frontend_name, "/dev/dvb/adapter%d/frontend0", adapter_num);
sprintf(demux_name, "/dev/dvb/adapter%d/demux0", adapter_num);
sprintf(dvr_name, "/dev/dvb/adapter%d/dvr0", adapter_num);
if((front1 = open(frontend_name,O_RDWR|O_NONBLOCK)) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Cannot open frontend %s.\n", frontend_name));
return GF_IO_ERR;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Frontend %s opened.\n", frontend_name));
}
if ((demux1=open(demux_name, O_RDWR|O_NONBLOCK)) < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Cannot open demux %s\n", demux_name));
return GF_IO_ERR;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Demux %s opened.\n", demux_name));
}
frp.frequency = tuner->freq;
frp.inversion = tuner->specInv;
frp.u.ofdm.bandwidth = tuner->bandwidth;
frp.u.ofdm.code_rate_HP = tuner->HP_CodeRate;
frp.u.ofdm.code_rate_LP = tuner->LP_CodeRate;
frp.u.ofdm.constellation = tuner->modulation;
frp.u.ofdm.transmission_mode = tuner->TransmissionMode;
frp.u.ofdm.guard_interval = tuner->guardInterval;
frp.u.ofdm.hierarchy_information = tuner->hierarchy;
if (ioctl(front1, FE_SET_FRONTEND, &frp) < 0) {
return GF_IO_ERR;
}
pesFilterParams.pid = 0x2000;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = DMX_OUT_TS_TAP;
pesFilterParams.pes_type = DMX_PES_OTHER;
pesFilterParams.flags = DMX_IMMEDIATE_START;
if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
return GF_IO_ERR;
}
if ((tuner->ts_fd = open(dvr_name, O_RDONLY)) < 0) {
return GF_IO_ERR;
}
return GF_OK;
}
GF_EXPORT
u32 gf_dvb_get_freq_from_url(const char *channels_config_path, const char *url)
{
FILE *channels_config_file;
char line[255], *tmp, *channel_name;
u32 freq;
tmp = strchr(url, '@');
if (tmp) tmp[0] = 0;
channel_name = (char *)url+6;
channels_config_file = gf_fopen(channels_config_path, "r");
if (!channels_config_file) return GF_BAD_PARAM;
freq = 0;
while(!feof(channels_config_file)) {
if ( fgets(line, 255, channels_config_file) != NULL) {
if (line[0]=='#') continue;
if (line[0]=='\r') continue;
if (line[0]=='\n') continue;
tmp = strchr(line, ':');
tmp[0] = 0;
if (!strcmp(line, channel_name)) {
char *tmp2;
tmp++;
tmp2 = strchr(tmp, ':');
if (tmp2) tmp2[0] = 0;
freq = (u32)atoi(tmp);
break;
}
}
}
return freq;
}
GF_Err gf_m2ts_demuxer_setup_dvb(GF_M2TS_Demuxer *ts, const char *url)
{
GF_Err e = GF_OK;
if (! ts->dvb_channels_conf_path) return GF_BAD_PARAM;
if (strnicmp(url, "dvb://", 6)) return GF_NOT_SUPPORTED;
if (!ts->tuner) GF_SAFEALLOC(ts->tuner, GF_Tuner);
if (ts->tuner->freq != 0 && ts->tuner->freq == gf_dvb_get_freq_from_url(ts->dvb_channels_conf_path, url)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Tuner already tuned to that frequency\n"));
return GF_OK;
}
e = gf_dvb_tune(ts->tuner, url, ts->dvb_channels_conf_path);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Unable to tune to frequency\n"));
return GF_SERVICE_ERROR;
}
return gf_m2ts_demuxer_play(ts);
}
#endif
static GF_Err gf_m2ts_demuxer_setup_file(GF_M2TS_Demuxer *ts, char *url)
{
if (url) {
if (ts->file && !strcmp(ts->filename, url)) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] TS file already being processed: %s\n", url));
return GF_IO_ERR;
}
strcpy(ts->filename, url);
if (!strncmp(url, "gmem://", 7)) {
u32 size;
void *mem_address;
if (sscanf(url, "gmem://%d@%p", &size, &mem_address) != 2)
return GF_IO_ERR;
ts->ts_data_chunk_size = size;
ts->ts_data_chunk = mem_address;
} else {
ts->file = gf_fopen(url, "rb");
if (!ts->file) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] Could not open TS file: %s\n", url));
return GF_IO_ERR;
}
strcpy(ts->filename, url);
gf_fseek(ts->file, 0, SEEK_END);
ts->file_size = gf_ftell(ts->file);
gf_fseek(ts->file, 0, SEEK_SET);
}
}
ts->end_range = ts->start_range = 0;
return gf_m2ts_demuxer_play(ts);
}
GF_EXPORT
GF_Err gf_m2ts_demuxer_setup(GF_M2TS_Demuxer *ts, const char *url, Bool loop)
{
char szURL[2048];
char *frag;
ts->duration = 0;
if(loop == 1) {
ts->loop_demux = 1;
GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Loop Mode activated \n"));
}
if (!url) {
return gf_m2ts_demuxer_setup_file(ts, NULL);
}
strcpy(szURL, url);
frag = strrchr(szURL, '#');
if (frag) frag[0] = 0;
if (!strnicmp(url, "udp://", 6)
|| !strnicmp(url, "mpegts-udp://", 13)
|| !strnicmp(url, "mpegts-tcp://", 13)
|| !strnicmp(url, "mpegts-sk://", 12)
) {
return gf_m2ts_demuxer_setup_live(ts, (char *) szURL);
}
#ifdef GPAC_HAS_LINUX_DVB
else if (!strnicmp(url, "dvb://", 6)) {
return gf_m2ts_demuxer_setup_dvb(ts, (char *) szURL);
}
#endif
else {
return gf_m2ts_demuxer_setup_file(ts, (char *) szURL);
}
return GF_NOT_SUPPORTED;
}
GF_EXPORT
GF_Err gf_m2ts_demuxer_close(GF_M2TS_Demuxer *ts)
{
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[TSDemux] Destroying demuxer\n"));
if (ts->th) {
if (ts->run_state == 1) {
ts->run_state = 0;
while (ts->run_state!=2) gf_sleep(0);
}
gf_th_del(ts->th);
ts->th = NULL;
}
if (ts->file) gf_fclose(ts->file);
ts->file = NULL;
ts->ts_data_chunk = NULL;
return GF_OK;
}
GF_EXPORT
GF_Err gf_m2ts_demuxer_play(GF_M2TS_Demuxer *ts)
{
ts->run_state = 1;
if(ts->th) {
return gf_th_run(ts->th, gf_m2ts_demuxer_run, ts);
} else {
return gf_m2ts_demuxer_run(ts);
}
}
#define M2TS_PROBE_SIZE 188000
GF_EXPORT
Bool gf_m2ts_probe_file(const char *fileName)
{
char buf[M2TS_PROBE_SIZE];
GF_Err e;
u32 size;
FILE *t;
GF_M2TS_Demuxer *ts;
if (!strncmp(fileName, "gmem://", 7)) {
u8 *mem_address;
if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) {
return GF_FALSE;
}
if (size>M2TS_PROBE_SIZE) size = M2TS_PROBE_SIZE;
memcpy(buf, mem_address, size);
} else {
t = gf_fopen(fileName, "rb");
if (!t) return 0;
size = (u32) fread(buf, 1, M2TS_PROBE_SIZE, t);
gf_fclose(t);
if ((s32) size <= 0) return 0;
}
ts = gf_m2ts_demux_new();
e = gf_m2ts_process_data(ts, buf, size);
if (!ts->pck_number) e = GF_BAD_PARAM;
gf_m2ts_demux_del(ts);
if (e) return 0;
return 1;
}
static void rewrite_pts_dts(unsigned char *ptr, u64 TS)
{
ptr[0] &= 0xf1;
ptr[0] |= (unsigned char)((TS&0x1c0000000ULL)>>29);
ptr[1] = (unsigned char)((TS&0x03fc00000ULL)>>22);
ptr[2] &= 0x1;
ptr[2] |= (unsigned char)((TS&0x0003f8000ULL)>>14);
ptr[3] = (unsigned char)((TS&0x000007f80ULL)>>7);
ptr[4] &= 0x1;
ptr[4] |= (unsigned char)((TS&0x00000007fULL)<<1);
assert(((u64)(ptr[0]&0xe)<<29) + ((u64)ptr[1]<<22) + ((u64)(ptr[2]&0xfe)<<14) + ((u64)ptr[3]<<7) + ((ptr[4]&0xfe)>>1) == TS);
}
#define ADJUST_TIMESTAMP(_TS) \
if (_TS < (u64) -ts_shift) _TS = pcr_mod + _TS + ts_shift; \
else _TS = _TS + ts_shift; \
while (_TS > pcr_mod) _TS -= pcr_mod; \
GF_Err gf_m2ts_restamp(char *buffer, u32 size, s64 ts_shift, u8 *is_pes)
{
u32 done = 0;
u64 pcr_mod;
pcr_mod = 0x80000000;
pcr_mod*=4;
while (done + 188 <= size) {
u8 *pesh;
u8 *pck;
u64 pcr_base=0, pcr_ext=0;
u16 pid;
u8 adaptation_field, adaptation_field_length;
pck = (u8*) buffer+done;
if (pck[0]!=0x47) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS Restamp] Invalid sync byte %X\n", pck[0]));
return GF_NON_COMPLIANT_BITSTREAM;
}
pid = ((pck[1] & 0x1f) <<8 ) + pck[2];
adaptation_field_length = 0;
adaptation_field = (pck[3] >> 4) & 0x3;
if ((adaptation_field==2) || (adaptation_field==3)) {
adaptation_field_length = pck[4];
if ( pck[5]&0x10 ) {
pcr_base = (((u64)pck[6])<<25) + (pck[7]<<17) + (pck[8]<<9) + (pck[9]<<1) + (pck[10]>>7);
pcr_ext = ((pck[10]&1)<<8) + pck[11];
ADJUST_TIMESTAMP(pcr_base);
pck[6] = (unsigned char)(0xff&(pcr_base>>25));
pck[7] = (unsigned char)(0xff&(pcr_base>>17));
pck[8] = (unsigned char)(0xff&(pcr_base>>9));
pck[9] = (unsigned char)(0xff&(pcr_base>>1));
pck[10] = (unsigned char)(((0x1&pcr_base)<<7) | 0x7e | ((0x100&pcr_ext)>>8));
if (pcr_ext != ((pck[10]&1)<<8) + pck[11]) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS Restamp] Sanity check failed for PCR restamping\n"));
return GF_IO_ERR;
}
pck[11] = (unsigned char)(0xff&pcr_ext);
}
adaptation_field_length++;
}
if (!is_pes[pid] || !(pck[1]&0x40)) {
done+=188;
continue;
}
pesh = &pck[4+adaptation_field_length];
if ((pesh[0]==0x00) && (pesh[1]==0x00) && (pesh[2]==0x01)) {
Bool has_pts, has_dts;
if ((pesh[6]&0xc0)!=0x80) {
done+=188;
continue;
}
has_pts = (pesh[7]&0x80);
has_dts = has_pts ? (pesh[7]&0x40) : 0;
if (has_pts) {
u64 PTS;
if (((pesh[9]&0xe0)>>4)!=0x2) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS Restamp] PID %4d: Wrong PES header, PTS decoding: '0010' expected\n", pid));
done+=188;
continue;
}
PTS = gf_m2ts_get_pts(pesh + 9);
ADJUST_TIMESTAMP(PTS);
rewrite_pts_dts(pesh+9, PTS);
}
if (has_dts) {
u64 DTS = gf_m2ts_get_pts(pesh + 14);
ADJUST_TIMESTAMP(DTS);
rewrite_pts_dts(pesh+14, DTS);
}
} else {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS Restamp] PID %4d: Wrong PES not beginning with start code\n", pid));
}
done+=188;
}
return GF_OK;
}
#endif