Mercurial > mplayer.hg
changeset 10253:978b12dcb9ef
- open new_ds_[audio | video] only when the relative streams are really available
- consequently, -nosound now works
- simplified the feeding (to ds_) function
- eliminated the previous buffering of ES data (so it should be a little faster)
- discard junk ES data after payload_size for the current pes packet is 0
- reduced the probe buffer
- better support for audio only TS (DAB seems to have many fans)
- fixes the wrong spacing (now fixed at 8 chars)
- makes static all the functions that are not exported
- comments the unused code that I could need in the future
patch by Nico <nsabbi@libero.it>
author | arpi |
---|---|
date | Sat, 07 Jun 2003 11:30:19 +0000 |
parents | d275152390ee |
children | eda683786f26 |
files | libmpdemux/demux_ts.c |
diffstat | 1 files changed, 635 insertions(+), 601 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdemux/demux_ts.c Fri Jun 06 19:57:37 2003 +0000 +++ b/libmpdemux/demux_ts.c Sat Jun 07 11:30:19 2003 +0000 @@ -1,23 +1,12 @@ /* * Demultiplexer for MPEG2 Transport Streams. * - * For the purposes of playing video, we make some assumptions about the - * kinds of TS we have to process. The most important simplification is to - * assume that the TS contains a single program (SPTS) because this then - * allows significant simplifications to be made in processing PATs. - * - * WARNING: Quite a hack was required in order to get files by MultiDec played back correctly. - * If it breaks anything else, just comment out the "#define DEMUX_PVA_MULTIDEC_HACK" below - * and it will not be compiled in. - * - * Feedback is appreciated. - * - * written by Matteo Giani - * based on FFmpeg (libavformat) sources - * + * Written by Nico <nsabbi@libero.it> + * Kind feedback is appreciated; 'sucks' and alike is not. + * Originally based on demux_pva.c written by Matteo Giani and FFmpeg (libavformat) sources * * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * @@ -30,7 +19,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include <stdio.h> #include <stdlib.h> @@ -47,19 +36,18 @@ #include "bswap.h" - #define TS_FEC_PACKET_SIZE 204 #define TS_PACKET_SIZE 188 #define NB_PID_MAX 8192 - + #define MAX_HEADER_SIZE 6 /* enough for PES header + length */ -#define MAX_PROBE_SIZE 1000000 +#define MAX_PROBE_SIZE 500000 #define NUM_CONSECUTIVE_TS_PACKETS 32 int ts_fastparse = 0; -typedef enum +typedef enum { UNKNOWN = -1, VIDEO_MPEG2 = 0x10000002, @@ -70,22 +58,22 @@ SPU_DVD = 0x3000000, SPU_DVB = 0x3000001, */ -} es_stream_type_t; +} es_stream_type_t; typedef struct { - int size; - unsigned char *start; + int size; + unsigned char *start; uint16_t payload_size; - es_stream_type_t type; - float pts, last_pts; - int pid; - int last_cc; // last cc code (-1 if first packet) + es_stream_type_t type; + float pts, last_pts; + int pid; + int last_cc; // last cc code (-1 if first packet) } ES_stream_t; typedef struct MpegTSContext { - int packet_size; // raw packet size, including FEC if present e.g. 188 bytes + int packet_size; // raw packet size, including FEC if present e.g. 188 bytes ES_stream_t *pids[NB_PID_MAX]; } MpegTSContext; @@ -94,32 +82,33 @@ MpegTSContext ts; } ts_priv_t; -int ts_parse(demuxer_t *demuxer, ES_stream_t *es, unsigned char *packet); + +static int ts_parse(demuxer_t *demuxer, ES_stream_t *es, unsigned char *packet, int probe); static uint8_t get_packet_size(const unsigned char *buf, int size) { - int i; + int i; - if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS)) - return 0; - - for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) - { - if (buf[i * TS_PACKET_SIZE] != 0x47) + if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS)) + return 0; + + for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); - goto try_fec; + if (buf[i * TS_PACKET_SIZE] != 0x47) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); + goto try_fec; + } + } + return TS_PACKET_SIZE; + +try_fec: + for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) + { + if (buf[i * TS_FEC_PACKET_SIZE] != 0x47) + return 0; } - } - return TS_PACKET_SIZE; - - try_fec: - for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) - { - if (buf[i * TS_FEC_PACKET_SIZE] != 0x47) - return 0; - } - return TS_FEC_PACKET_SIZE; + return TS_FEC_PACKET_SIZE; } @@ -127,156 +116,180 @@ int ts_check_file(demuxer_t * demuxer) { const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS); - unsigned char buf[buf_size], c, done = 0, *ptr; - uint32_t _read, i=1, count = 0; - int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok; + unsigned char buf[buf_size], done = 0, *ptr; + uint32_t _read, i, count = 0; + int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok, c; 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 TS...\n"); + while(! done) - { - while(((c=stream_read_char(demuxer->stream)) != 0x47) + { + i = 1; + c = 0; + + while(((c=stream_read_char(demuxer->stream)) != 0x47) + && (c >= 0) && (i < MAX_PROBE_SIZE) && ! demuxer->stream->eof - ) i++; - + ) i++; + + if(c != 0x47) { mp_msg(MSGT_DEMUX, MSGL_V, "NOT A TS FILE1\n"); done = 1; continue; } - + pos = stream_tell(demuxer->stream) - 1; buf[0] = c; _read = stream_read(demuxer->stream, &buf[1], buf_size-1); - + if(_read < buf_size-1) { mp_msg(MSGT_DEMUX, MSGL_V, "COULDN'T READ ENOUGH DATA, EXITING TS_CHECK\n"); stream_reset(demuxer->stream); return 0; } - + size = get_packet_size(buf, buf_size); if(size) done = 1; } - + mp_msg(MSGT_DEMUX, MSGL_V, "TRIED UP TO POSITION %u, FOUND %x, packet_size= %d\n", i, c, size); stream_seek(demuxer->stream, pos); - - //return size; + //LET'S CHECK continuity counters for(count = 0; count < NB_PID_MAX; count++) { - cc[count] = last_cc[count] = -1; + cc[count] = last_cc[count] = -1; } - - done = 0; + for(count = 0; count < NUM_CONSECUTIVE_TS_PACKETS; count++) { - ptr = &(buf[size * count]); - pid = ((ptr[1] & 0x1f) << 8) | ptr[2]; - mp_msg(MSGT_DEMUX, MSGL_V, "BUF: %02x %02x %02x %02x, PID %d, SIZE: %d \n", + ptr = &(buf[size * count]); + pid = ((ptr[1] & 0x1f) << 8) | ptr[2]; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "BUF: %02x %02x %02x %02x, PID %d, SIZE: %d \n", ptr[0], ptr[1], ptr[2], ptr[3], pid, size); - - if(pid == 8191) - continue; - - cc[pid] = (ptr[3] & 0xf); - cc_ok = (last_cc[pid] < 0) || ((((last_cc[pid] + 1) & 0x0f) == cc[pid])); - mp_msg(MSGT_DEMUX, MSGL_V, "PID %d, COMPARE CC %d AND LAST_CC %d\n", pid, cc[pid], last_cc[pid]); - if(! cc_ok) - return 0; - - last_cc[pid] = cc[pid]; - done++; + + if((pid == 8191) || (pid < 16)) + continue; + + cc[pid] = (ptr[3] & 0xf); + 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; + + last_cc[pid] = cc[pid]; + done++; } - - return size; + + return size; } -void ts_detect_streams(demuxer_t *demuxer) + +static void ts_detect_streams(demuxer_t *demuxer, uint32_t *a, uint32_t *v, int *fapid, int *fvpid) { - int video_found = 0, audio_found = 0; + int video_found = 0, audio_found = 0, i; off_t pos=0; ES_stream_t es; - int *apid, *vpid, *spid, fapid, fvpid, fspid; unsigned char tmp[TS_FEC_PACKET_SIZE]; - sh_video_t *sh_video = demuxer->video->sh; - sh_audio_t *sh_audio = demuxer->audio->sh; - - apid = &(demuxer->audio->id); - vpid = &(demuxer->video->id); - spid = &(demuxer->sub->id); - - + ts_priv_t *priv = (ts_priv_t*) demuxer->priv; + + mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %u\n", MAX_PROBE_SIZE); while(pos <= MAX_PROBE_SIZE) { - if(ts_parse(demuxer, &es, tmp)) - { - mp_msg(MSGT_DEMUXER, MSGL_V, "TYPE: %x, PID: %d\n", es.type, es.pid); - if(es.type == VIDEO_MPEG2) - { - sh_video->format = VIDEO_MPEG2; //MPEG2 video - if(*vpid == -1) - *vpid = fvpid = es.pid; - video_found = 1; - } - - if(es.type == AUDIO_MP2) - { - sh_audio->format = AUDIO_MP2; //MPEG1L2 audio - if(*apid == -1) - *apid = fapid = es.pid; - audio_found = 1; - } - - if(es.type == AUDIO_A52) + if(ts_parse(demuxer, &es, tmp, 1)) { - sh_audio->format = AUDIO_A52; //A52 audio - if(*apid == -1) - *apid = fapid = es.pid; - audio_found = 1; - } - - if(es.type == AUDIO_LPCM_BE) //LPCM AUDIO - { - sh_audio->format = AUDIO_LPCM_BE; - if(*apid == -1) - *apid = fapid = es.pid; - audio_found = 1; + mp_msg(MSGT_DEMUXER, MSGL_DBG2, "TYPE: %x, PID: %d\n", es.type, es.pid); + + if((*fvpid == -1) || (*fvpid == es.pid)) + { + if(es.type == VIDEO_MPEG2) + { + *v = VIDEO_MPEG2; + *fvpid = es.pid; + video_found = 1; + } + } + + if((*fvpid == -2) && audio_found) + { + *v = 0; + break; + } + + + if((*fapid == -1) || (*fapid == es.pid)) + { + if(es.type == AUDIO_MP2) + { + *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; + *fapid = es.pid; + audio_found = 1; + } + } + + if((*fapid == -2) && video_found) + { + *a = 0; + break; + } + + pos = stream_tell(demuxer->stream); + if(video_found && audio_found) + break; } - - pos = stream_tell(demuxer->stream); - if(video_found && audio_found) - break; - } } - + if(video_found) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2(pid=%d)...", fvpid); + mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2(pid=%d)...", *fvpid); else { - *vpid = -2; //WE DIDN'T MATCH ANY VIDEO STREAM, SO WE FORCE THE DEMUXER TO IGNORE VIDEO + //WE DIDN'T MATCH ANY VIDEO STREAM mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO!\n"); } - - if(sh_audio->format == AUDIO_MP2) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2(pid=%d)\n", fapid); - else if(sh_audio->format == AUDIO_A52) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)\n", fapid); - else if(sh_audio->format == AUDIO_LPCM_BE) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)\n", fapid); - else + + if(*a == AUDIO_MP2) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2(pid=%d)\n", *fapid); + else if(*a == AUDIO_A52) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)\n", *fapid); + else if(*a == AUDIO_LPCM_BE) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)\n", *fapid); + else { - *apid = -2; //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO - mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO!\n"); + //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO + mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO!\n"); + } + + for(i=0; i<8192; i++) + { + if(priv->ts.pids[i] != NULL) + { + priv->ts.pids[i]->payload_size = 0; + priv->ts.pids[i]->pts = priv->ts.pids[i]->last_pts = 0; + //priv->ts.pids[i]->type = UNKNOWN; + } } } @@ -288,58 +301,69 @@ uint8_t packet_size; sh_video_t *sh_video; sh_audio_t *sh_audio; + uint32_t at = 0, vt = 0; ts_priv_t * priv = (ts_priv_t*) demuxer->priv; - - - mp_msg(MSGT_DEMUX, MSGL_V, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", - demuxer->audio->id, demuxer->video->id, demuxer->sub->id); - - + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", + demuxer->audio->id, demuxer->video->id, demuxer->sub->id); + + demuxer->type= DEMUXER_TYPE_MPEG_TS; - + stream_reset(demuxer->stream); stream_seek(demuxer->stream, 0); - + packet_size = ts_check_file(demuxer); if(!packet_size) return NULL; - + priv = malloc(sizeof(ts_priv_t)); - + for(i=0; i < 8192; i++) priv->ts.pids[i] = NULL; priv->ts.packet_size = packet_size; - - + + demuxer->priv = priv; - + if(demuxer->stream->type != STREAMTYPE_FILE) demuxer->seekable=0; else demuxer->seekable = 1; - - - sh_video = new_sh_video(demuxer, 0); - sh_video->ds = demuxer->video; - demuxer->video->sh = sh_video; - - sh_audio = new_sh_audio(demuxer, 0); - sh_audio->ds = demuxer->audio; - demuxer->audio->sh = sh_audio; - - + + + 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); + + + if(vt) + { + 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"); + } + + if(at) + { + sh_audio = new_sh_audio(demuxer, 0); + sh_audio->ds = demuxer->audio; + sh_audio->format = at; + demuxer->audio->sh = sh_audio; + + mp_msg(MSGT_DEMUXER,MSGL_INFO, "OPENED_SH_AUDIO\n"); + } + + mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer..."); - if(! ts_fastparse) - ts_detect_streams(demuxer); - - - /* + 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? - return demuxer; + + return demuxer; } @@ -355,203 +379,243 @@ demuxer->priv=NULL; } } - + + -static int pes_parse2(unsigned char *buf, uint16_t packet_len, int is_start, ES_stream_t *es) +static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es) { - unsigned char *p; - uint32_t header_len; - int64_t pts; - uint32_t stream_id; - uint32_t pkt_len; + unsigned char *p; + uint32_t header_len; + int64_t pts, escr, dts; + uint32_t stream_id; + uint32_t pkt_len, es_rate; + //NEXT might be needed: + //uint8_t es_rate_flag, escr_flag, pts_flag; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(%X, %d, %d, ): \n", buf, packet_len, is_start); + //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); - if(packet_len == 0) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(,PACKET_LEN = 0, EXIT\n"); - return 0; - } - - if(packet_len > 184) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2, BUFFER LEN IS TOO BIG: %d, EXIT\n", packet_len); - return 0; - } - - - p = buf; - pkt_len = packet_len; + if(packet_len == 0) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(,PACKET_LEN = 0, EXIT\n"); + return 0; + } - if(! is_start) - { - es->pts = 0.0f; - es->start = p; - es->size = packet_len; - return es->size; - } - - /* we should have a PES packet here */ + if(packet_len > 184) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2, BUFFER LEN IS TOO BIG: %d, EXIT\n", packet_len); + return 0; + } + + + p = buf; + pkt_len = packet_len; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: HEADER %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]); - if (p[0] || p[1] || (p[2] != 1)) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: error HEADER %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); - return 0 ; - } + if (p[0] || p[1] || (p[2] != 1)) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: error HEADER %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); + return 0 ; + } + + packet_len -= 6; + if(packet_len==0) + return 0; + + es->payload_size = (p[4] << 8 | p[5]); + + stream_id = p[3]; + - packet_len -= 6; - - es->payload_size = p[4] << 8 | p[5]; - if (es->payload_size == 0) - es->payload_size = 65535; - - stream_id = p[3]; + if (p[7] & 0x80) + { /* pts available */ + pts = (int64_t)(p[9] & 0x0E) << 29 ; + pts |= p[10] << 22 ; + pts |= (p[11] & 0xFE) << 14 ; + pts |= p[12] << 7 ; + pts |= (p[13] & 0xFE) >> 1 ; - if(packet_len==0) - return 0; + es->pts = pts / 90000.0f; + } + else + es->pts = 0.0f; + + /* + CODE TO CALCULATE ES_RATE AND ESCR, ACTUALLY UNUSED BUT POSSIBLY NEEDED IN THE FUTURE + + pts_flag = ((p[7] & 0xc0) >> 6) & 3; + escr_flag = p[7] & 0x20; + es_rate_flag = p[7] & 0x10; + mp_msg(MSGT_DEMUX, MSGL_V, "pes_parse: ES_RATE_FLAG=%d, ESCR_FLAG=%d, PTS_FLAG=%d, byte=%02X\n", es_rate_flag, escr_flag, pts_flag, p[7]); - if (p[7] & 0x80) - { /* pts available */ - pts = (int64_t)(p[9] & 0x0E) << 29 ; - pts |= p[10] << 22 ; - pts |= (p[11] & 0xFE) << 14 ; - pts |= p[12] << 7 ; - pts |= (p[13] & 0xFE) >> 1 ; - - es->pts = pts / 90000.0f; - } - else - es->pts = 0.0f; + if(es_rate_flag) + { + char *base; + int bytes = 0; - header_len = p[8]; + if(pts_flag == 2) + bytes += 5; + else if(pts_flag == 3) + bytes += 10; - /* sometimes corruption on header_len causes segfault in memcpy below */ - if (header_len + 9 > pkt_len) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_ts: illegal value for PES_header_data_length (0x%02x)\n", header_len); - return 0; - } - - p += header_len + 9; - packet_len -= header_len + 3; + if(escr_flag) + bytes += 6; - if (stream_id == 0xbd) - { - /* hack : ac3 track */ - int track, spu_id; - - mp_msg(MSGT_DEMUX, MSGL_V, "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); - - track = p[0] & 0x0F; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 TRACK: %d\n", track); - - - /* - * we check the descriptor tag first because some stations - * 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)) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 SYNCWORD\n"); - es->start = p; - es->size = packet_len; - es->type = AUDIO_A52; - return es->size; - } - /* - else if (//m->descriptor_tag == 0x06 && - p[0] == 0x20 && p[1] == 0x00) + base = p[8+bytes]; + es_rate = ((base[0] & 0x7f) << 8) | (base[1] << 8) | (base[0] & 0xfe); + mp_msg(MSGT_DEMUX, MSGL_V, "demux_ts: ES_RATE=%d)\n", es_rate*50); + } + */ + + 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); + return 0; + } + + p += header_len + 9; + packet_len -= header_len + 3; + + if(es->payload_size) + es->payload_size -= header_len + 3; + + if (stream_id == 0xbd) { - // DVBSUB - long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; - es->start = p; - es->size = packet_len; - es->type = SPU_DVB + payload_len; - return es->size; - } - - else if ((p[0] & 0xE0) == 0x20) - { - spu_id = (p[0] & 0x1f); - es->start = p+1; - es->size = packet_len-1; - es->type = SPU_DVD + spu_id; - return es->size; - } - */ - else if ((p[0] & 0xF0) == 0x80) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 WITH HEADER\n"); - es->start = p+4; - es->size = packet_len - 4; - es->type = AUDIO_A52; - return es->size; - } - else if ((p[0]&0xf0) == 0xa0) - { - int pcm_offset; + /* hack : ac3 track */ + 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); + + track = p[0] & 0x0F; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 TRACK: %d\n", track); + + + /* + * we check the descriptor tag first because some stations + * 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)) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 SYNCWORD\n"); + es->start = p; + es->size = packet_len; + es->type = AUDIO_A52; + es->payload_size -= packet_len; + + return es->size; + } + /* + SUBS, it seems they are not streams in g1, what to do? + else if (//m->descriptor_tag == 0x06 && + p[0] == 0x20 && p[1] == 0x00) + { + // DVBSUB + long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; + es->start = p; + es->size = packet_len; + es->type = SPU_DVB + payload_len; + es->payload_size -= packet_len; + + return es->size; + } + + else if ((p[0] & 0xE0) == 0x20) + { + spu_id = (p[0] & 0x1f); + es->start = p+1; + es->size = packet_len-1; + es->type = SPU_DVD + spu_id; + es->payload_size -= packet_len; - for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ) - { - if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80) - { /* START */ - pcm_offset += 2; - break; - } - } + return es->size; + } + */ + else if ((p[0] & 0xF0) == 0x80) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "AC3 WITH HEADER\n"); + es->start = p+4; + es->size = packet_len - 4; + es->type = AUDIO_A52; + es->payload_size -= packet_len; + + return es->size; + } + else if ((p[0]&0xf0) == 0xa0) + { + int pcm_offset; - es->start = p + pcm_offset; - es->size = packet_len - pcm_offset; - es->type = AUDIO_LPCM_BE; - return es->size; + for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ) + { + if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80) + { /* START */ + pcm_offset += 2; + break; + } + } + + es->start = p + pcm_offset; + es->size = packet_len - pcm_offset; + es->type = AUDIO_LPCM_BE; + es->payload_size -= packet_len; + + return es->size; + } } - } - else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) - { - es->start = p; - es->size = packet_len; - es->type = VIDEO_MPEG2; - return es->size; - } - else if ((stream_id & 0xe0) == 0xc0) - { - int track; - track = stream_id & 0x1f; - es->start = p; - es->size = packet_len; - es->type = AUDIO_MP2; - return es->size; - } - else - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id); - } + else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) + { + es->start = p; + es->size = packet_len; + es->type = VIDEO_MPEG2; + if(es->payload_size) + es->payload_size -= packet_len; + + return es->size; + } + else if ((stream_id & 0xe0) == 0xc0) + { + int track; - return 0; + track = stream_id & 0x1f; + es->start = p; + es->size = packet_len; + es->type = AUDIO_MP2; + es->payload_size -= packet_len; + + return es->size; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id); + } + + return 0; } -int ts_sync(demuxer_t *demuxer) +static int ts_sync(stream_t *stream) { - uint8_t c=0; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "TS_SYNC \n"); - - while(((c=stream_read_char(demuxer->stream)) != 0x47) && ! demuxer->stream->eof); - - if(c == 0x47) - return c; - else - return 0; + int c=0; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "TS_SYNC \n"); + + while(((c=stream_read_char(stream)) != 0x47) && ! stream->eof); + + if(c == 0x47) + return c; + else + return 0; } @@ -561,240 +625,229 @@ // 0 = EOF or no stream found // 1 = successfully read a packet -int ts_parse(demuxer_t * demuxer , ES_stream_t *es, unsigned char *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; - uint16_t buf_size, is_start; - int len, pid, cc, cc_ok, afc; - unsigned char *p; + uint8_t done = 0; + int buf_size, is_start; + int len, pid, last_pid, cc, cc_ok, afc, _read; ts_priv_t * priv = (ts_priv_t*) demuxer->priv; - - - while(! done) - { - if(! ts_sync(demuxer)) - { - mp_msg(MSGT_DEMUX, MSGL_V, "TS_FILL_BUFFER: COULDN'T SYNC\n"); - return 0; - } - - len = stream_read(demuxer->stream, &packet[1], priv->ts.packet_size-1); - if (len != priv->ts.packet_size-1) - return 0; - - pid = ((packet[1] & 0x1f) << 8) | packet[2]; - tss = priv->ts.pids[pid]; //an ES stream - if(tss == NULL) + stream_t *stream = demuxer->stream; + char *p, tmp[TS_FEC_PACKET_SIZE]; + demux_stream_t *ds; + demux_packet_t *dp; + + + while(! done) //while pid=last_pid add_to_buffer { - tss = malloc(sizeof(ES_stream_t)); - if(! tss) - continue; - memset(tss, 0, sizeof(ES_stream_t)); - tss->pid = pid; - tss->last_cc = -1; - tss->type = UNKNOWN; - priv->ts.pids[pid] = tss; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "new TS pid=%u\n", pid); - } - - cc = (packet[3] & 0xf); - cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); - if(! cc_ok) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse: CCCheck NOT OK: %d -> %d\n", tss->last_cc, cc); - } - tss->last_cc = cc; - - - - /* skip adaptation field */ - afc = (packet[3] >> 4) & 3; - p = packet + 4; - if (afc == 0) /* reserved value */ - continue; - if (afc == 2) /* adaptation field only */ - continue; - if (afc == 3) - { - /* skip adapation field */ - p += p[0] + 1; - } - /* if past the end of packet, ignore */ - if (p >= packet + TS_PACKET_SIZE) - continue; - - // PES CONTENT STARTS HERE - - buf_size = TS_PACKET_SIZE - (p - packet); - - is_start = packet[1] & 0x40; - len = pes_parse2(p, buf_size, is_start, es); - - if(len) - { - es->pid = tss->pid; - - if(! is_start) - es->type = tss->type; + 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]; + + tss = priv->ts.pids[pid]; //an ES stream + if(tss == NULL) + { + tss = malloc(sizeof(ES_stream_t)); + if(! tss) + continue; + memset(tss, 0, sizeof(ES_stream_t)); + tss->pid = pid; + tss->last_cc = -1; + tss->type = UNKNOWN; + tss->payload_size = 0; + priv->ts.pids[pid] = tss; + mp_msg(MSGT_DEMUX, MSGL_V, "new TS pid=%u\n", pid); + } + + if((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) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse: CCCheck NOT OK: %d -> %d\n", tss->last_cc, cc); + } + 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) + { + 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; + } + + // PES CONTENT STARTS HERE + + buf_size = priv->ts.packet_size - _read; + + if(! probe) + { + if((tss->type == VIDEO_MPEG2) && (demuxer->video->id == tss->pid)) + ds = demuxer->video; + else if(((tss->type == AUDIO_MP2) || (tss->type == AUDIO_A52) || (tss->type == AUDIO_LPCM_BE)) + && (demuxer->audio->id == tss->pid)) + ds = demuxer->audio; + else + { + stream_read(stream, tmp, buf_size); + _read += buf_size; + continue; + } + } + + + if(is_start) + { + p = &packet[_read]; + stream_read(stream, p, buf_size); + _read += buf_size; + + len = pes_parse2(p, buf_size, es); + + if(len) + { + if(es->type == UNKNOWN) + continue; + + es->pid = tss->pid; + tss->type = es->type; + + if((es->pts < tss->last_pts) && es->pts) + mp_msg(MSGT_DEMUX, MSGL_V, "BACKWARDS PTS! : NEW: %f -> LAST: %f, PID %d\n", es->pts, tss->last_pts, tss->pid); + + if(es->pts == 0.0f) + es->pts = tss->pts = tss->last_pts; + else + tss->pts = tss->last_pts = es->pts; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse, NEW pid=%d, PSIZE: %u, type=%X, start=%X, len=%d\n", + es->pid, es->payload_size, es->type, es->start, es->size); + + tss->payload_size = es->payload_size; + + mp_msg(MSGT_DEMUX, MSGL_V, "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) + { + fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", es->size); + continue; + } + + 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; + } + } + } else { - tss->type = es->type; - tss->payload_size = es->payload_size; + uint16_t sz; + + if(tss->type == UNKNOWN) + { + stream_read(stream, tmp, buf_size); + continue; + } + + es->pid = tss->pid; + es->type = tss->type; + es->pts = tss->pts = tss->last_pts; + es->start = &packet[_read]; + + + if(tss->payload_size) + { + sz = min(tss->payload_size, buf_size); + tss->payload_size -= sz; + es->size = sz; + } + else + { + if(es->type == VIDEO_MPEG2) + sz = es->size = buf_size; + else + { + stream_read(stream, tmp, 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); + + mp_msg(MSGT_DEMUX, MSGL_V, "DOPO DS_READ_PACKET pid %d, size %d DS=%p\n", tss->pid, sz, ds); + return -sz; + + } + else + { + stream_read(stream, es->start, sz); + if(buf_size - sz) stream_read(stream, tmp, buf_size-sz); + + _read += buf_size; + + if(es->size) + return es->size; + else + continue; + } } - - if(es->pts == 0.0f) - es->pts = tss->pts = tss->last_pts; - else - tss->pts = tss->last_pts = es->pts; - - mp_msg(MSGT_DEMUX, MSGL_V, "ts_parse, pid=%d, PSIZE: %u, type=%X, start=%X, len=%d\n", es->pid, es->payload_size, es->type, es->start, es->size); - - return len; - } - } - - return 0; + } + + return 0; } - int demux_ts_fill_buffer(demuxer_t * demuxer) { - ES_stream_t es; - demux_packet_t *dp; - int len; - unsigned char packet[TS_FEC_PACKET_SIZE]; - int *apid, *vpid, *spid; - - apid = &(demuxer->audio->id); - vpid = &(demuxer->video->id); - spid = &(demuxer->sub->id); - - while((len = ts_parse(demuxer, &es, packet)) > 0) - { - mp_msg(MSGT_DEMUX, MSGL_V, "NEW_FILL_BUFFER, NEW_ADD_PACKET(%x, %d) type: %x, PTS: %f\n", es.start, es.size, es.type, es.pts); - - if(es.type == VIDEO_MPEG2) - { - if(ts_fastparse) - { - if(*vpid == -2) - continue; - - if(*vpid == -1) - *vpid = es.pid; - } - - if(*vpid != es.pid) - continue; - - dp = new_demux_packet(es.size); - if(! dp || ! dp->buffer) - { - fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size); - continue; - } - memcpy(dp->buffer, es.start, es.size); - dp->pts = es.pts; - dp->flags = 0; - dp->pos = stream_tell(demuxer->stream); - ds_add_packet(demuxer->video, dp); - mp_msg(MSGT_DEMUX, MSGL_V, "VIDEO pts=%f\n", es.pts); - return len; - } - - if((es.type == AUDIO_MP2) || (es.type == AUDIO_A52) || (es.type == AUDIO_LPCM_BE)) - { - mp_msg(MSGT_DEMUX, MSGL_V, "FILL_AUDIO %x \n", es.type); - - if(ts_fastparse) - { - if(*apid == -2) - continue; - - if(*apid == -1) - *apid = es.pid; - } - - if(*apid != es.pid) - continue; - - dp = new_demux_packet(es.size); - if(! dp || ! dp->buffer) - { - fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size); - continue; - } - memcpy(dp->buffer, es.start, es.size); - dp->flags = 0; - dp->pts = es.pts; - dp->pos = stream_tell(demuxer->stream); - ds_add_packet(demuxer->audio, dp); - mp_msg(MSGT_DEMUX, MSGL_V, "AUDIO pts=%f\r\n", es.pts); - return len; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "SKIP--------\n"); - } - return 0; + ES_stream_t es; + char packet[TS_FEC_PACKET_SIZE]; + + return -ts_parse(demuxer, &es, packet, 0); } -int stringent_ts_sync(demuxer_t *demuxer) -{ - ts_priv_t *priv = demuxer->priv; - uint8_t c = 0, done = 0, i, buf[TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS]; - off_t pos; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC packet_size: %d\n", priv->ts.packet_size); - - - if(! demuxer->seekable) - return 0; - - - while(! done) - { - while(((c=stream_read_char(demuxer->stream)) != 0x47) && !demuxer->stream->eof); - - if(c != 0x47) - { - stream_reset(demuxer->stream); - return 0; - } - - pos = stream_tell(demuxer->stream); - if(pos < 1) - pos = 1; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "dopo il while, pos=%u\n", pos); - - done = 1; - buf[0] = c; - stream_read(demuxer->stream, &buf[1], (priv->ts.packet_size * NUM_CONSECUTIVE_TS_PACKETS) - 1); - for(i = 0; i < 5; i++) - { - if (buf[i * priv->ts.packet_size] != 0x47) - done = 0; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "i: %d, char: %x\n", i, buf[i * priv->ts.packet_size]); - } - - if(done) - stream_seek(demuxer->stream, pos); - else - stream_seek(demuxer->stream, pos); - } - //stream_seek(demuxer->stream, pos+1); - mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC, STREAM_POS: %lu\n", stream_tell(demuxer->stream)); - return 0x47; -} - - -extern void resync_audio_stream(sh_audio_t *); - - int demux_seek_ts(demuxer_t * demuxer, float rel_seek_secs, int flags) { int total_bitrate=0; @@ -813,62 +866,43 @@ * with MPEG streams, the bitrate is not constant. Moreover, we do not take into account * the overhead caused by PVA and PES headers. * If the calculated absolute offset is negative, seek to the beginning of the file. + */ - + if(demuxer->audio->id != -2) { - a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps; - total_bitrate += a_bps; + a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps; + total_bitrate += a_bps; } - - if(demuxer->video->id != -2) + + if(demuxer->video->id != -2) { - v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps; - total_bitrate += v_bps; + v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps; + total_bitrate += v_bps; } - - if(! total_bitrate) + + if(! total_bitrate) { - mp_msg(MSGT_DEMUX, MSGL_V, "SEEK_TS, couldn't determine bitrate, no seek\n"); - return 0; + mp_msg(MSGT_DEMUX, MSGL_V, "SEEK_TS, couldn't determine bitrate, no seek\n"); + return 0; } - + dest_offset = stream_tell(demuxer->stream) + rel_seek_secs*total_bitrate; if(dest_offset < 0) dest_offset = 0; - + mp_msg(MSGT_DEMUX, MSGL_V, "SEEK TO: %f, BITRATE: %lu, FINAL_POS: %u \n", rel_seek_secs, total_bitrate, dest_offset); - + stream_seek(demuxer->stream, dest_offset); - /*if(!ts_sync(demuxer)) - { - mp_msg(MSGT_DEMUX, MSGL_V, "demux_ts: Couldn't seek!\n"); - return 0; - } - */ - ds_fill_buffer(d_video); if(sh_audio) { - ds_fill_buffer(d_audio); - resync_audio_stream(sh_audio); + ds_fill_buffer(d_audio); + resync_audio_stream(sh_audio); } return 1; } - - - -static int mpegts_read_close(MpegTSContext *ts) -{ - int i; - for(i=0;i<NB_PID_MAX;i++) - free(ts->pids[i]); - return 0; -} - - -