diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux.h | 32 | ||||
-rw-r--r-- | src/demuxers/demux_avi.c | 84 | ||||
-rw-r--r-- | src/demuxers/demux_elem.c | 43 | ||||
-rw-r--r-- | src/demuxers/demux_mpeg.c | 57 | ||||
-rw-r--r-- | src/demuxers/demux_mpeg_block.c | 379 | ||||
-rw-r--r-- | src/demuxers/demux_mpgaudio.c | 29 | ||||
-rw-r--r-- | src/demuxers/demux_pes.c | 96 | ||||
-rw-r--r-- | src/demuxers/demux_ts.c | 1693 | ||||
-rw-r--r-- | src/libmpeg2/decode.c | 6 | ||||
-rw-r--r-- | src/xine-engine/audio_decoder.c | 5 | ||||
-rw-r--r-- | src/xine-engine/buffer.h | 5 | ||||
-rw-r--r-- | src/xine-engine/video_decoder.c | 6 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 196 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 42 |
14 files changed, 1352 insertions, 1321 deletions
diff --git a/src/demuxers/demux.h b/src/demuxers/demux.h index 017af8f0f..3bdcae1b1 100644 --- a/src/demuxers/demux.h +++ b/src/demuxers/demux.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 the xine project + * Copyright (C) 2000, 2001 the xine project * * This file is part of xine, a unix video player. * @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux.h,v 1.8 2001/07/18 21:38:16 f1rmb Exp $ + * $Id: demux.h,v 1.9 2001/09/01 14:32:59 guenter Exp $ */ #ifndef HAVE_DEMUX_H @@ -35,7 +35,7 @@ extern "C" { #include "input_plugin.h" #endif -#define DEMUXER_PLUGIN_IFACE_VERSION 2 +#define DEMUXER_PLUGIN_IFACE_VERSION 3 #define DEMUX_OK 0 #define DEMUX_FINISHED 1 @@ -57,8 +57,7 @@ typedef char* (*gui_get_next_mrl_cb_t) (void); typedef void (*gui_branched_cb_t) (void); /* - * a demux plugin (no matter if it's staically built into xine - * or dynamically loaded at run-time) must implement these functions + * a demux plugin must implement these functions */ typedef struct demux_plugin_s demux_plugin_t; @@ -84,12 +83,20 @@ struct demux_plugin_s /* * start demux thread - * pos : 0..65535 + * + * for seekable streams, a start position can be specified + * + * start_pos : position in input source + * start_time : position measured in seconds from stream start + * + * if both parameters are !=0 start_pos will be used + * for non-seekable streams both values will be ignored */ void (*start) (demux_plugin_t *this, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, gui_get_next_mrl_cb_t next_mrl_cb, + off_t start_pos, int start_time, + gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) ; /* @@ -117,15 +124,18 @@ struct demux_plugin_s char* (*get_identifier) (void); + /* + * estimate stream length in seconds + * may return 0 for non-seekable streams + */ + + int (*get_stream_length) (demux_plugin_t *this); } ; /* - * for dynamic demux plugins: - * - * make sure you provide this (and only this!) function call: + * demuxer plugins should provide this (and only this!) function call: * * demux_plugin_t *init_demux_plugin (int iface_version, config_values_t *cfg); - * */ #ifdef __cplusplus diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c index 8e7c96044..2bdc9f64c 100644 --- a/src/demuxers/demux_avi.c +++ b/src/demuxers/demux_avi.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_avi.c,v 1.30 2001/09/01 01:51:50 jcdutton Exp $ + * $Id: demux_avi.c,v 1.31 2001/09/01 14:32:59 guenter Exp $ * * demultiplexer for avi streams * @@ -705,7 +705,6 @@ static int demux_avi_next (demux_avi_t *this) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->content = buf->mem; - buf->DTS = 0 ; /* FIXME */ audio_pts = get_audio_pts (this, this->avi->audio_posc, this->avi->audio_posb); video_pts = get_video_pts (this, this->avi->video_posf); @@ -723,7 +722,8 @@ static int demux_avi_next (demux_avi_t *this) { return 0; } - buf->input_pos = this->input->get_current_pos(this->input); + buf->input_pos = 0; + buf->input_time = 0; buf->type = this->avi->audio_type; buf->decoder_info[1] = this->avi->a_rate; /* Audio Rate */ @@ -740,9 +740,12 @@ static int demux_avi_next (demux_avi_t *this) { /* read video */ xprintf (VERBOSE|DEMUX|VAVI, "demux_avi: video \n"); - buf->PTS = video_pts; - buf->size = AVI_read_video (this, this->avi, buf->mem, 2048, &buf->decoder_info[0]); - buf->type = this->avi->video_type; + buf->PTS = video_pts; + buf->size = AVI_read_video (this, this->avi, buf->mem, 2048, &buf->decoder_info[0]); + buf->type = this->avi->video_type; + + buf->input_time = video_pts / 90000; + buf->input_pos = this->input->get_current_pos(this->input); if (buf->size<0) { buf->free_buffer (buf); @@ -849,13 +852,13 @@ static int demux_avi_get_status (demux_plugin_t *this_gen) { static void demux_avi_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, + off_t start_pos, int start_time, gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) { buf_element_t *buf; demux_avi_t *this = (demux_avi_t *) this_gen; - uint32_t video_pts; + uint32_t video_pts = 0; this->audio_fifo = audio_fifo; this->video_fifo = video_fifo; @@ -889,24 +892,39 @@ static void demux_avi_start (demux_plugin_t *this_gen, AVI_seek_start (this->avi); /* - * seek + * seek to start pos / time */ /* seek video */ - - while ( (this->avi->video_index[this->avi->video_posf].pos < pos) - || !(this->avi->video_index[this->avi->video_posf].flags & AVIIF_KEYFRAME) ) { - this->avi->video_posf++; - if (this->avi->video_posf>this->avi->video_frames) { - this->status = DEMUX_FINISHED; - return; + if (start_pos) { + while ( (this->avi->video_index[this->avi->video_posf].pos < start_pos) + || !(this->avi->video_index[this->avi->video_posf].flags & AVIIF_KEYFRAME) ) { + this->avi->video_posf++; + if (this->avi->video_posf>this->avi->video_frames) { + this->status = DEMUX_FINISHED; + return; + } } - } + + video_pts = get_video_pts (this, this->avi->video_posf); + + } else if (start_time) { - video_pts = get_video_pts (this, this->avi->video_posf); + video_pts = start_time * 90000; + + while ( (get_video_pts (this, this->avi->video_posf) < video_pts) + || !(this->avi->video_index[this->avi->video_posf].flags & AVIIF_KEYFRAME) ) { + this->avi->video_posf++; + if (this->avi->video_posf>this->avi->video_frames) { + this->status = DEMUX_FINISHED; + return; + } + } + } + /* seek audio */ if (!this->no_audio) { - /* seek audio */ + while (get_audio_pts (this, this->avi->audio_posc, 0) < video_pts) { this->avi->audio_posc++; if (this->avi->audio_posc>this->avi->audio_chunks) { @@ -916,6 +934,7 @@ static void demux_avi_start (demux_plugin_t *this_gen, } } + /* * send start buffers */ @@ -1028,8 +1047,6 @@ static int demux_avi_open(demux_plugin_t *this_gen, demux_avi_t *this = (demux_avi_t *) this_gen; - printf ("avi_open...\n"); fflush (stdout); - switch(stage) { case STAGE_BY_CONTENT: { @@ -1043,13 +1060,8 @@ static int demux_avi_open(demux_plugin_t *this_gen, this->input = input; - printf ("avi_init...\n"); fflush (stdout); - this->avi = AVI_init (this); - printf ("avi_init...done\n"); - - if (this->avi) { printf ("demux_avi: %ld frames\n", this->avi->video_frames); @@ -1100,14 +1112,25 @@ static char *demux_avi_get_id(void) { return "AVI"; } +static int demux_avi_get_stream_length (demux_plugin_t *this_gen) { + + demux_avi_t *this = (demux_avi_t *) this_gen; + + if (this->avi) { + return get_video_pts(this, this->avi->video_frames) / 90000 ; + } + + return 0; +} + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_avi_t *this; - if (iface != 2) { - printf( "demux_mpeg: plugin doesn't support plugin API version %d.\n" - "demux_mpeg: this means there's a version mismatch between xine and this " - "demux_mpeg: demuxer plugin.\nInstalling current input plugins should help.\n", + if (iface != 3) { + printf( "demux_avi: this plugin doesn't support plugin API version %d.\n" + "demux_avi: this means there's a version mismatch between xine and this " + "demux_avi: demuxer plugin.\nInstalling current demuxer plugins should help.\n", iface); return NULL; } @@ -1122,6 +1145,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_avi_close; this->demux_plugin.get_status = demux_avi_get_status; this->demux_plugin.get_identifier = demux_avi_get_id; + this->demux_plugin.get_stream_length = demux_avi_get_stream_length; return (demux_plugin_t *) this; } diff --git a/src/demuxers/demux_elem.c b/src/demuxers/demux_elem.c index 159623e9f..ddf0f4290 100644 --- a/src/demuxers/demux_elem.c +++ b/src/demuxers/demux_elem.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_elem.c,v 1.16 2001/08/25 08:40:08 guenter Exp $ + * $Id: demux_elem.c,v 1.17 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for elementary mpeg streams * @@ -82,7 +82,6 @@ static int demux_mpeg_elem_next (demux_mpeg_elem_t *this, int preview_mode) { else buf->decoder_info[0] = 1; - buf->DTS = 0; buf->PTS = 0; buf->input_pos = this->input->get_current_pos(this->input); buf->type = BUF_VIDEO_MPEG; @@ -174,11 +173,12 @@ static int demux_mpeg_elem_get_status (demux_plugin_t *this_gen) { * */ static void demux_mpeg_elem_start (demux_plugin_t *this_gen, - fifo_buffer_t *video_fifo, - fifo_buffer_t *audio_fifo, - off_t pos, - gui_get_next_mrl_cb_t next_mrl_cb, - gui_branched_cb_t branched_cb) { + fifo_buffer_t *video_fifo, + fifo_buffer_t *audio_fifo, + off_t start_pos, int start_time, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb) { + demux_mpeg_elem_t *this = (demux_mpeg_elem_t *) this_gen; buf_element_t *buf; @@ -187,12 +187,9 @@ static void demux_mpeg_elem_start (demux_plugin_t *this_gen, this->status = DEMUX_OK; - if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos, SEEK_SET); - } - - this->blocksize = 2048; + this->blocksize = this->input->get_blocksize(this->input); + if (!this->blocksize) + this->blocksize = 2048; buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_CONTROL_START; @@ -215,8 +212,10 @@ static void demux_mpeg_elem_start (demux_plugin_t *this_gen, num_buffers--; } - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos, SEEK_SET); + /* FIXME: implement time seek */ + + xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",start_pos); + this->input->seek (this->input, start_pos, SEEK_SET); } /* @@ -230,7 +229,7 @@ static void demux_mpeg_elem_start (demux_plugin_t *this_gen, * */ static int demux_mpeg_elem_open(demux_plugin_t *this_gen, - input_plugin_t *input, int stage) { + input_plugin_t *input, int stage) { demux_mpeg_elem_t *this = (demux_mpeg_elem_t *) this_gen; @@ -245,8 +244,7 @@ static int demux_mpeg_elem_open(demux_plugin_t *this_gen, if((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { input->seek(input, 0, SEEK_SET); - if(input->get_blocksize) - bs = input->get_blocksize(input); + bs = input->get_blocksize(input); if (bs<4) bs = 4; @@ -308,6 +306,10 @@ static void demux_mpeg_elem_close (demux_plugin_t *this) { /* nothing */ } +static int demux_mpeg_elem_get_stream_length(demux_plugin_t *this_gen, + input_plugin_t *input, int stage) { + return 0 ; /*FIXME: implement */ +} /* * */ @@ -315,10 +317,10 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_mpeg_elem_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_elem: plugin doesn't support plugin API version %d.\n" "demux_elem: this means there's a version mismatch between xine and this " - "demux_elem: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_elem: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } @@ -333,6 +335,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpeg_elem_close; this->demux_plugin.get_status = demux_mpeg_elem_get_status; this->demux_plugin.get_identifier = demux_mpeg_elem_get_id; + this->demux_plugin.get_stream_length = demux_mpeg_elem_get_stream_length; return &this->demux_plugin; } diff --git a/src/demuxers/demux_mpeg.c b/src/demuxers/demux_mpeg.c index 1096f310c..5eeb28f81 100644 --- a/src/demuxers/demux_mpeg.c +++ b/src/demuxers/demux_mpeg.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_mpeg.c,v 1.31 2001/08/28 19:16:19 guenter Exp $ + * $Id: demux_mpeg.c,v 1.32 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for mpeg 1/2 program streams * reads streams of variable blocksizes @@ -62,6 +62,8 @@ typedef struct demux_mpeg_s { int status; int preview_mode; + int rate; + int send_end_buffers; } demux_mpeg_t ; @@ -168,7 +170,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_AUDIO_A52 + track; buf->PTS = pts; - buf->DTS = 0 ; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -218,7 +219,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_AUDIO_MPEG + track; buf->PTS = pts; - buf->DTS = 0; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -268,7 +268,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_VIDEO_MPEG; buf->PTS = pts; - buf->DTS = 0; if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -390,12 +389,13 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int nID) } buf->type = BUF_AUDIO_MPEG + track ; buf->PTS = pts; - buf->DTS = 0; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else buf->decoder_info[0] = 1; buf->input_pos = this->input->get_current_pos(this->input); + if (this->rate) + buf->input_time = buf->input_pos / (this->rate * 50); if(this->audio_fifo) this->audio_fifo->put (this->audio_fifo, buf); @@ -404,8 +404,7 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int nID) xprintf (VERBOSE|DEMUX|VIDEO, ", video #%d", nID & 0x0f); - if(this->input->read_block) - buf = this->input->read_block (this->input, this->video_fifo, nLen); + buf = this->input->read_block (this->input, this->video_fifo, nLen); if (buf == NULL) { this->status = DEMUX_FINISHED; @@ -413,12 +412,13 @@ static void parse_mpeg1_packet (demux_mpeg_t *this, int nID) } buf->type = BUF_VIDEO_MPEG; buf->PTS = pts; - buf->DTS = 0; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else buf->decoder_info[0] = 1; buf->input_pos = this->input->get_current_pos(this->input); + if (this->rate) + buf->input_time = buf->input_pos / (this->rate * 50); this->video_fifo->put (this->video_fifo, buf); @@ -459,9 +459,19 @@ static uint32_t parse_pack(demux_mpeg_t *this) /* mux_rate */ - buf = read_bytes (this, 3) ; + if (!this->rate) { + buf = read_bytes (this,1); + this->rate = (buf & 0x7F) << 15; + buf = read_bytes (this,1); + this->rate |= (buf << 7); + buf = read_bytes (this,1); + this->rate |= (buf >> 1); + + /* printf ("demux_mpeg: mux_rate = %d\n",this->rate); */ + + } else + buf = read_bytes (this, 3) ; - /* printf (" mux_rate = %06x\n",buf); */ /* system header */ @@ -595,7 +605,7 @@ static int demux_mpeg_get_status (demux_plugin_t *this_gen) { static void demux_mpeg_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, + off_t start_pos, int start_time, gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) { @@ -605,6 +615,8 @@ static void demux_mpeg_start (demux_plugin_t *this_gen, this->video_fifo = video_fifo; this->audio_fifo = audio_fifo; + this->rate = 0; /* fixme */ + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = BUF_CONTROL_START; this->video_fifo->put (this->video_fifo, buf); @@ -636,8 +648,11 @@ static void demux_mpeg_start (demux_plugin_t *this_gen, } while ( (this->status == DEMUX_OK) && (num_buffers>0)) ; - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos+4, SEEK_SET); + if ( (!start_pos) && (start_time)) + start_pos = start_time * this->rate * 50; + + this->input->seek (this->input, start_pos+4, SEEK_SET); + } else read_bytes(this, 4); @@ -759,14 +774,25 @@ static void demux_mpeg_close (demux_plugin_t *this) { /* nothing */ } +static int demux_mpeg_get_stream_length (demux_plugin_t *this_gen) { + + demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + + if (this->rate) + return this->input->get_length (this->input) / (this->rate * 50); + else + return 0; + +} + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_mpeg_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_mpeg: plugin doesn't support plugin API version %d.\n" "demux_mpeg: this means there's a version mismatch between xine and this " - "demux_mpeg: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_mpeg: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } @@ -781,6 +807,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpeg_close; this->demux_plugin.get_status = demux_mpeg_get_status; this->demux_plugin.get_identifier = demux_mpeg_get_id; + this->demux_plugin.get_stream_length = demux_mpeg_get_stream_length; return (demux_plugin_t *) this; } diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c index ee6ebdf40..a7c602262 100644 --- a/src/demuxers/demux_mpeg_block.c +++ b/src/demuxers/demux_mpeg_block.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_mpeg_block.c,v 1.34 2001/08/31 17:57:54 jkeil Exp $ + * $Id: demux_mpeg_block.c,v 1.35 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for mpeg 1/2 program streams * @@ -56,6 +56,7 @@ typedef struct demux_mpeg_block_s { int status; int blocksize; + int rate; int send_end_buffers; @@ -72,12 +73,10 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m buf_element_t *buf = NULL; unsigned char *p; int bMpeg1=0; - uint32_t nHeaderLen; - uint32_t nPTS; - uint32_t nDTS; - uint32_t nPacketLen; - uint32_t nStreamID; - + uint32_t header_len; + uint32_t PTS; + uint32_t packet_len; + uint32_t stream_id; buf = this->input->read_block (this->input, this->video_fifo, this->blocksize); @@ -127,9 +126,13 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m else buf->decoder_info[0] = 1; + buf->input_pos = this->input->get_current_pos (this->input); + + if (this->rate) + buf->input_time = buf->input_pos / (this->rate * 50); + if (p[3] == 0xBA) { /* program stream pack header */ - int nStuffingBytes; xprintf (VERBOSE|DEMUX, "program stream pack header\n"); @@ -137,28 +140,59 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m if (bMpeg1) { + if (!this->rate) { + this->rate = (p[9] & 0x7F) << 15; + this->rate |= (p[10] << 7); + this->rate |= (p[11] >> 1); + } + + buf->input_time = buf->input_pos / (this->rate * 50); + p += 12; } else { /* mpeg2 */ - nStuffingBytes = p[0xD] & 0x07; + int num_stuffing_bytes; + + /* SCR decoding code works but is not used by xine + int scr; + + scr = (p[4] & 0x38) << 27 ; + scr |= (p[4] & 0x03) << 28 ; + scr |= p[5] << 20; + scr |= (p[6] & 0xF8) << 12 ; + scr |= (p[6] & 0x03) << 13 ; + scr |= p[7] << 5; + scr |= (p[8] & 0xF8) >> 3; + + optional - decode extension: + + scr *=300; + scr += ( (p[8] & 0x03 << 7) | (p[9] & 0xFE >> 1) ); + */ - xprintf (VERBOSE|DEMUX, "%d stuffing bytes\n",nStuffingBytes); + if (!this->rate) { + this->rate = (p[0xA] << 14); + this->rate |= (p[0xB] << 6); + this->rate |= (p[0xB] >> 2); + } + + num_stuffing_bytes = p[0xD] & 0x07; - p += 14 + nStuffingBytes; + p += 14 + num_stuffing_bytes; } } if (p[3] == 0xbb) { /* program stream system header */ - int nHeaderLen; + int header_len; xprintf (VERBOSE|DEMUX, "program stream system header\n"); - nHeaderLen = (p[4] << 8) | p[5]; + header_len = (p[4] << 8) | p[5]; - p += 6 + nHeaderLen; + p += 6 + header_len; } /* we should now have a PES packet here */ @@ -169,109 +203,109 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } - nPacketLen = p[4] << 8 | p[5]; - nStreamID = p[3]; + packet_len = p[4] << 8 | p[5]; + stream_id = p[3]; - xprintf (VERBOSE|DEMUX, "packet id = %02x len = %d\n",nStreamID, nPacketLen); + xprintf (VERBOSE|DEMUX, "packet id = %02x len = %d\n",stream_id, packet_len); if (bMpeg1) { - if (nStreamID == 0xBF) { + if (stream_id == 0xBF) { buf->free_buffer (buf); return ; } - p += 6; /* nPacketLen -= 6; */ + p += 6; /* packet_len -= 6; */ while ((p[0] & 0x80) == 0x80) { p++; - nPacketLen--; + packet_len--; /* printf ("stuffing\n");*/ } if ((p[0] & 0xc0) == 0x40) { /* STD_buffer_scale, STD_buffer_size */ p += 2; - nPacketLen -=2; + packet_len -=2; } - nPTS = 0; - nDTS = 0; + PTS = 0; if ((p[0] & 0xf0) == 0x20) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; p += 5; - nPacketLen -=5; + packet_len -=5; } else if ((p[0] & 0xf0) == 0x30) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; - nDTS = (p[ 5] & 0x0E) << 29 ; - nDTS |= p[ 6] << 22 ; - nDTS |= (p[ 7] & 0xFE) << 14 ; - nDTS |= p[ 8] << 7 ; - nDTS |= (p[ 9] & 0xFE) >> 1 ; + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; + /* DTS decoding code is working, but not used in xine + DTS = (p[ 5] & 0x0E) << 29 ; + DTS |= p[ 6] << 22 ; + DTS |= (p[ 7] & 0xFE) << 14 ; + DTS |= p[ 8] << 7 ; + DTS |= (p[ 9] & 0xFE) >> 1 ; + */ p += 10; - nPacketLen -= 10; + packet_len -= 10; } else { p++; - nPacketLen --; + packet_len --; } } else { /* mpeg 2 */ if (p[7] & 0x80) { /* PTS avail */ - nPTS = (p[ 9] & 0x0E) << 29 ; - nPTS |= p[10] << 22 ; - nPTS |= (p[11] & 0xFE) << 14 ; - nPTS |= p[12] << 7 ; - nPTS |= (p[13] & 0xFE) >> 1 ; + PTS = (p[ 9] & 0x0E) << 29 ; + PTS |= p[10] << 22 ; + PTS |= (p[11] & 0xFE) << 14 ; + PTS |= p[12] << 7 ; + PTS |= (p[13] & 0xFE) >> 1 ; } else - nPTS = 0; - - if (p[7] & 0x40) { /* PTS avail */ + PTS = 0; + + /* code is working but not used in xine + if (p[7] & 0x40) { - nDTS = (p[14] & 0x0E) << 29 ; - nDTS |= p[15] << 22 ; - nDTS |= (p[16] & 0xFE) << 14 ; - nDTS |= p[17] << 7 ; - nDTS |= (p[18] & 0xFE) >> 1 ; + DTS = (p[14] & 0x0E) << 29 ; + DTS |= p[15] << 22 ; + DTS |= (p[16] & 0xFE) << 14 ; + DTS |= p[17] << 7 ; + DTS |= (p[18] & 0xFE) >> 1 ; } else - nDTS = 0; + DTS = 0; + */ - nHeaderLen = p[8]; + header_len = p[8]; - p += nHeaderLen + 9; - nPacketLen -= nHeaderLen + 3; + p += header_len + 9; + packet_len -= header_len + 3; } - xprintf (VERBOSE|DEMUX, "stream_id=%x len=%d pts=%d dts=%d\n", nStreamID, nPacketLen, nPTS, nDTS); - - if (nStreamID == 0xbd) { + if (stream_id == 0xbd) { - int nTrack, nSPUID; + int track, spu_id; - nTrack = p[0] & 0x0F; /* hack : ac3 track */ + track = p[0] & 0x0F; /* hack : ac3 track */ if((p[0] & 0xE0) == 0x20) { - nSPUID = (p[0] & 0x1f); + spu_id = (p[0] & 0x1f); xprintf(VERBOSE|DEMUX, "SPU PES packet, id 0x%03x\n",p[0] & 0x1f); buf->content = p+1; - buf->size = nPacketLen-1; - buf->type = BUF_SPU_PACKAGE + nSPUID; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-1; + buf->type = BUF_SPU_PACKAGE + spu_id; + buf->PTS = PTS; buf->input_pos = this->input->get_current_pos(this->input); this->video_fifo->put (this->video_fifo, buf); @@ -281,14 +315,14 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m if ((p[0]&0xF0) == 0x80) { - xprintf (VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",nTrack); - /* printf ( "ac3 PES packet, track %02x\n",nTrack); */ + xprintf (VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",track); + /* printf ( "ac3 PES packet, track %02x\n",track); */ buf->content = p+4; - buf->size = nPacketLen-4; - buf->type = BUF_AUDIO_A52 + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-4; + buf->type = BUF_AUDIO_A52 + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -301,9 +335,9 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m int pcm_offset; - xprintf (VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",nPacketLen-4, p[0]); + xprintf (VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",packet_len-4, p[0]); - for( pcm_offset=0; ++pcm_offset < nPacketLen-1 ; ){ + for( pcm_offset=0; ++pcm_offset < packet_len-1 ; ){ if ( p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ pcm_offset += 2; break; @@ -311,10 +345,10 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m } buf->content = p+pcm_offset; - buf->size = nPacketLen-pcm_offset; - buf->type = BUF_AUDIO_LPCM_BE + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-pcm_offset; + buf->type = BUF_AUDIO_LPCM_BE + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -325,33 +359,33 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } - } else if ((nStreamID >= 0xbc) && ((nStreamID & 0xf0) == 0xe0)) { + } else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) { - xprintf (VERBOSE|DEMUX, "video %d\n", nStreamID); + xprintf (VERBOSE|DEMUX, "video %d\n", stream_id); buf->content = p; - buf->size = nPacketLen; + buf->size = packet_len; buf->type = BUF_VIDEO_MPEG; - buf->PTS = nPTS; - buf->DTS = nDTS; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); this->video_fifo->put (this->video_fifo, buf); return ; - } else if ((nStreamID & 0xe0) == 0xc0) { - int nTrack; + } else if ((stream_id & 0xe0) == 0xc0) { + int track; - nTrack = nStreamID & 0x1f; + track = stream_id & 0x1f; - xprintf (VERBOSE|DEMUX|MPEG, "mpg audio #%d", nTrack); + xprintf (VERBOSE|DEMUX|MPEG, "mpg audio #%d", track); buf->content = p; - buf->size = nPacketLen; - buf->type = BUF_AUDIO_MPEG + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS; + buf->size = packet_len; + buf->type = BUF_AUDIO_MPEG + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -362,7 +396,7 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } else { - xprintf (VERBOSE | DEMUX, "unknown packet, id = %x\n",nStreamID); + xprintf (VERBOSE | DEMUX, "unknown packet, id = %x\n",stream_id); } buf->free_buffer (buf); @@ -413,6 +447,126 @@ static void *demux_mpeg_block_loop (void *this_gen) { return NULL; } +/* estimate bitrate */ + +static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { + + buf_element_t *buf = NULL; + unsigned char *p; + int is_mpeg1=0; + off_t pos, last_pos; + off_t step; + uint32_t PTS, last_PTS; + int rate; + int count; + + if (!(this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE)) + return 0; + + pos = 0; + last_pos = 0; + last_PTS = 0; + rate = 0; + step = this->input->get_length (this->input) / 10; + step = (step / this->blocksize) * this->blocksize; + count = 0; + + this->input->seek (this->input, 0, SEEK_SET); + + while ((buf = this->input->read_block (this->input, this->video_fifo, this->blocksize)) ) { + + p = buf->content; /* len = this->mnBlocksize; */ + + if (p[3] == 0xBA) { /* program stream pack header */ + + is_mpeg1 = (p[4] & 0x40) == 0; + + if (is_mpeg1) + p += 12; + else + p += 14 + (p[0xD] & 0x07); + } + + if (p[3] == 0xbb) /* program stream system header */ + p += 6 + ((p[4] << 8) | p[5]); + + /* we should now have a PES packet here */ + + if (p[0] || p[1] || (p[2] != 1)) { + printf ("demux_mpeg_block: error %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); + buf->free_buffer (buf); + return rate; + } + + PTS = 0; + + if (is_mpeg1) { + + if (p[3] != 0xBF) { /* stream_id */ + + p += 6; /* packet_len -= 6; */ + + while ((p[0] & 0x80) == 0x80) { + p++; /* stuffing */ + } + + if ((p[0] & 0xc0) == 0x40) { + /* STD_buffer_scale, STD_buffer_size */ + p += 2; + } + + if ( ((p[0] & 0xf0) == 0x20) || ((p[0] & 0xf0) == 0x30) ) { + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; + } + } + } else { /* mpeg 2 */ + + if (p[7] & 0x80) { /* PTS avail */ + + PTS = (p[ 9] & 0x0E) << 29 ; + PTS |= p[10] << 22 ; + PTS |= (p[11] & 0xFE) << 14 ; + PTS |= p[12] << 7 ; + PTS |= (p[13] & 0xFE) >> 1 ; + + } else + PTS = 0; + } + + if (PTS) { + + if ( (pos>last_pos) && (PTS>last_PTS) ) { + int cur_rate; + + cur_rate = ((pos - last_pos)*90000) / ((PTS - last_PTS) * 50); + + rate = (count * rate + cur_rate) / (count+1); + + count ++; + + /* printf ("demux_mpeg_block: cur_rate = %d, overall rate : %d\n", cur_rate, rate); */ + } + + last_pos = pos; + last_PTS = PTS; + pos += step; + } else + pos += (off_t) this->blocksize; + + buf->free_buffer (buf); + + if (this->input->seek (this->input, pos, SEEK_SET) == (off_t)-1) + break; + } + + return rate; + +} + static void demux_mpeg_block_close (demux_plugin_t *this_gen) { demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; @@ -462,7 +616,7 @@ static int demux_mpeg_block_get_status (demux_plugin_t *this_gen) { static void demux_mpeg_block_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, + off_t start_pos, int start_time, gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) { @@ -475,9 +629,6 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, this->next_mrl_cb = next_mrl_cb; this->branched_cb = branched_cb; - pos /= (off_t) this->blocksize; - pos *= (off_t) this->blocksize; - /* * send start buffer */ @@ -492,6 +643,8 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, this->audio_fifo->put (this->audio_fifo, buf); } + this->rate = demux_mpeg_block_estimate_rate (this); + if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { int num_buffers = NUM_PREVIEW_BUFFERS; @@ -505,8 +658,18 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, num_buffers --; } - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos, SEEK_SET); + if (start_pos) { + start_pos /= (off_t) this->blocksize; + start_pos *= (off_t) this->blocksize; + + this->input->seek (this->input, start_pos, SEEK_SET); + } else if (start_time) { + start_pos = start_time * this->rate * 50; + start_pos /= (off_t) this->blocksize; + start_pos *= (off_t) this->blocksize; + + this->input->seek (this->input, start_pos, SEEK_SET); + } } /* @@ -645,14 +808,25 @@ static char *demux_mpeg_block_get_id(void) { return "MPEG_BLOCK"; } +static int demux_mpeg_block_get_stream_length (demux_plugin_t *this_gen) { + + demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; + + if (this->rate) + return this->input->get_length (this->input) / (this->rate * 50); + else + return 0; + +} + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_mpeg_block_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_mpeg: plugin doesn't support plugin API version %d.\n" "demux_mpeg: this means there's a version mismatch between xine and this " - "demux_mpeg: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_mpeg: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } @@ -667,6 +841,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpeg_block_close; this->demux_plugin.get_status = demux_mpeg_block_get_status; this->demux_plugin.get_identifier = demux_mpeg_block_get_id; + this->demux_plugin.get_stream_length = demux_mpeg_block_get_stream_length; this->scratch = xmalloc_aligned (512, 4096); diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c index 9f2a8c9c9..fb967cb89 100644 --- a/src/demuxers/demux_mpgaudio.c +++ b/src/demuxers/demux_mpgaudio.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_mpgaudio.c,v 1.16 2001/08/12 15:12:54 guenter Exp $ + * $Id: demux_mpgaudio.c,v 1.17 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for mpeg audio (i.e. mp3) streams * @@ -38,7 +38,7 @@ #include "monitor.h" #include "demux.h" -#define DEMUX_MPGAUDIO_IFACE_VERSION 1 +#define DEMUX_MPGAUDIO_IFACE_VERSION 3 typedef struct { @@ -92,7 +92,6 @@ static int demux_mpgaudio_next (demux_mpgaudio_t *this) { return 0; } - buf->DTS = 0; buf->PTS = 0; buf->input_pos = this->input->get_current_pos(this->input); buf->type = BUF_AUDIO_MPEG; @@ -179,7 +178,7 @@ static int demux_mpgaudio_get_status (demux_plugin_t *this_gen) { static void demux_mpgaudio_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, + off_t start_pos, int start_time, gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) { demux_mpgaudio_t *this = (demux_mpgaudio_t *) this_gen; @@ -191,8 +190,11 @@ static void demux_mpgaudio_start (demux_plugin_t *this_gen, this->status = DEMUX_OK; if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos, SEEK_SET); + xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",start_pos); + this->input->seek (this->input, start_pos, SEEK_SET); + + /* FIMXE: implement seeking to start_time */ + } buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); @@ -277,9 +279,6 @@ static int demux_mpgaudio_open(demux_plugin_t *this_gen, return DEMUX_CANNOT_HANDLE; } -/* - * - */ static char *demux_mpgaudio_get_id(void) { return "MPGAUDIO"; } @@ -288,14 +287,21 @@ static void demux_mpgaudio_close (demux_plugin_t *this) { /* nothing */ } +static int demux_mpgaudio_get_stream_length (demux_plugin_t *this) { + /* FIXME: implement */ + + return 0; +} + + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_mpgaudio_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_mpeg: plugin doesn't support plugin API version %d.\n" "demux_mpeg: this means there's a version mismatch between xine and this " - "demux_mpeg: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_mpeg: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } @@ -310,6 +316,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpgaudio_close; this->demux_plugin.get_status = demux_mpgaudio_get_status; this->demux_plugin.get_identifier = demux_mpgaudio_get_id; + this->demux_plugin.get_stream_length = demux_mpgaudio_get_stream_length; return &this->demux_plugin; } diff --git a/src/demuxers/demux_pes.c b/src/demuxers/demux_pes.c index 419b0a3fa..4f746eb0c 100644 --- a/src/demuxers/demux_pes.c +++ b/src/demuxers/demux_pes.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_pes.c,v 1.5 2001/08/28 19:16:19 guenter Exp $ + * $Id: demux_pes.c,v 1.6 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for mpeg 2 PES (Packetized Elementary Streams) * reads streams of variable blocksizes @@ -45,7 +45,7 @@ static uint32_t xine_debug; -typedef struct demux_mpeg_s { +typedef struct demux_pes_s { demux_plugin_t demux_plugin; @@ -63,9 +63,9 @@ typedef struct demux_mpeg_s { int send_end_buffers; -} demux_mpeg_t ; +} demux_pes_t ; -static uint32_t read_bytes (demux_mpeg_t *this, int n) { +static uint32_t read_bytes (demux_pes_t *this, int n) { uint32_t res; uint32_t i; @@ -107,7 +107,7 @@ static uint32_t read_bytes (demux_mpeg_t *this, int n) { return res; } -static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { +static void parse_mpeg2_packet (demux_pes_t *this, int nID) { int nLen, i; uint32_t w, flags, header_len, pts; @@ -167,7 +167,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_AUDIO_A52 + track; buf->PTS = pts; - buf->DTS = 0 ; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -217,7 +216,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_AUDIO_MPEG + track; buf->PTS = pts; - buf->DTS = 0; /* FIXME */ if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -267,7 +265,6 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } buf->type = BUF_VIDEO_MPEG; buf->PTS = pts; - buf->DTS = 0; if (this->preview_mode) buf->decoder_info[0] = 0; else @@ -288,7 +285,7 @@ static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { } -static uint32_t parse_pack(demux_mpeg_t *this) +static uint32_t parse_pack(demux_pes_t *this) { uint32_t buf ; @@ -307,7 +304,7 @@ static uint32_t parse_pack(demux_mpeg_t *this) } -static void demux_mpeg_resync (demux_mpeg_t *this, uint32_t buf) { +static void demux_pes_resync (demux_pes_t *this, uint32_t buf) { while ((buf !=0x000001) && (this->status == DEMUX_OK)) { xprintf (VERBOSE|DEMUX, "resync : %08x\n",buf); @@ -315,9 +312,9 @@ static void demux_mpeg_resync (demux_mpeg_t *this, uint32_t buf) { } } -static void *demux_mpeg_loop (void *this_gen) { +static void *demux_pes_loop (void *this_gen) { - demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + demux_pes_t *this = (demux_pes_t *) this_gen; buf_element_t *buf; uint32_t w; @@ -325,7 +322,7 @@ static void *demux_mpeg_loop (void *this_gen) { w = parse_pack (this); if (w != 0x000001) - demux_mpeg_resync (this, w); + demux_pes_resync (this, w); } while (this->status == DEMUX_OK) ; @@ -353,12 +350,12 @@ static void *demux_mpeg_loop (void *this_gen) { return NULL; } -static void demux_mpeg_stop (demux_plugin_t *this_gen) { +static void demux_pes_stop (demux_plugin_t *this_gen) { - demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + demux_pes_t *this = (demux_pes_t *) this_gen; buf_element_t *buf; - printf ("demux_mpeg: stop...\n"); + printf ("demux_pes: stop...\n"); if (this->status != DEMUX_OK) { @@ -392,19 +389,19 @@ static void demux_mpeg_stop (demux_plugin_t *this_gen) { } -static int demux_mpeg_get_status (demux_plugin_t *this_gen) { - demux_mpeg_t *this = (demux_mpeg_t *) this_gen; +static int demux_pes_get_status (demux_plugin_t *this_gen) { + demux_pes_t *this = (demux_pes_t *) this_gen; return this->status; } -static void demux_mpeg_start (demux_plugin_t *this_gen, - fifo_buffer_t *video_fifo, - fifo_buffer_t *audio_fifo, - off_t pos, - gui_get_next_mrl_cb_t next_mrl_cb, - gui_branched_cb_t branched_cb) +static void demux_pes_start (demux_plugin_t *this_gen, + fifo_buffer_t *video_fifo, + fifo_buffer_t *audio_fifo, + off_t start_pos, int start_time, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb) { - demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + demux_pes_t *this = (demux_pes_t *) this_gen; buf_element_t *buf; this->video_fifo = video_fifo; @@ -435,14 +432,17 @@ static void demux_mpeg_start (demux_plugin_t *this_gen, w = parse_pack (this); if (w != 0x000001) - demux_mpeg_resync (this, w); + demux_pes_resync (this, w); num_buffers --; } while ( (this->status == DEMUX_OK) && (num_buffers>0)) ; - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos+3, SEEK_SET); + xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",start_pos); + this->input->seek (this->input, start_pos+3, SEEK_SET); + + /* FIXME: implement time seek */ + } else read_bytes(this, 3); @@ -450,13 +450,13 @@ static void demux_mpeg_start (demux_plugin_t *this_gen, this->send_end_buffers = 1; this->status = DEMUX_OK ; - pthread_create (&this->thread, NULL, demux_mpeg_loop, this) ; + pthread_create (&this->thread, NULL, demux_pes_loop, this) ; } -static int demux_mpeg_open(demux_plugin_t *this_gen, +static int demux_pes_open(demux_plugin_t *this_gen, input_plugin_t *input, int stage) { - demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + demux_pes_t *this = (demux_pes_t *) this_gen; this->input = input; @@ -535,36 +535,44 @@ static int demux_mpeg_open(demux_plugin_t *this_gen, return DEMUX_CANNOT_HANDLE; } -static char *demux_mpeg_get_id(void) { +static char *demux_pes_get_id(void) { return "MPEG_PES"; } -static void demux_mpeg_close (demux_plugin_t *this) { +static void demux_pes_close (demux_plugin_t *this) { /* nothing */ } +static int demux_pes_get_stream_length (demux_plugin_t *this_gen) { + + /* demux_pes_t *this = (demux_pes_t *) this_gen; */ + + return 0; /* FIXME: implement */ +} + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { - demux_mpeg_t *this; + demux_pes_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_pes: plugin doesn't support plugin API version %d.\n" "demux_pes: this means there's a version mismatch between xine and this " - "demux_pes: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_pes: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } - this = xmalloc (sizeof (demux_mpeg_t)); + this = xmalloc (sizeof (demux_pes_t)); xine_debug = config->lookup_int (config, "xine_debug", 0); - this->demux_plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION; - this->demux_plugin.open = demux_mpeg_open; - this->demux_plugin.start = demux_mpeg_start; - this->demux_plugin.stop = demux_mpeg_stop; - this->demux_plugin.close = demux_mpeg_close; - this->demux_plugin.get_status = demux_mpeg_get_status; - this->demux_plugin.get_identifier = demux_mpeg_get_id; + this->demux_plugin.interface_version = 3; + this->demux_plugin.open = demux_pes_open; + this->demux_plugin.start = demux_pes_start; + this->demux_plugin.stop = demux_pes_stop; + this->demux_plugin.close = demux_pes_close; + this->demux_plugin.get_status = demux_pes_get_status; + this->demux_plugin.get_identifier = demux_pes_get_id; + this->demux_plugin.get_stream_length = demux_pes_get_stream_length; return (demux_plugin_t *) this; } diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c index 335ca5502..1b022d54a 100644 --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_ts.c,v 1.10 2001/08/31 17:57:54 jkeil Exp $ + * $Id: demux_ts.c,v 1.11 2001/09/01 14:33:00 guenter Exp $ * * Demultiplexer for MPEG2 Transport Streams. * @@ -46,6 +46,9 @@ * * 29-Jul-2001 shaheedhaque Reviewed by: n/a * Compiles! + + * + * TODO: do without memcpys, seeking (if possible), preview buffers */ #ifdef HAVE_CONFIG_H @@ -85,244 +88,286 @@ * Describe a single elementary stream. */ typedef struct { - unsigned int pid; - fifo_buffer_t *fifo; - int type; - buf_element_t *buf; - int pes_buf_next; - int pes_len; - int pes_len_zero; - unsigned int counter; + unsigned int pid; + fifo_buffer_t *fifo; + int type; + buf_element_t *buf; + int pes_buf_next; + int pes_len; + int pes_len_zero; + unsigned int counter; + } demux_ts_media; typedef struct { + /* + * The first field must be the "base class" for the plugin! + */ + demux_plugin_t plugin; + + fifo_buffer_t *fifoAudio; + fifo_buffer_t *fifoVideo; + + input_plugin_t *input; + + pthread_t thread; + + int status; + + int broken_pes; + int buf_type; + + int blockSize; + int rate; + demux_ts_media media[MAX_PIDS]; + /* + * Stuff to do with the transport header. As well as the video + * and audio PIDs, we keep the index of the corresponding entry + * inthe media[] array. + */ + unsigned int programNumber; + unsigned int pmtPid; + unsigned int pcrPid; + unsigned int videoPid; + unsigned int audioPid; + unsigned int videoMedia; + unsigned int audioMedia; +} demux_ts; + +static uint32_t xine_debug; + + +/* + * demux_ts_parse_pat + * + * Parse a program association table (PAT). + * The PAT is expected to be exactly one section long, + * and that section is expected to be contained in a single TS packet. + * + * The PAT is assumed to contain a single program definition, though + * we can cope with the stupidity of SPTSs which contain NITs. + */ +static void demux_ts_parse_pat (demux_ts *this, unsigned char *originalPkt, + unsigned char *pkt, unsigned int pus) { + + unsigned int length; + unsigned char *program; + unsigned int programNumber; + unsigned int pmtPid; + unsigned int programCount; + + /* + * A PAT in a single section should start with a payload unit start + * indicator set. + */ + if (!pus) { + printf ("demux_ts: demux error! PAT without payload unit start\n"); + return; + } + + /* + * PAT packets with a pus start with a pointer. Skip it! + */ + pkt += pkt[4]; + if (pkt - originalPkt > PKT_SIZE) { + printf ("demux_ts: demux error! PAT with invalid pointer\n"); + return; + } + if (!(pkt[10] & 0x01)) { + /* + * Not current! + */ + return; + } + length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; + if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { + printf ("demux_ts: demux error! PAT with invalid section length\n"); + return; + } + if ((pkt[11]) || (pkt[12])) { + printf ("demux_ts: demux error! PAT with invalid section %02x of %02x\n", pkt[11], pkt[12]); + return; + } + + /* + * TBD: at this point, we should check the CRC. Its not that expensive, and + * the consequences of getting it wrong are dire! + */ + + /* + * Process all programs in the program loop. + */ + programCount = 0; + for (program = pkt + 13; program < pkt + 13 + length - 9; program += 4) { + programNumber = ((unsigned int)program[0] << 8) | program[1]; + /* - * The first field must be the "base class" for the plugin! + * Skip NITs completely. */ - demux_plugin_t plugin; + if (!programNumber) + continue; + programCount++; + pmtPid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; + + /* + * If we have yet to learn our program number, then learn it. + */ + if (this->programNumber == INVALID_PROGRAM) { + xprintf(VERBOSE|DEMUX, "acquiring programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); + this->programNumber = programNumber; + this->pmtPid = pmtPid; + } else { + if (this->programNumber != programNumber) { + fprintf(stderr, "demux error! MPTS: programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); + } else { + if (this->pmtPid != pmtPid) { + xprintf(VERBOSE|DEMUX, "pmtPid changed %04x\n", pmtPid); + this->pmtPid = pmtPid; + } + } + } + } +} - fifo_buffer_t *fifoAudio; - fifo_buffer_t *fifoVideo; - fifo_buffer_t *fifoSPU; +static int demux_ts_parse_pes_header (demux_ts *this, buf_element_t *buf, int packet_len) { - input_plugin_t *input; + unsigned char *p; + uint32_t header_len; + uint32_t PTS; + uint32_t stream_id; - pthread_t thread; + p = buf->mem; - int mnAudioChannel; - int mnSPUChannel; - int status; + /* we should have a PES packet here */ - int blockSize; - demux_ts_media media[MAX_PIDS]; - /* - * Stuff to do with the transport header. As well as the video - * and audio PIDs, we keep the index of the corresponding entry - * inthe media[] array. - */ - unsigned int programNumber; - unsigned int pmtPid; - unsigned int pcrPid; - unsigned int videoPid; - unsigned int audioPid; - unsigned int videoMedia; - unsigned int audioMedia; -} demux_ts; + if (p[0] || p[1] || (p[2] != 1)) { + printf ("demux_ts: error %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); + return 0 ; + } -/* -** -** PRIVATE FUNCTIONS -** -*/ -static void *demux_ts_loop( - void *gen_this); -static void demux_ts_pat_parse( - demux_ts *this, - unsigned char *originalPkt, - unsigned char *pkt, - unsigned int pus); -static void demux_ts_pes_buffer( - demux_ts *this, - unsigned char *ts, - unsigned int mediaIndex, - unsigned int pus, - unsigned int cc, - unsigned int len); -static void demux_ts_pes_new( - demux_ts *this, - unsigned int mediaIndex, - unsigned int pid, - fifo_buffer_t *fifo); -static void demux_ts_pmt_parse( - demux_ts *this, - unsigned char *originalPkt, - unsigned char *pkt, - unsigned int pus); -static void demux_ts_parse_ts( - demux_ts *this); -static void demux_ts_queue_pes( - demux_ts *this, - buf_element_t *buf); -static void demux_ts_close( - demux_plugin_t *gen_this); -static char *demux_ts_get_id( - void); -static int demux_ts_get_status( - demux_plugin_t *this_gen); -static int demux_ts_open( - demux_plugin_t *this_gen, - input_plugin_t *input, - int stage); -static void demux_ts_start( - demux_plugin_t *this_gen, - fifo_buffer_t *fifoVideo, - fifo_buffer_t *fifoAudio, - off_t pos, - gui_get_next_mrl_cb_t next_mrl_cb, - gui_branched_cb_t branched_cb); -static void demux_ts_stop( - demux_plugin_t *this_gen); + packet_len -= 6; + /* packet_len = p[4] << 8 | p[5]; */ + stream_id = p[3]; -/* -** -** DATA -** -*/ -static uint32_t xine_debug; + if (packet_len==0) + return 0; -/* - * Sit in a loop eating data. - */ -static void *demux_ts_loop( - void *gen_this) -{ - demux_ts *this = (demux_ts *)gen_this; - buf_element_t *buf; + xprintf(VERBOSE|DEMUX, "packet stream id = %02x len = %d\n", + stream_id, packet_len); - /* - * TBD: why do we not appear at the beginning of the file? - */ -this->input->seek(this->input, 0, SEEK_SET); -fprintf (stderr, "demux %u demux_ts_loop seeking back to start of file! \n", __LINE__); - do { - demux_ts_parse_ts(this); - } while (this->status == DEMUX_OK) ; + if (p[7] & 0x80) { /* PTS avail */ - xprintf(VERBOSE|DEMUX, "demux loop finished (status: %d)\n", this->status); + PTS = (p[ 9] & 0x0E) << 29 ; + PTS |= p[10] << 22 ; + PTS |= (p[11] & 0xFE) << 14 ; + PTS |= p[12] << 7 ; + PTS |= (p[13] & 0xFE) >> 1 ; + + } else + PTS = 0; - this->status = DEMUX_FINISHED; - buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); - buf->type = BUF_CONTROL_END; - buf->decoder_info[0] = 0; /* stream finished */ - this->fifoVideo->put(this->fifoVideo, buf); + /* code works but not used in xine + if (p[7] & 0x40) { + + DTS = (p[14] & 0x0E) << 29 ; + DTS |= p[15] << 22 ; + DTS |= (p[16] & 0xFE) << 14 ; + DTS |= p[17] << 7 ; + DTS |= (p[18] & 0xFE) >> 1 ; + + } else + DTS = 0; + */ + + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); + /* FIXME: not working correctly */ + buf->input_time = buf->input_pos / (this->rate * 50); + + header_len = p[8]; - if (this->fifoAudio) { - buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); - buf->type = BUF_CONTROL_END; - buf->decoder_info[0] = 0; /* stream finished */ - this->fifoAudio->put(this->fifoAudio, buf); - } - pthread_exit(NULL); - return NULL; -} + p += header_len + 9; + packet_len -= header_len + 3; -/* - * NAME demux_ts_pat_parse - * - * Parse a PAT. The PAT is expected to be exactly one section long, - * and that section is expected to be contained in a single TS packet. - * - * The PAT is assumed to contain a single program definition, though - * we can cope with the stupidity of SPTSs which contain NITs. - */ -static void demux_ts_pat_parse( - demux_ts *this, - unsigned char *originalPkt, - unsigned char *pkt, - unsigned int pus) -{ - unsigned int length; - unsigned char *program; - unsigned int programNumber; - unsigned int pmtPid; - unsigned int programCount; + if (stream_id == 0xbd) { - /* - * A PAT in a single section should start with a payload unit start - * indicator set. - */ - if (!pus) { - fprintf (stderr, "demux error! PAT without payload unit start\n"); - return; - } + int track, spu_id; - /* - * PAT packets with a pus start with a pointer. Skip it! - */ - pkt += pkt[4]; - if (pkt - originalPkt > PKT_SIZE) { - fprintf (stderr, "demux error! PAT with invalid pointer\n"); - return; - } - if (!(pkt[10] & 0x01)) { - /* - * Not current! - */ - return; - } - length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; - if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { - fprintf (stderr, "demux error! PAT with invalid section length\n"); - return; - } - if ((pkt[11]) || (pkt[12])) { - fprintf (stderr, "demux error! PAT with invalid section %02x of %02x\n", pkt[11], pkt[12]); - return; - } + track = p[0] & 0x0F; /* hack : ac3 track */ - /* - * TBD: at this point, we should check the CRC. Its not that expensive, and - * the consequences of getting it wrong are dire! - */ + if ((p[0] & 0xE0) == 0x20) { - /* - * Process all programs in the program loop. - */ - programCount = 0; - for (program = pkt + 13; program < pkt + 13 + length - 9; program += 4) { - programNumber = ((unsigned int)program[0] << 8) | program[1]; - - /* - * Skip NITs completely. - */ - if (!programNumber) - continue; - programCount++; - pmtPid = (((unsigned int)program[2] & 0x1f) << 8) | program[3]; - - /* - * If we have yet to learn our program number, then learn it. - */ - if (this->programNumber == INVALID_PROGRAM) { - xprintf(VERBOSE|DEMUX, "acquiring programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); - this->programNumber = programNumber; - this->pmtPid = pmtPid; - } else { - if (this->programNumber != programNumber) { - fprintf(stderr, "demux error! MPTS: programNumber=%u pmtPid=%04x\n", programNumber, pmtPid); - } else { - if (this->pmtPid != pmtPid) { - xprintf(VERBOSE|DEMUX, "pmtPid changed %04x\n", pmtPid); - this->pmtPid = pmtPid; - } - } - } + spu_id = (p[0] & 0x1f); + + buf->content = p+1; + buf->size = packet_len-1; + buf->type = BUF_SPU_PACKAGE + spu_id; + + this->buf_type = BUF_SPU_PACKAGE + spu_id; + + return 1; + } else if ((p[0] & 0xF0) == 0x80) { + + buf->content = p+4; + buf->size = packet_len - 4; + buf->type = BUF_AUDIO_A52 + track; + + this->buf_type = BUF_AUDIO_A52 + track; + + return 1; + + } else if ((p[0]&0xf0) == 0xa0) { + + int pcm_offset; + + for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ){ + if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ + pcm_offset += 2; + break; + } + } + + buf->content = p+pcm_offset; + buf->size = packet_len-pcm_offset; + buf->type = BUF_AUDIO_LPCM_BE + track; + + this->buf_type = BUF_AUDIO_LPCM_BE + track; + + return 1; } + + } else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) { + + buf->content = p; + buf->size = packet_len; + buf->type = BUF_VIDEO_MPEG; + this->buf_type = BUF_VIDEO_MPEG; + + return 1; + + } else if ((stream_id & 0xe0) == 0xc0) { + + int track; + + track = stream_id & 0x1f; + + buf->content = p; + buf->size = packet_len; + buf->type = BUF_AUDIO_MPEG + track; + this->buf_type = BUF_AUDIO_MPEG + track; + + return 1; + + } else { + xprintf(VERBOSE | DEMUX, "unknown packet, id = %x\n",stream_id); + } + + return 0 ; } /* - * Manage a buffer for a PES stream. + * buffer arriving pes data * Input is 188 bytes of Transport stream * Build a PES packet. PES packets can get as big as 65536 * If PES packet length was empty(zero) work it out based on seeing the next PUS. @@ -330,126 +375,96 @@ static void demux_ts_pat_parse( * then queue it. The queuing routine might have to cut it up to make bits < 4096. FIXME: implement cut up. * Currently if PES packets are >4096, corruption occurs. */ -static void demux_ts_pes_buffer( - demux_ts *this, - unsigned char *ts, - unsigned int mediaIndex, - unsigned int pus, - unsigned int cc, - unsigned int len) -{ - demux_ts_media *m = &this->media[mediaIndex]; - if (!m->fifo) return; /* To avoid segfault if Video out or Audio out plugin not loaded */ - /* - * By checking the CC here, we avoid the need to check for the no-payload - * case (i.e. adaptation field only) when it does not get bumped. - */ - if (m->counter != INVALID_CC) { - if ((m->counter & 0x0f) != cc) { - fprintf(stderr, "dropped input packet cc = %d expected = %d\n", cc, m->counter); - } + +static void demux_ts_buffer_pes(demux_ts *this, unsigned char *ts, + unsigned int mediaIndex, + unsigned int pus, + unsigned int cc, + unsigned int len) { + + buf_element_t *buf; + + demux_ts_media *m = &this->media[mediaIndex]; + if (!m->fifo) { + + printf ("fifo unavailable (%d)\n", mediaIndex); + + return; /* To avoid segfault if video out or audio out plugin not loaded */ + + } + + /* + * By checking the CC here, we avoid the need to check for the no-payload + * case (i.e. adaptation field only) when it does not get bumped. + */ + if (m->counter != INVALID_CC) { + if ((m->counter & 0x0f) != cc) { + printf("demux_ts: dropped input packet cc = %d expected = %d\n", cc, m->counter); } - m->counter = cc; - m->counter++; - if (pus) { - /* new PES packet */ - if (ts[0] || ts[1] || ts[2] != 1) { - fprintf(stderr, "PUS set but no PES header (corrupt stream?)\n"); - m->buf->free_buffer(m->buf); - m->buf = 0; - m->pes_len_zero=0; - return; - } - if (m->buf) { - if(m->pes_len_zero) { -/* - fprintf(stderr,"Queuing ZERO PES %02X %02X %02X %02X %02X\n", m->buf->mem[3], m->buf->mem[4], m->buf->mem[5], - (m->pes_buf_next-6) & 0xff, - (m->pes_buf_next-6) >> 8 ); - */ - m->buf->mem[5]=(m->pes_buf_next - 6 ) & 0xff; - m->buf->mem[4]=(m->pes_buf_next - 6 ) >> 8; - demux_ts_queue_pes(this, m->buf); - m->buf = 0; - m->pes_len_zero=0; - } else { - - fprintf(stderr, "PUS set but last PES not complete (corrupt stream?) %d %d %d\n", - m->pes_buf_next, m->pes_len, m->pes_len_zero); - - m->buf->free_buffer(m->buf); - m->buf = 0; - /* return; */ - } - } - m->pes_len = ((ts[4] << 8) | ts[5]) ; - if (m->pes_len) { - m->pes_len+=6; - m->pes_len_zero=0; - } else { - m->pes_len_zero=1; - } -/* - fprintf(stderr,"starting new pes, len = %d %d %02X\n", m->pes_len, m->pes_len_zero,ts[3]); - */ - if (m->fifo) { /* allow running without sound card */ - m->buf = m->fifo->buffer_pool_alloc(m->fifo); - memcpy(m->buf->mem, ts, len); - m->pes_buf_next = len; - } - return; - } else if (m->buf) { - if( m->pes_buf_next+len <= m->buf->max_size) { - memcpy(m->buf->mem+m->pes_buf_next, ts, len); - m->pes_buf_next += len; - if( !m->pes_len_zero) { - if (m->pes_buf_next == m->pes_len ) { -/* - fprintf(stderr,"Queuing PES - len = %d\n", m->pes_len); - fprintf(stderr,"Queuing PES %02X\n", m->buf->mem[3]); - */ - demux_ts_queue_pes(this, m->buf); - m->buf = 0; - } else if ( m->pes_buf_next > m->pes_len) { - fprintf(stderr, "too much data read for PES (corrupt stream?)\n"); - m->buf->free_buffer(m->buf); - m->buf = 0; - m->pes_len_zero=0; - } - } - } else { - fprintf(stderr, "Buffer overflow on data read for PES (discontinuity ?)\n"); - /* FIXME: Implement discontinuity sensing */ - m->buf->free_buffer(m->buf); - m->buf = 0; - m->pes_len_zero=0; - } - + } + + m->counter = cc; + m->counter++; + + if (pus) { + + /* new PES packet */ + + if (ts[0] || ts[1] || ts[2] != 1) { + fprintf(stderr, "PUS set but no PES header (corrupt stream?)\n"); + return; + } + + buf = m->fifo->buffer_pool_alloc(m->fifo); + + memcpy (buf->mem, ts, len); /* FIXME: reconstruct parser to do without memcpys */ + + if (!demux_ts_parse_pes_header(this, buf, len)) { + buf->free_buffer(buf); + this->broken_pes = 1; + printf ("demux_ts: broken pes encountered\n"); } else { - /* - fprintf(stderr, "nowhere to buffer input. Waiting for PUS. \n"); - */ + this->broken_pes = 0; + + buf->decoder_info[0] = 1; + + m->fifo->put (m->fifo, buf); } + + } else if (!this->broken_pes) { + + buf = m->fifo->buffer_pool_alloc(m->fifo); + + memcpy (buf->mem, ts, len); /* FIXME: reconstruct parser to do without memcpys */ + + buf->content = buf->mem; + buf->size = len; + buf->type = this->buf_type; + buf->PTS = 0; + buf->input_pos = this->input->get_current_pos(this->input); + buf->decoder_info[0] = 1; + + m->fifo->put (m->fifo, buf); + } } /* * Create a buffer for a PES stream. */ -static void demux_ts_pes_new( - demux_ts *this, - unsigned int mediaIndex, - unsigned int pid, - fifo_buffer_t *fifo) -{ - demux_ts_media *m = &this->media[mediaIndex]; - - /* new PID seen - initialise stuff */ - m->pid = pid; - m->fifo = fifo; - m->buf = 0; - m->pes_buf_next = 0; - m->pes_len = 0; - m->counter = INVALID_CC; +static void demux_ts_pes_new(demux_ts *this, + unsigned int mediaIndex, + unsigned int pid, + fifo_buffer_t *fifo) { + + demux_ts_media *m = &this->media[mediaIndex]; + + /* new PID seen - initialise stuff */ + m->pid = pid; + m->fifo = fifo; + m->buf = 0; + m->pes_buf_next = 0; + m->pes_len = 0; + m->counter = INVALID_CC; } /* @@ -461,147 +476,145 @@ static void demux_ts_pes_new( * In other words, the PMT is assumed to describe a reasonable number of * video, audio and other streams (with descriptors). */ -static void demux_ts_pmt_parse( - demux_ts *this, - unsigned char *originalPkt, - unsigned char *pkt, - unsigned int pus) -{ - typedef enum +static void demux_ts_parse_pmt(demux_ts *this, + unsigned char *originalPkt, + unsigned char *pkt, + unsigned int pus) { + typedef enum { - ISO_11172_VIDEO = 1, // 1 - ISO_13818_VIDEO = 2, // 2 - ISO_11172_AUDIO = 3, // 3 - ISO_13818_AUDIO = 4, // 4 - ISO_13818_PRIVATE = 5, // 5 - ISO_13818_PES_PRIVATE = 6, // 6 - ISO_13522_MHEG = 7, // 7 - ISO_13818_DSMCC = 8, // 8 - ISO_13818_TYPE_A = 9, // 9 - ISO_13818_TYPE_B = 10, // a - ISO_13818_TYPE_C = 11, // b - ISO_13818_TYPE_D = 12, // c - ISO_13818_TYPE_E = 13, // d - ISO_13818_AUX = 14 + ISO_11172_VIDEO = 1, // 1 + ISO_13818_VIDEO = 2, // 2 + ISO_11172_AUDIO = 3, // 3 + ISO_13818_AUDIO = 4, // 4 + ISO_13818_PRIVATE = 5, // 5 + ISO_13818_PES_PRIVATE = 6, // 6 + ISO_13522_MHEG = 7, // 7 + ISO_13818_DSMCC = 8, // 8 + ISO_13818_TYPE_A = 9, // 9 + ISO_13818_TYPE_B = 10, // a + ISO_13818_TYPE_C = 11, // b + ISO_13818_TYPE_D = 12, // c + ISO_13818_TYPE_E = 13, // d + ISO_13818_AUX = 14 } streamType; - unsigned int length; - unsigned int programInfoLength; - unsigned int codedLength; - unsigned int mediaIndex; - unsigned int pid; - unsigned char *stream; - - /* - * A PMT in a single section should start with a payload unit start - * indicator set. - */ - if (!pus) { - fprintf (stderr, "demux error! PMT without payload unit start\n"); - return; - } - - /* - * PMT packets with a pus start with a pointer. Skip it! - */ - pkt += pkt[4]; - if (pkt - originalPkt > PKT_SIZE) { - fprintf (stderr, "demux error! PMT with invalid pointer\n"); - return; - } - if (!(pkt[10] & 0x01)) { - /* - * Not current! - */ - return; - } - length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; - if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { - fprintf (stderr, "demux error! PMT with invalid section length\n"); - return; - } - if ((pkt[11]) || (pkt[12])) { - fprintf (stderr, "demux error! PMT with invalid section %02x of %02x\n", pkt[11], pkt[12]); - return; - } - - /* - * TBD: at this point, we should check the CRC. Its not that expensive, and - * the consequences of getting it wrong are dire! - */ - + unsigned int length; + unsigned int programInfoLength; + unsigned int codedLength; + unsigned int mediaIndex; + unsigned int pid; + unsigned char *stream; + + /* + * A PMT in a single section should start with a payload unit start + * indicator set. + */ + if (!pus) { + fprintf (stderr, "demux error! PMT without payload unit start\n"); + return; + } + + /* + * PMT packets with a pus start with a pointer. Skip it! + */ + pkt += pkt[4]; + if (pkt - originalPkt > PKT_SIZE) { + fprintf (stderr, "demux error! PMT with invalid pointer\n"); + return; + } + if (!(pkt[10] & 0x01)) { /* - * ES definitions start here...we are going to learn upto one video - * PID and one audio PID. + * Not current! */ - - programInfoLength = (((unsigned int)pkt[15] & 0x0f) << 8) | pkt[16]; - stream = &pkt[17] + programInfoLength; - codedLength = 13 + programInfoLength; + return; + } + length = (((unsigned int)pkt[6] & 0x3) << 8) | pkt[7]; + if (pkt - originalPkt > BODY_SIZE - 1 - 3 - (int)length) { + fprintf (stderr, "demux error! PMT with invalid section length\n"); + return; + } + if ((pkt[11]) || (pkt[12])) { + fprintf (stderr, "demux error! PMT with invalid section %02x of %02x\n", pkt[11], pkt[12]); + return; + } + + /* + * TBD: at this point, we should check the CRC. Its not that expensive, and + * the consequences of getting it wrong are dire! + */ + + /* + * ES definitions start here...we are going to learn upto one video + * PID and one audio PID. + */ + + programInfoLength = (((unsigned int)pkt[15] & 0x0f) << 8) | pkt[16]; + stream = &pkt[17] + programInfoLength; + codedLength = 13 + programInfoLength; + if (codedLength > length) { + fprintf (stderr, "demux error! PMT with inconsistent progInfo length\n"); + return; + } + length -= codedLength; + + /* + * Extract the elementary streams. + */ + mediaIndex = 0; + while (length > 0) { + unsigned int streamInfoLength; + + pid = (((unsigned int)stream[1] & 0x1f) << 8) | stream[2]; + streamInfoLength = (((unsigned int)stream[3] & 0xf) << 8) | stream[4]; + codedLength = 5 + streamInfoLength; if (codedLength > length) { - fprintf (stderr, "demux error! PMT with inconsistent progInfo length\n"); - return; + fprintf (stderr, "demux error! PMT with inconsistent streamInfo length\n"); + return; } - length -= codedLength; - + /* - * Extract the elementary streams. + * Squirrel away the first audio and the first video stream. TBD: there + * should really be a way to select the stream of interest. */ - mediaIndex = 0; - while (length > 0) { - unsigned int streamInfoLength; - - pid = (((unsigned int)stream[1] & 0x1f) << 8) | stream[2]; - streamInfoLength = (((unsigned int)stream[3] & 0xf) << 8) | stream[4]; - codedLength = 5 + streamInfoLength; - if (codedLength > length) { - fprintf (stderr, "demux error! PMT with inconsistent streamInfo length\n"); - return; - } - - /* - * Squirrel away the first audio and the first video stream. TBD: there - * should really be a way to select the stream of interest. - */ - switch (stream[0]) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - if (this->videoPid == INVALID_PID) { - xprintf(VERBOSE|DEMUX, "video pid %04x\n", pid); - demux_ts_pes_new(this, mediaIndex, pid, this->fifoVideo); - } - this->videoPid = pid; - this->videoMedia = mediaIndex; - break; - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - if (this->audioPid == INVALID_PID) { - xprintf(VERBOSE|DEMUX, "audio pid %04x\n", pid); - demux_ts_pes_new(this, mediaIndex, pid, this->fifoAudio); - } - this->audioPid = pid; - this->audioMedia = mediaIndex; - break; - default: - break; - } - mediaIndex++; - stream += codedLength; - length -= codedLength; + switch (stream[0]) { + case ISO_11172_VIDEO: + case ISO_13818_VIDEO: + if (this->videoPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "video pid %04x\n", pid); + demux_ts_pes_new(this, mediaIndex, pid, this->fifoVideo); + } + this->videoPid = pid; + this->videoMedia = mediaIndex; + break; + case ISO_11172_AUDIO: + case ISO_13818_AUDIO: + if (this->audioPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "audio pid %04x\n", pid); + demux_ts_pes_new(this, mediaIndex, pid, this->fifoAudio); + } + this->audioPid = pid; + this->audioMedia = mediaIndex; + break; + default: + break; } - - /* - * Get the current PCR PID. - */ - pid = (((unsigned int)pkt[13] & 0x1f) << 8) | - pkt[14]; - if (this->pcrPid != pid) { - if (this->pcrPid == INVALID_PID) { - xprintf(VERBOSE|DEMUX, "pcr pid %04x\n", pid); - } else { - xprintf(VERBOSE|DEMUX, "pcr pid changed %04x\n", pid); - } - this->pcrPid = pid; + mediaIndex++; + stream += codedLength; + length -= codedLength; + } + + /* + * Get the current PCR PID. + */ + pid = (((unsigned int)pkt[13] & 0x1f) << 8) | + pkt[14]; + if (this->pcrPid != pid) { + if (this->pcrPid == INVALID_PID) { + xprintf(VERBOSE|DEMUX, "pcr pid %04x\n", pid); + } else { + xprintf(VERBOSE|DEMUX, "pcr pid changed %04x\n", pid); } + this->pcrPid = pid; + } } /********************************************************************* @@ -632,26 +645,24 @@ static void demux_ts_pmt_parse( /* When we've acquired sync, we need to set all of the continuity * counters to an invalid value to disable the sequence checking */ -static void resetAllCCs(demux_ts * this) -{ - int i; - for (i = 0; i != MAX_PIDS; ++i) - this->media[i].counter = INVALID_CC; +static void resetAllCCs(demux_ts * this) { + int i; + for (i = 0; i != MAX_PIDS; ++i) + this->media[i].counter = INVALID_CC; } /* Find the first sync byte in the packet pointed to by p */ -static int searchForSyncByte(const unsigned char * p) -{ - const unsigned char * start = p, * end = p + PKT_SIZE; - - while (p != end && *p != SYNC_BYTE) - p++; - - if (p == end) - return -1; - else - return p - start; +static int searchForSyncByte(const unsigned char * p) { + const unsigned char * start = p, * end = p + PKT_SIZE; + + while (p != end && *p != SYNC_BYTE) + p++; + + if (p == end) + return -1; + else + return p - start; } /* Main synchronisation routine. @@ -660,52 +671,51 @@ static int searchForSyncByte(const unsigned char * p) * loop, so its harmless and easier than doing the packet looping internally. */ -static unsigned char * demux_synchronise(demux_ts * this) -{ - static int in, out, count; /* statics are zeroed */ - static unsigned char buf[BUF_SIZE]; - - int syncByte, syncBytePosn; - unsigned char * retPtr = NULL; - - if (this->input->read(this->input, &buf[in], PKT_SIZE) != PKT_SIZE) { - if (count > 0) { - int oldOut = out; /* drain pipeline on end of stream */ - BUMP(out); - count--; - retPtr = &buf[oldOut]; - } else { - this->status = DEMUX_FINISHED; - } - return retPtr; - } - - syncBytePosn = out; - WRAP_ADD(syncBytePosn, count * PKT_SIZE, BUF_SIZE - PKT_SIZE); - syncByte = buf[syncBytePosn]; - - if (syncByte != SYNC_BYTE) { /* new packet not in sync */ - int syncPosn = searchForSyncByte(&buf[in]); - if (syncPosn > 0) { - memmove(&buf[0], &buf[in + syncPosn], PKT_SIZE - syncPosn); - in = PKT_SIZE - syncPosn; - } else { - in = 0; /* no sync byte in packet, so start again */ - } - out = count = 0; - } else { /* this packet extends the sync run */ - BUMP(in); - count++; - if (count > MIN_SYNCS) { /* sync acquired */ - int oldOut = out; - resetAllCCs(this); - BUMP(out); - count--; - retPtr = &buf[oldOut]; - } +static unsigned char * demux_synchronise(demux_ts * this) { + static int in, out, count; /* statics are zeroed */ + static unsigned char buf[BUF_SIZE]; + + int syncByte, syncBytePosn; + unsigned char * retPtr = NULL; + + if (this->input->read(this->input, &buf[in], PKT_SIZE) != PKT_SIZE) { + if (count > 0) { + int oldOut = out; /* drain pipeline on end of stream */ + BUMP(out); + count--; + retPtr = &buf[oldOut]; + } else { + this->status = DEMUX_FINISHED; } - return retPtr; + } + + syncBytePosn = out; + WRAP_ADD(syncBytePosn, count * PKT_SIZE, BUF_SIZE - PKT_SIZE); + syncByte = buf[syncBytePosn]; + + if (syncByte != SYNC_BYTE) { /* new packet not in sync */ + int syncPosn = searchForSyncByte(&buf[in]); + if (syncPosn > 0) { + memmove(&buf[0], &buf[in + syncPosn], PKT_SIZE - syncPosn); + in = PKT_SIZE - syncPosn; + } else { + in = 0; /* no sync byte in packet, so start again */ + } + out = count = 0; + } else { /* this packet extends the sync run */ + BUMP(in); + count++; + if (count > MIN_SYNCS) { /* sync acquired */ + int oldOut = out; + resetAllCCs(this); + BUMP(out); + count--; + retPtr = &buf[oldOut]; + } + } + + return retPtr; } #undef BUMP @@ -714,423 +724,223 @@ static unsigned char * demux_synchronise(demux_ts * this) #undef BUF_SIZE #undef SYNC_BYTE -/***************************************************************************/ - -static void demux_ts_parse_ts( - demux_ts *this) -{ - /* unsigned char originalPkt[PKT_SIZE]; */ - unsigned char * originalPkt; - unsigned int sync_byte; - unsigned int transport_error_indicator; - unsigned int payload_unit_start_indicator; - unsigned int transport_priority; - unsigned int pid; - unsigned int transport_scrambling_control; - unsigned int adaption_field_control; - unsigned int continuity_counter; - unsigned int data_offset; - unsigned int data_len; - - /* get next synchronised packet, or NULL */ - originalPkt = demux_synchronise(this); - if (originalPkt == NULL) - return; - - sync_byte=originalPkt[0]; - transport_error_indicator = (originalPkt[1] >> 7) & 0x01; - payload_unit_start_indicator = (originalPkt[1] >> 6) & 0x01; - transport_priority = (originalPkt[1] >> 5) & 0x01; - pid = ((originalPkt[1] << 8) | originalPkt[2]) & 0x1fff; - transport_scrambling_control = (originalPkt[3] >> 6) & 0x03; - adaption_field_control = (originalPkt[3] >> 4) & 0x03; - continuity_counter = originalPkt[3] & 0x0f; +/* transport stream packet layer */ + +static void demux_ts_parse_packet (demux_ts *this) { + + unsigned char *originalPkt; + unsigned int sync_byte; + unsigned int transport_error_indicator; + unsigned int payload_unit_start_indicator; + unsigned int transport_priority; + unsigned int pid; + unsigned int transport_scrambling_control; + unsigned int adaption_field_control; + unsigned int continuity_counter; + unsigned int data_offset; + unsigned int data_len; + + /* get next synchronised packet, or NULL */ + originalPkt = demux_synchronise(this); + if (originalPkt == NULL) + return; + + sync_byte = originalPkt[0]; + transport_error_indicator = (originalPkt[1] >> 7) & 0x01; + payload_unit_start_indicator = (originalPkt[1] >> 6) & 0x01; + transport_priority = (originalPkt[1] >> 5) & 0x01; + pid = ((originalPkt[1] << 8) | originalPkt[2]) & 0x1fff; + transport_scrambling_control = (originalPkt[3] >> 6) & 0x03; + adaption_field_control = (originalPkt[3] >> 4) & 0x03; + continuity_counter = originalPkt[3] & 0x0f; + + /* + * Discard packets that are obviously bad. + * FIXME: maybe search for 0x47 is the first 188 bytes[packet size] of stream. + */ + if (sync_byte != 0x47) { + fprintf (stderr, "demux error! invalid ts sync byte %02x\n",originalPkt[0]); + return; + } + if (transport_error_indicator) { + fprintf (stderr, "demux error! transport error\n"); + return; + } + + data_offset=4; + if (adaption_field_control & 0x1) { /* - * Discard packets that are obviously bad. - * FIXME: maybe search for 0x47 is the first 188 bytes[packet size] of stream. + * Has a payload! Calculate & check payload length. */ - if (sync_byte != 0x47) { - fprintf (stderr, "demux error! invalid ts sync byte %02x\n",originalPkt[0]); - return; - } - if (transport_error_indicator) { - fprintf (stderr, "demux error! transport error\n"); - return; + if (adaption_field_control & 0x2) { + /* + * Skip adaptation header. + */ + data_offset+=originalPkt[4]+1; } -/* - for(n=0;n<4;n++) {fprintf(stderr,"%02X ",originalPkt[n]);} - fprintf(stderr," sync:%02X TE:%02X PUS:%02X TP:%02X PID:%04X TSC:%02X AFC:%02X CC:%02X\n", - sync_byte, - transport_error_indicator, - payload_unit_start_indicator, - transport_priority, - pid, - transport_scrambling_control, - adaption_field_control, - continuity_counter ); - */ - - data_offset=4; - if (adaption_field_control & 0x1) { - /* - * Has a payload! Calculate & check payload length. - */ - if (adaption_field_control & 0x2) { - /* - * Skip adaptation header. - */ - data_offset+=originalPkt[4]+1; - } - data_len = PKT_SIZE - data_offset; - if (data_len > PKT_SIZE) { - fprintf (stderr, "demux error! invalid payload size %d\n",data_len); - } else { - - /* - * Do the demuxing in descending order of packet frequency! - */ - if (pid == this->videoPid ) { - demux_ts_pes_buffer(this, originalPkt+data_offset, this->videoMedia, payload_unit_start_indicator, continuity_counter, data_len); - } else if (pid == this->audioPid) { - demux_ts_pes_buffer(this, originalPkt+data_offset, this->audioMedia, payload_unit_start_indicator, continuity_counter, data_len); - } else if (pid == this->pmtPid) { - demux_ts_pmt_parse(this, originalPkt, originalPkt+data_offset-4, payload_unit_start_indicator); - } else if (pid == 0) { - demux_ts_pat_parse(this, originalPkt, originalPkt+data_offset-4, payload_unit_start_indicator); - } else if (pid == 0x1fff) { - /* fprintf(stderr,"Null Packet\n"); */ - } - } - } - - /* - * Now check for PCRs. First test for an adaptation header, since - * that is the most likely test to fail. - */ -} - -static void demux_ts_queue_pes( - demux_ts *this, - buf_element_t *buf) -{ - unsigned char *p; - int bMpeg1=0; - uint32_t nHeaderLen; - uint32_t nPTS; - uint32_t nDTS; - uint32_t nPacketLen; - uint32_t nStreamID; - - p = buf->mem; /* len = this->blockSize; */ - /* FIXME: HACK to get the decoders working */ - buf->decoder_info[0] = 1; - /* we should have a PES packet here */ - - if (p[0] || p[1] || (p[2] != 1)) { - fprintf (stderr, "demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); - buf->free_buffer(buf); - return ; - } - nPacketLen = p[4] << 8 | p[5]; - nStreamID = p[3]; + data_len = PKT_SIZE - data_offset; - xprintf(VERBOSE|DEMUX, "packet stream id = %02x len = %d\n",nStreamID, nPacketLen); + if (data_len > PKT_SIZE) { - if (bMpeg1) { + printf ("demux_ts: demux error! invalid payload size %d\n",data_len); - if (nStreamID == 0xBF) { - buf->free_buffer(buf); - return ; - } - - p += 6; /* nPacketLen -= 6; */ - - while ((p[0] & 0x80) == 0x80) { - p++; - nPacketLen--; - /* printf ("stuffing\n");*/ - } - - if ((p[0] & 0xc0) == 0x40) { - /* STD_buffer_scale, STD_buffer_size */ - p += 2; - nPacketLen -=2; - } - - nPTS = 0; - nDTS = 0; - if ((p[0] & 0xf0) == 0x20) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; - p += 5; - nPacketLen -=5; - } else if ((p[0] & 0xf0) == 0x30) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; - nDTS = (p[ 5] & 0x0E) << 29 ; - nDTS |= p[ 6] << 22 ; - nDTS |= (p[ 7] & 0xFE) << 14 ; - nDTS |= p[ 8] << 7 ; - nDTS |= (p[ 9] & 0xFE) >> 1 ; - p += 10; - nPacketLen -= 10; } else { - p++; - nPacketLen --; + + /* + * Do the demuxing in descending order of packet frequency! + */ + if (pid == this->videoPid ) { + demux_ts_buffer_pes (this, originalPkt+data_offset, this->videoMedia, + payload_unit_start_indicator, continuity_counter, data_len); + } else if (pid == this->audioPid) { + demux_ts_buffer_pes (this, originalPkt+data_offset, this->audioMedia, + payload_unit_start_indicator, continuity_counter, data_len); + } else if (pid == this->pmtPid) { + demux_ts_parse_pmt (this, originalPkt, originalPkt+data_offset-4, payload_unit_start_indicator); + } else if (pid == 0) { + demux_ts_parse_pat (this, originalPkt, originalPkt+data_offset-4, payload_unit_start_indicator); + } else if (pid == 0x1fff) { + /* fprintf(stderr,"Null Packet\n"); */ + } } + } + +} - } else { /* mpeg 2 */ - - if (p[7] & 0x80) { /* PTS avail */ - - nPTS = (p[ 9] & 0x0E) << 29 ; - nPTS |= p[10] << 22 ; - nPTS |= (p[11] & 0xFE) << 14 ; - nPTS |= p[12] << 7 ; - nPTS |= (p[13] & 0xFE) >> 1 ; - - } else - nPTS = 0; - - if (p[7] & 0x40) { /* PTS avail */ - - nDTS = (p[14] & 0x0E) << 29 ; - nDTS |= p[15] << 22 ; - nDTS |= (p[16] & 0xFE) << 14 ; - nDTS |= p[17] << 7 ; - nDTS |= (p[18] & 0xFE) >> 1 ; - - } else - nDTS = 0; - - - nHeaderLen = p[8]; +/* + * Sit in a loop eating data. + */ +static void *demux_ts_loop(void *gen_this) { - p += nHeaderLen + 9; - nPacketLen -= nHeaderLen + 3; + demux_ts *this = (demux_ts *)gen_this; + buf_element_t *buf; + + do { + demux_ts_parse_packet(this); + } while (this->status == DEMUX_OK) ; + + xprintf(VERBOSE|DEMUX, "demux loop finished (status: %d)\n", this->status); + + this->status = DEMUX_FINISHED; + buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->fifoVideo->put(this->fifoVideo, buf); + + if (this->fifoAudio) { + buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->fifoAudio->put(this->fifoAudio, buf); } + pthread_exit(NULL); + return NULL; +} - xprintf(VERBOSE|DEMUX, "stream_id=%x len=%d pts=%d dts=%d\n", nStreamID, nPacketLen, nPTS, nDTS); - - if (nStreamID == 0xbd) { +static void demux_ts_close(demux_plugin_t *gen_this) { - int nTrack,nSPUID; + /* nothing */ +} - nTrack = p[0] & 0x0F; /* hack : ac3 track */ +static char *demux_ts_get_id(void) { + return "MPEG_TS"; +} - if((p[0] & 0xE0) == 0x20) { - nSPUID = (p[0] & 0x1f); +static int demux_ts_get_status(demux_plugin_t *this_gen) { - xprintf(VERBOSE|DEMUX, "SPU PES packet, id 0x%03x\n",p[0] & 0x1f); + demux_ts *this = (demux_ts *)this_gen; - if((this->mnSPUChannel >= 0) - && (this->fifoSPU != NULL) - && (nSPUID == this->mnSPUChannel)) { - buf->content = p+1; - buf->size = nPacketLen-1; - buf->type = BUF_SPU_PACKAGE; - buf->PTS = nPTS; - buf->DTS = nDTS ; - buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); + return this->status; +} - this->fifoSPU->put(this->fifoSPU, buf); - return; +static int demux_ts_open(demux_plugin_t *this_gen, input_plugin_t *input, + int stage) { + + demux_ts *this = (demux_ts *) this_gen; + char *mrl; + char *media; + char *ending; + + switch (stage) { + case STAGE_BY_EXTENSION: + mrl = input->get_mrl(input); + media = strstr(mrl, "://"); + if (media) { + fprintf (stderr, "demux %u ts_open! \n", __LINE__); + if ((!(strncasecmp(mrl, "stdin", 5))) || (!(strncasecmp(mrl, "fifo", 4)))) { + if(!(strncasecmp(media+3, "ts", 3))) { + break; + } + return DEMUX_CANNOT_HANDLE; + } + else if (strncasecmp(mrl, "file", 4)) { + return DEMUX_CANNOT_HANDLE; } } - - if (((p[0]&0xF0) == 0x80) && (nTrack == this->mnAudioChannel)) { - - xprintf(VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",nTrack); - /* printf ( "ac3 PES packet, track %02x\n",nTrack); */ - - buf->content = p+4; - buf->size = nPacketLen-4; - buf->type = BUF_AUDIO_A52; - buf->PTS = nPTS; - buf->DTS = nDTS ; - buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); - - this->fifoAudio->put(this->fifoAudio, buf); - return ; - } else if (((p[0]&0xf0) == 0xa0) || (nTrack == (this->mnAudioChannel-16))) { - - int pcm_offset; - - xprintf(VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",nPacketLen-4, p[0]); - - /* printf ("PCM!!!!!!!!!!!!!!!!!!!!!!!\n"); */ - - for( pcm_offset=0; ++pcm_offset < nPacketLen-1 ; ){ - if ( p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ - pcm_offset += 2; - break; - } + ending = strrchr(mrl, '.'); + if (ending) { + xprintf(VERBOSE|DEMUX, "demux_ts_open: ending %s of %s\n", ending, mrl); + if ((!strcasecmp(ending, ".m2t")) || (!strcasecmp(ending, ".ts"))) { + break; } - - buf->content = p+pcm_offset; - buf->size = nPacketLen-pcm_offset; - buf->type = BUF_AUDIO_LPCM_BE; - buf->PTS = nPTS; - buf->DTS = nDTS ; - buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); - - this->fifoAudio->put(this->fifoAudio, buf); - return ; } - - } else if ((nStreamID >= 0xbc) && ((nStreamID & 0xf0) == 0xe0)) { - - xprintf(VERBOSE|DEMUX, "video %X\n", nStreamID); - - buf->content = p; - buf->size = nPacketLen; - buf->type = BUF_VIDEO_MPEG; - buf->PTS = nPTS; - buf->DTS = nDTS; - - this->fifoVideo->put(this->fifoVideo, buf); - return ; - - } else if ((nStreamID & 0xe0) == 0xc0) { - int nTrack; - - nTrack = nStreamID & 0x1f; - - xprintf(VERBOSE|DEMUX|MPEG, "mpg audio #%d\n", nTrack); - xprintf(VERBOSE|DEMUX|MPEG, "bMpeg1=%d this->mnAudioChannel %d\n", bMpeg1, this->mnAudioChannel); - -// if ((bMpeg1 && (nTrack == this->mnAudioChannel)) -// || (!bMpeg1 && (nTrack == (this->mnAudioChannel-8)))) { - - buf->content = p; - buf->size = nPacketLen; - buf->type = BUF_AUDIO_MPEG; - buf->PTS = nPTS; - buf->DTS = nDTS; - buf->input_pos = this->input->seek(this->input, 0, SEEK_CUR); - - this->fifoAudio->put(this->fifoAudio, buf); - return ; -// } - - } else { - xprintf(VERBOSE | DEMUX, "unknown packet, id = %x\n",nStreamID); + return DEMUX_CANNOT_HANDLE; + default: + return DEMUX_CANNOT_HANDLE; } - - buf->free_buffer(buf); - return ; -} - -static void demux_ts_close( - demux_plugin_t *gen_this) -{ - /* nothing */ + + this->input = input; + this->blockSize = PKT_SIZE; + return DEMUX_CAN_HANDLE; } -static char *demux_ts_get_id( - void) -{ - return "MPEG_TS"; -} +static void demux_ts_start(demux_plugin_t *this_gen, + fifo_buffer_t *fifoVideo, + fifo_buffer_t *fifoAudio, + off_t start_pos, int start_time, + gui_get_next_mrl_cb_t next_mrl_cb, + gui_branched_cb_t branched_cb) { -static int demux_ts_get_status( - demux_plugin_t *this_gen) -{ - demux_ts *this = (demux_ts *)this_gen; - return this->status; -} - -static int demux_ts_open( - demux_plugin_t *this_gen, - input_plugin_t *input, - int stage) -{ - demux_ts *this = (demux_ts *) this_gen; - char *mrl; - char *media; - char *ending; - - switch (stage) { - case STAGE_BY_EXTENSION: - mrl = input->get_mrl(input); - media = strstr(mrl, "://"); - if (media) { -fprintf (stderr, "demux %u ts_open! \n", __LINE__); - if ((!(strncasecmp(mrl, "stdin", 5))) || (!(strncasecmp(mrl, "fifo", 4)))) { - if(!(strncasecmp(media+3, "ts", 3))) { - break; - } - return DEMUX_CANNOT_HANDLE; - } - else if (strncasecmp(mrl, "file", 4)) { - return DEMUX_CANNOT_HANDLE; - } - } - ending = strrchr(mrl, '.'); - if (ending) { - xprintf(VERBOSE|DEMUX, "demux_ts_open: ending %s of %s\n", ending, mrl); - if ((!strcasecmp(ending, ".m2t")) || (!strcasecmp(ending, ".ts"))) { - break; - } - } - return DEMUX_CANNOT_HANDLE; - default: - return DEMUX_CANNOT_HANDLE; - } + demux_ts *this = (demux_ts *)this_gen; + buf_element_t *buf; + + this->fifoVideo = fifoVideo; + this->fifoAudio = fifoAudio; + + /* + * send start buffers + */ + buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); + buf->type = BUF_CONTROL_START; + this->fifoVideo->put(this->fifoVideo, buf); + if (this->fifoAudio) { + buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); + buf->type = BUF_CONTROL_START; + this->fifoAudio->put(this->fifoAudio, buf); + } + + this->status = DEMUX_OK ; + this->broken_pes = 1; - this->input = input; - this->blockSize = PKT_SIZE; - return DEMUX_CAN_HANDLE; -} + + if ((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) != 0 ) { -static void demux_ts_start( - demux_plugin_t *this_gen, - fifo_buffer_t *fifoVideo, - fifo_buffer_t *fifoAudio, - off_t pos, - gui_get_next_mrl_cb_t next_mrl_cb, - gui_branched_cb_t branched_cb) -{ - demux_ts *this = (demux_ts *)this_gen; - buf_element_t *buf; + if ( (!start_pos) && (start_time)) + start_pos = start_time * this->rate * 50; - this->fifoVideo = fifoVideo; - this->fifoAudio = fifoAudio; + this->input->seek (this->input, start_pos, SEEK_SET); - /* - * Send reset buffer. - */ - buf = this->fifoVideo->buffer_pool_alloc(this->fifoVideo); - buf->type = BUF_CONTROL_START; - this->fifoVideo->put(this->fifoVideo, buf); - if (this->fifoAudio) { - buf = this->fifoAudio->buffer_pool_alloc(this->fifoAudio); - buf->type = BUF_CONTROL_START; - this->fifoAudio->put(this->fifoAudio, buf); - } + } - this->status = DEMUX_OK ; - if (this->input->get_blocksize(this->input)) - this->blockSize = this->input->get_blocksize(this->input); - pos /= (off_t)this->blockSize; - pos *= (off_t)this->blockSize; - - /* - * Now start demuxing. - */ - pthread_create(&this->thread, NULL, demux_ts_loop, this); + /* + * Now start demuxing. + */ + pthread_create(&this->thread, NULL, demux_ts_loop, this); } -static void demux_ts_stop( - demux_plugin_t *this_gen) +static void demux_ts_stop(demux_plugin_t *this_gen) { demux_ts *this = (demux_ts *)this_gen; buf_element_t *buf; @@ -1166,45 +976,56 @@ static void demux_ts_stop( } } -demux_plugin_t *init_demuxer_plugin( - int iface, - config_values_t *config) -{ - demux_ts *this; - int i; - - if (iface != 2) { - printf( - "demux_ts: plugin doesn't support plugin API version %d.\n" - "demux_ts: this means there's a version mismatch between xine and this " - "demux_ts: demuxer plugin.\nInstalling current input plugins should help.\n", - iface); - return NULL; - } +static int demux_ts_get_stream_length (demux_plugin_t *this_gen) { - /* - * Initialise the generic plugin. - */ - this = xmalloc(sizeof(*this)); - xine_debug = config->lookup_int(config, "xine_debug", 0); - this->plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION; - this->plugin.open = demux_ts_open; - this->plugin.start = demux_ts_start; - this->plugin.stop = demux_ts_stop; - this->plugin.close = demux_ts_close; - this->plugin.get_status = demux_ts_get_status; - this->plugin.get_identifier = demux_ts_get_id; + demux_ts *this = (demux_ts *)this_gen; - /* - * Initialise our specialised data. - */ - this->mnSPUChannel = -1; /* Turn off SPU by default */ - for (i = 0; i < MAX_PIDS; i++) - this->media[i].pid = INVALID_PID; - this->programNumber = INVALID_PROGRAM; - this->pmtPid = INVALID_PID; - this->pcrPid = INVALID_PID; - this->videoPid = INVALID_PID; - this->audioPid = INVALID_PID; - return (demux_plugin_t *)this; + return this->input->get_length (this->input) / (this->rate * 50); } + + +demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { + + demux_ts *this; + int i; + + if (iface != 3) { + printf("demux_ts: plugin doesn't support plugin API version %d.\n" + "demux_ts: this means there's a version mismatch between xine and this " + "demux_ts: demuxer plugin.\nInstalling current demux plugins should help.\n", + iface); + return NULL; + } + + /* + * Initialise the generic plugin. + */ + this = xmalloc(sizeof(*this)); + xine_debug = config->lookup_int(config, "xine_debug", 0); + this->plugin.interface_version = DEMUXER_PLUGIN_IFACE_VERSION; + this->plugin.open = demux_ts_open; + this->plugin.start = demux_ts_start; + this->plugin.stop = demux_ts_stop; + this->plugin.close = demux_ts_close; + this->plugin.get_status = demux_ts_get_status; + this->plugin.get_identifier = demux_ts_get_id; + this->plugin.get_stream_length = demux_ts_get_stream_length; + + /* + * Initialise our specialised data. + */ + for (i = 0; i < MAX_PIDS; i++) + this->media[i].pid = INVALID_PID; + this->programNumber = INVALID_PROGRAM; + this->pmtPid = INVALID_PID; + this->pcrPid = INVALID_PID; + this->videoPid = INVALID_PID; + this->audioPid = INVALID_PID; + + this->rate = 16000; /* FIXME */ + + return (demux_plugin_t *)this; +} + + + diff --git a/src/libmpeg2/decode.c b/src/libmpeg2/decode.c index c08dc3ed2..58a9d4e32 100644 --- a/src/libmpeg2/decode.c +++ b/src/libmpeg2/decode.c @@ -300,7 +300,13 @@ static inline uint8_t * copy_chunk (mpeg2dec_t * mpeg2dec, if (limit > end) limit = end; + /* + printf ("copy chunk current %08x\n", current ); + printf ("copy chunk end %08x\n", end); fflush(stdout); + */ + while (1) { + byte = *current++; if (shift != 0x00000100) { shift = (shift | byte) << 8; diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 0a98a15d8..707160c58 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_decoder.c,v 1.31 2001/08/25 08:48:12 guenter Exp $ + * $Id: audio_decoder.c,v 1.32 2001/09/01 14:33:00 guenter Exp $ * * * functions that implement audio decoding @@ -54,6 +54,9 @@ void *audio_decoder_loop (void *this_gen) { if (buf->input_pos) this->cur_input_pos = buf->input_pos; + if (buf->input_time) + this->cur_input_time = buf->input_time; + /* * Call update status callback function if * there is no video decoder initialized, like diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index de98971f5..9cd17add0 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer.h,v 1.7 2001/08/31 17:57:54 jkeil Exp $ + * $Id: buffer.h,v 1.8 2001/09/01 14:33:00 guenter Exp $ * * * contents: @@ -109,8 +109,9 @@ struct buf_element_s { uint32_t size ; /* size of _content_ */ uint32_t max_size; uint32_t type; - uint32_t PTS, DTS; + uint32_t PTS; off_t input_pos; /* remember where this buf came from in the input source */ + int input_time;/* time offset in seconds from beginning of stream */ uint32_t decoder_info[4]; /* additional decoder flags and other dec-spec. stuff */ void (*free_buffer) (buf_element_t *buf); diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index 64d9748e4..83e716cae 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: video_decoder.c,v 1.44 2001/08/28 19:16:20 guenter Exp $ + * $Id: video_decoder.c,v 1.45 2001/09/01 14:33:00 guenter Exp $ * */ @@ -66,6 +66,8 @@ void *video_decoder_loop (void *this_gen) { buf = this->video_fifo->get (this->video_fifo); if (buf->input_pos) this->cur_input_pos = buf->input_pos; + if (buf->input_time) + this->cur_input_time = buf->input_time; /* printf ("video_decoder: got buffer %d\n", buf->type); */ @@ -182,7 +184,7 @@ void *video_decoder_loop (void *this_gen) { decoder->get_identifier()); } - + decoder->decode_data (this->cur_video_decoder_plugin, buf); } } else diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index a4878d7b9..b2abd26a0 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.c,v 1.52 2001/08/29 11:14:12 guenter Exp $ + * $Id: xine.c,v 1.53 2001/09/01 14:33:00 guenter Exp $ * * top-level xine functions * @@ -75,11 +75,11 @@ void xine_stop (xine_t *this) { pthread_mutex_unlock (&this->xine_lock); return; } - else if(this->status == XINE_PAUSE) { - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->paused = 0; - this->audio_mute = 0; - } + + + this->metronom->set_speed (this->metronom, SPEED_NORMAL); + this->speed = SPEED_NORMAL; + this->audio_mute = 0; this->status = XINE_STOP; printf ("xine_stop: stopping demuxer\n"); @@ -89,8 +89,6 @@ void xine_stop (xine_t *this) { this->cur_demuxer_plugin = NULL; } - printf ("xine_stop: closing input\n"); - if(this->cur_input_plugin) { this->cur_input_plugin->close(this->cur_input_plugin); /* @@ -174,20 +172,38 @@ static int find_demuxer(xine_t *this, const char *MRL) { return 0; } -static void xine_play_internal (xine_t *this, char *mrl, - int spos, off_t pos) { +void xine_play (xine_t *this, char *mrl, + int start_pos, int start_time) { double share ; - off_t len; + off_t pos, len; int i; - xprintf (VERBOSE|LOOP, "xine open %s, start pos = %d\n", mrl, spos); + xprintf (VERBOSE|LOOP, "xine open %s, start pos = %d\n", mrl, start_pos); - printf ("xine_play_internal: open %s, start pos = %d\n", mrl, spos); + pthread_mutex_lock (&this->xine_lock); - if (this->status != XINE_STOP) { - printf ("xine_play_internal: error: xine is not stopped\n"); - return; + printf ("xine_play: open %s, start pos = %d\n", mrl, start_pos); + + /* + * stop engine? + */ + + if (this->status == XINE_PLAY) { + + if(this->cur_demuxer_plugin) { + this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); + } + + if(this->cur_input_plugin) { + + if (strcmp (mrl, this->cur_mrl)) + this->cur_input_plugin->close(this->cur_input_plugin); + else + this->cur_input_plugin->stop(this->cur_input_plugin); + } + + this->status = XINE_STOP; } /* @@ -204,8 +220,9 @@ static void xine_play_internal (xine_t *this, char *mrl, } if (!this->cur_input_plugin) { - perror ("open input source"); + printf ("xine: cannot find input plugin for this MRL\n"); this->cur_demuxer_plugin = NULL; + pthread_mutex_unlock (&this->xine_lock); return; } @@ -224,6 +241,7 @@ static void xine_play_internal (xine_t *this, char *mrl, if(!find_demuxer(this, mrl)) { printf ("xine: couldn't find demuxer for >%s<\n", mrl); + pthread_mutex_unlock (&this->xine_lock); return; } @@ -234,94 +252,32 @@ static void xine_play_internal (xine_t *this, char *mrl, * start demuxer */ - if (spos) { + if (start_pos) { len = this->cur_input_plugin->get_length (this->cur_input_plugin); - share = (double) spos / 65535; + share = (double) start_pos / 65535; pos = (off_t) (share * len) ; - } + } else + pos = 0; this->cur_demuxer_plugin->start (this->cur_demuxer_plugin, this->video_fifo, this->audio_fifo, - pos, + pos, start_time, this->get_next_mrl_cb, this->branched_cb); this->status = XINE_PLAY; strncpy (this->cur_mrl, mrl, 1024); - printf ("xine: demuxer started\n"); - -} + this->metronom->set_speed (this->metronom, SPEED_NORMAL); + this->audio_mute = 0; + this->speed = SPEED_NORMAL; -void xine_play (xine_t *this, char *MRL, int spos) { - - pthread_mutex_lock (&this->xine_lock); - - if(this->status == XINE_PAUSE) { - - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->paused = 0; - this->audio_mute = 0; - - if(this->cur_demuxer_plugin) { - this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); - this->cur_demuxer_plugin = NULL; - } - - printf ("xine_stop: closing input\n"); - - if(this->cur_input_plugin) { - this->cur_input_plugin->close(this->cur_input_plugin); - } - - this->status = XINE_STOP; - - } - else if (this->status != XINE_STOP) { - - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->audio_mute = 0; - - pthread_mutex_unlock (&this->xine_lock); - return; - } - - xine_play_internal (this, MRL, spos, (off_t) 0); + printf ("xine_play: demuxer started\n"); pthread_mutex_unlock (&this->xine_lock); } -void xine_seek (xine_t *this, char *mrl, int pos) { - - pthread_mutex_lock (&this->xine_lock); - - printf ("xine_seek\n"); - - if (this->status == XINE_PLAY || this->status == XINE_PAUSE) { - - if(this->status == XINE_PAUSE) { - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->paused = 0; - this->audio_mute = 0; - } - - if(this->cur_demuxer_plugin) { - this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); - } - - if(this->cur_input_plugin) { - this->cur_input_plugin->stop(this->cur_input_plugin); - } - - this->status = XINE_STOP; - } - - xine_play_internal (this, mrl, pos, (off_t)0); - - pthread_mutex_unlock (&this->xine_lock); -} - int xine_eject (xine_t *this) { if(this->cur_input_plugin == NULL) @@ -347,11 +303,9 @@ void xine_exit (xine_t *this) { pthread_mutex_lock (&this->xine_lock); - if(this->status == XINE_PAUSE) { - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->paused = 0; - this->status = XINE_STOP; - } + this->metronom->set_speed (this->metronom, SPEED_NORMAL); + this->speed = SPEED_NORMAL; + this->status = XINE_STOP; /* * stop decoder threads @@ -391,37 +345,6 @@ void xine_exit (xine_t *this) { } -void xine_pause (xine_t *this) { - - pthread_mutex_lock (&this->xine_lock); - - printf ("xine_pause\n"); - - if (this->status != XINE_PLAY && this->status != XINE_PAUSE ) { - printf ("xine: error, pause called when not in playback mode\n"); - pthread_mutex_unlock (&this->xine_lock); - return; - } - - if (this->paused) { - - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->audio_mute = 0; - this->paused = 0; - this->status = XINE_PLAY; - - } else { - - this->metronom->set_speed (this->metronom, SPEED_PAUSE); - this->paused = 1; - this->audio_mute = 2; - this->status = XINE_PAUSE; - - } - - pthread_mutex_unlock (&this->xine_lock); -} - static void event_handler(xine_t *xine, event_t *event, void *data) { /* Check Xine handle/current input plugin is not NULL */ if((xine == NULL) || (xine->cur_input_plugin == NULL)) { @@ -658,8 +581,11 @@ void xine_set_speed (xine_t *this, int speed) { this->metronom->set_speed (this->metronom, speed); - this->audio_mute = speed != SPEED_NORMAL; - this->paused = speed == SPEED_PAUSE; + if (speed == SPEED_PAUSE) + this->audio_mute = 2; + else + this->audio_mute = speed != SPEED_NORMAL; + this->speed = speed; pthread_mutex_unlock (&this->xine_lock); @@ -669,3 +595,21 @@ void xine_set_speed (xine_t *this, int speed) { int xine_get_speed (xine_t *this) { return this->speed; } + +/* + * time measurement / seek + */ + +int xine_get_current_time (xine_t *this) { + return this->cur_input_time; +} + +int xine_get_stream_length (xine_t *this) { + + if(this->cur_demuxer_plugin) + return this->cur_demuxer_plugin->get_stream_length (this->cur_demuxer_plugin); + + return 0; +} + + diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 56290bb79..33af5169d 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_internal.h,v 1.42 2001/08/28 22:52:57 f1rmb Exp $ + * $Id: xine_internal.h,v 1.43 2001/09/01 14:33:00 guenter Exp $ * */ @@ -120,7 +120,6 @@ typedef void (*gui_stream_end_cb_t)(int nStatus); #define XINE_STOP 0 #define XINE_PLAY 1 #define XINE_QUIT 2 -#define XINE_PAUSE 3 typedef struct xine_s xine_t; @@ -146,6 +145,7 @@ struct xine_s { int status; int speed; off_t cur_input_pos; + int cur_input_time; char cur_mrl[1024]; spu_functions_t *spu_out; @@ -166,7 +166,6 @@ struct xine_s { video_decoder_t *video_decoder_plugins[DECODER_PLUGIN_MAX]; video_decoder_t *cur_video_decoder_plugin; int video_finished; - int paused; ao_instance_t *audio_out; fifo_buffer_t *audio_fifo; @@ -211,29 +210,18 @@ xine_t *xine_init (vo_driver_t *vo, gui_branched_cb_t branched_cb); /* - * open a stream and play it + * open a stream sekk to a given position and play it * - * name : mrl to open - * pos : start position 0..65535 + * name : mrl to open + * start_pos : position in input source (0..65535) + * start_time : position measured in seconds from stream start * - */ -void xine_play (xine_t *this, char *MRL, int pos); - - -/* - * seek the stream to pos, and play it - * - * name : mrl to open - * pos : start position 0..65535 + * if both parameters are !=0 start_pos will be used + * for non-seekable streams both values will be ignored * */ -void xine_seek (xine_t *this, char *MRL, int pos); - +void xine_play (xine_t *this, char *MRL, int start_pos, int start_time); -/* - * toggle pause mode - */ -void xine_pause (xine_t *this); /* * set/get playback speed @@ -280,6 +268,18 @@ int xine_get_status (xine_t *this); int xine_get_current_position (xine_t *this); /* + * get current position measured in seconds from + * the beginning of the stream + */ +int xine_get_current_time (xine_t *this); + +/* + * estimate length of input stream in seconds + * may return 0 if stream is not seekable + */ +int xine_get_stream_length (xine_t *this); + +/* * return the current audio channel */ int xine_get_audio_channel (xine_t *this); |