aboutsummaryrefslogtreecommitdiffhomepage
path: root/libmpdemux
diff options
context:
space:
mode:
authorGravatar arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-08-24 18:07:00 +0000
committerGravatar arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-08-24 18:07:00 +0000
commit511946aa0a3fc4afce0379e0ae5d5a8d2eba1754 (patch)
tree429064154a2b493ba5f7c0be30c07bddefea9894 /libmpdemux
parentcce8e3c630256135a7cf82b32f9f6209fcd07a34 (diff)
- seek() is always synchronized to keyframes, so the decoders don't
crash anymore; successfully tested with libmpeg2 and ffmpeg12 - support for tables PAT and PMT, used the associate pids to program and to play the right streams - option -tsprog <number> to specify the chosen program (-vid and -aid still override the single stream pids) - initial support for MPEG4 in TS (M4V is working, but not AAC yet) - defragmenting mechanism (without buffering, so it has 0 added cost) to improve the playback of high bitrate movies - refers to demux_mpg_control() to get length and percentage position in the stream patch by Nico <nsabbi@libero.it> git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@10687 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/demux_ts.c1141
1 files changed, 981 insertions, 160 deletions
diff --git a/libmpdemux/demux_ts.c b/libmpdemux/demux_ts.c
index 1631b2dc5f..8ae1c3f842 100644
--- a/libmpdemux/demux_ts.c
+++ b/libmpdemux/demux_ts.c
@@ -42,20 +42,23 @@
#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_MPEG1 = 0x10000001,
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 +84,65 @@ typedef struct MpegTSContext {
typedef struct {
+ demux_stream_t *ds;
+ demux_packet_t *pack;
+ int offset, buffer_size;
+ int broken; //set if it's the final part of a chunk (doesn't have a corresponding 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_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_len;
+ uint16_t es_cnt;
+ struct pmt_es_t {
+ uint16_t pid;
+ uint32_t type; //it's 8 bit long, but cast to the right type as FOURCC
+ uint16_t descr_length;
+ } *es;
+} pmt_t;
+
+typedef struct {
MpegTSContext ts;
+ int is_synced; //synced to the beginning of priv->last_pid PES header
+ 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 +182,11 @@ int ts_check_file(demuxer_t * demuxer)
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 +203,7 @@ int ts_check_file(demuxer_t * demuxer)
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 +241,7 @@ int ts_check_file(demuxer_t * demuxer)
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 +261,173 @@ int ts_check_file(demuxer_t * demuxer)
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 inline int32_t progid_for_pid(ts_priv_t *priv, int pid, int32_t req) //finds the first program listing a pid
+{
+ 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)
+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;
+ 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)
{
+ pos = stream_tell(demuxer->stream);
if(ts_parse(demuxer, &es, tmp, 1))
{
- mp_msg(MSGT_DEMUXER, MSGL_DBG2, "TYPE: %x, PID: %d\n", es.type, es.pid);
+ is_audio = ((es.type == AUDIO_MP2) || (es.type == AUDIO_A52) || (es.type == AUDIO_LPCM_BE) || (es.type == AUDIO_AAC));
+ is_video = ((es.type == VIDEO_MPEG1) || (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;
+
+ 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_DBG2, "TYPE: %x, PID: %d, PROG FOUND: %d\n", es.type, es.pid, *prog);
- if((*fvpid == -1) || (*fvpid == es.pid))
+ 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 +435,54 @@ static void ts_detect_streams(demuxer_t *demuxer, uint32_t *a, uint32_t *v, int
}
- 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_MPEG1 ? 1 : (*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)
@@ -326,6 +504,7 @@ demuxer_t *demux_open_ts(demuxer_t * demuxer)
sh_audio_t *sh_audio;
uint32_t at = 0, vt = 0;
ts_priv_t * priv = (ts_priv_t*) demuxer->priv;
+ demuxer_t *od;
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);
@@ -333,6 +512,7 @@ demuxer_t *demux_open_ts(demuxer_t * demuxer)
demuxer->type= DEMUXER_TYPE_MPEG_TS;
+
stream_reset(demuxer->stream);
stream_seek(demuxer->stream, 0);
@@ -341,30 +521,46 @@ demuxer_t *demux_open_ts(demuxer_t * demuxer)
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->ts.packet_size = packet_size;
+ priv->pat.progs = NULL;
+ priv->pat.progs_cnt = 0;
+ priv->pmt = NULL;
+ priv->pmt_cnt = 0;
- demuxer->priv = priv;
+ priv->ts.packet_size = packet_size;
- if(demuxer->stream->type != STREAMTYPE_FILE) demuxer->seekable=0;
- else demuxer->seekable = 1;
+ demuxer->priv = priv;
+ if(demuxer->stream->type != STREAMTYPE_FILE)
+ demuxer->seekable = 0;
+ 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);
+ stream_seek(demuxer->stream, 0); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES?
+ 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)
{
+ if(vt == VIDEO_MPEG4)
+ demuxer->file_format= DEMUXER_TYPE_MPEG4_IN_TS;
+
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,14 +574,38 @@ demuxer_t *demux_open_ts(demuxer_t * demuxer)
}
- 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_len = 0;
+
+ demuxer->filepos = stream_tell(demuxer->stream);
return demuxer;
}
@@ -407,15 +627,18 @@ void demux_close_ts(demuxer_t * demuxer)
-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 +719,7 @@ static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es)
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 +732,10 @@ static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es)
if(es->payload_size)
es->payload_size -= header_len + 3;
+
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 +749,14 @@ static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es)
* 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 +831,19 @@ static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es)
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 +856,16 @@ static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es)
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 +892,425 @@ static int ts_sync(stream_t *stream)
}
+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 = 0;
+ 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_len == 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_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_len]), &buff[m], 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;
+
+
+ //beginning of 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);
+ }
+
+ return 1;
+}
+
+
+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=0;
+
+ 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_len == 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_len = 0;
+ skip = buff[0] + 1;
+ m = min(skip, size);
+
+ pmt->skip = skip - m;
+
+ if(m == size)
+ return 0;
+ }
+
+ memcpy(&(pmt->buffer[pmt->buffer_len]), &buff[m], size - m);
+ pmt->progid = progid;
+ 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:
+ pmt->es[idx].type = VIDEO_MPEG1;
+ break;
+ 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) //possible DVB-AC3
+ 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 = NULL;
+ 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);
+ demuxer->filepos = stream_tell(demuxer->stream);
+ 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 +1324,14 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
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 +1340,167 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
}
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++;
+ 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;
+ 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))
+ if(((tss->type == VIDEO_MPEG1) || (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);
+ stream_skip(stream, buf_size);
_read += buf_size;
continue;
}
+
+ //IS IT TIME TO QUEUE DATA to the dp_packet?
+ 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_DBG2, "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,29 +1523,35 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
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);
+ demuxer->filepos = stream_tell(demuxer->stream) - es->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;
}
}
+ else
+ return 0;
}
else
{
@@ -802,10 +1559,11 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
if(tss->type == UNKNOWN)
{
- stream_read(stream, tmp, buf_size);
+ stream_skip(stream, buf_size);
continue;
}
+
es->pid = tss->pid;
es->type = tss->type;
es->pts = tss->pts = tss->last_pts;
@@ -820,26 +1578,34 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
}
else
{
- if(es->type == VIDEO_MPEG2)
+ if((es->type == VIDEO_MPEG1) || (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,72 +1626,127 @@ static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet,
}
-int demux_ts_fill_buffer(demuxer_t * demuxer)
+extern void resync_audio_stream(sh_audio_t *sh_audio);
+extern void skip_audio_frame(sh_audio_t *sh_audio);
+
+static void reset_fifos(ts_priv_t* priv, int a, int v)
{
- ES_stream_t es;
- char packet[TS_FEC_PACKET_SIZE];
+ if(a)
+ {
+ priv->fifo[0].pack = NULL;
+ priv->fifo[0].offset = 0;
+ priv->fifo[0].buffer_size = 0;
+ priv->fifo[0].broken = 1;
+ priv->is_synced = 0;
+ }
- return -ts_parse(demuxer, &es, packet, 0);
+ if(v)
+ {
+ priv->fifo[1].pack = NULL;
+ priv->fifo[1].offset = 0;
+ priv->fifo[1].buffer_size = 0;
+ priv->fifo[1].broken = 1;
+ priv->is_synced = 0;
+ }
}
-
-
-
-int demux_seek_ts(demuxer_t * demuxer, float rel_seek_secs, int flags)
+void demux_seek_ts(demuxer_t *demuxer,float rel_seek_secs,int flags)
{
- 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;
sh_audio_t *sh_audio=d_audio->sh;
sh_video_t *sh_video=d_video->sh;
+ ts_priv_t * priv = (ts_priv_t*) demuxer->priv;
+ int i, video_stats;
+ //================= seek in MPEG ==========================
+ off_t newpos = (flags&1)?demuxer->movi_start:demuxer->filepos;
- /*
- * Compute absolute offset inside the stream. Approximate total bitrate with sum of bitrates
- * reported by the audio and video codecs. The seek is not accurate because, just like
- * 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.
+ ts_dump_streams(demuxer->priv);
+ reset_fifos(priv, sh_audio != NULL, sh_video != NULL);
- */
+ video_stats = (sh_video != NULL);
+ if(video_stats)
+ video_stats = sh_video->i_bps;
- if(demuxer->audio->id != -2)
+ if(flags & 2) // float seek 0..1
+ newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs;
+ else
{
- a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps;
- total_bitrate += a_bps;
- }
+ // time seek (secs)
- if(demuxer->video->id != -2)
- {
- v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps;
- total_bitrate += v_bps;
+ if(! video_stats) // unspecified or VBR
+ newpos += 2324*75*rel_seek_secs; // 174.3 kbyte/sec
+ else
+ newpos += video_stats*rel_seek_secs;
}
- if(! total_bitrate)
- {
- 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;
+ if(newpos<demuxer->movi_start)
+ newpos = demuxer->movi_start = 0; //begininng of stream
+
+#ifdef _LARGEFILE_SOURCE
+ newpos &= ~((long long) (STREAM_BUFFER_SIZE - 1)); /* sector boundary */
+#else
+ newpos &= ~(STREAM_BUFFER_SIZE - 1); /* sector boundary */
+#endif
+
+ reset_fifos(priv, sh_audio != NULL, sh_video != NULL);
- mp_msg(MSGT_DEMUX, MSGL_V, "SEEK TO: %f, BITRATE: %lu, FINAL_POS: %u \n", rel_seek_secs, total_bitrate, dest_offset);
+ if(sh_audio != NULL)
+ ds_free_packs(d_audio);
+ if(sh_video != NULL)
+ ds_free_packs(d_video);
- stream_seek(demuxer->stream, dest_offset);
+ stream_seek(demuxer->stream, newpos);
- ds_fill_buffer(d_video);
- if(sh_audio)
+
+ if(sh_video != NULL)
+ ds_fill_buffer(d_video);
+
+ if(sh_audio != NULL)
{
ds_fill_buffer(d_audio);
resync_audio_stream(sh_audio);
}
- return 1;
+ while(sh_video != NULL)
+ {
+ if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts)
+ {
+ float a_pts=d_audio->pts;
+ a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+ if(d_video->pts>a_pts)
+ {
+ skip_audio_frame(sh_audio); // sync audio
+ continue;
+ }
+ }
+
+
+ i = sync_video_packet(d_video);
+ if(sh_video->format == VIDEO_MPEG1 || sh_video->format == VIDEO_MPEG2)
+ {
+ if(i==0x1B3 || i==0x1B8) break; // found it!
+ }
+ else //MPEG4
+ {
+ if(i==0x1B6) break; // found it!
+ }
+
+ if(!i || !skip_video_packet(d_video)) break; // EOF?
+ }
}
+int demux_ts_fill_buffer(demuxer_t * demuxer)
+{
+ ES_stream_t es;
+ char packet[TS_FEC_PACKET_SIZE];
+
+ return -ts_parse(demuxer, &es, packet, 0);
+}
+
+
+