From 27e92b12d2d0e28e73e806442409b2621acfbf2b Mon Sep 17 00:00:00 2001 From: Joachim Koenig Date: Tue, 24 Jul 2001 16:08:51 +0000 Subject: PES demultiplexer CVS patchset: 340 CVS date: 2001/07/24 16:08:51 --- src/demuxers/Makefile.am | 5 +- src/demuxers/demux_mpeg.c | 6 +- src/demuxers/demux_pes.c | 572 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 579 insertions(+), 4 deletions(-) create mode 100644 src/demuxers/demux_pes.c (limited to 'src') diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index e55504f1e..fe12b26f7 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -11,7 +11,7 @@ libdir = $(XINE_PLUGINDIR) # lib_LTLIBRARIES = xineplug_dmx_avi.la xineplug_dmx_mpeg_block.la \ xineplug_dmx_mpeg.la xineplug_dmx_mpeg_elem.la \ - xineplug_dmx_mpeg_audio.la + xineplug_dmx_mpeg_audio.la xineplug_dmx_mpeg_pes.la xineplug_dmx_avi_la_SOURCES = demux_avi.c xineplug_dmx_avi_la_LDFLAGS = -avoid-version -module @@ -29,6 +29,9 @@ xineplug_dmx_mpeg_audio_la_LDFLAGS = -avoid-version -module xineplug_dmx_mpeg_elem_la_SOURCES = demux_elem.c xineplug_dmx_mpeg_elem_la_LDFLAGS = -avoid-version -module +xineplug_dmx_mpeg_pes_la_SOURCES = demux_pes.c +xineplug_dmx_mpeg_pes_la_LDFLAGS = -avoid-version -module + include_HEADERS = demux.h ## diff --git a/src/demuxers/demux_mpeg.c b/src/demuxers/demux_mpeg.c index 43a185e08..de0fbc2d7 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.26 2001/07/14 13:56:10 guenter Exp $ + * $Id: demux_mpeg.c,v 1.27 2001/07/24 16:09:22 joachim_koenig Exp $ * * demultiplexer for mpeg 1/2 program streams * reads streams of variable blocksizes @@ -683,7 +683,7 @@ static int demux_mpeg_open(demux_plugin_t *this_gen, } } break; - +#if 0 case 0xe0: if((buf[6] & 0xc0) != 0x80) { uint32_t pckbuf ; @@ -695,7 +695,7 @@ static int demux_mpeg_open(demux_plugin_t *this_gen, } } break; - +#endif } } } diff --git a/src/demuxers/demux_pes.c b/src/demuxers/demux_pes.c new file mode 100644 index 000000000..100a4f756 --- /dev/null +++ b/src/demuxers/demux_pes.c @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2000 the xine project + * + * This file is part of xine, a unix video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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.1 2001/07/24 16:08:51 joachim_koenig Exp $ + * + * demultiplexer for mpeg 2 PES (Packetized Elementary Streams) + * reads streams of variable blocksizes + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "monitor.h" +#include "xine_internal.h" +#include "demux.h" +#include "utils.h" + +#define NUM_PREVIEW_BUFFERS 400 + +static uint32_t xine_debug; + +typedef struct demux_mpeg_s { + + demux_plugin_t demux_plugin; + + fifo_buffer_t *audio_fifo; + fifo_buffer_t *video_fifo; + + input_plugin_t *input; + + pthread_t thread; + + unsigned char dummy_space[100000]; + + int status; + int preview_mode; + + int send_end_buffers; + +} demux_mpeg_t ; + +static uint32_t read_bytes (demux_mpeg_t *this, int n) { + + uint32_t res; + uint32_t i; + unsigned char buf[6]; + + buf[4]=0; + + + i = this->input->read (this->input, buf, n); + + if (i != n) { + + this->status = DEMUX_FINISHED; + + xprintf (VERBOSE|DEMUX, "Unexpected end of stream\n"); + } + + + switch (n) { + case 1: + res = buf[0]; + break; + case 2: + res = (buf[0]<<8) | buf[1]; + break; + case 3: + res = (buf[0]<<16) | (buf[1]<<8) | buf[2]; + break; + case 4: + res = (buf[2]<<8) | buf[3] | (buf[1]<<16) | (buf[0] << 24); + break; + default: + fprintf (stderr, + "How how - something wrong in wonderland demux:read_bytes (%d)\n", + n); + exit (1); + } + + return res; +} + +static void parse_mpeg2_packet (demux_mpeg_t *this, int nID) { + + int nLen, i; + uint32_t w, flags, header_len, pts; + buf_element_t *buf = NULL; + + nLen = read_bytes(this, 2); + + + if (nID==0xbd) { + + int track; + + xprintf (VERBOSE|DEMUX|AC3, ",ac3"); + + w = read_bytes(this, 1); + flags = read_bytes(this, 1); + header_len = read_bytes(this, 1); + + nLen -= header_len + 3; + + pts=0; + + if ((flags & 0x80) == 0x80) { + + w = read_bytes(this, 1); + pts = (w & 0x0e) << 29 ; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) << 14; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) >> 1; + + xprintf (VERBOSE|DEMUX|VPTS, ", pts=%d",pts); + + header_len -= 5 ; + } + + /* read rest of header */ + i = this->input->read (this->input, this->dummy_space, header_len+4); + + track = this->dummy_space[0] & 0x0F ; + + xprintf (VERBOSE|DEMUX, ", track=%02x", track); + + /* contents */ + + if(this->audio_fifo) + buf = this->input->read_block (this->input, this->audio_fifo, nLen-4); + else { + this->input->read (this->input, this->dummy_space, nLen); + return; + } + + if (buf == NULL) { + this->status = DEMUX_FINISHED; + return ; + } + buf->type = BUF_AUDIO_AC3 + 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->audio_fifo) + this->audio_fifo->put (this->audio_fifo, buf); + + } else if ((nID & 0xe0) == 0xc0) { + int track = nID & 0x1f; + + xprintf (VERBOSE|DEMUX|AUDIO, ", audio #%d", track); + + w = read_bytes(this, 1); + flags = read_bytes(this, 1); + header_len = read_bytes(this, 1); + + nLen -= header_len + 3; + + pts = 0; + + if ((flags & 0x80) == 0x80) { + + w = read_bytes(this, 1); + pts = (w & 0x0e) << 29 ; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) << 14; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) >> 1; + + xprintf (VERBOSE|DEMUX|VPTS, ", pts=%d",pts); + + header_len -= 5 ; + } + + /* read rest of header */ + i = this->input->read (this->input, this->dummy_space, header_len); + + if(this->audio_fifo) + buf = this->input->read_block (this->input, this->audio_fifo, nLen); + + if (buf == NULL) { + this->status = DEMUX_FINISHED; + return ; + } + 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->audio_fifo) + this->audio_fifo->put (this->audio_fifo, buf); + + } else if ((nID >= 0xbc) && ((nID & 0xf0) == 0xe0)) { + + xprintf (VERBOSE|DEMUX|VIDEO, ",video"); + + w = read_bytes(this, 1); + flags = read_bytes(this, 1); + header_len = read_bytes(this, 1); + + nLen -= header_len + 3; + + pts = 0; + + if ((flags & 0x80) == 0x80) { + + w = read_bytes(this, 1); + pts = (w & 0x0e) << 29 ; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) << 14; + w = read_bytes(this, 2); + pts |= (w & 0xFFFE) >> 1; + + xprintf (VERBOSE|DEMUX|VPTS, ", pts=%d",pts); + + header_len -= 5 ; + } + + /* read rest of header */ + i = this->input->read (this->input, this->dummy_space, header_len); + + /* contents */ + + if(this->audio_fifo) + buf = this->input->read_block (this->input, this->audio_fifo, nLen); + + if (buf == NULL) { + this->status = DEMUX_FINISHED; + return ; + } + buf->type = BUF_VIDEO_MPEG; + buf->PTS = pts; + buf->DTS = 0; + 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); + + this->video_fifo->put (this->video_fifo, buf); + + } else { + xprintf (VERBOSE|DEMUX, ",unknown stream - skipped"); + + i = this->input->read (this->input, this->dummy_space, nLen); + /* (*this->input->seek) (nLen,SEEK_CUR); */ + } + + xprintf (VERBOSE|DEMUX, ")\n"); + +} + + +static uint32_t parse_pack(demux_mpeg_t *this) +{ + uint32_t buf ; + + buf = read_bytes (this, 1) ; + + if (this->status != DEMUX_OK) + return buf; + + parse_mpeg2_packet (this, buf & 0xFF); + + buf = read_bytes (this, 3); + + xprintf (VERBOSE|DEMUX, "}\n"); + + return buf; + +} + +static void demux_mpeg_resync (demux_mpeg_t *this, uint32_t buf) { + + while ((buf !=0x000001) && (this->status == DEMUX_OK)) { + xprintf (VERBOSE|DEMUX, "resync : %08x\n",buf); + buf = (buf << 8) | read_bytes (this, 1); + } +} + +static void *demux_mpeg_loop (void *this_gen) { + + demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + buf_element_t *buf; + uint32_t w; + + do { + w = parse_pack (this); + + if (w != 0x000001) + demux_mpeg_resync (this, w); + + } while (this->status == DEMUX_OK) ; + + if (this->send_end_buffers) { + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 0; /* stream finished */ + this->audio_fifo->put (this->audio_fifo, buf); + } + } + + xprintf (VERBOSE|DEMUX, "demux loop finished (status: %d, buf:%x)\n", + this->status, w); + printf ("demux loop finished (status: %d, buf:%x)\n", + this->status, w); + + pthread_exit(NULL); + + return NULL; +} + +static void demux_mpeg_stop (demux_plugin_t *this_gen) { + void *p; + demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + buf_element_t *buf; + + printf ("demux_mpeg: stop...\n"); + + if (this->status != DEMUX_OK) { + + this->video_fifo->clear(this->video_fifo); + if(this->audio_fifo) + this->audio_fifo->clear(this->audio_fifo); + + return; + } + + this->send_end_buffers = 0; + this->status = DEMUX_FINISHED; + + pthread_join (this->thread, &p); + + this->video_fifo->clear(this->video_fifo); + if(this->audio_fifo) + this->audio_fifo->clear(this->audio_fifo); + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_END; + buf->decoder_info[0] = 1; /* forced */ + this->audio_fifo->put (this->audio_fifo, buf); + } + +} + +static int demux_mpeg_get_status (demux_plugin_t *this_gen) { + demux_mpeg_t *this = (demux_mpeg_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) +{ + demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + buf_element_t *buf; + + this->video_fifo = video_fifo; + this->audio_fifo = audio_fifo; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = BUF_CONTROL_START; + this->video_fifo->put (this->video_fifo, buf); + + if(this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_CONTROL_START; + this->audio_fifo->put (this->audio_fifo, buf); + } + + if ((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) != 0 ) { + + uint32_t w; + int num_buffers = NUM_PREVIEW_BUFFERS; + + this->preview_mode = 1; + + this->input->seek (this->input, 3, SEEK_SET); + + this->status = DEMUX_OK ; + + do { + w = parse_pack (this); + + if (w != 0x000001) + demux_mpeg_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); + } else + read_bytes(this, 3); + + this->preview_mode = 0; + this->send_end_buffers = 1; + this->status = DEMUX_OK ; + + pthread_create (&this->thread, NULL, demux_mpeg_loop, this) ; +} + +static int demux_mpeg_open(demux_plugin_t *this_gen, + input_plugin_t *input, int stage) { + + demux_mpeg_t *this = (demux_mpeg_t *) this_gen; + + this->input = input; + + switch(stage) { + + case STAGE_BY_CONTENT: { + uint8_t buf[4096]; + + if((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { + input->seek(input, 0, SEEK_SET); + + if(input->get_blocksize(input)) + return DEMUX_CANNOT_HANDLE; + + if(input->read(input, buf, 6)) { + + if(buf[0] || buf[1] || (buf[2] != 0x01)) + return DEMUX_CANNOT_HANDLE; + + switch(buf[3]) { + + case 0xe0: + case 0xc0: + case 0xc1: + case 0xbd: + + return DEMUX_CAN_HANDLE; + break; + + } + } + } + return DEMUX_CANNOT_HANDLE; + } + break; + + case STAGE_BY_EXTENSION: { + char *media; + char *ending; + char *MRL = input->get_mrl(input); + + media = strstr(MRL, "://"); + if(media) { + if((!(strncasecmp(MRL, "stdin", 5))) + || (!(strncasecmp(MRL, "fifo", 4)))) { + if(!(strncasecmp(media+3, "pes", 3))) { + this->input = input; + return DEMUX_CAN_HANDLE; + } + return DEMUX_CANNOT_HANDLE; + } + else if(strncasecmp(MRL, "file", 4)) { + return DEMUX_CANNOT_HANDLE; + } + } + + ending = strrchr(MRL, '.'); + xprintf(VERBOSE|DEMUX, "demux_pes_can_handle: ending %s of %s\n", + ending, MRL); + + if(!ending) + return DEMUX_CANNOT_HANDLE; + + if(!strcasecmp(ending, ".vdr")) { + this->input = input; + return DEMUX_CAN_HANDLE; + } + } + break; + + default: + return DEMUX_CANNOT_HANDLE; + break; + } + + return DEMUX_CANNOT_HANDLE; +} + +static void demux_mpeg_select_spu_channel (int nChannel) { +} + +static char *demux_mpeg_get_id(void) { + return "MPEG_PES"; +} + +static void demux_mpeg_close (demux_plugin_t *this) { + /* nothing */ +} + +demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { + + demux_mpeg_t *this; + + if (iface != 2) { + 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", + iface); + return NULL; + } + + this = xmalloc (sizeof (demux_mpeg_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; + + return (demux_plugin_t *) this; +} -- cgit v1.2.3