summaryrefslogtreecommitdiff
path: root/src/demuxers
diff options
context:
space:
mode:
authorDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-04-18 22:33:39 +0000
committerDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-04-18 22:33:39 +0000
commitdb6b7c2e1c52c536a7f9690a410bf69817e0b2c5 (patch)
treefdaf7537abca3d4875ad21322c54888914ed15a2 /src/demuxers
downloadxine-lib-db6b7c2e1c52c536a7f9690a410bf69817e0b2c5.tar.gz
xine-lib-db6b7c2e1c52c536a7f9690a410bf69817e0b2c5.tar.bz2
Initial revision
CVS patchset: 1 CVS date: 2001/04/18 22:33:39
Diffstat (limited to 'src/demuxers')
-rw-r--r--src/demuxers/Makefile.am48
-rw-r--r--src/demuxers/demux.h125
-rw-r--r--src/demuxers/demux_avi.c982
-rw-r--r--src/demuxers/demux_elem.c284
-rw-r--r--src/demuxers/demux_mpeg.c626
-rw-r--r--src/demuxers/demux_mpeg_block.c519
-rw-r--r--src/demuxers/demux_mpgaudio.c440
7 files changed, 3024 insertions, 0 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
new file mode 100644
index 000000000..46e5bc8b6
--- /dev/null
+++ b/src/demuxers/Makefile.am
@@ -0,0 +1,48 @@
+CFLAGS = @BUILD_LIB_STATIC@ @GLOBAL_CFLAGS@
+
+noinst_LTLIBRARIES = libdemux.la
+
+#libdemux_la_SOURCES = demux_avi.c demux_mpeg_block.c demux_mpeg.c \
+# demux_mpgaudio.c demux_elem.c
+libdemux_la_SOURCES = demux_avi.c demux_mpeg_block.c demux_mpeg.c
+#libdemux_la_DEPENDENCIES = libsdeps
+#libdemux_la_LIBADD = $(top_builddir)/libmpg123/libmpg123.la
+
+include_HEADERS = demux.h
+
+#libsdeps:
+# @cd $(top_builddir)/libmpg123 && $(MAKE) libmpg123.la
+
+##
+## Install header files (default=$includedir/xine)
+##
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(includedir)/xine
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+ echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p"; \
+ $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p; \
+ done
+
+
+##
+## Remove them
+##
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ list='$(include_HEADERS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(includedir)/xine/$$p; \
+ done
+
+debug:
+ $(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+mostlyclean-generic:
+ -rm -f *~ \#* .*~ .\#*
+
+maintainer-clean-generic:
+ -@echo "This command is intended for maintainers to use;"
+ -@echo "it deletes files that may require special tools to rebuild."
+ -rm -f Makefile.in
+
diff --git a/src/demuxers/demux.h b/src/demuxers/demux.h
new file mode 100644
index 000000000..6fda091fe
--- /dev/null
+++ b/src/demuxers/demux.h
@@ -0,0 +1,125 @@
+/*
+ * 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.h,v 1.1 2001/04/18 22:33:54 f1rmb Exp $
+ */
+
+#ifndef HAVE_DEMUX_H
+#define HAVE_DEMUX_H
+
+#include "buffer.h"
+#include "xine.h"
+#if defined(XINE_COMPILE)
+#include "input/input_plugin.h"
+#else
+#include "input_plugin.h"
+#endif
+
+#define DEMUX_OK 0
+#define DEMUX_FINISHED 1
+
+#define DEMUX_CANNOT_HANDLE 0
+#define DEMUX_CAN_HANDLE 1
+
+#define DEMUX_DEFAULT_STRATEGY 0
+#define DEMUX_REVERT_STRATEGY 1
+#define DEMUX_CONTENT_STRATEGY 2
+#define DEMUX_EXTENSION_STRATEGY 3
+
+#define STAGE_BY_CONTENT 1
+#define STAGE_BY_EXTENSION 2
+
+/*
+ * a demux plugin (no matter if it's staically built into xine
+ * or dynamically loaded at run-time) must implement these functions
+ */
+
+typedef struct demux_plugin_s demux_plugin_t;
+
+struct demux_plugin_s
+{
+ /*
+ * ask demuxer to open the given stream (input-plugin)
+ * using the content-detection method specified in <stage>
+ *
+ * return values:
+ * DEMUX_CAN_HANDLE on success
+ * DEMUX_CANNOT_HANDLE on failure
+ */
+
+ int (*open) (demux_plugin_t *this, input_plugin_t *ip,
+ int stage);
+
+ /*
+ * start demux thread
+ * pos : 0..65535
+ */
+
+ void (*start) (demux_plugin_t *this, fifo_buffer_t *video_fifo,
+ fifo_buffer_t *audio_fifo, fifo_buffer_t *spu_fifo,
+ off_t pos) ;
+
+ /*
+ * stop & kill demux thread, free resources associated with current
+ * input stream
+ */
+
+ void (*stop) (demux_plugin_t *this) ;
+
+ /*
+ * close demuxer, free all resources
+ */
+
+ void (*close) (demux_plugin_t *this) ;
+
+ /*
+ * returns DEMUX_OK or DEMUX_FINISHED
+ */
+
+ int (*get_status) (demux_plugin_t *this) ;
+
+ /*
+ * return human readable identifier for this plugin
+ */
+
+ char* (*get_identifier) (demux_plugin_t *this);
+
+} ;
+
+/*
+ * for dynamic demux plugins:
+ *
+ * make sure you provide this (and only this!) function call:
+ *
+ * demux_plugin_t *init_demux_plugin (config_values_t *cfg, uint32_t xd);
+ *
+ */
+
+demux_plugin_t *init_demux_mpeg (config_values_t *cfg, uint32_t xd);
+
+demux_plugin_t *init_demux_mpeg_block (config_values_t *cfg, uint32_t xd);
+
+demux_plugin_t *init_demux_avi (config_values_t *cfg, uint32_t xd);
+
+demux_plugin_t *init_demux_mpeg_audio (config_values_t *cfg, uint32_t xd);
+
+demux_plugin_t *init_demux_mpeg_elem(config_values_t *cfg, uint32_t xd);
+
+#endif
+
diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c
new file mode 100644
index 000000000..badcadc7d
--- /dev/null
+++ b/src/demuxers/demux_avi.c
@@ -0,0 +1,982 @@
+/*
+ * 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_avi.c,v 1.1 2001/04/18 22:33:55 f1rmb Exp $
+ *
+ * demultiplexer for avi streams
+ *
+ * part of the code is taken from
+ * avilib (C) 1999 Rainer Johanni <Rainer@Johanni.de>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xine.h"
+#include "monitor.h"
+#include "demux.h"
+#include "utils.h"
+#include "libw32dll/wine/mmreg.h"
+#include "libw32dll/wine/avifmt.h"
+#include "libw32dll/wine/vfw.h"
+
+/* The following variable indicates the kind of error */
+
+static uint32_t xine_debug;
+
+typedef struct
+{
+ long pos;
+ long len;
+} video_index_entry_t;
+
+typedef struct
+{
+ long pos;
+ long len;
+ long tot;
+} audio_index_entry_t;
+
+typedef struct
+{
+ long width; /* Width of a video frame */
+ long height; /* Height of a video frame */
+ long dwScale, dwRate;
+ double fps; /* Frames per second */
+
+ char compressor[8]; /* Type of compressor, 4 bytes + padding for 0 byte */
+ long video_strn; /* Video stream number */
+ long video_frames; /* Number of video frames */
+ char video_tag[4]; /* Tag of video data */
+ long video_posf; /* Number of next frame to be read
+ (if index present) */
+ long video_posb; /* Video position: byte within frame */
+
+ long a_fmt; /* Audio format, see #defines below */
+ long a_chans; /* Audio channels, 0 for no audio */
+ long a_rate; /* Rate in Hz */
+ long a_bits; /* bits per audio sample */
+ long audio_strn; /* Audio stream number */
+ long audio_bytes; /* Total number of bytes of audio data */
+ long audio_chunks; /* Chunks of audio data in the file */
+ char audio_tag[4]; /* Tag of audio data */
+ long audio_posc; /* Audio position: chunk */
+ long audio_posb; /* Audio position: byte within chunk */
+
+ long pos; /* position in file */
+ long n_idx; /* number of index entries actually filled */
+ long max_idx; /* number of index entries actually allocated */
+ unsigned char (*idx)[16]; /* index entries (AVI idx1 tag) */
+ video_index_entry_t *video_index;
+ audio_index_entry_t *audio_index;
+ BITMAPINFOHEADER bih;
+ char wavex[64];
+ off_t movi_start;
+ uint32_t AVI_errno;
+} avi_t;
+
+typedef struct demux_avi_s {
+ demux_plugin_t demux_plugin;
+
+ fifo_buffer_t *audio_fifo;
+ fifo_buffer_t *video_fifo;
+
+ input_plugin_t *input;
+
+ avi_t *avi;
+
+ pthread_t thread;
+
+ int status;
+
+ uint32_t video_step;
+ uint32_t avg_bytes_per_sec;
+} demux_avi_t ;
+
+#define AVI_ERR_SIZELIM 1 /* The write of the data would exceed
+ the maximum size of the AVI file.
+ This is more a warning than an error
+ since the file may be closed safely */
+
+#define AVI_ERR_OPEN 2 /* Error opening the AVI file - wrong path
+ name or file nor readable/writable */
+
+#define AVI_ERR_READ 3 /* Error reading from AVI File */
+
+#define AVI_ERR_WRITE 4 /* Error writing to AVI File,
+ disk full ??? */
+
+#define AVI_ERR_WRITE_INDEX 5 /* Could not write index to AVI file
+ during close, file may still be
+ usable */
+
+#define AVI_ERR_CLOSE 6 /* Could not write header to AVI file
+ or not truncate the file during close,
+ file is most probably corrupted */
+
+#define AVI_ERR_NOT_PERM 7 /* Operation not permitted:
+ trying to read from a file open
+ for writing or vice versa */
+
+#define AVI_ERR_NO_MEM 8 /* malloc failed */
+
+#define AVI_ERR_NO_AVI 9 /* Not an AVI file */
+
+#define AVI_ERR_NO_HDRL 10 /* AVI file has no has no header list,
+ corrupted ??? */
+
+#define AVI_ERR_NO_MOVI 11 /* AVI file has no has no MOVI list,
+ corrupted ??? */
+
+#define AVI_ERR_NO_VIDS 12 /* AVI file contains no video data */
+
+#define AVI_ERR_NO_IDX 13 /* The file has been opened with
+ getIndex==0, but an operation has been
+ performed that needs an index */
+
+static unsigned long str2ulong(unsigned char *str)
+{
+ return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
+}
+
+static unsigned long str2ushort(unsigned char *str)
+{
+ return ( str[0] | (str[1]<<8) );
+}
+
+static void long2str(unsigned char *dst, int n)
+{
+ dst[0] = (n )&0xff;
+ dst[1] = (n>> 8)&0xff;
+ dst[2] = (n>>16)&0xff;
+ dst[3] = (n>>24)&0xff;
+}
+
+static void AVI_close(avi_t *AVI)
+{
+ if(AVI->idx) free(AVI->idx);
+ if(AVI->video_index) free(AVI->video_index);
+ if(AVI->audio_index) free(AVI->audio_index);
+ free(AVI);
+}
+
+#define ERR_EXIT(x) \
+{ \
+ AVI->AVI_errno = x; \
+ return 0; \
+}
+
+#define PAD_EVEN(x) ( ((x)+1) & ~1 )
+
+static int avi_sampsize(avi_t *AVI)
+{
+ int s;
+ s = ((AVI->a_bits+7)/8)*AVI->a_chans;
+ if(s==0) s=1; /* avoid possible zero divisions */
+ return s;
+}
+
+static int avi_add_index_entry(avi_t *AVI, unsigned char *tag,
+ long flags, long pos, long len)
+{
+ void *ptr;
+
+ if(AVI->n_idx>=AVI->max_idx)
+ {
+ ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
+ if(ptr == 0)
+ {
+ AVI->AVI_errno = AVI_ERR_NO_MEM;
+ return -1;
+ }
+ AVI->max_idx += 4096;
+ AVI->idx = (unsigned char((*)[16]) ) ptr;
+ }
+
+ /* Add index entry */
+
+ memcpy(AVI->idx[AVI->n_idx],tag,4);
+ long2str(AVI->idx[AVI->n_idx]+ 4,flags);
+ long2str(AVI->idx[AVI->n_idx]+ 8,pos);
+ long2str(AVI->idx[AVI->n_idx]+12,len);
+
+ /* Update counter */
+
+ AVI->n_idx++;
+
+ return 0;
+}
+
+static avi_t *AVI_init(demux_avi_t *this)
+{
+ avi_t *AVI;
+ long i, n, idx_type;
+ unsigned char *hdrl_data;
+ long hdrl_len=0;
+ long nvi, nai, ioff;
+ long tot;
+ int lasttag = 0;
+ int vids_strh_seen = 0;
+ int vids_strf_seen = 0;
+ int auds_strh_seen = 0;
+ int auds_strf_seen = 0;
+ int num_stream = 0;
+ char data[256];
+
+ /* Create avi_t structure */
+
+ AVI = (avi_t *) xmalloc(sizeof(avi_t));
+ if(AVI==NULL)
+ {
+ AVI->AVI_errno = AVI_ERR_NO_MEM;
+ return 0;
+ }
+ memset((void *)AVI,0,sizeof(avi_t));
+
+ /* Read first 12 bytes and check that this is an AVI file */
+
+ if( this->input->read(data,12) != 12 ) ERR_EXIT(AVI_ERR_READ) ;
+
+ if( strncasecmp(data ,"RIFF",4) !=0 ||
+ strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI) ;
+ /* Go through the AVI file and extract the header list,
+ the start position of the 'movi' list and an optionally
+ present idx1 tag */
+
+ hdrl_data = 0;
+
+ while(1) {
+ if (this->input->read(data,8) != 8 ) break; /* We assume it's EOF */
+
+ n = str2ulong(data+4);
+ n = PAD_EVEN(n);
+
+ if(strncasecmp(data,"LIST",4) == 0)
+ {
+ if( this->input->read(data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
+ n -= 4;
+ if(strncasecmp(data,"hdrl",4) == 0)
+ {
+ hdrl_len = n;
+ hdrl_data = (unsigned char *) xmalloc(n);
+ if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM)
+ if( this->input->read(hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
+ }
+ else if(strncasecmp(data,"movi",4) == 0)
+ {
+ AVI->movi_start = this->input->seek(0,SEEK_CUR);
+ this->input->seek(n,SEEK_CUR);
+ }
+ else
+ this->input->seek(n,SEEK_CUR);
+ }
+ else if(strncasecmp(data,"idx1",4) == 0)
+ {
+ /* n must be a multiple of 16, but the reading does not
+ break if this is not the case */
+
+ AVI->n_idx = AVI->max_idx = n/16;
+ AVI->idx = (unsigned char((*)[16]) ) xmalloc(n);
+ if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
+ if( this->input->read((char *)AVI->idx,n) != n ) ERR_EXIT(AVI_ERR_READ)
+ }
+ else
+ this->input->seek(n,SEEK_CUR);
+ }
+
+ if(!hdrl_data) ERR_EXIT(AVI_ERR_NO_HDRL) ;
+ if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI) ;
+
+ /* Interpret the header list */
+
+ for(i=0;i<hdrl_len;)
+ {
+ /* List tags are completly ignored */
+
+ if(strncasecmp(hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
+
+ n = str2ulong(hdrl_data+i+4);
+ n = PAD_EVEN(n);
+
+ /* Interpret the tag and its args */
+
+ if(strncasecmp(hdrl_data+i,"strh",4)==0)
+ {
+ i += 8;
+ if(strncasecmp(hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
+ {
+ memcpy(AVI->compressor,hdrl_data+i+4,4);
+ AVI->compressor[4] = 0;
+ AVI->dwScale = str2ulong(hdrl_data+i+20);
+ AVI->dwRate = str2ulong(hdrl_data+i+24);
+
+ if(AVI->dwScale!=0)
+ AVI->fps = (double)AVI->dwRate/(double)AVI->dwScale;
+ this->video_step = (long) (90000.0 / AVI->fps);
+
+ AVI->video_frames = str2ulong(hdrl_data+i+32);
+ AVI->video_strn = num_stream;
+ vids_strh_seen = 1;
+ lasttag = 1; /* vids */
+ }
+ else if (strncasecmp (hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
+ {
+ AVI->audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI);
+ AVI->audio_strn = num_stream;
+ auds_strh_seen = 1;
+ lasttag = 2; /* auds */
+ }
+ else
+ lasttag = 0;
+ num_stream++;
+ }
+ else if(strncasecmp(hdrl_data+i,"strf",4)==0)
+ {
+ i += 8;
+ if(lasttag == 1) {
+ /* printf ("size : %d\n",sizeof(AVI->bih)); */
+ memcpy (&AVI->bih, hdrl_data+i, sizeof(AVI->bih));
+ /* stream_read(demuxer->stream,(char*) &avi_header.bih,MIN(size2,sizeof(avi_header.bih))); */
+ AVI->width = str2ulong(hdrl_data+i+4);
+ AVI->height = str2ulong(hdrl_data+i+8);
+
+ /*
+ printf ("size : %d x %d (%d x %d)\n", AVI->width, AVI->height, AVI->bih.biWidth, AVI->bih.biHeight);
+ printf(" biCompression %d='%.4s'\n", AVI->bih.biCompression,
+ &AVI->bih.biCompression);
+ */
+ vids_strf_seen = 1;
+ }
+ else if(lasttag == 2)
+ {
+ memcpy (&AVI->wavex, hdrl_data+i, n);
+
+ AVI->a_fmt = str2ushort(hdrl_data+i );
+ AVI->a_chans = str2ushort(hdrl_data+i+2);
+ AVI->a_rate = str2ulong (hdrl_data+i+4);
+ AVI->a_bits = str2ushort(hdrl_data+i+14);
+ this->avg_bytes_per_sec = str2ulong (hdrl_data+i+8);
+ auds_strf_seen = 1;
+ }
+ lasttag = 0;
+ }
+ else
+ {
+ i += 8;
+ lasttag = 0;
+ }
+
+ i += n;
+ }
+
+ free(hdrl_data);
+
+ if(!vids_strh_seen || !vids_strf_seen || AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS)
+
+ AVI->video_tag[0] = AVI->video_strn/10 + '0';
+ AVI->video_tag[1] = AVI->video_strn%10 + '0';
+ AVI->video_tag[2] = 'd';
+ AVI->video_tag[3] = 'b';
+
+ /* Audio tag is set to "99wb" if no audio present */
+ if(!AVI->a_chans) AVI->audio_strn = 99;
+
+ AVI->audio_tag[0] = AVI->audio_strn/10 + '0';
+ AVI->audio_tag[1] = AVI->audio_strn%10 + '0';
+ AVI->audio_tag[2] = 'w';
+ AVI->audio_tag[3] = 'b';
+
+ this->input->seek(AVI->movi_start,SEEK_SET);
+
+ /* if the file has an idx1, check if this is relative
+ to the start of the file or to the start of the movi list */
+
+ idx_type = 0;
+
+ if(AVI->idx)
+ {
+ long pos, len;
+
+ /* Search the first videoframe in the idx1 and look where
+ it is in the file */
+
+ for(i=0;i<AVI->n_idx;i++)
+ if( strncasecmp(AVI->idx[i],AVI->video_tag,3)==0 ) break;
+ if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
+
+ pos = str2ulong(AVI->idx[i]+ 8);
+ len = str2ulong(AVI->idx[i]+12);
+
+ this->input->seek(pos,SEEK_SET);
+ if(this->input->read(data,8)!=8) ERR_EXIT(AVI_ERR_READ) ;
+ if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
+ {
+ idx_type = 1; /* Index from start of file */
+ }
+ else
+ {
+ this->input->seek(pos+AVI->movi_start-4,SEEK_SET);
+ if(this->input->read(data,8)!=8) ERR_EXIT(AVI_ERR_READ) ;
+ if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
+ {
+ idx_type = 2; /* Index from start of movi list */
+ }
+ }
+ /* idx_type remains 0 if neither of the two tests above succeeds */
+ }
+
+ if(idx_type == 0)
+ {
+ /* we must search through the file to get the index */
+
+ this->input->seek( AVI->movi_start, SEEK_SET);
+
+ AVI->n_idx = 0;
+
+ while(1)
+ {
+ if( this->input->read(data,8) != 8 ) break;
+ n = str2ulong(data+4);
+
+ /* The movi list may contain sub-lists, ignore them */
+
+ if(strncasecmp(data,"LIST",4)==0)
+ {
+ this->input->seek(4,SEEK_CUR);
+ continue;
+ }
+
+ /* Check if we got a tag ##db, ##dc or ##wb */
+
+ if( ( (data[2]=='d' || data[2]=='D') &&
+ (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
+ || ( (data[2]=='w' || data[2]=='W') &&
+ (data[3]=='b' || data[3]=='B') ) )
+ {
+ avi_add_index_entry(AVI,data,0,this->input->seek(0,SEEK_CUR)-8,n);
+ }
+
+ this->input->seek(PAD_EVEN(n),SEEK_CUR);
+ }
+ idx_type = 1;
+ }
+
+ /* Now generate the video index and audio index arrays */
+
+ nvi = 0;
+ nai = 0;
+
+ for(i=0;i<AVI->n_idx;i++)
+ {
+ if(strncasecmp(AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
+ if(strncasecmp(AVI->idx[i],AVI->audio_tag,4) == 0) nai++;
+ }
+
+ AVI->video_frames = nvi;
+ AVI->audio_chunks = nai;
+
+ if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS) ;
+
+ AVI->video_index = (video_index_entry_t *) xmalloc(nvi*sizeof(video_index_entry_t));
+ if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM) ;
+
+ if(AVI->audio_chunks) {
+ AVI->audio_index = (audio_index_entry_t *) xmalloc(nai*sizeof(audio_index_entry_t));
+ if(AVI->audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM) ;
+ }
+
+ nvi = 0;
+ nai = 0;
+ tot = 0;
+ ioff = idx_type == 1 ? 8 : AVI->movi_start+4;
+
+ for(i=0;i<AVI->n_idx;i++)
+ {
+ if(strncasecmp(AVI->idx[i],AVI->video_tag,3) == 0)
+ {
+ AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
+ AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
+ nvi++;
+ }
+ if(strncasecmp(AVI->idx[i],AVI->audio_tag,4) == 0)
+ {
+ AVI->audio_index[nai].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
+ AVI->audio_index[nai].len = str2ulong(AVI->idx[i]+12);
+ AVI->audio_index[nai].tot = tot;
+ tot += AVI->audio_index[nai].len;
+ nai++;
+ }
+ }
+
+ AVI->audio_bytes = tot;
+
+ /* Reposition the file */
+
+ this->input->seek(AVI->movi_start,SEEK_SET);
+ AVI->video_posf = 0;
+ AVI->video_posb = 0;
+
+ return AVI;
+}
+
+static long AVI_frame_size(avi_t *AVI, long frame)
+{
+ if(!AVI->video_index) { AVI->AVI_errno = AVI_ERR_NO_IDX; return -1; }
+
+ if(frame < 0 || frame >= AVI->video_frames) return 0;
+ return(AVI->video_index[frame].len);
+}
+
+static void AVI_seek_start(avi_t *AVI)
+{
+ AVI->video_posf = 0;
+ AVI->video_posb = 0;
+}
+
+static int AVI_set_video_position(avi_t *AVI, long frame)
+{
+ if(!AVI->video_index) { AVI->AVI_errno = AVI_ERR_NO_IDX; return -1; }
+
+ if (frame < 0 ) frame = 0;
+ AVI->video_posf = frame;
+ AVI->video_posb = 0;
+ return 0;
+}
+
+static int AVI_set_audio_position(avi_t *AVI, long byte)
+{
+ long n0, n1, n;
+
+ if(!AVI->audio_index) { AVI->AVI_errno = AVI_ERR_NO_IDX; return -1; }
+
+ if(byte < 0) byte = 0;
+
+ /* Binary search in the audio chunks */
+
+ n0 = 0;
+ n1 = AVI->audio_chunks;
+
+ while(n0<n1-1)
+ {
+ n = (n0+n1)/2;
+ if(AVI->audio_index[n].tot>byte)
+ n1 = n;
+ else
+ n0 = n;
+ }
+
+ AVI->audio_posc = n0;
+ AVI->audio_posb = byte - AVI->audio_index[n0].tot;
+
+ return 0;
+}
+
+static long AVI_read_audio(demux_avi_t *this, avi_t *AVI, char *audbuf,
+ long bytes, int *bFrameDone)
+{
+ long nr, pos, left, todo;
+
+ if(!AVI->audio_index) { AVI->AVI_errno = AVI_ERR_NO_IDX; return -1; }
+
+ nr = 0; /* total number of bytes read */
+
+ /* printf ("avi audio package len: %d\n", AVI->audio_index[AVI->audio_posc].len); */
+
+
+ while(bytes>0)
+ {
+ left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb;
+ if(left==0)
+ {
+ AVI->audio_posc++;
+ AVI->audio_posb = 0;
+ if (nr>0) {
+ *bFrameDone = 1;
+ return nr;
+ }
+ left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb;
+ }
+ if(bytes<left)
+ todo = bytes;
+ else
+ todo = left;
+ pos = AVI->audio_index[AVI->audio_posc].pos + AVI->audio_posb;
+ /* printf ("demux_avi: read audio from %d\n", pos); */
+ if (this->input->seek (pos, SEEK_SET)<0)
+ return -1;
+ if (this->input->read(audbuf+nr,todo) != todo)
+ {
+ AVI->AVI_errno = AVI_ERR_READ;
+ *bFrameDone = 0;
+ return -1;
+ }
+ bytes -= todo;
+ nr += todo;
+ AVI->audio_posb += todo;
+ }
+
+ left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb;
+ *bFrameDone = (left==0);
+
+ return nr;
+}
+
+static long AVI_read_video(demux_avi_t *this, avi_t *AVI, char *vidbuf,
+ long bytes, int *bFrameDone)
+{
+ long nr, pos, left, todo;
+
+ if(!AVI->video_index) { AVI->AVI_errno = AVI_ERR_NO_IDX; return -1; }
+
+ nr = 0; /* total number of bytes read */
+
+ while(bytes>0)
+ {
+ left = AVI->video_index[AVI->video_posf].len - AVI->video_posb;
+ if(left==0)
+ {
+ AVI->video_posf++;
+ AVI->video_posb = 0;
+ if (nr>0) {
+ *bFrameDone = 1;
+ return nr;
+ }
+ left = AVI->video_index[AVI->video_posf].len - AVI->video_posb;
+ }
+ if(bytes<left)
+ todo = bytes;
+ else
+ todo = left;
+ pos = AVI->video_index[AVI->video_posf].pos + AVI->video_posb;
+ /* printf ("demux_avi: read video from %d\n", pos); */
+ if (this->input->seek (pos, SEEK_SET)<0)
+ return -1;
+ if (this->input->read(vidbuf+nr,todo) != todo)
+ {
+ AVI->AVI_errno = AVI_ERR_READ;
+ *bFrameDone = 0;
+ return -1;
+ }
+ bytes -= todo;
+ nr += todo;
+ AVI->video_posb += todo;
+ }
+
+ left = AVI->video_index[AVI->video_posf].len - AVI->video_posb;
+ *bFrameDone = (left==0);
+
+ return nr;
+}
+
+static int demux_avi_next (demux_avi_t *this) {
+
+ buf_element_t *buf;
+
+ if (this->avi->video_frames <= this->avi->video_posf)
+ return 0;
+
+ buf = this->audio_fifo->buffer_pool_alloc ();
+
+ buf->content = buf->mem;
+ buf->DTS = 0 ; /* FIXME */
+
+ if (this->avi->audio_index[this->avi->audio_posc].pos<
+ this->avi->video_index[this->avi->video_posf].pos) {
+
+ /* read audio */
+ xprintf (VERBOSE|DEMUX|VAVI, "demux_avi: audio \n");
+ /* pBuf->nPTS = (uint32_t) (90000.0 * (this->avi->audio_index[this->avi->audio_posc].tot + this->avi->audio_posb) / this->nAvgBytesPerSec) ; */
+
+ buf->size = AVI_read_audio (this, this->avi, buf->mem, 2048, &buf->frame_end);
+ buf->PTS = 0;
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ switch (this->avi->a_fmt) {
+ case 0x01:
+ buf->type = BUF_AUDIO_LPCM;
+ break;
+ case 0x2000:
+ buf->type = BUF_AUDIO_AC3;
+ break;
+ case 0x50:
+ case 0x55:
+ buf->type = BUF_AUDIO_MPEG;
+ break;
+ case 0x161:
+ buf->type = BUF_AUDIO_AVI;
+ break;
+ default:
+ printf ("demux_avi: unknown audio type 0x%lx =>exit\n", this->avi->a_fmt);
+ this->status = DEMUX_FINISHED;
+ buf->type = BUF_AUDIO_MPEG;
+ break;
+ }
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ } else {
+ /* read video */
+ xprintf (VERBOSE|DEMUX|VAVI, "demux_avi: video \n");
+
+ buf->PTS = 0;
+ /* buf->nPTS = this->avi->video_posf * this->video_step ; */
+ buf->size = AVI_read_video (this, this->avi, buf->mem, 2048, &buf->frame_end);
+ buf->type = BUF_VIDEO_AVI ;
+
+ this->video_fifo->put (this->video_fifo, buf);
+ }
+
+ xprintf (VERBOSE|DEMUX|VAVI, "size : %d\n",buf->size);
+
+ return (buf->size>0);
+}
+
+static void *demux_avi_loop (void *this_gen) {
+
+ buf_element_t *buf;
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+
+ do {
+ if (!demux_avi_next(this))
+ this->status = DEMUX_FINISHED;
+
+ } while (this->status == DEMUX_OK) ;
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->video_fifo->put (this->video_fifo, buf);
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ xprintf (VERBOSE|DEMUX, "demux_avi: demux loop finished.\n");
+
+ return NULL;
+}
+
+static void demux_avi_stop (demux_plugin_t *this_gen) {
+ void *p;
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+
+ this->status = DEMUX_FINISHED;
+
+ pthread_join (this->thread, &p);
+
+ AVI_close (this->avi);
+ this->avi = NULL;
+}
+
+static void demux_avi_close (demux_plugin_t *this_gen) {
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+ free(this);
+}
+
+static int demux_avi_get_status (demux_plugin_t *this_gen) {
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+ return this->status;
+}
+
+static void demux_avi_start (demux_plugin_t *this_gen,
+ fifo_buffer_t *bufVideo,
+ fifo_buffer_t *bufAudio,
+ fifo_buffer_t *bufSPU,
+ off_t pos)
+{
+ buf_element_t *buf;
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+
+ this->audio_fifo = bufVideo;
+ this->video_fifo = bufAudio;
+
+ this->status = DEMUX_OK;
+
+ this->avi = AVI_init(this);
+
+ if (!this->avi) {
+ printf ("demux_avi: init failed, avi_errno=%d .\n", this->avi->AVI_errno);
+ this->status = DEMUX_FINISHED;
+ return;
+ }
+
+ printf ("demux_avi: video format = %s, audio format = 0x%lx\n",
+ this->avi->compressor, this->avi->a_fmt);
+
+ AVI_seek_start (this->avi);
+
+ /*
+ * seek
+ */
+
+ /* seek audio */
+ while (this->avi->audio_index[this->avi->audio_posc].pos < pos) {
+ this->avi->audio_posc++;
+ if (this->avi->audio_posc>this->avi->audio_chunks) {
+ this->status = DEMUX_FINISHED;
+ return;
+ }
+ }
+
+ /* seek video */
+
+ /*
+ while (this->avi->video_index[this->avi->video_posf].pos < pos) {
+ this->avi->video_posf++;
+ if (this->avi->video_posf>this->avi->video_frames) {
+ this->mnStatus = DEMUX_FINISHED;
+ return;
+ }
+ }
+ */
+
+
+ this->avi->video_posf = (long) (((double) this->avi->audio_index[this->avi->audio_posc].tot / (double) this->avi->audio_bytes) * (double) this->avi->video_frames);
+
+
+ /*
+ * send start buffers
+ */
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->video_fifo->put (this->video_fifo, buf);
+
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->content = buf->mem;
+ this->avi->bih.biSize = this->video_step; /* HACK */
+ memcpy (buf->content, &this->avi->bih, sizeof (this->avi->bih));
+ buf->size = sizeof (this->avi->bih);
+ buf->type = BUF_VIDEO_AVI;
+ this->video_fifo->put (this->video_fifo, buf);
+
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->content = buf->mem;
+ memcpy (buf->content, &this->avi->wavex,
+ sizeof (this->avi->wavex));
+ buf->size = sizeof (this->avi->wavex);
+ buf->type = BUF_AUDIO_AVI;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ pthread_create (&this->thread, NULL, demux_avi_loop, this) ;
+}
+
+static int demux_avi_open(demux_plugin_t *this_gen, input_plugin_t *input, int stage) {
+
+ demux_avi_t *this = (demux_avi_t *) this_gen;
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT: {
+ uint8_t buf[4096];
+
+ if (input->get_blocksize())
+ return DEMUX_CANNOT_HANDLE;
+
+ if (!(input->get_capabilities() & INPUT_CAP_SEEKABLE))
+ return DEMUX_CANNOT_HANDLE;
+
+ input->seek(0, SEEK_SET);
+
+ if(input->read(buf, 4)) {
+
+ if((buf[0] == 0x52)
+ && (buf[1] == 0x49)
+ && (buf[2] == 0x46)
+ && (buf[3] == 0x46)) {
+ this->input = input;
+ this->avi = AVI_init (this);
+ if (this->avi)
+ return DEMUX_CAN_HANDLE;
+ else {
+ printf ("demux_avi: AVI_init failed.\n");
+ return DEMUX_CANNOT_HANDLE;
+ }
+ }
+
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *ending, *mrl;
+
+ mrl = this->input->get_mrl ();
+
+ ending = strrchr(mrl, '.');
+ xprintf(VERBOSE|DEMUX, "demux_avi_can_handle: ending %s of %s\n",
+ ending, mrl);
+
+ if(ending) {
+ if(!strcasecmp(ending, ".avi")) {
+ this->input = input;
+ this->avi = AVI_init (this);
+ if (this->avi)
+ return DEMUX_CAN_HANDLE;
+ else {
+ printf ("demux_avi: AVI_init failed.\n");
+ return DEMUX_CANNOT_HANDLE;
+ }
+ }
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+static char *demux_avi_get_id(demux_plugin_t *this) {
+ return "AVI";
+}
+
+demux_plugin_t *init_demux_avi(config_values_t *cfg, uint32_t xd) {
+
+ demux_avi_t *this = xmalloc (sizeof (demux_avi_t));
+
+ xine_debug = xd;
+
+ this->demux_plugin.open = demux_avi_open;
+ this->demux_plugin.start = demux_avi_start;
+ this->demux_plugin.stop = demux_avi_stop;
+ 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;
+
+
+ return (demux_plugin_t *) this;
+}
diff --git a/src/demuxers/demux_elem.c b/src/demuxers/demux_elem.c
new file mode 100644
index 000000000..855c22e17
--- /dev/null
+++ b/src/demuxers/demux_elem.c
@@ -0,0 +1,284 @@
+/*
+ * 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_elem.c,v 1.1 2001/04/18 22:33:58 f1rmb Exp $
+ *
+ * demultiplexer for elementary mpeg streams
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "xine.h"
+#include "monitor.h"
+#include "demux.h"
+
+static uint32_t xine_debug;
+
+typedef struct _demux_mpeg_elem_globals {
+ fifo_buffer_t *mBufVideo;
+ fifo_buffer_t *mBufAudio;
+
+ input_plugin_t *mInput;
+ pthread_t mThread;
+ int mnBlocksize;
+
+ int mnStatus;
+} demux_mpeg_elem_globals_t ;
+
+static demux_mpeg_elem_globals_t gDemuxMpegElem;
+static fifobuf_functions_t *Ffb;
+
+/*
+ *
+ */
+static int demux_mpeg_elem_next (void) {
+
+ buf_element_t *pBuf;
+
+ pBuf = Ffb->buffer_pool_alloc ();
+
+ pBuf->pContent = pBuf->pMem;
+ pBuf->nDTS = 0;
+ pBuf->nPTS = 0;
+ pBuf->nSize = gDemuxMpegElem.mInput->read(pBuf->pMem,
+ gDemuxMpegElem.mnBlocksize);
+ pBuf->nType = BUF_MPEGELEMENT;
+ pBuf->nInputPos = gDemuxMpegElem.mInput->seek (0, SEEK_CUR);
+
+ Ffb->fifo_buffer_put (gDemuxMpegElem.mBufVideo, pBuf);
+
+ return (pBuf->nSize==gDemuxMpegElem.mnBlocksize);
+}
+
+/*
+ *
+ */
+static void *demux_mpeg_elem_loop (void *dummy) {
+ buf_element_t *pBuf;
+
+ do {
+
+ if (!demux_mpeg_elem_next())
+ gDemuxMpegElem.mnStatus = DEMUX_FINISHED;
+
+ } while (gDemuxMpegElem.mnStatus == DEMUX_OK) ;
+
+ xprintf (VERBOSE|DEMUX, "demux loop finished (status: %d)\n",
+ gDemuxMpegElem.mnStatus);
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_STREAMEND;
+ Ffb->fifo_buffer_put (gDemuxMpegElem.mBufVideo, pBuf);
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_STREAMEND;
+ Ffb->fifo_buffer_put (gDemuxMpegElem.mBufAudio, pBuf);
+
+ return NULL;
+}
+
+/*
+ *
+ */
+static void demux_mpeg_elem_stop (void) {
+ void *p;
+
+ gDemuxMpegElem.mnStatus = DEMUX_FINISHED;
+
+ Ffb->fifo_buffer_clear(gDemuxMpegElem.mBufVideo);
+ Ffb->fifo_buffer_clear(gDemuxMpegElem.mBufAudio);
+
+ pthread_join (gDemuxMpegElem.mThread, &p);
+}
+
+/*
+ *
+ */
+static int demux_mpeg_elem_get_status (void) {
+ return gDemuxMpegElem.mnStatus;
+}
+
+/*
+ *
+ */
+static void demux_mpeg_elem_start (input_plugin_t *input_plugin,
+ fifo_buffer_t *bufVideo,
+ fifo_buffer_t *bufAudio,
+ fifo_buffer_t *bufSPU,
+ off_t pos)
+{
+ buf_element_t *pBuf;
+
+ gDemuxMpegElem.mInput = input_plugin;
+ gDemuxMpegElem.mBufVideo = bufVideo;
+ gDemuxMpegElem.mBufAudio = bufAudio;
+
+ gDemuxMpegElem.mnStatus = DEMUX_OK;
+ /*
+ if ((gDemuxMpegElem.mInput->get_capabilities() & INPUT_CAP_SEEKABLE) != 0 ) {
+ xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos);
+
+ gDemuxMpegElem.mInput->seek (pos, SEEK_SET);
+ }
+ else { */
+ if((gDemuxMpegElem.mInput->get_capabilities() & INPUT_CAP_SEEKABLE) != 0)
+ gDemuxMpegElem.mInput->seek (pos, SEEK_SET);
+/* } */
+
+ gDemuxMpegElem.mnBlocksize = 2048;
+ // pos /= (off_t) gDemuxMpegElem.mnBlocksize;
+ // pos *= (off_t) gDemuxMpegElem.mnBlocksize;
+ // xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos);
+
+ // gDemuxMpegElem.mInput->seek (pos, SEEK_SET);
+
+ /*
+ * send reset buffer
+ */
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_RESET;
+ Ffb->fifo_buffer_put (gDemuxMpegElem.mBufVideo, pBuf);
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_RESET;
+ Ffb->fifo_buffer_put (gDemuxMpegElem.mBufAudio, pBuf);
+
+ /*
+ * now start demuxing
+ */
+
+ pthread_create (&gDemuxMpegElem.mThread, NULL, demux_mpeg_elem_loop, NULL) ;
+}
+
+/*
+ *
+ */
+static void demux_mpeg_elem_select_audio_channel (int nChannel) {
+}
+
+/*
+ *
+ */
+static void demux_mpeg_elem_select_spu_channel (int nChannel) {
+}
+
+/*
+ *
+ */
+static int demux_mpeg_elem_open(input_plugin_t *ip,
+ const char *MRL, int stage) {
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT: {
+ uint8_t buf[4096];
+ int bs = 0;
+
+ if(!ip)
+ return DEMUX_CANNOT_HANDLE;
+
+ if((ip->get_capabilities() & INPUT_CAP_SEEKABLE) != 0) {
+ ip->seek(0, SEEK_SET);
+
+ if(ip->get_blocksize)
+ bs = ip->get_blocksize();
+
+ bs = (bs > 4) ? bs : 4;
+
+ if(ip->read(buf, bs)) {
+
+ if(buf[0] || buf[1] || (buf[2] != 0x01))
+ return DEMUX_CANNOT_HANDLE;
+
+ switch(buf[3]) {
+ case 0xb3:
+ return DEMUX_CAN_HANDLE;
+ break;
+ }
+ }
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *suffix;
+
+ suffix = strrchr(MRL, '.');
+ xprintf(VERBOSE|DEMUX, "demux_pure_can_handle: suffix %s of %s\n",
+ suffix, MRL);
+
+ if(suffix) {
+ if(!strcasecmp(suffix, ".mpv"))
+ return DEMUX_CAN_HANDLE;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+/*
+ *
+ */
+static char *demux_mpeg_elem_get_id(void) {
+ return "MPEG_ELEM";
+}
+
+/*
+ *
+ */
+static demux_functions_t demux_mpeg_elem_functions = {
+ NULL,
+ NULL,
+ demux_mpeg_elem_open,
+ demux_mpeg_elem_start,
+ demux_mpeg_elem_stop,
+ demux_mpeg_elem_get_status,
+ demux_mpeg_elem_select_audio_channel,
+ demux_mpeg_elem_select_spu_channel,
+ demux_mpeg_elem_get_id
+};
+
+/*
+ *
+ */
+demux_functions_t *init_demux_mpeg_elem(fifobuf_functions_t *f, uint32_t xd) {
+
+ Ffb = f;
+ xine_debug = xd;
+ return &demux_mpeg_elem_functions;
+}
diff --git a/src/demuxers/demux_mpeg.c b/src/demuxers/demux_mpeg.c
new file mode 100644
index 000000000..9fcb37df4
--- /dev/null
+++ b/src/demuxers/demux_mpeg.c
@@ -0,0 +1,626 @@
+/*
+ * 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_mpeg.c,v 1.1 2001/04/18 22:33:58 f1rmb Exp $
+ *
+ * demultiplexer for mpeg 1/2 program streams
+ * reads streams of variable blocksizes
+ *
+ * currently only used for mpeg-1-files
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "monitor.h"
+#include "xine.h"
+#include "demux.h"
+#include "utils.h"
+
+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;
+} 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 (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;
+
+ nLen = read_bytes(this, 2);
+
+ xprintf (VERBOSE|DEMUX|MPEG, " mpeg2 packet (len=%d",nLen);
+
+ 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->dummy_space, header_len+4);
+
+ track = this->dummy_space[0] & 0x0F ;
+
+ xprintf (VERBOSE|DEMUX, ", track=%02x", track);
+
+ /* contents */
+
+ buf = this->input->read_block (this->audio_fifo, nLen-4);
+
+ buf->type = BUF_AUDIO_AC3 + track;
+ buf->PTS = pts;
+ buf->DTS = 0 ; /* FIXME */
+ buf->input_pos = this->input->get_current_pos ();
+
+ 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->dummy_space, header_len);
+
+ buf = this->input->read_block (this->audio_fifo, nLen);
+
+ buf->type = BUF_AUDIO_MPEG + track;
+ buf->PTS = pts;
+ buf->DTS = 0; /* FIXME */
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ 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->dummy_space, header_len);
+
+ /* contents */
+
+ buf = this->input->read_block (this->audio_fifo, nLen);
+
+ buf->type = BUF_VIDEO_MPEG;
+ buf->PTS = pts;
+ buf->DTS = 0;
+
+ this->video_fifo->put (this->video_fifo, buf);
+
+ } else {
+ xprintf (VERBOSE|DEMUX, ",unknown stream - skipped");
+
+ i = this->input->read (this->dummy_space, nLen);
+ /* (*this->input->seek) (nLen,SEEK_CUR); */
+ }
+
+ xprintf (VERBOSE|DEMUX, ")\n");
+
+}
+
+static void parse_mpeg1_packet (demux_mpeg_t *this, int nID)
+{
+ int nLen;
+ uint32_t w;
+ int i;
+ int pts;
+ buf_element_t *buf;
+
+ xprintf (VERBOSE|DEMUX, " packet (");
+
+ nLen = read_bytes(this, 2);
+
+ xprintf (VERBOSE|DEMUX, "len=%d",nLen);
+
+ pts=0;
+
+ if (nID != 0xbf) {
+
+ w = read_bytes(this, 1); nLen--;
+
+ while ((w & 0x80) == 0x80) {
+
+ if (this->status != DEMUX_OK)
+ return;
+
+ /* stuffing bytes */
+ w = read_bytes(this, 1); nLen--;
+ }
+
+ if ((w & 0xC0) == 0x40) {
+
+ if (this->status != DEMUX_OK)
+ return;
+
+ /* buffer_scale, buffer size */
+ w = read_bytes(this, 1); nLen--;
+ w = read_bytes(this, 1); nLen--;
+ }
+
+ if ((w & 0xF0) == 0x20) {
+
+ if (this->status != DEMUX_OK)
+ return;
+
+ pts = (w & 0xe) << 29 ;
+ w = read_bytes(this, 2); nLen -= 2;
+
+ pts |= (w & 0xFFFE) << 14;
+
+ w = read_bytes(this, 2); nLen -= 2;
+ pts |= (w & 0xFFFE) >> 1;
+
+ xprintf (VERBOSE|DEMUX|VPTS, ", pts=%d",pts);
+
+ /* pts = 0; */
+
+ } else if ((w & 0xF0) == 0x30) {
+
+ if (this->status != DEMUX_OK)
+ return;
+
+ pts = (w & 0x0e) << 29 ;
+ w = read_bytes(this, 2); nLen -= 2;
+
+ pts |= (w & 0xFFFE) << 14;
+
+ w = read_bytes(this, 2); nLen -= 2;
+
+ pts |= (w & 0xFFFE) >> 1;
+
+/* printf ("pts2=%d\n",pts); */
+ xprintf (VERBOSE|DEMUX|VPTS, ", pts2=%d",pts);
+
+ /* Decoding Time Stamp */
+ w = read_bytes(this, 3); nLen -= 3;
+ w = read_bytes(this, 2); nLen -= 2;
+ } else {
+ xprintf (VERBOSE|DEMUX, ", w = %02x",w);
+ if (w != 0x0f)
+ xprintf (VERBOSE|DEMUX, " ERROR w (%02x) != 0x0F ",w);
+ }
+
+ }
+
+ if ((nID & 0xe0) == 0xc0) {
+ int track = nID & 0x1f;
+
+ xprintf (VERBOSE|DEMUX|AUDIO, ", audio #%d", track);
+
+ buf = this->input->read_block (this->audio_fifo, nLen);
+
+ buf->type = BUF_AUDIO_MPEG + track ;
+ buf->PTS = pts;
+ buf->DTS = 0; /* FIXME */
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ } else if ((nID & 0xf0) == 0xe0) {
+
+ xprintf (VERBOSE|DEMUX|VIDEO, ", video #%d", nID & 0x0f);
+
+ buf = this->input->read_block (this->video_fifo, nLen);
+
+ buf->type = BUF_VIDEO_MPEG;
+ buf->PTS = pts;
+ buf->DTS = 0; /* FIXME */
+
+ this->video_fifo->put (this->video_fifo, buf);
+
+ } else if (nID == 0xbd) {
+ xprintf (VERBOSE|DEMUX|AC3, ", ac3");
+ i = this->input->read (this->dummy_space, nLen);
+ } else {
+ xprintf (VERBOSE|DEMUX, ", unknown (nID = %d)",nID);
+ this->input->read (this->dummy_space, nLen);
+ }
+
+ xprintf (VERBOSE|DEMUX, ")\n");
+}
+
+static uint32_t parse_pack(demux_mpeg_t *this)
+{
+ uint32_t buf ;
+ char scratch[1024];
+ int mpeg_version;
+
+ xprintf (VERBOSE|DEMUX, "pack {\n");
+
+ /* system_clock_reference */
+ buf = read_bytes (this, 1);
+ xprintf (VERBOSE|DEMUX|VIDEO, " mpeg version : %02x",buf>>4);
+
+ if ((buf>>4) == 4) {
+ xprintf (VERBOSE|DEMUX|VIDEO, " => mpeg II \n");
+ buf = read_bytes(this, 2);
+ mpeg_version = 2;
+ } else {
+ xprintf (VERBOSE|DEMUX|VIDEO, " => mpeg I \n");
+ mpeg_version = 1;
+ }
+
+ buf = read_bytes (this, 2);
+ buf = read_bytes (this, 2);
+
+ /* mux_rate */
+
+ buf = read_bytes (this, 3) ;
+
+ /* printf (" mux_rate = %06x\n",buf); */
+
+ /* system header */
+
+ buf = read_bytes (this, 4) ;
+
+ /* printf (" code = %08x\n",buf);*/
+
+ if (buf == 0x000001bb) {
+ buf = read_bytes (this, 2);
+ xprintf (VERBOSE|DEMUX, " system_header (%d +6 bytes)\n",buf);
+
+ this->input->read (scratch,buf);
+
+ buf = read_bytes (this, 4) ;
+ }
+
+ /* printf (" code = %08x\n",buf); */
+
+ while ( ((buf & 0xFFFFFF00) == 0x00000100)
+ && ((buf & 0xff) != 0xba) ) {
+
+ if (this->status != DEMUX_OK)
+ return buf;
+
+ if (mpeg_version == 1)
+ parse_mpeg1_packet (this, buf & 0xFF);
+ else
+ parse_mpeg2_packet (this, buf & 0xFF);
+
+ buf = read_bytes (this, 4);
+ xprintf (VERBOSE|DEMUX, " code = %08x\n",buf);
+ }
+
+ xprintf (VERBOSE|DEMUX, "}\n");
+
+ return buf;
+
+}
+
+static void demux_mpeg_resync (demux_mpeg_t *this, uint32_t buf) {
+
+ while ((buf !=0x000001ba) && (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 != 0x000001ba)
+ demux_mpeg_resync (this, w);
+
+ } while (this->status == DEMUX_OK) ;
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->video_fifo->put (this->video_fifo, buf);
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ xprintf (VERBOSE|DEMUX, "demux loop finished (status: %d, buf:%x)\n",
+ this->status, w);
+
+ return NULL;
+}
+
+static void demux_mpeg_stop (demux_plugin_t *this_gen) {
+ void *p;
+ demux_mpeg_t *this = (demux_mpeg_t *) this_gen;
+
+ this->status = DEMUX_FINISHED;
+
+ pthread_join (this->thread, &p);
+}
+
+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,
+ fifo_buffer_t *spu_fifo,
+ off_t pos)
+{
+ demux_mpeg_t *this = (demux_mpeg_t *) this_gen;
+ buf_element_t *buf;
+
+ this->video_fifo = video_fifo;
+ this->audio_fifo = audio_fifo;
+
+ this->status = DEMUX_OK;
+
+ if ((this->input->get_capabilities () & INPUT_CAP_SEEKABLE) != 0 ) {
+ xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos);
+ this->input->seek (pos+4, SEEK_SET);
+ }
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->video_fifo->put (this->video_fifo, buf);
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ pthread_create (&this->thread, NULL, demux_mpeg_loop, this) ;
+}
+
+static int demux_mpeg_open(demux_plugin_t *this_gen, input_plugin_t *ip, int stage) {
+
+ demux_mpeg_t *this = (demux_mpeg_t *) this_gen;
+
+ this->input = ip;
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT: {
+ uint8_t buf[4096];
+
+ if((ip->get_capabilities() & INPUT_CAP_SEEKABLE) != 0) {
+ ip->seek(0, SEEK_SET);
+
+ if(ip->get_blocksize())
+ return DEMUX_CANNOT_HANDLE;
+
+ if(ip->read(buf, 6)) {
+
+ if(buf[0] || buf[1] || (buf[2] != 0x01))
+ return DEMUX_CANNOT_HANDLE;
+
+ switch(buf[3]) {
+
+ case 0xba:
+ if((buf[4] & 0xf0) == 0x20)
+ return DEMUX_CAN_HANDLE;
+ break;
+
+ case 0xe0:
+ if((buf[6] & 0xc0) != 0x80)
+ return DEMUX_CAN_HANDLE;
+ break;
+
+ }
+ }
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *media;
+ char *ending;
+ char *MRL = ip->get_mrl();
+
+ media = strstr(MRL, "://");
+ if(media) {
+ if((!(strncasecmp(MRL, "stdin", 5)))
+ || (!(strncasecmp(MRL, "fifo", 4)))) {
+ if(!(strncasecmp((media+3), "mpeg1", 5))) {
+ perr("%s(%d)mpeg\n", __FUNCTION__, stage);
+ return DEMUX_CAN_HANDLE;
+ }
+ else if(!(strncasecmp((media+3), "mpeg2", 5))) {
+ return DEMUX_CANNOT_HANDLE;
+ }
+ fprintf(stderr, "You should specify mpeg(mpeg1/mpeg2) stream type.\n");
+ return DEMUX_CANNOT_HANDLE;
+ }
+ else if(strncasecmp(MRL, "file", 4)) {
+ return DEMUX_CANNOT_HANDLE;
+ }
+ }
+
+ ending = strrchr(MRL, '.');
+ xprintf(VERBOSE|DEMUX, "demux_mpeg_can_handle: ending %s of %s\n",
+ ending, MRL);
+
+ if(!ending)
+ return DEMUX_CANNOT_HANDLE;
+
+ if(!strcasecmp(ending, ".mpg")
+ || (!strcasecmp(ending, ".mpeg"))) {
+ 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(demux_plugin_t *this) {
+ return "MPEG";
+}
+
+static void demux_mpeg_close (demux_plugin_t *this) {
+ /* nothing */
+}
+
+demux_plugin_t *init_demux_mpeg(config_values_t *cfg, uint32_t xd) {
+
+ demux_mpeg_t *this = xmalloc (sizeof (demux_mpeg_t));
+
+ xine_debug = xd;
+
+ 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;
+}
+
diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c
new file mode 100644
index 000000000..531bf44aa
--- /dev/null
+++ b/src/demuxers/demux_mpeg_block.c
@@ -0,0 +1,519 @@
+/*
+ * 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_mpeg_block.c,v 1.1 2001/04/18 22:33:58 f1rmb Exp $
+ *
+ * demultiplexer for mpeg 1/2 program streams
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "xine.h"
+#include "monitor.h"
+#include "demux.h"
+#include "utils.h"
+
+static uint32_t xine_debug;
+
+typedef struct demux_mpeg_block_s {
+ demux_plugin_t demux_plugin;
+
+ fifo_buffer_t *audio_fifo;
+ fifo_buffer_t *video_fifo;
+ fifo_buffer_t *spu_fifo;
+
+ input_plugin_t *input;
+
+ pthread_t thread;
+
+ int status;
+
+ int blocksize;
+} demux_mpeg_block_t ;
+
+
+static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *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;
+
+
+ buf = this->input->read_block (this->video_fifo, this->blocksize);
+
+ if (buf==NULL) {
+ this->status = DEMUX_FINISHED;
+ return ;
+ }
+
+ p = buf->content; /* len = this->mnBlocksize; */
+
+ if (p[3] == 0xBA) { /* program stream pack header */
+
+ int nStuffingBytes;
+
+ xprintf (VERBOSE|DEMUX, "program stream pack header\n");
+
+ bMpeg1 = (p[4] & 0x40) == 0;
+
+ if (bMpeg1) {
+
+ p += 12;
+
+ } else { /* mpeg2 */
+
+ nStuffingBytes = p[0xD] & 0x07;
+
+ xprintf (VERBOSE|DEMUX, "%d stuffing bytes\n",nStuffingBytes);
+
+ p += 14 + nStuffingBytes;
+ }
+ }
+
+
+ if (p[3] == 0xbb) { /* program stream system header */
+
+ int nHeaderLen;
+
+ xprintf (VERBOSE|DEMUX, "program stream system header\n");
+
+ nHeaderLen = (p[4] << 8) | p[5];
+
+ p += 6 + nHeaderLen;
+ }
+
+ /* we should now 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];
+
+ xprintf (VERBOSE|DEMUX, "packet id = %02x len = %d\n",nStreamID, nPacketLen);
+
+ if (bMpeg1) {
+
+ 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 --;
+ }
+
+ } 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];
+
+ p += nHeaderLen + 9;
+ nPacketLen -= nHeaderLen + 3;
+ }
+
+ xprintf (VERBOSE|DEMUX, "stream_id=%x len=%d pts=%d dts=%d\n", nStreamID, nPacketLen, nPTS, nDTS);
+
+ if (nStreamID == 0xbd) {
+
+ int nTrack, nSPUID;
+
+ nTrack = p[0] & 0x0F; /* hack : ac3 track */
+
+ if((p[0] & 0xE0) == 0x20) {
+ nSPUID = (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->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->spu_fifo->put (this->spu_fifo, buf);
+
+ return;
+ }
+
+ if ((p[0]&0xF0) == 0x80) {
+
+ 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_AC3 + nTrack;
+ buf->PTS = nPTS;
+ buf->DTS = nDTS ;
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ return ;
+ } else if ((p[0]&0xf0) == 0xa0) {
+
+ int pcm_offset;
+
+ xprintf (VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",nPacketLen-4, p[0]);
+
+ for( pcm_offset=0; ++pcm_offset < nPacketLen-1 ; ){
+ if ( p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */
+ pcm_offset += 2;
+ break;
+ }
+ }
+
+ buf->content = p+pcm_offset;
+ buf->size = nPacketLen-pcm_offset;
+ buf->type = BUF_AUDIO_LPCM + nTrack;
+ buf->PTS = nPTS;
+ buf->DTS = nDTS ;
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ return ;
+ }
+
+ } else if ((nStreamID >= 0xbc) && ((nStreamID & 0xf0) == 0xe0)) {
+
+ xprintf (VERBOSE|DEMUX, "video %d\n", nStreamID);
+
+ buf->content = p;
+ buf->size = nPacketLen;
+ buf->type = BUF_VIDEO_MPEG;
+ buf->PTS = nPTS;
+ buf->DTS = nDTS;
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->video_fifo->put (this->video_fifo, buf);
+
+ return ;
+
+ } else if ((nStreamID & 0xe0) == 0xc0) {
+ int nTrack;
+
+ nTrack = nStreamID & 0x1f;
+
+ xprintf (VERBOSE|DEMUX|MPEG, "mpg audio #%d", nTrack);
+
+ buf->content = p;
+ buf->size = nPacketLen;
+ buf->type = BUF_AUDIO_MPEG + nTrack;
+ buf->PTS = nPTS;
+ buf->DTS = nDTS;
+ buf->input_pos = this->input->seek (0, SEEK_CUR);
+
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ return ;
+
+ } else {
+ xprintf (VERBOSE | DEMUX, "unknown packet, id = %x\n",nStreamID);
+ }
+
+ buf->free_buffer (buf);
+
+ return ;
+
+}
+
+static void *demux_mpeg_block_loop (void *this_gen) {
+
+ buf_element_t *buf;
+ demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
+
+ do {
+
+ demux_mpeg_block_parse_pack(this);
+
+ } while (this->status == DEMUX_OK) ;
+
+ xprintf (VERBOSE|DEMUX, "demux loop finished (status: %d)\n",
+ this->mnStatus);
+
+ this->status = DEMUX_FINISHED;
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->video_fifo->put (this->video_fifo, buf);
+
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_END;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ return NULL;
+}
+
+static void demux_mpeg_block_stop (demux_plugin_t *this_gen) {
+
+ demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
+ void *p;
+
+ this->status = DEMUX_FINISHED;
+
+ pthread_join (this->thread, &p);
+}
+
+static int demux_mpeg_block_get_status (demux_plugin_t *this_gen) {
+ demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
+
+ return this->status;
+}
+
+static void demux_mpeg_block_start (demux_plugin_t *this_gen,
+ fifo_buffer_t *video_fifo,
+ fifo_buffer_t *audio_fifo,
+ fifo_buffer_t *spu_fifo,
+ off_t pos)
+{
+
+ demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
+ buf_element_t *buf;
+
+ this->video_fifo = video_fifo;
+ this->audio_fifo = audio_fifo;
+ this->spu_fifo = spu_fifo;
+
+ this->status = DEMUX_OK;
+
+ pos /= (off_t) this->blocksize;
+ pos *= (off_t) this->blocksize;
+
+ if((this->input->get_capabilities() & INPUT_CAP_SEEKABLE) != 0) {
+ xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos);
+ this->input->seek (pos, SEEK_SET);
+ }
+
+ /*
+ * send start buffer
+ */
+
+ buf = this->video_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->video_fifo->put (this->video_fifo, buf);
+ buf = this->audio_fifo->buffer_pool_alloc ();
+ buf->type = BUF_CONTROL_START;
+ this->audio_fifo->put (this->audio_fifo, buf);
+
+ /*
+ * now start demuxing
+ */
+
+ pthread_create (&this->thread, NULL, demux_mpeg_block_loop, this) ;
+}
+
+static int demux_mpeg_block_open(demux_plugin_t *this_gen,
+ input_plugin_t *input, int stage) {
+
+ demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
+
+ this->input = input;
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT: {
+ uint8_t buf[4096];
+
+ if((input->get_capabilities() & INPUT_CAP_SEEKABLE) != 0) {
+ input->seek(0, SEEK_SET);
+
+ this->blocksize = input->get_blocksize();
+
+ if (!this->blocksize)
+ return DEMUX_CANNOT_HANDLE;
+
+ if (input->read(buf, this->blocksize)) {
+
+ if(buf[0] || buf[1] || (buf[2] != 0x01))
+ return DEMUX_CANNOT_HANDLE;
+
+ switch(buf[3]) {
+
+ case 0xba:
+ if((buf[4] & 0xc0) == 0x40)
+ return DEMUX_CAN_HANDLE;
+
+ break;
+
+ case 0xe0:
+ if((buf[6] & 0xc0) == 0x80)
+ return DEMUX_CAN_HANDLE;
+
+ break;
+
+ }
+ }
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *media;
+ char *ending;
+ char *MRL;
+
+ MRL = input->get_mrl ();
+
+ media = strstr(MRL, "://");
+ if(media) {
+ if(!strncmp(MRL, "dvd", 3)
+ || !strncmp(MRL, "fifo", 4)
+ || (((!strncmp(MRL, "stdin", 5) || !strncmp(MRL, "fifo", 4))
+ && (!strncmp((media+3), "mpeg2", 5) )))
+ ) {
+ this->blocksize = 2048;
+ return DEMUX_CAN_HANDLE;
+ }
+ if(!strncmp(MRL, "vcd", 3)) {
+ this->blocksize = 2324;
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+
+ /*
+ * check ending
+ */
+
+ ending = strrchr(MRL, '.');
+
+ xprintf(VERBOSE|DEMUX, "demux_mpeg_block_can_handle: ending %s of %s\n",
+ ending ? ending :"(none)", MRL);
+
+ if(!ending)
+ return DEMUX_CANNOT_HANDLE;
+
+ if(!strcasecmp(ending, ".vob")) {
+ this->blocksize = 2048;
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+static char *demux_mpeg_block_get_id(demux_plugin_t *this) {
+ return "MPEG_BLOCK";
+}
+
+static void demux_mpeg_block_close (demux_plugin_t *this) {
+ /* nothing */
+}
+
+demux_plugin_t *init_demux_mpeg_block(config_values_t *cfg, uint32_t xd) {
+
+ demux_mpeg_block_t *this = xmalloc (sizeof (demux_mpeg_block_t));
+
+ xine_debug = xd;
+
+ this->demux_plugin.open = demux_mpeg_block_open;
+ this->demux_plugin.start = demux_mpeg_block_start;
+ this->demux_plugin.stop = demux_mpeg_block_stop;
+ 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;
+
+ return (demux_plugin_t *) this;
+}
diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c
new file mode 100644
index 000000000..8eea5bddf
--- /dev/null
+++ b/src/demuxers/demux_mpgaudio.c
@@ -0,0 +1,440 @@
+/*
+ * 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_mpgaudio.c,v 1.1 2001/04/18 22:33:58 f1rmb Exp $
+ *
+ * demultiplexer for mpeg audio (i.e. mp3) streams
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xine.h"
+#include "monitor.h"
+#include "demux.h"
+
+#include "libmpg123/mpg123.h"
+#include "libmpg123/mpglib.h"
+
+/* The following variable indicates the kind of error */
+
+static uint32_t xine_debug;
+
+typedef struct _demux_mpgaudio_globals {
+ fifo_buffer_t *mBufAudio;
+ fifo_buffer_t *mBufVideo;
+
+ input_plugin_t *mInput;
+
+ pthread_t mThread;
+
+ int mnStatus;
+} demux_mpgaudio_globals_t ;
+
+static demux_mpgaudio_globals_t gDemuxMpgAudio;
+static fifobuf_functions_t *Ffb;
+
+/*
+ * ***********************************************************************
+ * Adds some (very slightly hacked) parts of libmpg123 here:
+ * I don't want to link the lib to this demuxer.
+ */
+static int ssize;
+static int grp_3tab[32 * 3] = {0,};
+static int grp_5tab[128 * 3] = {0,};
+static int grp_9tab[1024 * 3] = {0,};
+static real mpg123_muls[27][64];
+static int tabsel_123[2][3][16] = {
+ {
+ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}},
+
+ {
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}}
+};
+static long mpg123_freqs[9] = {
+ 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000
+};
+/*
+ *
+ */
+static void mpg123_init_layer2(void) {
+ static double mulmul[27] = {
+ 0.0, -2.0 / 3.0, 2.0 / 3.0,
+ 2.0 / 7.0, 2.0 / 15.0, 2.0 / 31.0, 2.0 / 63.0, 2.0 / 127.0, 2.0 / 255.0,
+ 2.0 / 511.0, 2.0 / 1023.0, 2.0 / 2047.0, 2.0 / 4095.0, 2.0 / 8191.0,
+ 2.0 / 16383.0, 2.0 / 32767.0, 2.0 / 65535.0,
+ -4.0 / 5.0, -2.0 / 5.0, 2.0 / 5.0, 4.0 / 5.0,
+ -8.0 / 9.0, -4.0 / 9.0, -2.0 / 9.0, 2.0 / 9.0, 4.0 / 9.0, 8.0 / 9.0
+ };
+ static int base[3][9] = {
+ {1, 0, 2,},
+ {17, 18, 0, 19, 20,},
+ {21, 1, 22, 23, 0, 24, 25, 2, 26}
+ };
+ int i, j, k, l, len;
+ real *table;
+ static int tablen[3] = { 3, 5, 9 };
+ static int *itable, *tables[3] = { grp_3tab, grp_5tab, grp_9tab };
+
+ for (i = 0; i < 3; i++) {
+ itable = tables[i];
+ len = tablen[i];
+ for (j = 0; j < len; j++)
+ for (k = 0; k < len; k++)
+ for (l = 0; l < len; l++) {
+ *itable++ = base[i][l];
+ *itable++ = base[i][k];
+ *itable++ = base[i][j];
+ }
+ }
+
+ for (k = 0; k < 27; k++) {
+ double m = mulmul[k];
+
+ table = mpg123_muls[k];
+ for (j = 3, i = 0; i < 63; i++, j--)
+ *table++ = m * pow(2.0, (double) j / 3.0);
+ *table++ = 0.0;
+ }
+}
+/*
+ *
+ */
+static int mpg123_decode_header(struct frame *fr, unsigned long newhead) {
+ if (newhead & (1 << 20)) {
+ fr->lsf = (newhead & (1 << 19)) ? 0x0 : 0x1;
+ fr->mpeg25 = 0;
+ }
+ else {
+ fr->lsf = 1;
+ fr->mpeg25 = 1;
+ }
+ fr->lay = 4 - ((newhead >> 17) & 3);
+ if (fr->mpeg25) {
+ fr->sampling_frequency = 6 + ((newhead >> 10) & 0x3);
+ }
+ else
+ fr->sampling_frequency = ((newhead >> 10) & 0x3) + (fr->lsf * 3);
+
+ fr->error_protection = ((newhead >> 16) & 0x1) ^ 0x1;
+
+ if (fr->mpeg25) /* allow Bitrate change for 2.5 ... */
+ fr->bitrate_index = ((newhead >> 12) & 0xf);
+
+ fr->bitrate_index = ((newhead >> 12) & 0xf);
+ fr->padding = ((newhead >> 9) & 0x1);
+ fr->extension = ((newhead >> 8) & 0x1);
+ fr->mode = ((newhead >> 6) & 0x3);
+ fr->mode_ext = ((newhead >> 4) & 0x3);
+ fr->copyright = ((newhead >> 3) & 0x1);
+ fr->original = ((newhead >> 2) & 0x1);
+ fr->emphasis = newhead & 0x3;
+
+ fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
+
+ ssize = 0;
+
+ if (!fr->bitrate_index)
+ return (0);
+
+ switch (fr->lay) {
+ case 1:
+ mpg123_init_layer2(); /* inits also shared tables with layer1 */
+ fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
+ fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+ fr->framesize = ((fr->framesize + fr->padding) << 2) - 4;
+ break;
+ case 2:
+ mpg123_init_layer2(); /* inits also shared tables with layer1 */
+ fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
+ fr->framesize /= mpg123_freqs[fr->sampling_frequency];
+ fr->framesize += fr->padding - 4;
+ break;
+ case 3:
+ if (fr->lsf)
+ ssize = (fr->stereo == 1) ? 9 : 17;
+ else
+ ssize = (fr->stereo == 1) ? 17 : 32;
+ if (fr->error_protection)
+ ssize += 2;
+ fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
+ fr->framesize /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf);
+ fr->framesize = fr->framesize + fr->padding - 4;
+ break;
+ default:
+ return (0);
+ }
+ if(fr->framesize > MAXFRAMESIZE)
+ return 0;
+ return 1;
+}
+/*
+ *
+ */
+static int mpg123_head_check(unsigned long head) {
+ if ((head & 0xffe00000) != 0xffe00000)
+ return 0;
+ if (!((head >> 17) & 3))
+ return 0;
+ if (((head >> 12) & 0xf) == 0xf)
+ return 0;
+ if (!((head >> 12) & 0xf))
+ return 0;
+ if (((head >> 10) & 0x3) == 0x3)
+ return 0;
+ if (((head >> 19) & 1) == 1
+ && ((head >> 17) & 3) == 3
+ && ((head >> 16) & 1) == 1)
+ return 0;
+ if ((head & 0xffff0000) == 0xfffe0000)
+ return 0;
+
+ return 1;
+}
+/*
+ * End of libmpg123 adds.
+ ************************************************************************
+ */
+
+int demux_mpgaudio_next (void) {
+
+ buf_element_t *pBuf;
+
+ pBuf = Ffb->buffer_pool_alloc ();
+
+ pBuf->pContent = pBuf->pMem;
+ pBuf->nDTS = 0 ; /* FIXME ? */
+ pBuf->nPTS = 0 ; /* FIXME ? */
+ pBuf->nSize = gDemuxMpgAudio.mInput->read (pBuf->pMem, 2048) ;
+ pBuf->nType = BUF_MPEGAUDIO; /* FIXME */
+ pBuf->nInputPos = gDemuxMpgAudio.mInput->seek (0, SEEK_CUR);
+
+ Ffb->fifo_buffer_put (gDemuxMpgAudio.mBufAudio, pBuf);
+
+ return (pBuf->nSize==2048);
+}
+
+static void *demux_mpgaudio_loop (void *dummy) {
+
+ buf_element_t *pBuf;
+
+ do {
+ if (!demux_mpgaudio_next())
+ gDemuxMpgAudio.mnStatus = DEMUX_FINISHED;
+
+ } while (gDemuxMpgAudio.mnStatus == DEMUX_OK) ;
+
+ xprintf (VERBOSE|DEMUX, "mpgaudio demux loop finished (status: %d)\n",
+ gDemuxMpgAudio.mnStatus);
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_STREAMEND;
+ Ffb->fifo_buffer_put (gDemuxMpgAudio.mBufVideo, pBuf);
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_STREAMEND;
+ Ffb->fifo_buffer_put (gDemuxMpgAudio.mBufAudio, pBuf);
+
+ return NULL;
+}
+
+static void demux_mpgaudio_stop (void) {
+ void *p;
+
+ gDemuxMpgAudio.mnStatus = DEMUX_FINISHED;
+
+ Ffb->fifo_buffer_clear(gDemuxMpgAudio.mBufVideo);
+ Ffb->fifo_buffer_clear(gDemuxMpgAudio.mBufAudio);
+
+ pthread_join (gDemuxMpgAudio.mThread, &p);
+}
+
+static int demux_mpgaudio_get_status (void) {
+ return gDemuxMpgAudio.mnStatus;
+}
+
+static void demux_mpgaudio_start (input_plugin_t *input_plugin,
+ fifo_buffer_t *bufVideo,
+ fifo_buffer_t *bufAudio,
+ fifo_buffer_t *bufSPU, off_t pos)
+{
+ buf_element_t *pBuf;
+
+ gDemuxMpgAudio.mInput = input_plugin;
+ gDemuxMpgAudio.mBufVideo = bufVideo;
+ gDemuxMpgAudio.mBufAudio = bufAudio;
+
+ gDemuxMpgAudio.mnStatus = DEMUX_OK;
+
+ if((gDemuxMpgAudio.mInput->get_capabilities() & INPUT_CAP_SEEKABLE) != 0)
+ gDemuxMpgAudio.mInput->seek (pos, SEEK_SET);
+
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_RESET;
+ Ffb->fifo_buffer_put (gDemuxMpgAudio.mBufVideo, pBuf);
+ pBuf = Ffb->buffer_pool_alloc ();
+ pBuf->nType = BUF_RESET;
+ Ffb->fifo_buffer_put (gDemuxMpgAudio.mBufAudio, pBuf);
+
+ pthread_create (&gDemuxMpgAudio.mThread, NULL, demux_mpgaudio_loop, NULL) ;
+}
+
+static void demux_mpgaudio_select_audio_channel (int nChannel) {
+}
+
+static void demux_mpgaudio_select_spu_channel (int nChannel) {
+}
+
+static int demux_mpgaudio_open(input_plugin_t *ip,
+ const char *MRL, int stage) {
+
+ switch(stage) {
+
+ case STAGE_BY_CONTENT: {
+ uint8_t buf[4096];
+ uint8_t *pbuf;
+ struct frame fr;
+ uint32_t head;
+ int in_buf, i;
+ int bs = 0;
+
+ if(!ip)
+ return DEMUX_CANNOT_HANDLE;
+
+ if((ip->get_capabilities() & INPUT_CAP_SEEKABLE) != 0) {
+ ip->seek(0, SEEK_SET);
+
+ if(ip->get_blocksize)
+ bs = ip->get_blocksize();
+
+ if(bs > 4)
+ return DEMUX_CANNOT_HANDLE;
+
+ if(!bs)
+ bs = 4;
+
+ if(ip->read(buf, bs)) {
+
+ /* Not an AVI ?? */
+ if(buf[0] || buf[1] || (buf[2] != 0x01) || (buf[3] != 0x46)) {
+
+ pbuf = (uint8_t *) malloc(1024);
+ head = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+
+ while(!mpg123_head_check(head)) {
+
+ in_buf = ip->read(pbuf, 1024);
+
+ if(in_buf == 0) {
+ free(pbuf);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ for(i = 0; i < in_buf; i++) {
+ head <<= 8;
+ head |= pbuf[i];
+
+ if(mpg123_head_check(head)) {
+ ip->seek(i+1-in_buf, SEEK_CUR);
+ break;
+ }
+ }
+ }
+ free(pbuf);
+
+ if(decode_header(&fr, head)) {
+
+ if((ip->seek(fr.framesize, SEEK_CUR)) <= 0)
+ return DEMUX_CANNOT_HANDLE;
+
+ if((ip->read(buf, 4)) != 4)
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ head = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+
+ if(mpg123_head_check(head) &&
+ (((head >> 8) & 0x1) == 0x0) && (((head >> 6) & 0x3) == 0x1))
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+ }
+ return DEMUX_CANNOT_HANDLE;
+ }
+ break;
+
+ case STAGE_BY_EXTENSION: {
+ char *suffix;
+
+ suffix = strrchr(MRL, '.');
+ xprintf(VERBOSE|DEMUX, "demux_mpgaudio_can_handle: suffix %s of %s\n",
+ suffix, MRL);
+
+ if(!suffix)
+ return DEMUX_CANNOT_HANDLE;
+
+ if(!strcasecmp(suffix, ".mp3")
+ || (!strcasecmp(suffix, ".mp2"))) {
+ return DEMUX_CAN_HANDLE;
+ }
+ }
+ break;
+
+ default:
+ return DEMUX_CANNOT_HANDLE;
+ break;
+ }
+
+ return DEMUX_CANNOT_HANDLE;
+}
+
+static char *demux_mpgaudio_get_id(void) {
+ return "MPEGAUDIO";
+}
+
+static demux_functions_t demux_mpgaudio_functions = {
+ NULL,
+ NULL,
+ demux_mpgaudio_open,
+ demux_mpgaudio_start,
+ demux_mpgaudio_stop,
+ demux_mpgaudio_get_status,
+ demux_mpgaudio_select_audio_channel,
+ demux_mpgaudio_select_spu_channel,
+ demux_mpgaudio_get_id
+};
+
+demux_functions_t *init_demux_mpeg_audio(fifobuf_functions_t *f, uint32_t xd) {
+
+ Ffb = f;
+ xine_debug = xd;
+ return &demux_mpgaudio_functions;
+}