diff -Naur MPlayer-20030814/cfg-common.h MPlayer-20030814-new/cfg-common.h --- MPlayer-20030814/cfg-common.h 2003-08-13 20:56:02.000000000 +0200 +++ MPlayer-20030814-new/cfg-common.h 2003-08-15 00:19:14.000000000 +0200 @@ -181,7 +181,7 @@ {"flip", &flip, CONF_TYPE_FLAG, 0, -1, 1, NULL}, {"noflip", &flip, CONF_TYPE_FLAG, 0, -1, 0, NULL}, - {"tsfastparse", &ts_fastparse, CONF_TYPE_INT, 0, 0, 0, NULL}, + {"tsprog", &ts_prog, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL}, // draw by slices or whole frame (useful with libmpeg2/libavcodec) {"slices", &vd_use_slices, CONF_TYPE_FLAG, 0, 0, 1, NULL}, @@ -273,7 +273,7 @@ extern char* audio_stream; extern char* sub_stream; extern int demuxer_type, audio_demuxer_type, sub_demuxer_type; -extern int ts_fastparse; +extern int ts_prog; #include "libmpdemux/tv.h" diff -Naur MPlayer-20030814/libmpdemux/demuxer.c MPlayer-20030814-new/libmpdemux/demuxer.c --- MPlayer-20030814/libmpdemux/demuxer.c 2003-08-07 14:40:14.000000000 +0200 +++ MPlayer-20030814-new/libmpdemux/demuxer.c 2003-08-15 00:32:52.000000000 +0200 @@ -616,7 +616,7 @@ (ex: tv,mf). */ -static demuxer_t* demux_open_stream(stream_t *stream,int file_format,int audio_id,int video_id,int dvdsub_id,char* filename){ +demuxer_t* demux_open_stream(stream_t *stream,int file_format,int audio_id,int video_id,int dvdsub_id,char* filename){ //int file_format=(*file_format_ptr); diff -Naur MPlayer-20030814/libmpdemux/demuxer.h MPlayer-20030814-new/libmpdemux/demuxer.h --- MPlayer-20030814/libmpdemux/demuxer.h 2003-06-09 02:24:22.000000000 +0200 +++ MPlayer-20030814-new/libmpdemux/demuxer.h 2003-08-15 00:06:04.000000000 +0200 @@ -155,6 +155,21 @@ return dp; } +inline static void resize_demux_packet(demux_packet_t* dp, int len) +{ + if(len) + { + dp->buffer=(unsigned char *)realloc(dp->buffer,len+8); + memset(dp->buffer+len,0,8); + } + else + { + if(dp->buffer) free(dp->buffer); + dp->buffer=NULL; + } + dp->len=len; +} + inline static demux_packet_t* clone_demux_packet(demux_packet_t* pack){ demux_packet_t* dp=(demux_packet_t*)malloc(sizeof(demux_packet_t)); while(pack->master) pack=pack->master; // find the master diff -Naur MPlayer-20030814/libmpdemux/demux_ts.c MPlayer-20030814-new/libmpdemux/demux_ts.c --- MPlayer-20030814/libmpdemux/demux_ts.c 2003-06-19 20:20:15.000000000 +0200 +++ MPlayer-20030814-new/libmpdemux/demux_ts.c 2003-08-15 00:07:58.000000000 +0200 @@ -42,20 +42,22 @@ #define MAX_HEADER_SIZE 6 /* enough for PES header + length */ #define MAX_CHECK_SIZE 65535 -#define MAX_PROBE_SIZE 1000000 +#define MAX_PROBE_SIZE 2000000 #define NUM_CONSECUTIVE_TS_PACKETS 32 #define NUM_CONSECUTIVE_AUDIO_PACKETS 348 -int ts_fastparse = 0; +int ts_prog; typedef enum { UNKNOWN = -1, VIDEO_MPEG2 = 0x10000002, + VIDEO_MPEG4 = 0x10000004, AUDIO_MP2 = 0x50, AUDIO_A52 = 0x2000, - AUDIO_LPCM_BE = 0x10001 + AUDIO_LPCM_BE = 0x10001, + AUDIO_AAC = (('A' << 24) | ('4' << 16) | ('P' << 8) | 'M') /*, SPU_DVD = 0x3000000, SPU_DVB = 0x3000001, @@ -81,7 +83,69 @@ typedef struct { + demux_stream_t *ds; + demux_packet_t *pack; + int offset, buffer_size; + int broken; //set if it's the final part before without a correspondig is_start +} av_fifo_t; + +typedef struct { + uint8_t skip; + uint8_t table_id; + uint8_t ssi; + uint16_t section_length; + uint16_t ts_id; + uint8_t version_number; + uint8_t curr_next; + uint8_t section_number; + uint8_t last_section_number; + struct pat_progs_t { + uint16_t id; + uint16_t pmt_pid; + } *progs; + uint16_t progs_cnt; + char buffer[65535]; + uint8_t buffer_pos; + uint8_t buffer_len; + } pat_t; + +typedef struct { + uint16_t progid; + uint8_t skip; + uint8_t table_id; + uint8_t ssi; + uint16_t section_length; + uint8_t version_number; + uint8_t curr_next; + uint8_t section_number; + uint8_t last_section_number; + uint16_t PCR_PID; + uint16_t prog_descr_length; + char buffer[2048]; + uint8_t buffer_pos; + uint8_t buffer_len; + uint16_t es_cnt; + struct pmt_es_t { + uint16_t pid; + uint32_t type; //it's 8 bit long, but cast to the same type as FOURCC + uint16_t descr_length; + //descriptor + } *es; +} pmt_t; + +typedef struct { MpegTSContext ts; + int is_synced; //synced to the beginning of priv->last_pid PES header + //int buffer_size;//last dp buffer_size allocated + int last_afc; //bytes read from the last adaption field + int last_pid; // + int is_start; + int eof; + av_fifo_t fifo[2]; //0 for audio, 1 for video + pat_t pat; + pmt_t *pmt; + uint16_t pmt_cnt; + uint32_t prog; } ts_priv_t; @@ -121,11 +185,11 @@ const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS); unsigned char buf[buf_size], done = 0, *ptr; uint32_t _read, i, count = 0, is_ts; - int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok, c; + int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok, c, good, bad; uint8_t size = 0; off_t pos = 0; - mp_msg(MSGT_DEMUX, MSGL_V, "Checking for TS...\n"); + mp_msg(MSGT_DEMUX, MSGL_V, "Checking for MPEG-TS...\n"); is_ts = 0; while(! done) @@ -142,7 +206,7 @@ if(c != 0x47) { - mp_msg(MSGT_DEMUX, MSGL_V, "NOT A TS FILE1\n"); + mp_msg(MSGT_DEMUX, MSGL_V, "THIS DOESN'T LOOK LIKE AN MPEG-TS FILE!\n"); is_ts = 0; done = 1; continue; @@ -180,6 +244,7 @@ return 0; //LET'S CHECK continuity counters + good = bad = 0; for(count = 0; count < NB_PID_MAX; count++) { cc[count] = last_cc[count] = -1; @@ -199,46 +264,173 @@ cc_ok = (last_cc[pid] < 0) || ((((last_cc[pid] + 1) & 0x0f) == cc[pid])); mp_msg(MSGT_DEMUX, MSGL_DBG2, "PID %d, COMPARE CC %d AND LAST_CC %d\n", pid, cc[pid], last_cc[pid]); if(! cc_ok) - return 0; + //return 0; + bad++; + else + good++; last_cc[pid] = cc[pid]; - done++; } - return size; + mp_msg(MSGT_DEMUX, MSGL_V, "GOOD CC: %d, BAD CC: %d\n", good, bad); + + if(good >= bad) + return size; + else + return 0; } +static inline int32_t progid_idx_in_pmt(ts_priv_t *priv, uint16_t progid) +{ + int x; + + if(priv->pmt == NULL) + return -1; + + for(x = 0; x < priv->pmt_cnt; x++) + { + if(priv->pmt[x].progid == progid) + return x; + } + + return -1; +} -static void ts_detect_streams(demuxer_t *demuxer, uint32_t *a, uint32_t *v, int *fapid, int *fvpid) +static inline int32_t progid_for_pid(ts_priv_t *priv, int pid, int32_t req) //finds the first program listing a pid { - int video_found = 0, audio_found = 0, i, num_packets = 0; + int i, j; + pmt_t *pmt; + + + if(priv->pmt == NULL) + return -1; + + + for(i=0; i < priv->pmt_cnt; i++) + { + pmt = &(priv->pmt[i]); + + if(pmt->es == NULL) + return -1; + + for(j = 0; j < pmt->es_cnt; j++) + { + if(pmt->es[j].pid == pid) + { + if((req == 0) || (req == pmt->progid)) + return pmt->progid; + } + } + + } + return -1; +} + + +static void ts_detect_streams(demuxer_t *demuxer, uint32_t *a, uint32_t *v, int *fapid, int *fvpid, int32_t *prog) +{ + int video_found = 0, audio_found = 0, i, num_packets = 0, req_apid, req_vpid; + int is_audio, is_video, has_tables; + int32_t p, chosen_pid; off_t pos=0; ES_stream_t es; unsigned char tmp[TS_FEC_PACKET_SIZE]; ts_priv_t *priv = (ts_priv_t*) demuxer->priv; + priv->is_synced = 0; + priv->last_afc = 0; + priv->last_pid = 8192; //invalid pid + priv->is_start = 0; + priv->eof = 0; - mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %u\n", MAX_PROBE_SIZE); + req_apid = *fapid; + req_vpid = *fvpid; + + has_tables = 0; + mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %u, PROG: %d\n", MAX_PROBE_SIZE, *prog); while(pos <= MAX_PROBE_SIZE) { if(ts_parse(demuxer, &es, tmp, 1)) { - mp_msg(MSGT_DEMUXER, MSGL_DBG2, "TYPE: %x, PID: %d\n", es.type, es.pid); + pos = stream_tell(demuxer->stream); + is_audio = ((es.type == AUDIO_MP2) || (es.type == AUDIO_A52) || (es.type == AUDIO_LPCM_BE) || (es.type == AUDIO_AAC)); + is_video = ((es.type == VIDEO_MPEG2) || (es.type == VIDEO_MPEG4)); + + if((! is_audio) && (! is_video)) + continue; + + if(is_video) + { + chosen_pid = (req_vpid == es.pid); + if((! chosen_pid) && (req_vpid > 0)) + continue; + } + else if(is_audio) + { + chosen_pid = (req_apid == es.pid); + if((! chosen_pid) && (req_apid > 0)) + continue; + } + if(req_vpid < 0 && req_apid < 0) + chosen_pid = 1; - if((*fvpid == -1) || (*fvpid == es.pid)) + p = progid_for_pid(priv, es.pid, *prog); + if(p != -1) + has_tables++; + + if((*prog == 0) && (p != -1)) + { + if(chosen_pid) + *prog = p; + } + + if((*prog > 0) && (*prog != p)) + { + if(audio_found) + { + if(is_video && (req_vpid == es.pid)) + { + *v = es.type; + *fvpid = es.pid; + video_found = 1; + break; + } + } + + if(video_found) + { + if(is_audio && (req_apid == es.pid)) + { + *a = es.type; + *fapid = es.pid; + audio_found = 1; + break; + } + } + + + continue; + } + + + mp_msg(MSGT_DEMUXER, MSGL_V, "TYPE: %x, PID: %d, PROG FOUND: %d\n", es.type, es.pid, *prog); + + + if(is_video) { - if(es.type == VIDEO_MPEG2) + if((req_vpid == -1) || (req_vpid == es.pid)) { - *v = VIDEO_MPEG2; + *v = es.type; *fvpid = es.pid; video_found = 1; } } - if(((*fvpid == -2) || (num_packets >= NUM_CONSECUTIVE_AUDIO_PACKETS)) && audio_found) + + if(((req_vpid == -2) || (num_packets >= NUM_CONSECUTIVE_AUDIO_PACKETS)) && audio_found) { //novideo or we have at least 348 audio packets (64 KB) without video (TS with audio only) *v = 0; @@ -246,65 +438,54 @@ } - if((*fapid == -1) || (*fapid == es.pid)) + if(is_audio) { - if(es.type == AUDIO_MP2) + if((req_apid == -1) || (req_apid == es.pid)) { - *a = AUDIO_MP2; //MPEG1L2 audio - *fapid = es.pid; - audio_found = 1; - } - - if(es.type == AUDIO_A52) - { - *a = AUDIO_A52; //A52 audio - *fapid = es.pid; - audio_found = 1; - } - - if(es.type == AUDIO_LPCM_BE) //LPCM AUDIO - { - *a = AUDIO_LPCM_BE; + *a = es.type; *fapid = es.pid; audio_found = 1; } } if(audio_found && (*fapid == es.pid) && (! video_found)) - num_packets++; + num_packets++; - if((*fapid == -2) && video_found) + if((req_apid == -2) && video_found) { *a = 0; break; } - pos = stream_tell(demuxer->stream); - if(video_found && audio_found) - break; + if((has_tables==0) && (video_found && audio_found) && (pos >= 1000000)) + break; } } if(video_found) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2(pid=%d)...", *fvpid); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG%d(pid=%d)...", (*v == VIDEO_MPEG2 ? 2 : 4), *fvpid); else { //WE DIDN'T MATCH ANY VIDEO STREAM - mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO!\n"); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO! "); } if(*a == AUDIO_MP2) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2(pid=%d)\n", *fapid); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2(pid=%d)", *fapid); else if(*a == AUDIO_A52) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)\n", *fapid); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)", *fapid); else if(*a == AUDIO_LPCM_BE) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)\n", *fapid); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)", *fapid); + else if(*a == AUDIO_AAC) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO AAC(pid=%d)", *fapid); else { //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO - mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO!\n"); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO! "); } + mp_msg(MSGT_DEMUXER, MSGL_INFO, " PROGRAM N. %d\n", *prog); + for(i=0; i<8192; i++) { if(priv->ts.pids[i] != NULL) @@ -341,9 +522,21 @@ return NULL; priv = malloc(sizeof(ts_priv_t)); + if(priv == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "DEMUX_OPEN_TS, couldn't allocate %lu bytes, exit\n", + sizeof(ts_priv_t)); + return NULL; + } for(i=0; i < 8192; i++) priv->ts.pids[i] = NULL; + priv->pat.progs = NULL; + priv->pat.progs_cnt = 0; + + priv->pmt = NULL; + priv->pmt_cnt = 0; + priv->ts.packet_size = packet_size; @@ -353,18 +546,39 @@ else demuxer->seekable = 1; - ts_detect_streams(demuxer, &at, &vt, &demuxer->audio->id, &demuxer->video->id); - mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer2, audio: %x(pid %d), video: %x(pid %d)...\n", at, demuxer->audio->id, vt, demuxer->video->id); + ts_detect_streams(demuxer, &at, &vt, &demuxer->audio->id, &demuxer->video->id, &ts_prog); + mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer, audio: %x(pid %d), video: %x(pid %d)...\n", at, demuxer->audio->id, vt, demuxer->video->id); if(vt) { - sh_video = new_sh_video(demuxer, 0); - sh_video->ds = demuxer->video; - sh_video->format = vt; - demuxer->video->sh = sh_video; + if(vt == VIDEO_MPEG4) + { + demuxer_t *od; + stream_t *s; + sh_video_t *sh_v; + + s = new_ds_stream(demuxer->video); + od = demux_open_stream(s, DEMUXER_TYPE_MPEG4_ES, -1, -1, -1, NULL); + if(od != NULL) + { + sh_v = new_sh_video(od, 0); + sh_v->ds = od->video; + demuxer->video->sh = sh_v; + } + else + mp_msg(MSGT_DEMUXER,MSGL_ERR, "ERROR! COULDN'T OPEN MPEG4 DEMUXER\n"); + } + + else + { + sh_video = new_sh_video(demuxer, 0); + sh_video->ds = demuxer->video; + sh_video->format = vt; + demuxer->video->sh = sh_video; + } - mp_msg(MSGT_DEMUXER,MSGL_INFO, "OPENED_SH_VIDEO, VD: %x\n"); + mp_msg(MSGT_DEMUXER,MSGL_INFO, "OPENED_SH_VIDEO\n"); } if(at) @@ -378,13 +592,36 @@ } - mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer..."); + mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer2\n"); demuxer->movi_start = 0; demuxer->movi_end = demuxer->stream->end_pos; - stream_seek(demuxer->stream, 0); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES? + stream_seek(demuxer->stream, 0); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES? + + + + priv->is_synced = 0; + + priv->last_afc = 0; + priv->last_pid = 8192; //invalid pid + priv->is_start = 0; + + for(i=0; i< 2; i++) + { + priv->fifo[i].pack = NULL; + priv->fifo[i].offset = 0; + priv->fifo[i].broken = 1; + } + priv->fifo[0].ds = demuxer->audio; + priv->fifo[1].ds = demuxer->video; + + priv->fifo[0].buffer_size = 1536; + priv->fifo[1].buffer_size = 32767; + priv->eof = 0; + priv->pat.buffer_pos = 0; + priv->pat.buffer_len = 0; return demuxer; } @@ -407,15 +644,18 @@ -static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es) +static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es, int32_t type_from_pmt) { unsigned char *p; uint32_t header_len; - int64_t pts, escr, dts; + int64_t pts; uint32_t stream_id; - uint32_t pkt_len, es_rate; - //NEXT might be needed: + uint32_t pkt_len; + + //THE FOLLOWING CODE might be needed in the future: //uint8_t es_rate_flag, escr_flag, pts_flag; + //int64_t escr, dts; + //uint32_t es_rate; //Here we are always at the start of a PES packet mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(%X, %d): \n", buf, packet_len); @@ -496,7 +736,7 @@ header_len = p[8]; - /* sometimes corruption on header_len causes segfault in memcpy below */ + if (header_len + 9 > pkt_len) //9 are the bytes read up to the header_length field { mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_ts: illegal value for PES_header_data_length (0x%02x)\n", header_len); @@ -509,10 +749,12 @@ if(es->payload_size) es->payload_size -= header_len + 3; + //mp_msg(MSGT_DEMUX, MSGL_INFO, "TTM: 0x%x, ID: %x\n", type_from_pmt, stream_id); + if (stream_id == 0xbd) { /* hack : ac3 track */ - int track, spu_id; + int track; //, spu_id; mp_msg(MSGT_DEMUX, MSGL_DBG3, "pes_parse2: audio buf = %02X %02X %02X %02X %02X %02X %02X %02X, 80: %d\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0] & 0x80); @@ -526,10 +768,14 @@ * do not include any of the ac3 header info in their audio tracks * these "raw" streams may begin with a byte that looks like a stream type. */ - if( /* ac3 - raw or syncword */ - (p[0] == 0x0B && p[1] == 0x77)) + + + if( + (type_from_pmt == AUDIO_A52) || /* ac3 - raw */ + (p[0] == 0x0B && p[1] == 0x77) /* ac3 - syncword */ + ) { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 SYNCWORD\n"); + mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 RAW OR SYNCWORD\n"); es->start = p; es->size = packet_len; es->type = AUDIO_A52; @@ -604,6 +850,19 @@ return es->size; } + else if ((stream_id == 0xfa)) + { + if(type_from_pmt != -1) //MP4 A/V + { + es->start = p; + es->size = packet_len; + es->type = type_from_pmt; + if(es->payload_size) + es->payload_size -= packet_len; + + return es->size; + } + } else if ((stream_id & 0xe0) == 0xc0) { int track; @@ -616,6 +875,16 @@ return es->size; } + else if (type_from_pmt != -1) //as a last resort here we trust the PMT, if present + { + es->start = p; + es->size = packet_len; + es->type = type_from_pmt; + es->payload_size -= packet_len; + + return es->size; + } + else { mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id); @@ -642,40 +911,428 @@ } +static void ts_dump_streams(ts_priv_t *priv) +{ + int i; + + for(i = 0; i < 2; i++) + { + if((priv->fifo[i].pack != NULL) && (priv->fifo[i].offset != 0)) + { + resize_demux_packet(priv->fifo[i].pack, priv->fifo[i].offset); + ds_add_packet(priv->fifo[i].ds, priv->fifo[i].pack); + } + } + + priv->eof = 1; +} + + +static inline int32_t prog_idx_in_pat(ts_priv_t *priv, uint16_t progid) +{ + int x; + + if(priv->pat.progs == NULL) + return -1; + + for(x = 0; x < priv->pat.progs_cnt; x++) + { + if(priv->pat.progs[x].id == progid) + return x; + } + + return -1; +} + + +static inline int32_t prog_id_in_pat(ts_priv_t *priv, uint16_t pid) +{ + int x; + + if(priv->pat.progs == NULL) + return -1; + + for(x = 0; x < priv->pat.progs_cnt; x++) + { + if(priv->pat.progs[x].pmt_pid == pid) + return priv->pat.progs[x].id; + } + + return -1; +} + + +static int parse_pat(ts_priv_t * priv, int is_start, unsigned char *buff, int size) +{ + uint8_t skip, m; + unsigned char *ptr; + unsigned char *base, *crc; + int entries, i, sections; + uint16_t progid; + uint32_t o_crc, calc_crc; + + //PRE-FILLING + if(! is_start) + { + if(priv->pat.buffer_pos == 0) //a broken packet + { + return 0; + } + + if(priv->pat.skip) + m = min(priv->pat.skip, size); + + priv->pat.skip -= m; + if(m == size) + return -1; //keep on buffering + } + else //IS_START, replace the old content + { + priv->pat.buffer_pos = 0; + priv->pat.buffer_len = 0; + skip = buff[0]+1; + m = min(skip, size); + + priv->pat.skip = skip - m; + + if(m == size) + return -1; + } + + //FILLING + memcpy(&(priv->pat.buffer[priv->pat.buffer_pos]), &buff[m], size - m); + priv->pat.buffer_pos += size - m; + priv->pat.buffer_len += size - m; + + //PARSING + ptr = priv->pat.buffer; + + priv->pat.table_id = ptr[0]; + priv->pat.ssi = (ptr[1] >> 7) & 0x1; + priv->pat.curr_next = ptr[5] & 0x01; + priv->pat.ts_id = (ptr[3] << 8 ) | ptr[4]; + priv->pat.version_number = (ptr[5] >> 1) & 0x1F; + priv->pat.section_length = ((ptr[1] & 0x03) << 8 ) | ptr[2]; + priv->pat.section_number = ptr[6]; + priv->pat.last_section_number = ptr[7]; + + /*CRC CHECK + crc = &(priv->pat.buffer[priv->pat.section_length - 4]); + o_crc = (crc[0] << 24) | (crc[1] << 16) | (crc[2] << 8) | crc[3]; + calc_crc = CalcCRC32(0xFFFFFFFFL, priv->pat.buffer, priv->pat.section_length); + printf("CRC ORIGINALE: %x, CALCOLATO: %x\n", o_crc, calc_crc); + */ + + + if((! priv->pat.curr_next) || (priv->pat.table_id != 0)) // || (! priv->pat.ssi)) + return 0; + + + //controllare se la dimensione delle sezioni eccede priv->pat.buffer_len + //controllare il CRC32 + + + //sections loop + sections = priv->pat.last_section_number - priv->pat.section_number + 1; + mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PAT, section %d of %d, TOTAL: %d\n", priv->pat.section_number, priv->pat.last_section_number, sections); + + if(priv->pat.section_length + 3 > priv->pat.buffer_len) + { + mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PAT, section larger than buffer size: %d > %d, EXIT\n", + priv->pat.section_length, priv->pat.buffer_len - 3); + + return -1; //KEEP ON FILLING THE TABLE + } + + entries = (int) (priv->pat.section_length - 9) / 4; //entries per section + + + for(i=0; i < entries; i++) + { + int32_t idx; + base = &ptr[8 + i*4]; + progid = (base[0] << 8) | base[1]; + + if((idx = prog_idx_in_pat(priv, progid)) == -1) + { + int sz = sizeof(struct pat_progs_t) * (priv->pat.progs_cnt+1); + priv->pat.progs = (struct pat_progs_t*) realloc(priv->pat.progs, sz); + if(priv->pat.progs == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PAT: COULDN'T REALLOC %d bytes, NEXT\n", sz); + break; + } + + idx = priv->pat.progs_cnt; + priv->pat.progs_cnt++; + } + + priv->pat.progs[idx].id = progid; + priv->pat.progs[idx].pmt_pid = ((base[2] & 0x1F) << 8) | base[3]; + mp_msg(MSGT_DEMUX, MSGL_V, "PROG: %d (%d-th of %d), PMT: %d\n", priv->pat.progs[idx].id, i+1, entries, priv->pat.progs[idx].pmt_pid); + } +} + + +static inline int32_t es_pid_in_pmt(pmt_t * pmt, uint16_t pid) +{ + int i; + + if(pmt == NULL) + return -1; + + if(pmt->es == NULL) + return -1; + + for(i = 0; i < pmt->es_cnt; i++) + { + if(pmt->es[i].pid == pid) + return i; + } + + return -1; +} + + + +static int parse_pmt(ts_priv_t * priv, uint16_t progid, uint16_t pid, int is_start, unsigned char *buff, int size) +{ + unsigned char *base, *es_base; + pmt_t *pmt; + int32_t idx, es_count, section_bytes; + uint8_t skip, m; + + idx = progid_idx_in_pmt(priv, progid); + + if(idx == -1) + { + int sz = (priv->pmt_cnt + 1) * sizeof(pmt_t); + priv->pmt = (pmt_t *) realloc(priv->pmt, sz); + if(priv->pmt == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FILL_PMT: COULDN'T REALLOC %d bytes, NEXT\n", sz); + return NULL; + } + + idx = priv->pmt_cnt; + memset(&(priv->pmt[idx]), 0, sizeof(pmt_t)); + priv->pmt_cnt++; + } + + pmt = &(priv->pmt[idx]); + + + if(! is_start) + { + if(pmt->buffer_pos == 0) + { + //BROKEN PMT PACKET, DISCARD + return -1; + } + + if(pmt->skip) + m = min(pmt->skip, size); + + pmt->skip -= m; + if(m == size) + return 0; + } + else + { + pmt->buffer_pos = 0; + pmt->buffer_len = 0; + skip = buff[0] + 1; + m = min(skip, size); + + pmt->skip = skip - m; + + if(m == size) + return 0; + } + + memcpy(&(pmt->buffer[pmt->buffer_pos]), &buff[m], size - m); + pmt->progid = progid; + pmt->buffer_pos += size - m; + pmt->buffer_len += size - m; + + + mp_msg(MSGT_DEMUX, MSGL_V, "FILL_PMT(prog=%d), PMT_len: %d, IS_START: %d, TSPID: %d\n", + progid, pmt->buffer_len, is_start, pid); + + base = pmt->buffer; + + + pmt->table_id = base[0]; + pmt->ssi = base[1] & 0x80; + pmt->section_length = (((base[1] & 0xf) << 8 ) | base[2]); + pmt->version_number = (base[5] >> 1) & 0x1f; + pmt->curr_next = (base[5] & 1); + pmt->section_number = base[6]; + pmt->last_section_number = base[7]; + pmt->PCR_PID = ((base[8] & 0x1f) << 8 ) | base[9]; + pmt->prog_descr_length = ((base[10] & 0xf) << 8 ) | base[11]; + + + + if((pmt->curr_next == 0) || (pmt->table_id != 2)) + return -1; + + + + if(pmt->section_length + 3 > pmt->buffer_len) + { + mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT, SECTION LENGTH TOO LARGE FOR CURRENT BUFFER (%d vs %d), NEXT TIME\n", pmt->section_length, pmt->buffer_len); + return -1; + } + + if(pmt->prog_descr_length > pmt->section_length - 9) + { + mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT, INVALID PROG_DESCR LENGTH (%d vs %d)\n", pmt->prog_descr_length, pmt->section_length - 9); + return -1; + } + + + es_base = &base[12 + pmt->prog_descr_length]; //the beginning of th ES loop + + section_bytes= pmt->section_length - 13 - pmt->prog_descr_length; + es_count = 0; + + while(section_bytes >= 5) + { + int es_pid, es_type; + + es_type = es_base[0]; + es_pid = ((es_base[1] & 0x1f) << 8) | es_base[2]; + + idx = es_pid_in_pmt(pmt, es_pid); + if(idx == -1) + { + int sz = sizeof(struct pmt_es_t) * (pmt->es_cnt + 1); + pmt->es = (struct pmt_es_t *) realloc(pmt->es, sz); + if(pmt->es == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PMT, COULDN'T ALLOCATE %d bytes for PMT_ES\n", sz); + continue; + } + idx = pmt->es_cnt; + pmt->es_cnt++; + } + + pmt->es[idx].descr_length = ((es_base[3] & 0xf) << 8) | es_base[4]; + + if(pmt->es[idx].descr_length > section_bytes - 5) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PMT, ES_DESCR_LENGTH TOO LARGE %d > %d, EXIT %d bytes for PMT_ES\n", + pmt->es[idx].descr_length, section_bytes - 5); + return -1; + } + pmt->es[idx].pid = es_pid; + pmt->es[idx].type = es_type; + + switch(es_type) + { + case 1: + case 2: + pmt->es[idx].type = VIDEO_MPEG2; + break; + case 3: + case 4: + pmt->es[idx].type = AUDIO_MP2; + break; + case 6: + { + int j; + for(j = 5; j < pmt->es[idx].descr_length; j += es_base[j+1] +2) + if(es_base[j] == 0x6a) + pmt->es[idx].type = AUDIO_A52; + } + break; + + case 0x10: + pmt->es[idx].type = VIDEO_MPEG4; + break; + case 0x11: + pmt->es[idx].type = AUDIO_AAC; + break; + + case 0x81: + pmt->es[idx].type = AUDIO_A52; + break; + } + + + section_bytes -= 5 + pmt->es[idx].descr_length; + mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT(%d INDEX %d), STREAM: %d, FOUND pid=0x%x (%d), type=0x%x, ES_DESCR_LENGTH: %d, bytes left: %d\n", + progid, idx, es_count, pmt->es[idx].pid, pmt->es[idx].pid, pmt->es[idx].type, pmt->es[idx].descr_length, section_bytes); + + + es_base += 5 + pmt->es[idx].descr_length; + + es_count++; + } + + return 1; +} + // 0 = EOF or no stream found -// 1 = successfully read a packet +// else = number of bytes written to the packet static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet, int probe) { ES_stream_t *tss; uint8_t done = 0; int buf_size, is_start; - int len, pid, last_pid, cc, cc_ok, afc, _read; + int len, pid, cc, cc_ok, afc, _read; ts_priv_t * priv = (ts_priv_t*) demuxer->priv; stream_t *stream = demuxer->stream; char *p, tmp[TS_FEC_PACKET_SIZE]; - demux_stream_t *ds; - demux_packet_t *dp; + demux_stream_t *ds = NULL; + demux_packet_t **dp = NULL; + int *dp_offset = 0, *buffer_size = 0, *broken; + int32_t progid, pid_idx, pid_type; - while(! done) //while pid=last_pid add_to_buffer + while(! done) { - if(! ts_sync(stream)) + if(stream_eof(stream)) { - mp_msg(MSGT_DEMUX, MSGL_V, "TS_PARSE: COULDN'T SYNC\n"); - return 0; + if(! priv->eof) + { + ts_dump_streams(priv); + return -1; + } + else + return 0; } - len = stream_read(stream, &packet[1], 3); - if (len != 3) - return 0; + + if(! priv->is_synced) + { + if(! ts_sync(stream)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "TS_PARSE: COULDN'T SYNC\n"); + return 0; + } + + len = stream_read(stream, &packet[1], 3); + if (len != 3) + return 0; + } _read = 4; - is_start = packet[1] & 0x40; - pid = ((packet[1] & 0x1f) << 8) | packet[2]; + if(! priv->is_synced) + { + is_start = packet[1] & 0x40; + pid = ((packet[1] & 0x1f) << 8) | packet[2]; + } + else + { + is_start = priv->is_start; + pid = priv->last_pid; + } tss = priv->ts.pids[pid]; //an ES stream if(tss == NULL) @@ -689,11 +1346,14 @@ tss->type = UNKNOWN; tss->payload_size = 0; priv->ts.pids[pid] = tss; - mp_msg(MSGT_DEMUX, MSGL_V, "new TS pid=%u\n", pid); + mp_msg(MSGT_DEMUX, MSGL_INFO, "\nNew TS pid=%u\n", pid); } - if((pid < 16) || (pid == 8191)) //invalid pid + + + if(((pid > 1) && (pid < 16)) || (pid == 8191)) //invalid pid continue; + cc = (packet[3] & 0xf); cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); if(! cc_ok) @@ -702,54 +1362,173 @@ } tss->last_cc = cc; - /* skip adaptation field */ - afc = (packet[3] >> 4) & 3; - if (afc == 0) /* reserved value */ - continue; - if (afc == 2) /* adaptation field only */ - continue; - if (afc == 3) + + if(! priv->is_synced) { - int c; - stream_read(stream, &packet[_read], 1); - c = packet[_read]; - _read++; - - c = min(c, priv->ts.packet_size - _read); - stream_read(stream, &packet[_read], c); - _read += c; + priv->last_afc = 0; + /* skip adaptation field */ + afc = (packet[3] >> 4) & 3; + if (afc == 0) /* reserved value */ + continue; + if (afc == 2) /* adaptation field only */ + continue; + if (afc == 3) + { + int c; + stream_read(stream, &packet[_read], 1); + c = packet[_read]; + _read++; + + c = min(c, priv->ts.packet_size - _read); + stream_read(stream, &packet[_read], c); + _read += c; - if(_read == priv->ts.packet_size) - continue; + priv->last_afc = c + 1; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "AFC: %d\n", priv->last_afc); + + if(_read == priv->ts.packet_size) + continue; + } + } + else + { + _read += priv->last_afc; + priv->last_afc = 0; } // PES CONTENT STARTS HERE buf_size = priv->ts.packet_size - _read; + //LET'S PARSE TABLES + + + if(pid == 0) + { + stream_read(stream,&packet[_read], buf_size); + parse_pat(priv, is_start, &packet[_read], buf_size); + priv->is_synced = 0; + continue; + } + else + { + progid = prog_id_in_pat(priv, pid); + if(((progid != -1) || (pid == 16))) + { + stream_read(stream,&packet[_read], buf_size); + parse_pmt(priv, progid, pid, is_start, &packet[_read], buf_size); + priv->is_synced = 0; + continue; + } + } + + + if(! probe) { - if((tss->type == VIDEO_MPEG2) && (demuxer->video->id == tss->pid)) + //mp_msg(MSGT_DEMUX, MSGL_V, "demux_VID: %d, demux_AID: %d, TSSID: %d\n", demuxer->video->id, demuxer->audio->id, tss->pid); + if(((tss->type == VIDEO_MPEG2) || (tss->type == VIDEO_MPEG4)) + && (demuxer->video->id == tss->pid)) + { ds = demuxer->video; - else if(((tss->type == AUDIO_MP2) || (tss->type == AUDIO_A52) || (tss->type == AUDIO_LPCM_BE)) + + dp = &priv->fifo[1].pack; + dp_offset = &priv->fifo[1].offset; + buffer_size = &priv->fifo[1].buffer_size; + broken = &priv->fifo[1].broken; + } + else if(((tss->type == AUDIO_MP2) || (tss->type == AUDIO_A52) || (tss->type == AUDIO_LPCM_BE) || (tss->type == AUDIO_AAC)) && (demuxer->audio->id == tss->pid)) + { ds = demuxer->audio; + + dp = &priv->fifo[0].pack; + dp_offset = &priv->fifo[0].offset; + buffer_size = &priv->fifo[0].buffer_size; + broken = &priv->fifo[0].broken; + } else { - stream_read(stream, tmp, buf_size); + //mp_msg(MSGT_DEMUX, MSGL_V, "SKIPPING %d bytes\n", buf_size); + stream_skip(stream, buf_size); _read += buf_size; continue; } + + //IS IT TIME TO QUEUE DATA? + if(is_start && (*dp != NULL) && (*dp_offset > 0)) + { + priv->last_pid = pid; + priv->is_synced = 1; + priv->is_start = is_start; + + if(! *broken) + { + int ret = *dp_offset; + resize_demux_packet(*dp, ret); //shrinked to the right size + + ds_add_packet(ds, *dp); + mp_msg(MSGT_DEMUX, MSGL_V, "ADDED %d bytes to %s fifo, PTS=%f\n", ret, (ds == demuxer->audio ? "audio" : "video"), (*dp)->pts); + + + *dp = NULL; + *dp_offset = 0; + + + return -ret; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "BROKEN PES, DISCARDING\n"); + free_demux_packet(*dp); + + *dp = NULL; + *dp_offset = 0; + + + continue; + } + } + + priv->last_pid = pid; + + if(*dp == NULL) + { + *dp = new_demux_packet(*buffer_size); //es->size + *dp_offset = 0; + if(! *dp) + { + fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", *buffer_size); + continue; + } + mp_msg(MSGT_DEMUX, MSGL_DBG2, "CREATED DP(%d)\n", *buffer_size); + } + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "NOW PACKET_SIZE = %d, DP_OFFSET = %d\n", *buffer_size, *dp_offset); } + priv->is_synced = 0; + if(is_start) { + mp_msg(MSGT_DEMUX, MSGL_V, "IS_START\n"); + + //priv->is_synced = 0; + p = &packet[_read]; stream_read(stream, p, buf_size); _read += buf_size; - len = pes_parse2(p, buf_size, es); + + pid_idx = es_pid_in_pmt(priv->pmt, pid); + if(pid_idx == -1) + pid_type = UNKNOWN; + else + pid_type = priv->pmt->es[pid_idx].type; + + + len = pes_parse2(p, buf_size, es, pid_type); if(len) { @@ -772,27 +1551,30 @@ tss->payload_size = es->payload_size; - mp_msg(MSGT_DEMUX, MSGL_V, "ts_parse, NOW tss->PSIZE=%u\n", tss->payload_size); + mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse, NOW tss->PSIZE=%u\n", tss->payload_size); if(probe) return es->size; else { - dp = new_demux_packet(es->size); - if(! dp || ! dp->buffer) + *broken = 0; + if(*dp_offset + es->size > *buffer_size) { - fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", es->size); - continue; + *buffer_size = *dp_offset + es->size + TS_FEC_PACKET_SIZE; + resize_demux_packet(*dp, *buffer_size); + //we'll skip at least one RESIZE() in the next iteration of ts_parse() + mp_msg(MSGT_DEMUX, MSGL_DBG2, "RESIZE DP TO %d\n", *buffer_size); } + memcpy(&((*dp)->buffer[*dp_offset]), es->start, es->size); + *dp_offset += es->size; + (*dp)->flags = 0; + (*dp)->pts = es->pts; + (*dp)->pos = stream_tell(demuxer->stream); + *broken = 0; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "INIT PACKET, TYPE=%x, PTS: %f\n", es->type, es->pts); - memcpy(dp->buffer, es->start, es->size); - dp->flags = 0; - dp->pts = es->pts; - dp->pos = stream_tell(demuxer->stream); - ds_add_packet(ds, dp); - - return -es->size; + continue; } } } @@ -802,7 +1584,7 @@ if(tss->type == UNKNOWN) { - stream_read(stream, tmp, buf_size); + stream_skip(stream, buf_size); continue; } @@ -820,26 +1602,34 @@ } else { - if(es->type == VIDEO_MPEG2) + if((es->type == VIDEO_MPEG2) || (es->type == VIDEO_MPEG4)) sz = es->size = buf_size; else { - stream_read(stream, tmp, buf_size); + stream_skip(stream, buf_size); continue; } } - if(! probe) { - ds_read_packet(ds, stream, sz, tss->last_pts, stream_tell(stream), 0); - if(buf_size - sz) - stream_read(stream, tmp, buf_size - sz); + if(*dp_offset + sz > *buffer_size) + { + *buffer_size = *dp_offset + sz + TS_FEC_PACKET_SIZE; + resize_demux_packet(*dp, *buffer_size); + //we'll skip at least one RESIZE() in the next iteration of ts_parse() + mp_msg(MSGT_DEMUX, MSGL_DBG2, "RESIZE DP TO %d\n", *buffer_size); + } - mp_msg(MSGT_DEMUX, MSGL_V, "DOPO DS_READ_PACKET pid %d, size %d DS=%p\n", tss->pid, sz, ds); - return -sz; + stream_read(stream, &((*dp)->buffer[*dp_offset]), sz); + *dp_offset += sz; + + if(buf_size - sz) + stream_skip(stream, buf_size - sz); + + continue; } else { @@ -860,6 +1650,7 @@ } + int demux_ts_fill_buffer(demuxer_t * demuxer) { ES_stream_t es; @@ -875,7 +1666,6 @@ { int total_bitrate=0; off_t dest_offset; - ts_priv_t * priv = demuxer->priv; int a_bps, v_bps; demux_stream_t *d_audio=demuxer->audio; demux_stream_t *d_video=demuxer->video; @@ -895,13 +1685,13 @@ if(demuxer->audio->id != -2) { - a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps; + a_bps = sh_audio->i_bps; total_bitrate += a_bps; } if(demuxer->video->id != -2) { - v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps; + v_bps = sh_video->i_bps; total_bitrate += v_bps; }