summaryrefslogtreecommitdiff
path: root/src/demuxers/demux_avi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/demuxers/demux_avi.c')
-rw-r--r--src/demuxers/demux_avi.c982
1 files changed, 982 insertions, 0 deletions
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;
+}