avilib.c

00001 /*
00002  *  avilib.c
00003  *
00004  *  Copyright (C) Thomas Östreich - June 2001
00005  *  multiple audio track support Copyright (C) 2002 Thomas Östreich
00006  *
00007  *  Original code:
00008  *  Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
00009  *
00010  *  This file is part of transcode, a linux video stream processing tool
00011  *
00012  *  transcode is free software; you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation; either version 2, or (at your option)
00015  *  any later version.
00016  *
00017  *  transcode is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU General Public License for more details.
00021  *
00022  *  You should have received a copy of the GNU General Public License
00023  *  along with GNU Make; see the file COPYING.  If not, write to
00024  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
00025  *
00026  */
00027 
00028 //SLM
00029 #ifdef WIN32
00030 #include <io.h>
00031 #define ftruncate _chsize
00032 #define strncasecmp _strnicmp
00033 typedef int ssize_t;
00034 #endif
00035 
00036 #ifdef __CYGWIN__
00037 #include <unistd.h>
00038 #endif
00039 
00040 #include "avilib.h"
00041 //#include <time.h>
00042 
00043 #define INFO_LIST
00044 
00045 /* The following variable indicates the kind of error */
00046 
00047 long AVI_errno = 0;
00048 
00049 #define MAX_INFO_STRLEN 64
00050 static char id_str[MAX_INFO_STRLEN];
00051 
00052 #define FRAME_RATE_SCALE 1000000
00053 
00054 /*******************************************************************
00055  *                                                                 *
00056  *    Utilities for writing an AVI File                            *
00057  *                                                                 *
00058  *******************************************************************/
00059 
00060 static size_t avi_read(int fd, char *buf, size_t len)
00061 {
00062    size_t n = 0;
00063    size_t r = 0;
00064 
00065    while (r < len) {
00066       n = read (fd, buf + r, len - r);
00067 
00068       if ((ssize_t)n <= 0)
00069           return r;
00070       r += n;
00071    }
00072 
00073    return r;
00074 }
00075 
00076 static size_t avi_write (int fd, char *buf, size_t len)
00077 {
00078    size_t n = 0;
00079    size_t r = 0;
00080 
00081    while (r < len) {
00082       n = write (fd, buf + r, len - r);
00083       if ((ssize_t)n < 0)
00084          return n;
00085 
00086       r += n;
00087    }
00088    return r;
00089 }
00090 
00091 /* HEADERBYTES: The number of bytes to reserve for the header */
00092 
00093 #define HEADERBYTES 2048
00094 
00095 /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
00096     the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */
00097 
00098 #define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES)
00099 
00100 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
00101 
00102 
00103 /* Copy n into dst as a 4 byte, little endian number.
00104    Should also work on big endian machines */
00105 
00106 static void long2str(unsigned char *dst, int n)
00107 {
00108    dst[0] = (n    )&0xff;
00109    dst[1] = (n>> 8)&0xff;
00110    dst[2] = (n>>16)&0xff;
00111    dst[3] = (n>>24)&0xff;
00112 }
00113 
00114 /* Convert a string of 4 or 2 bytes to a number,
00115    also working on big endian machines */
00116 
00117 static unsigned long str2ulong(unsigned char *str)
00118 {
00119    return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
00120 }
00121 static unsigned long str2ushort(unsigned char *str)
00122 {
00123    return ( str[0] | (str[1]<<8) );
00124 }
00125 
00126 /* Calculate audio sample size from number of bits and number of channels.
00127    This may have to be adjusted for eg. 12 bits and stereo */
00128 
00129 static int avi_sampsize(avi_t *AVI, int j)
00130 {
00131    int s;
00132    s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
00133    //   if(s==0) s=1; /* avoid possible zero divisions */
00134    if(s<4) s=4; /* avoid possible zero divisions */
00135    return s;
00136 }
00137 
00138 /* Add a chunk (=tag and data) to the AVI file,
00139    returns -1 on write error, 0 on success */
00140 
00141 static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length)
00142 {
00143    unsigned char c[8];
00144 
00145    /* Copy tag and length int c, so that we need only 1 write system call
00146       for these two values */
00147 
00148    memcpy(c,tag,4);
00149    long2str(c+4,length);
00150 
00151    /* Output tag, length and data, restore previous position
00152       if the write fails */
00153 
00154    length = PAD_EVEN(length);
00155 
00156    if( avi_write(AVI->fdes,(char *)c,8) != 8 ||
00157        avi_write(AVI->fdes,(char *)data,length) != length )
00158    {
00159       lseek(AVI->fdes,AVI->pos,SEEK_SET);
00160       AVI_errno = AVI_ERR_WRITE;
00161       return -1;
00162    }
00163 
00164    /* Update file position */
00165 
00166    AVI->pos += 8 + length;
00167 
00168    //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
00169 
00170    return 0;
00171 }
00172 
00173 static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned long len)
00174 {
00175    void *ptr;
00176 
00177    if(AVI->n_idx>=AVI->max_idx) {
00178      ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
00179 
00180      if(ptr == 0) {
00181        AVI_errno = AVI_ERR_NO_MEM;
00182        return -1;
00183      }
00184      AVI->max_idx += 4096;
00185      AVI->idx = (unsigned char((*)[16]) ) ptr;
00186    }
00187 
00188    /* Add index entry */
00189 
00190    //   fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
00191 
00192    memcpy(AVI->idx[AVI->n_idx],tag,4);
00193    long2str(AVI->idx[AVI->n_idx]+ 4,flags);
00194    long2str(AVI->idx[AVI->n_idx]+ 8, pos);
00195    long2str(AVI->idx[AVI->n_idx]+12, len);
00196 
00197    /* Update counter */
00198 
00199    AVI->n_idx++;
00200 
00201    if(len>AVI->max_len) AVI->max_len=len;
00202 
00203    return 0;
00204 }
00205 
00206 //SLM
00207 #ifndef S_IRUSR
00208 #define S_IRWXU       00700       /* read, write, execute: owner */
00209 #define S_IRUSR       00400       /* read permission: owner */
00210 #define S_IWUSR       00200       /* write permission: owner */
00211 #define S_IXUSR       00100       /* execute permission: owner */
00212 #define S_IRWXG       00070       /* read, write, execute: group */
00213 #define S_IRGRP       00040       /* read permission: group */
00214 #define S_IWGRP       00020       /* write permission: group */
00215 #define S_IXGRP       00010       /* execute permission: group */
00216 #define S_IRWXO       00007       /* read, write, execute: other */
00217 #define S_IROTH       00004       /* read permission: other */
00218 #define S_IWOTH       00002       /* write permission: other */
00219 #define S_IXOTH       00001       /* execute permission: other */
00220 #endif
00221 
00222 /*
00223    AVI_open_output_file: Open an AVI File and write a bunch
00224                          of zero bytes as space for the header.
00225 
00226    returns a pointer to avi_t on success, a zero pointer on error
00227 */
00228 
00229 avi_t* AVI_open_output_file(char * filename)
00230 {
00231    avi_t *AVI;
00232    int i;
00233 
00234    int mask;
00235 
00236    unsigned char AVI_header[HEADERBYTES];
00237 
00238    /* Allocate the avi_t struct and zero it */
00239 
00240    AVI = (avi_t *) malloc(sizeof(avi_t));
00241    if(AVI==0)
00242    {
00243       AVI_errno = AVI_ERR_NO_MEM;
00244       return 0;
00245    }
00246    memset((void *)AVI,0,sizeof(avi_t));
00247 
00248    /* Since Linux needs a long time when deleting big files,
00249       we do not truncate the file when we open it.
00250       Instead it is truncated when the AVI file is closed */
00251 
00252    mask = umask (0);
00253    umask (mask);
00254 
00255 #ifdef WIN32
00256    AVI->fdes = open(filename, O_RDWR|O_CREAT|O_BINARY, (S_IRUSR | S_IWUSR) &~ mask);
00257 #else
00258    AVI->fdes = open(filename, O_RDWR|O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) &~ mask);
00259 #endif
00260    if (AVI->fdes < 0)
00261    {
00262       AVI_errno = AVI_ERR_OPEN;
00263       free(AVI);
00264       return 0;
00265    }
00266 
00267    /* Write out HEADERBYTES bytes, the header will go here
00268       when we are finished with writing */
00269 
00270    for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0;
00271    i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES);
00272    if (i != HEADERBYTES)
00273    {
00274       close(AVI->fdes);
00275       AVI_errno = AVI_ERR_WRITE;
00276       free(AVI);
00277       return 0;
00278    }
00279 
00280    AVI->pos  = HEADERBYTES;
00281    AVI->mode = AVI_MODE_WRITE; /* open for writing */
00282 
00283    //init
00284    AVI->anum = 0;
00285    AVI->aptr = 0;
00286 
00287    return AVI;
00288 }
00289 
00290 void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor)
00291 {
00292    /* may only be called if file is open for writing */
00293 
00294    if(AVI->mode==AVI_MODE_READ) return;
00295 
00296    AVI->width  = width;
00297    AVI->height = height;
00298    AVI->fps    = fps;
00299 
00300    if(strncmp(compressor, "RGB", 3)==0) {
00301      memset(AVI->compressor, 0, 4);
00302    } else {
00303      memcpy(AVI->compressor,compressor,4);
00304    }
00305 
00306    AVI->compressor[4] = 0;
00307 
00308    avi_update_header(AVI);
00309 }
00310 
00311 void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate)
00312 {
00313    /* may only be called if file is open for writing */
00314 
00315    if(AVI->mode==AVI_MODE_READ) return;
00316 
00317    //inc audio tracks
00318    AVI->aptr=AVI->anum;
00319    ++AVI->anum;
00320 
00321    if(AVI->anum > AVI_MAX_TRACKS) {
00322      fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
00323      exit(1);
00324    }
00325 
00326    AVI->track[AVI->aptr].a_chans = channels;
00327    AVI->track[AVI->aptr].a_rate  = rate;
00328    AVI->track[AVI->aptr].a_bits  = bits;
00329    AVI->track[AVI->aptr].a_fmt   = format;
00330    AVI->track[AVI->aptr].mp3rate = mp3rate;
00331 
00332    avi_update_header(AVI);
00333 }
00334 
00335 #define OUT4CC(s) \
00336    if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
00337 
00338 #define OUTLONG(n) \
00339    if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
00340 
00341 #define OUTSHRT(n) \
00342    if(nhb<=HEADERBYTES-2) { \
00343       AVI_header[nhb  ] = (n   )&0xff; \
00344       AVI_header[nhb+1] = (n>>8)&0xff; \
00345    } \
00346    nhb += 2
00347 
00348 
00349 //ThOe write preliminary AVI file header: 0 frames, max vid/aud size
00350 int avi_update_header(avi_t *AVI)
00351 {
00352    int njunk, sampsize, hasIndex, ms_per_frame, frate, flag;
00353    int movi_len, hdrl_start, strl_start, j;
00354    unsigned char AVI_header[HEADERBYTES];
00355    long nhb;
00356 
00357    //assume max size
00358    movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
00359 
00360    //assume index will be written
00361    hasIndex=1;
00362 
00363    if(AVI->fps < 0.001) {
00364      frate=0;
00365      ms_per_frame=0;
00366    } else {
00367      frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
00368      ms_per_frame=(int) (1000000/AVI->fps + 0.5);
00369    }
00370 
00371    /* Prepare the file header */
00372 
00373    nhb = 0;
00374 
00375    /* The RIFF header */
00376 
00377    OUT4CC ("RIFF");
00378    OUTLONG(movi_len);    // assume max size
00379    OUT4CC ("AVI ");
00380 
00381    /* Start the header list */
00382 
00383    OUT4CC ("LIST");
00384    OUTLONG(0);        /* Length of list in bytes, don't know yet */
00385    hdrl_start = nhb;  /* Store start position */
00386    OUT4CC ("hdrl");
00387 
00388    /* The main AVI header */
00389 
00390    /* The Flags in AVI File header */
00391 
00392 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
00393 #define AVIF_MUSTUSEINDEX       0x00000020
00394 #define AVIF_ISINTERLEAVED      0x00000100
00395 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
00396 #define AVIF_WASCAPTUREFILE     0x00010000
00397 #define AVIF_COPYRIGHTED        0x00020000
00398 
00399    OUT4CC ("avih");
00400    OUTLONG(56);                 /* # of bytes to follow */
00401    OUTLONG(ms_per_frame);       /* Microseconds per frame */
00402    //ThOe ->0
00403    //   OUTLONG(10000000);           /* MaxBytesPerSec, I hope this will never be used */
00404    OUTLONG(0);
00405    OUTLONG(0);                  /* PaddingGranularity (whatever that might be) */
00406                                 /* Other sources call it 'reserved' */
00407    flag = AVIF_ISINTERLEAVED;
00408    if(hasIndex) flag |= AVIF_HASINDEX;
00409    if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
00410    OUTLONG(flag);               /* Flags */
00411    OUTLONG(0);                  // no frames yet
00412    OUTLONG(0);                  /* InitialFrames */
00413 
00414    OUTLONG(AVI->anum+1);
00415 
00416    OUTLONG(0);                  /* SuggestedBufferSize */
00417    OUTLONG(AVI->width);         /* Width */
00418    OUTLONG(AVI->height);        /* Height */
00419                                 /* MS calls the following 'reserved': */
00420    OUTLONG(0);                  /* TimeScale:  Unit used to measure time */
00421    OUTLONG(0);                  /* DataRate:   Data rate of playback     */
00422    OUTLONG(0);                  /* StartTime:  Starting time of AVI data */
00423    OUTLONG(0);                  /* DataLength: Size of AVI data chunk    */
00424 
00425 
00426    /* Start the video stream list ---------------------------------- */
00427 
00428    OUT4CC ("LIST");
00429    OUTLONG(0);        /* Length of list in bytes, don't know yet */
00430    strl_start = nhb;  /* Store start position */
00431    OUT4CC ("strl");
00432 
00433    /* The video stream header */
00434 
00435    OUT4CC ("strh");
00436    OUTLONG(56);                 /* # of bytes to follow */
00437    OUT4CC ("vids");             /* Type */
00438    OUT4CC (AVI->compressor);    /* Handler */
00439    OUTLONG(0);                  /* Flags */
00440    OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
00441    OUTLONG(0);                  /* InitialFrames */
00442    OUTLONG(FRAME_RATE_SCALE);              /* Scale */
00443    OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
00444    OUTLONG(0);                  /* Start */
00445    OUTLONG(0);                  // no frames yet
00446    OUTLONG(0);                  /* SuggestedBufferSize */
00447    OUTLONG(-1);                 /* Quality */
00448    OUTLONG(0);                  /* SampleSize */
00449    OUTLONG(0);                  /* Frame */
00450    OUTLONG(0);                  /* Frame */
00451    //   OUTLONG(0);                  /* Frame */
00452    //OUTLONG(0);                  /* Frame */
00453 
00454    /* The video stream format */
00455 
00456    OUT4CC ("strf");
00457    OUTLONG(40);                 /* # of bytes to follow */
00458    OUTLONG(40);                 /* Size */
00459    OUTLONG(AVI->width);         /* Width */
00460    OUTLONG(AVI->height);        /* Height */
00461    OUTSHRT(1); OUTSHRT(24);     /* Planes, Count */
00462    OUT4CC (AVI->compressor);    /* Compression */
00463    // ThOe (*3)
00464    OUTLONG(AVI->width*AVI->height*3);  /* SizeImage (in bytes?) */
00465    OUTLONG(0);                  /* XPelsPerMeter */
00466    OUTLONG(0);                  /* YPelsPerMeter */
00467    OUTLONG(0);                  /* ClrUsed: Number of colors used */
00468    OUTLONG(0);                  /* ClrImportant: Number of colors important */
00469 
00470    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00471 
00472    long2str(AVI_header+strl_start-4,nhb-strl_start);
00473 
00474 
00475    /* Start the audio stream list ---------------------------------- */
00476 
00477    for(j=0; j<AVI->anum; ++j) {
00478 
00479        sampsize = avi_sampsize(AVI, j);
00480 
00481        OUT4CC ("LIST");
00482        OUTLONG(0);        /* Length of list in bytes, don't know yet */
00483        strl_start = nhb;  /* Store start position */
00484        OUT4CC ("strl");
00485 
00486        /* The audio stream header */
00487 
00488        OUT4CC ("strh");
00489        OUTLONG(56);            /* # of bytes to follow */
00490        OUT4CC ("auds");
00491 
00492        // -----------
00493        // ThOe
00494        OUTLONG(0);             /* Format (Optionally) */
00495        // -----------
00496 
00497        OUTLONG(0);             /* Flags */
00498        OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
00499        OUTLONG(0);             /* InitialFrames */
00500 
00501        // ThOe /4
00502        OUTLONG(sampsize/4);      /* Scale */
00503        OUTLONG(1000*AVI->track[j].mp3rate/8);
00504        OUTLONG(0);             /* Start */
00505        OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   /* Length */
00506        OUTLONG(0);             /* SuggestedBufferSize */
00507        OUTLONG(-1);            /* Quality */
00508 
00509        // ThOe /4
00510        OUTLONG(sampsize/4);    /* SampleSize */
00511 
00512        OUTLONG(0);             /* Frame */
00513        OUTLONG(0);             /* Frame */
00514        //       OUTLONG(0);             /* Frame */
00515        //OUTLONG(0);             /* Frame */
00516 
00517        /* The audio stream format */
00518 
00519        OUT4CC ("strf");
00520        OUTLONG(16);                   /* # of bytes to follow */
00521        OUTSHRT(AVI->track[j].a_fmt);           /* Format */
00522        OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
00523        OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
00524        // ThOe
00525        OUTLONG(1000*AVI->track[j].mp3rate/8);
00526        //ThOe (/4)
00527 
00528        OUTSHRT(sampsize/4);           /* BlockAlign */
00529 
00530 
00531        OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
00532 
00533        /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00534 
00535        long2str(AVI_header+strl_start-4,nhb-strl_start);
00536    }
00537 
00538    /* Finish header list */
00539 
00540    long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00541 
00542 
00543    /* Calculate the needed amount of junk bytes, output junk */
00544 
00545    njunk = HEADERBYTES - nhb - 8 - 12;
00546 
00547    /* Safety first: if njunk <= 0, somebody has played with
00548       HEADERBYTES without knowing what (s)he did.
00549       This is a fatal error */
00550 
00551    if(njunk<=0)
00552      {
00553        fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
00554        exit(1);
00555      }
00556 
00557    OUT4CC ("JUNK");
00558    OUTLONG(njunk);
00559    memset(AVI_header+nhb,0,njunk);
00560 
00561    //2001-11-14 added id string
00562 
00563    if(njunk > strlen(id_str)+8) {
00564      //sprintf(id_str, "%s-%s", PACKAGE, VERSION);
00565      //memcpy(AVI_header+nhb, id_str, strlen(id_str));
00566    }
00567 
00568    nhb += njunk;
00569 
00570    /* Start the movi list */
00571 
00572    OUT4CC ("LIST");
00573    OUTLONG(movi_len); /* Length of list in bytes */
00574    OUT4CC ("movi");
00575 
00576    /* Output the header, truncate the file to the number of bytes
00577       actually written, report an error if someting goes wrong */
00578 
00579    if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
00580         avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
00581         lseek(AVI->fdes,AVI->pos,SEEK_SET)<0)
00582      {
00583        AVI_errno = AVI_ERR_CLOSE;
00584        return -1;
00585      }
00586 
00587    return 0;
00588 }
00589 
00590 /*
00591   Write the header of an AVI file and close it.
00592   returns 0 on success, -1 on write error.
00593 */
00594 
00595 static int avi_close_output_file(avi_t *AVI)
00596 {
00597 
00598    int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
00599    unsigned long movi_len;
00600    int hdrl_start, strl_start, j;
00601    unsigned char AVI_header[HEADERBYTES];
00602    long nhb;
00603 
00604 #ifdef INFO_LIST
00605    long info_len;
00606 //   time_t calptr;
00607 #endif
00608 
00609    /* Calculate length of movi list */
00610 
00611    movi_len = AVI->pos - HEADERBYTES + 4;
00612 
00613    /* Try to ouput the index entries. This may fail e.g. if no space
00614       is left on device. We will report this as an error, but we still
00615       try to write the header correctly (so that the file still may be
00616       readable in the most cases */
00617 
00618    idxerror = 0;
00619    //   fprintf(stderr, "pos=%lu, index_len=%ld\n", AVI->pos, AVI->n_idx*16);
00620    ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
00621    hasIndex = (ret==0);
00622    //fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex);
00623 
00624    if(ret) {
00625      idxerror = 1;
00626      AVI_errno = AVI_ERR_WRITE_INDEX;
00627    }
00628 
00629    /* Calculate Microseconds per frame */
00630 
00631    if(AVI->fps < 0.001) {
00632      frate=0;
00633      ms_per_frame=0;
00634    } else {
00635      frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
00636      ms_per_frame=(int) (1000000/AVI->fps + 0.5);
00637    }
00638 
00639    /* Prepare the file header */
00640 
00641    nhb = 0;
00642 
00643    /* The RIFF header */
00644 
00645    OUT4CC ("RIFF");
00646    OUTLONG(AVI->pos - 8);    /* # of bytes to follow */
00647    OUT4CC ("AVI ");
00648 
00649    /* Start the header list */
00650 
00651    OUT4CC ("LIST");
00652    OUTLONG(0);        /* Length of list in bytes, don't know yet */
00653    hdrl_start = nhb;  /* Store start position */
00654    OUT4CC ("hdrl");
00655 
00656    /* The main AVI header */
00657 
00658    /* The Flags in AVI File header */
00659 
00660 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
00661 #define AVIF_MUSTUSEINDEX       0x00000020
00662 #define AVIF_ISINTERLEAVED      0x00000100
00663 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
00664 #define AVIF_WASCAPTUREFILE     0x00010000
00665 #define AVIF_COPYRIGHTED        0x00020000
00666 
00667    OUT4CC ("avih");
00668    OUTLONG(56);                 /* # of bytes to follow */
00669    OUTLONG(ms_per_frame);       /* Microseconds per frame */
00670    //ThOe ->0
00671    //   OUTLONG(10000000);           /* MaxBytesPerSec, I hope this will never be used */
00672    OUTLONG(0);
00673    OUTLONG(0);                  /* PaddingGranularity (whatever that might be) */
00674                                 /* Other sources call it 'reserved' */
00675    flag = AVIF_ISINTERLEAVED;
00676    if(hasIndex) flag |= AVIF_HASINDEX;
00677    if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
00678    OUTLONG(flag);               /* Flags */
00679    OUTLONG(AVI->video_frames);  /* TotalFrames */
00680    OUTLONG(0);                  /* InitialFrames */
00681 
00682    OUTLONG(AVI->anum+1);
00683 //   if (AVI->track[0].audio_bytes)
00684 //      { OUTLONG(2); }           /* Streams */
00685 //   else
00686 //      { OUTLONG(1); }           /* Streams */
00687 
00688    OUTLONG(0);                  /* SuggestedBufferSize */
00689    OUTLONG(AVI->width);         /* Width */
00690    OUTLONG(AVI->height);        /* Height */
00691                                 /* MS calls the following 'reserved': */
00692    OUTLONG(0);                  /* TimeScale:  Unit used to measure time */
00693    OUTLONG(0);                  /* DataRate:   Data rate of playback     */
00694    OUTLONG(0);                  /* StartTime:  Starting time of AVI data */
00695    OUTLONG(0);                  /* DataLength: Size of AVI data chunk    */
00696 
00697 
00698    /* Start the video stream list ---------------------------------- */
00699 
00700    OUT4CC ("LIST");
00701    OUTLONG(0);        /* Length of list in bytes, don't know yet */
00702    strl_start = nhb;  /* Store start position */
00703    OUT4CC ("strl");
00704 
00705    /* The video stream header */
00706 
00707    OUT4CC ("strh");
00708    OUTLONG(56);                 /* # of bytes to follow */
00709    OUT4CC ("vids");             /* Type */
00710    OUT4CC (AVI->compressor);    /* Handler */
00711    OUTLONG(0);                  /* Flags */
00712    OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
00713    OUTLONG(0);                  /* InitialFrames */
00714    OUTLONG(FRAME_RATE_SCALE);              /* Scale */
00715    OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
00716    OUTLONG(0);                  /* Start */
00717    OUTLONG(AVI->video_frames);  /* Length */
00718    OUTLONG(0);                  /* SuggestedBufferSize */
00719    OUTLONG(-1);                 /* Quality */
00720    OUTLONG(0);                  /* SampleSize */
00721    OUTLONG(0);                  /* Frame */
00722    OUTLONG(0);                  /* Frame */
00723    //   OUTLONG(0);                  /* Frame */
00724    //OUTLONG(0);                  /* Frame */
00725 
00726    /* The video stream format */
00727 
00728    OUT4CC ("strf");
00729    OUTLONG(40);                 /* # of bytes to follow */
00730    OUTLONG(40);                 /* Size */
00731    OUTLONG(AVI->width);         /* Width */
00732    OUTLONG(AVI->height);        /* Height */
00733    OUTSHRT(1); OUTSHRT(24);     /* Planes, Count */
00734    OUT4CC (AVI->compressor);    /* Compression */
00735    // ThOe (*3)
00736    OUTLONG(AVI->width*AVI->height*3);  /* SizeImage (in bytes?) */
00737    OUTLONG(0);                  /* XPelsPerMeter */
00738    OUTLONG(0);                  /* YPelsPerMeter */
00739    OUTLONG(0);                  /* ClrUsed: Number of colors used */
00740    OUTLONG(0);                  /* ClrImportant: Number of colors important */
00741 
00742    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00743 
00744    long2str(AVI_header+strl_start-4,nhb-strl_start);
00745 
00746    /* Start the audio stream list ---------------------------------- */
00747 
00748    for(j=0; j<AVI->anum; ++j) {
00749 
00750      //if (AVI->track[j].a_chans && AVI->track[j].audio_bytes)
00751        {
00752 
00753          sampsize = avi_sampsize(AVI, j);
00754 
00755          OUT4CC ("LIST");
00756          OUTLONG(0);        /* Length of list in bytes, don't know yet */
00757          strl_start = nhb;  /* Store start position */
00758          OUT4CC ("strl");
00759 
00760          /* The audio stream header */
00761 
00762          OUT4CC ("strh");
00763          OUTLONG(56);            /* # of bytes to follow */
00764          OUT4CC ("auds");
00765 
00766          // -----------
00767          // ThOe
00768          OUTLONG(0);             /* Format (Optionally) */
00769            // -----------
00770 
00771          OUTLONG(0);             /* Flags */
00772          OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
00773          OUTLONG(0);             /* InitialFrames */
00774 
00775          // ThOe /4
00776          OUTLONG(sampsize/4);      /* Scale */
00777          OUTLONG(1000*AVI->track[j].mp3rate/8);
00778          OUTLONG(0);             /* Start */
00779          OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   /* Length */
00780          OUTLONG(0);             /* SuggestedBufferSize */
00781          OUTLONG(-1);            /* Quality */
00782 
00783          // ThOe /4
00784          OUTLONG(sampsize/4);    /* SampleSize */
00785 
00786          OUTLONG(0);             /* Frame */
00787          OUTLONG(0);             /* Frame */
00788          //         OUTLONG(0);             /* Frame */
00789          //OUTLONG(0);             /* Frame */
00790 
00791          /* The audio stream format */
00792 
00793          OUT4CC ("strf");
00794          OUTLONG(16);                   /* # of bytes to follow */
00795          OUTSHRT(AVI->track[j].a_fmt);           /* Format */
00796          OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
00797          OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
00798          // ThOe
00799          OUTLONG(1000*AVI->track[j].mp3rate/8);
00800          //ThOe (/4)
00801 
00802          OUTSHRT(sampsize/4);           /* BlockAlign */
00803 
00804 
00805          OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
00806 
00807          /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00808        }
00809        long2str(AVI_header+strl_start-4,nhb-strl_start);
00810    }
00811 
00812    /* Finish header list */
00813 
00814    long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00815 
00816 
00817    // add INFO list --- (0.6.0pre4)
00818 
00819 #ifdef INFO_LIST
00820    OUT4CC ("LIST");
00821 
00822    //FIXME
00823    info_len = MAX_INFO_STRLEN + 12;
00824    OUTLONG(info_len);
00825    OUT4CC ("INFO");
00826 
00827 //   OUT4CC ("INAM");
00828 //   OUTLONG(MAX_INFO_STRLEN);
00829 
00830 //   sprintf(id_str, "\t");
00831 //   memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00832 //   memcpy(AVI_header+nhb, id_str, strlen(id_str));
00833 //   nhb += MAX_INFO_STRLEN;
00834 
00835    OUT4CC ("ISFT");
00836    OUTLONG(MAX_INFO_STRLEN);
00837 
00838    //sprintf(id_str, "%s-%s", PACKAGE, VERSION);
00839    memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00840    //memcpy(AVI_header+nhb, id_str, strlen(id_str));
00841    nhb += MAX_INFO_STRLEN;
00842 
00843 //   OUT4CC ("ICMT");
00844 //   OUTLONG(MAX_INFO_STRLEN);
00845 
00846 //   calptr=time(NULL);
00847 //   sprintf(id_str, "\t%s %s", ctime(&calptr), "");
00848 //   memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00849 //   memcpy(AVI_header+nhb, id_str, 25);
00850 //   nhb += MAX_INFO_STRLEN;
00851 #endif
00852 
00853    // ----------------------------
00854 
00855    /* Calculate the needed amount of junk bytes, output junk */
00856 
00857    njunk = HEADERBYTES - nhb - 8 - 12;
00858 
00859    /* Safety first: if njunk <= 0, somebody has played with
00860       HEADERBYTES without knowing what (s)he did.
00861       This is a fatal error */
00862 
00863    if(njunk<=0)
00864    {
00865       fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
00866       exit(1);
00867    }
00868 
00869    OUT4CC ("JUNK");
00870    OUTLONG(njunk);
00871    memset(AVI_header+nhb,0,njunk);
00872 
00873    nhb += njunk;
00874 
00875    /* Start the movi list */
00876 
00877    OUT4CC ("LIST");
00878    OUTLONG(movi_len); /* Length of list in bytes */
00879    OUT4CC ("movi");
00880 
00881    /* Output the header, truncate the file to the number of bytes
00882       actually written, report an error if someting goes wrong */
00883 
00884    if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
00885         avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
00886         ftruncate(AVI->fdes,AVI->pos)<0 )
00887    {
00888       AVI_errno = AVI_ERR_CLOSE;
00889       return -1;
00890    }
00891 
00892    if(idxerror) return -1;
00893 
00894    return 0;
00895 }
00896 
00897 /*
00898    AVI_write_data:
00899    Add video or audio data to the file;
00900 
00901    Return values:
00902     0    No error;
00903    -1    Error, AVI_errno is set appropriatly;
00904 
00905 */
00906 
00907 static int avi_write_data(avi_t *AVI, char *data, unsigned long length, int audio, int keyframe)
00908 {
00909    int n;
00910 
00911    unsigned char astr[5];
00912 
00913    /* Check for maximum file length */
00914 
00915    if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) {
00916      AVI_errno = AVI_ERR_SIZELIM;
00917      return -1;
00918    }
00919 
00920    /* Add index entry */
00921 
00922    //set tag for current audio track
00923    sprintf((char *)astr, "0%1dwb", (int)(AVI->aptr+1));
00924 
00925    if(audio)
00926      n = avi_add_index_entry(AVI,astr,0x00,AVI->pos,length);
00927    else
00928      n = avi_add_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
00929 
00930    if(n) return -1;
00931 
00932    /* Output tag and data */
00933 
00934    if(audio)
00935      n = avi_add_chunk(AVI,astr,(unsigned char *)data,length);
00936    else
00937      n = avi_add_chunk(AVI,(unsigned char *)"00db",(unsigned char *)data,length);
00938 
00939    if (n) return -1;
00940 
00941    return 0;
00942 }
00943 
00944 int AVI_write_frame(avi_t *AVI, char *data, long bytes, int keyframe)
00945 {
00946   unsigned long pos;
00947 
00948   if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
00949 
00950   pos = AVI->pos;
00951 
00952   if(avi_write_data(AVI,data,bytes,0,keyframe)) return -1;
00953 
00954   AVI->last_pos = pos;
00955   AVI->last_len = bytes;
00956   AVI->video_frames++;
00957   return 0;
00958 }
00959 
00960 int AVI_dup_frame(avi_t *AVI)
00961 {
00962    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
00963 
00964    if(AVI->last_pos==0) return 0; /* No previous real frame */
00965    if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
00966    AVI->video_frames++;
00967    AVI->must_use_index = 1;
00968    return 0;
00969 }
00970 
00971 int AVI_write_audio(avi_t *AVI, char *data, long bytes)
00972 {
00973    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
00974 
00975    if( avi_write_data(AVI,data,bytes,1,0) ) return -1;
00976    AVI->track[AVI->aptr].audio_bytes += bytes;
00977    return 0;
00978 }
00979 
00980 
00981 int AVI_append_audio(avi_t *AVI, char *data, long bytes)
00982 {
00983 
00984   long i, length, pos;
00985   unsigned char c[4];
00986 
00987   if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
00988 
00989   // update last index entry:
00990 
00991   --AVI->n_idx;
00992   length = str2ulong(AVI->idx[AVI->n_idx]+12);
00993   pos    = str2ulong(AVI->idx[AVI->n_idx]+8);
00994 
00995   //update;
00996   long2str(AVI->idx[AVI->n_idx]+12,length+bytes);
00997 
00998   ++AVI->n_idx;
00999 
01000   AVI->track[AVI->aptr].audio_bytes += bytes;
01001 
01002   //update chunk header
01003   lseek(AVI->fdes, pos+4, SEEK_SET);
01004   long2str(c, length+bytes);
01005   avi_write(AVI->fdes, (char *)c, 4);
01006 
01007   lseek(AVI->fdes, pos+8+length, SEEK_SET);
01008 
01009   i=PAD_EVEN(length + bytes);
01010 
01011   bytes = i - length;
01012   avi_write(AVI->fdes, data, bytes);
01013   AVI->pos = pos + 8 + i;
01014 
01015   return 0;
01016 }
01017 
01018 
01019 long AVI_bytes_remain(avi_t *AVI)
01020 {
01021    if(AVI->mode==AVI_MODE_READ) return 0;
01022 
01023    return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
01024 }
01025 
01026 long AVI_bytes_written(avi_t *AVI)
01027 {
01028    if(AVI->mode==AVI_MODE_READ) return 0;
01029 
01030    return (AVI->pos + 8 + 16*AVI->n_idx);
01031 }
01032 
01033 int AVI_set_audio_track(avi_t *AVI, int track)
01034 {
01035 
01036   if(track < 0 || track + 1 > AVI->anum) return(-1);
01037 
01038   //this info is not written to file anyway
01039   AVI->aptr=track;
01040   return 0;
01041 }
01042 
01043 int AVI_get_audio_track(avi_t *AVI)
01044 {
01045     return(AVI->aptr);
01046 }
01047 
01048 
01049 /*******************************************************************
01050  *                                                                 *
01051  *    Utilities for reading video and audio from an AVI File       *
01052  *                                                                 *
01053  *******************************************************************/
01054 
01055 int AVI_close(avi_t *AVI)
01056 {
01057    int ret, i;
01058 
01059    /* If the file was open for writing, the header and index still have
01060       to be written */
01061 
01062    if(AVI->mode == AVI_MODE_WRITE)
01063       ret = avi_close_output_file(AVI);
01064    else
01065       ret = 0;
01066 
01067    /* Even if there happened an error, we first clean up */
01068 
01069    close(AVI->fdes);
01070    if(AVI->idx) free(AVI->idx);
01071    if(AVI->video_index) free(AVI->video_index);
01072    //FIXME
01073    //if(AVI->audio_index) free(AVI->audio_index);
01074    if (AVI->bitmap_info_header)
01075      free(AVI->bitmap_info_header);
01076    for (i = 0; i < AVI->anum; i++) {
01077      if (AVI->wave_format_ex[i])
01078        free(AVI->wave_format_ex[i]);
01079      if (AVI->track[i].audio_chunks)
01080        free(AVI->track[i].audio_index);
01081    }
01082    free(AVI);
01083 
01084    return ret;
01085 }
01086 
01087 
01088 #define ERR_EXIT(x) \
01089 { \
01090    AVI_close(AVI); \
01091    AVI_errno = x; \
01092    return 0; \
01093 }
01094 
01095 avi_t *AVI_open_input_file(const char *filename, int getIndex)
01096 {
01097   avi_t *AVI=NULL;
01098 
01099   /* Create avi_t structure */
01100 
01101   AVI = (avi_t *) malloc(sizeof(avi_t));
01102   if(AVI==NULL)
01103     {
01104       AVI_errno = AVI_ERR_NO_MEM;
01105       return 0;
01106     }
01107   memset((void *)AVI,0,sizeof(avi_t));
01108 
01109   AVI->mode = AVI_MODE_READ; /* open for reading */
01110 
01111   /* Open the file */
01112 
01113 #ifdef WIN32
01114   AVI->fdes = open(filename,O_RDONLY|O_BINARY);
01115 #else
01116   AVI->fdes = open(filename,O_RDONLY);
01117 #endif
01118   if(AVI->fdes < 0)
01119     {
01120       AVI_errno = AVI_ERR_OPEN;
01121       free(AVI);
01122       return 0;
01123     }
01124 
01125   avi_parse_input_file(AVI, getIndex);
01126 
01127   AVI->aptr=0; //reset
01128 
01129   return AVI;
01130 }
01131 
01132 avi_t *AVI_open_fd(int fd, int getIndex)
01133 {
01134   avi_t *AVI=NULL;
01135 
01136   /* Create avi_t structure */
01137 
01138   AVI = (avi_t *) malloc(sizeof(avi_t));
01139   if(AVI==NULL)
01140     {
01141       AVI_errno = AVI_ERR_NO_MEM;
01142       return 0;
01143     }
01144   memset((void *)AVI,0,sizeof(avi_t));
01145 
01146   AVI->mode = AVI_MODE_READ; /* open for reading */
01147 
01148   // file alread open
01149   AVI->fdes = fd;
01150 
01151   avi_parse_input_file(AVI, getIndex);
01152 
01153   AVI->aptr=0; //reset
01154 
01155   return AVI;
01156 }
01157 
01158 int avi_parse_input_file(avi_t *AVI, int getIndex)
01159 {
01160   long i, rate, scale, idx_type;
01161   off_t n;
01162   unsigned char *hdrl_data;
01163   long header_offset=0, hdrl_len=0;
01164   long nvi, nai[AVI_MAX_TRACKS], ioff;
01165   long tot[AVI_MAX_TRACKS];
01166   int j;
01167   int lasttag = 0;
01168   int vids_strh_seen = 0;
01169   int vids_strf_seen = 0;
01170   int auds_strh_seen = 0;
01171   //  int auds_strf_seen = 0;
01172   int num_stream = 0;
01173   char data[256];
01174 
01175   /* Read first 12 bytes and check that this is an AVI file */
01176 
01177    if( avi_read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
01178 
01179    if( strncasecmp(data  ,"RIFF",4) !=0 ||
01180        strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
01181 
01182    /* Go through the AVI file and extract the header list,
01183       the start position of the 'movi' list and an optionally
01184       present idx1 tag */
01185 
01186    hdrl_data = 0;
01187 
01188    while(1)
01189    {
01190       if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
01191 
01192       n = str2ulong((unsigned char *)data+4);
01193       n = PAD_EVEN(n);
01194 
01195       if(strncasecmp(data,"LIST",4) == 0)
01196       {
01197          if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
01198          n -= 4;
01199          if(strncasecmp(data,"hdrl",4) == 0)
01200          {
01201             hdrl_len = n;
01202             hdrl_data = (unsigned char *) malloc(n);
01203             if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM);
01204 
01205             // offset of header
01206 
01207             header_offset = lseek(AVI->fdes,0,SEEK_CUR);
01208 
01209             if( avi_read(AVI->fdes,(char *)hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
01210          }
01211          else if(strncasecmp(data,"movi",4) == 0)
01212          {
01213             AVI->movi_start = lseek(AVI->fdes,0,SEEK_CUR);
01214             lseek(AVI->fdes,n,SEEK_CUR);
01215          }
01216          else
01217             lseek(AVI->fdes,n,SEEK_CUR);
01218       }
01219       else if(strncasecmp(data,"idx1",4) == 0)
01220       {
01221          /* n must be a multiple of 16, but the reading does not
01222             break if this is not the case */
01223 
01224          AVI->n_idx = AVI->max_idx = n/16;
01225          AVI->idx = (unsigned  char((*)[16]) ) malloc(n);
01226          if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
01227          if(avi_read(AVI->fdes, (char *) AVI->idx, n) != n ) ERR_EXIT(AVI_ERR_READ)
01228       }
01229       else
01230          lseek(AVI->fdes,n,SEEK_CUR);
01231    }
01232 
01233    if(!hdrl_data      ) ERR_EXIT(AVI_ERR_NO_HDRL)
01234    if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
01235 
01236    /* Interpret the header list */
01237 
01238    for(i=0;i<hdrl_len;)
01239    {
01240       /* List tags are completly ignored */
01241 
01242       if(strncasecmp((char *)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
01243 
01244       n = str2ulong(hdrl_data+i+4);
01245       n = PAD_EVEN(n);
01246 
01247       /* Interpret the tag and its args */
01248 
01249       if(strncasecmp((char *)hdrl_data+i,"strh",4)==0)
01250       {
01251          i += 8;
01252          if(strncasecmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
01253          {
01254             memcpy(AVI->compressor,hdrl_data+i+4,4);
01255             AVI->compressor[4] = 0;
01256 
01257             // ThOe
01258             AVI->v_codech_off = header_offset + i+4;
01259 
01260             scale = str2ulong(hdrl_data+i+20);
01261             rate  = str2ulong(hdrl_data+i+24);
01262             if(scale!=0) AVI->fps = (double)rate/(double)scale;
01263             AVI->video_frames = str2ulong(hdrl_data+i+32);
01264             AVI->video_strn = num_stream;
01265             AVI->max_len = 0;
01266             vids_strh_seen = 1;
01267             lasttag = 1; /* vids */
01268          }
01269          else if (strncasecmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
01270          {
01271 
01272            //inc audio tracks
01273            AVI->aptr=AVI->anum;
01274            ++AVI->anum;
01275 
01276            if(AVI->anum > AVI_MAX_TRACKS) {
01277              fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
01278              return(-1);
01279            }
01280 
01281            AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
01282            AVI->track[AVI->aptr].audio_strn = num_stream;
01283            //           auds_strh_seen = 1;
01284            lasttag = 2; /* auds */
01285 
01286            // ThOe
01287            AVI->track[AVI->aptr].a_codech_off = header_offset + i;
01288 
01289          }
01290          else
01291             lasttag = 0;
01292          num_stream++;
01293       }
01294       else if(strncasecmp((char *)hdrl_data+i,"strf",4)==0)
01295       {
01296          i += 8;
01297          if(lasttag == 1)
01298          {
01299             BITMAPINFOHEADER_avilib bih;
01300 
01301             memcpy(&bih, hdrl_data + i, sizeof(BITMAPINFOHEADER_avilib));
01302             AVI->bitmap_info_header = (BITMAPINFOHEADER_avilib *)malloc(bih.bi_size);
01303             if (AVI->bitmap_info_header != NULL)
01304               memcpy(AVI->bitmap_info_header, hdrl_data + i, bih.bi_size);
01305 
01306             AVI->width  = str2ulong(hdrl_data+i+4);
01307             AVI->height = str2ulong(hdrl_data+i+8);
01308                     vids_strf_seen = 1;
01309             //ThOe
01310             AVI->v_codecf_off = header_offset + i+16;
01311 
01312             memcpy(AVI->compressor2, hdrl_data+i+16, 4);
01313             AVI->compressor2[4] = 0;
01314 
01315          }
01316          else if(lasttag == 2)
01317          {
01318             WAVEFORMATEX_avilib *wfe;
01319             char *nwfe;
01320             int wfes;
01321 
01322             if ((hdrl_len - i) < sizeof(WAVEFORMATEX_avilib))
01323               wfes = hdrl_len - i;
01324             else
01325               wfes = sizeof(WAVEFORMATEX_avilib);
01326             wfe = (WAVEFORMATEX_avilib *)malloc(sizeof(WAVEFORMATEX_avilib));
01327             if (wfe != NULL) {
01328               memset(wfe, 0, sizeof(WAVEFORMATEX_avilib));
01329               memcpy(wfe, hdrl_data + i, wfes);
01330               if (wfe->cb_size != 0) {
01331                 nwfe = (char *)realloc(wfe, sizeof(WAVEFORMATEX_avilib) +
01332                                        wfe->cb_size);
01333                 if (nwfe != 0) {
01334                   off_t lpos = lseek(AVI->fdes, 0, SEEK_CUR);
01335                   lseek(AVI->fdes, header_offset + i + sizeof(WAVEFORMATEX_avilib),
01336                         SEEK_SET);
01337                   wfe = (WAVEFORMATEX_avilib *)nwfe;
01338                   nwfe = &nwfe[sizeof(WAVEFORMATEX_avilib)];
01339                   avi_read(AVI->fdes, nwfe, wfe->cb_size);
01340                   lseek(AVI->fdes, lpos, SEEK_SET);
01341                 }
01342               }
01343               AVI->wave_format_ex[AVI->aptr] = wfe;
01344             }
01345 
01346             AVI->track[AVI->aptr].a_fmt   = str2ushort(hdrl_data+i  );
01347 
01348             //ThOe
01349             AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
01350 
01351             AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
01352             AVI->track[AVI->aptr].a_rate  = str2ulong (hdrl_data+i+4);
01353             //ThOe: read mp3bitrate
01354             AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
01355             //:ThOe
01356             AVI->track[AVI->aptr].a_bits  = str2ushort(hdrl_data+i+14);
01357             //            auds_strf_seen = 1;
01358          }
01359          lasttag = 0;
01360       }
01361       else
01362       {
01363          i += 8;
01364          lasttag = 0;
01365       }
01366 
01367       i += n;
01368    }
01369 
01370    free(hdrl_data);
01371 
01372    if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
01373 
01374    AVI->video_tag[0] = AVI->video_strn/10 + '0';
01375    AVI->video_tag[1] = AVI->video_strn%10 + '0';
01376    AVI->video_tag[2] = 'd';
01377    AVI->video_tag[3] = 'b';
01378 
01379    /* Audio tag is set to "99wb" if no audio present */
01380    if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
01381 
01382    for(j=0; j<AVI->anum; ++j) {
01383      AVI->track[j].audio_tag[0] = (j+1)/10 + '0';
01384      AVI->track[j].audio_tag[1] = (j+1)%10 + '0';
01385      AVI->track[j].audio_tag[2] = 'w';
01386      AVI->track[j].audio_tag[3] = 'b';
01387    }
01388 
01389    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
01390 
01391    /* get index if wanted */
01392 
01393    if(!getIndex) return(0);
01394 
01395    /* if the file has an idx1, check if this is relative
01396       to the start of the file or to the start of the movi list */
01397 
01398    idx_type = 0;
01399 
01400    if(AVI->idx)
01401    {
01402       off_t pos, len;
01403 
01404       /* Search the first videoframe in the idx1 and look where
01405          it is in the file */
01406 
01407       for(i=0;i<AVI->n_idx;i++)
01408          if( strncasecmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
01409       if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
01410 
01411       pos = str2ulong(AVI->idx[i]+ 8);
01412       len = str2ulong(AVI->idx[i]+12);
01413 
01414       lseek(AVI->fdes,pos,SEEK_SET);
01415       if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
01416       if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
01417       {
01418          idx_type = 1; /* Index from start of file */
01419       }
01420       else
01421       {
01422          lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
01423          if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
01424          if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
01425          {
01426             idx_type = 2; /* Index from start of movi list */
01427          }
01428       }
01429       /* idx_type remains 0 if neither of the two tests above succeeds */
01430    }
01431 
01432    if(idx_type == 0)
01433    {
01434       /* we must search through the file to get the index */
01435 
01436       lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
01437 
01438       AVI->n_idx = 0;
01439 
01440       while(1)
01441       {
01442          if( avi_read(AVI->fdes,data,8) != 8 ) break;
01443          n = str2ulong((unsigned char *)data+4);
01444 
01445          /* The movi list may contain sub-lists, ignore them */
01446 
01447          if(strncasecmp(data,"LIST",4)==0)
01448          {
01449             lseek(AVI->fdes,4,SEEK_CUR);
01450             continue;
01451          }
01452 
01453          /* Check if we got a tag ##db, ##dc or ##wb */
01454 
01455          if( ( (data[2]=='d' || data[2]=='D') &&
01456                (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
01457              || ( (data[2]=='w' || data[2]=='W') &&
01458                   (data[3]=='b' || data[3]=='B') ) )
01459            {
01460            avi_add_index_entry(AVI,(unsigned char *)data,0,lseek(AVI->fdes,0,SEEK_CUR)-8,n);
01461          }
01462 
01463          lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
01464       }
01465       idx_type = 1;
01466    }
01467 
01468    /* Now generate the video index and audio index arrays */
01469 
01470    nvi = 0;
01471    for(j=0; j<AVI->anum; ++j) nai[j] = 0;
01472 
01473    for(i=0;i<AVI->n_idx;i++) {
01474 
01475      if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
01476 
01477      for(j=0; j<AVI->anum; ++j) if(strncasecmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
01478    }
01479 
01480    AVI->video_frames = nvi;
01481    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
01482 
01483 //   fprintf(stderr, "chunks = %ld %d %s\n", AVI->track[0].audio_chunks, AVI->anum, AVI->track[0].audio_tag);
01484 
01485    if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
01486    AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
01487    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
01488 
01489    for(j=0; j<AVI->anum; ++j) {
01490        if(AVI->track[j].audio_chunks) {
01491            AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry));
01492            memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
01493            if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
01494        }
01495    }
01496 
01497    nvi = 0;
01498    for(j=0; j<AVI->anum; ++j) nai[j] = tot[j] = 0;
01499 
01500    ioff = idx_type == 1 ? 8 : AVI->movi_start+4;
01501 
01502    for(i=0;i<AVI->n_idx;i++) {
01503 
01504      //video
01505      if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
01506        AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
01507        AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
01508        AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
01509        nvi++;
01510      }
01511 
01512      //audio
01513      for(j=0; j<AVI->anum; ++j) {
01514 
01515        if(strncasecmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
01516          AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
01517          AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
01518          AVI->track[j].audio_index[nai[j]].tot = tot[j];
01519          tot[j] += AVI->track[j].audio_index[nai[j]].len;
01520          nai[j]++;
01521        }
01522      }
01523    }
01524 
01525 
01526    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
01527 
01528    /* Reposition the file */
01529 
01530    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
01531    AVI->video_pos = 0;
01532 
01533    return(0);
01534 }
01535 
01536 long AVI_video_frames(avi_t *AVI)
01537 {
01538    return AVI->video_frames;
01539 }
01540 int  AVI_video_width(avi_t *AVI)
01541 {
01542    return AVI->width;
01543 }
01544 int  AVI_video_height(avi_t *AVI)
01545 {
01546    return AVI->height;
01547 }
01548 double AVI_frame_rate(avi_t *AVI)
01549 {
01550    return AVI->fps;
01551 }
01552 char* AVI_video_compressor(avi_t *AVI)
01553 {
01554    return AVI->compressor2;
01555 }
01556 
01557 long AVI_max_video_chunk(avi_t *AVI)
01558 {
01559    return AVI->max_len;
01560 }
01561 
01562 int AVI_audio_tracks(avi_t *AVI)
01563 {
01564     return(AVI->anum);
01565 }
01566 
01567 int AVI_audio_channels(avi_t *AVI)
01568 {
01569    return AVI->track[AVI->aptr].a_chans;
01570 }
01571 
01572 long AVI_audio_mp3rate(avi_t *AVI)
01573 {
01574    return AVI->track[AVI->aptr].mp3rate;
01575 }
01576 
01577 int AVI_audio_bits(avi_t *AVI)
01578 {
01579    return AVI->track[AVI->aptr].a_bits;
01580 }
01581 
01582 int AVI_audio_format(avi_t *AVI)
01583 {
01584    return AVI->track[AVI->aptr].a_fmt;
01585 }
01586 
01587 long AVI_audio_rate(avi_t *AVI)
01588 {
01589    return AVI->track[AVI->aptr].a_rate;
01590 }
01591 
01592 long AVI_audio_bytes(avi_t *AVI)
01593 {
01594    return AVI->track[AVI->aptr].audio_bytes;
01595 }
01596 
01597 long AVI_audio_chunks(avi_t *AVI)
01598 {
01599    return AVI->track[AVI->aptr].audio_chunks;
01600 }
01601 
01602 long AVI_audio_codech_offset(avi_t *AVI)
01603 {
01604    return AVI->track[AVI->aptr].a_codech_off;
01605 }
01606 
01607 long AVI_audio_codecf_offset(avi_t *AVI)
01608 {
01609    return AVI->track[AVI->aptr].a_codecf_off;
01610 }
01611 
01612 long  AVI_video_codech_offset(avi_t *AVI)
01613 {
01614     return AVI->v_codech_off;
01615 }
01616 
01617 long  AVI_video_codecf_offset(avi_t *AVI)
01618 {
01619     return AVI->v_codecf_off;
01620 }
01621 
01622 long AVI_frame_size(avi_t *AVI, long frame)
01623 {
01624    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01625    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01626 
01627    if(frame < 0 || frame >= AVI->video_frames) return 0;
01628    return(AVI->video_index[frame].len);
01629 }
01630 
01631 long AVI_audio_size(avi_t *AVI, long frame)
01632 {
01633   if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01634   if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01635 
01636   if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return 0;
01637   return(AVI->track[AVI->aptr].audio_index[frame].len);
01638 }
01639 
01640 long AVI_get_video_position(avi_t *AVI, long frame)
01641 {
01642    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01643    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01644 
01645    if(frame < 0 || frame >= AVI->video_frames) return 0;
01646    return(AVI->video_index[frame].pos);
01647 }
01648 
01649 
01650 int AVI_seek_start(avi_t *AVI)
01651 {
01652    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01653 
01654    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
01655    AVI->video_pos = 0;
01656    return 0;
01657 }
01658 
01659 int AVI_set_video_position(avi_t *AVI, long frame)
01660 {
01661    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01662    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01663 
01664    if (frame < 0 ) frame = 0;
01665    AVI->video_pos = frame;
01666    return 0;
01667 }
01668 
01669 int AVI_set_audio_bitrate(avi_t *AVI, long bitrate)
01670 {
01671    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01672 
01673    AVI->track[AVI->aptr].mp3rate = bitrate;
01674    return 0;
01675 }
01676 
01677 
01678 long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe)
01679 {
01680    long n;
01681 
01682    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01683    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01684 
01685    if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
01686    n = AVI->video_index[AVI->video_pos].len;
01687 
01688    *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
01689 
01690    lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
01691 
01692    if (avi_read(AVI->fdes,vidbuf,n) != n)
01693    {
01694       AVI_errno = AVI_ERR_READ;
01695       return -1;
01696    }
01697 
01698    AVI->video_pos++;
01699 
01700    return n;
01701 }
01702 
01703 int AVI_set_audio_position(avi_t *AVI, long byte)
01704 {
01705    long n0, n1, n;
01706 
01707    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01708    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01709 
01710    if(byte < 0) byte = 0;
01711 
01712    /* Binary search in the audio chunks */
01713 
01714    n0 = 0;
01715    n1 = AVI->track[AVI->aptr].audio_chunks;
01716 
01717    while(n0<n1-1)
01718    {
01719       n = (n0+n1)/2;
01720       if(AVI->track[AVI->aptr].audio_index[n].tot>byte)
01721          n1 = n;
01722       else
01723          n0 = n;
01724    }
01725 
01726    AVI->track[AVI->aptr].audio_posc = n0;
01727    AVI->track[AVI->aptr].audio_posb = byte - AVI->track[AVI->aptr].audio_index[n0].tot;
01728 
01729    return 0;
01730 }
01731 
01732 long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes)
01733 {
01734    long nr, pos, left, todo;
01735 
01736    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01737    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01738 
01739    nr = 0; /* total number of bytes read */
01740 
01741    while(bytes>0)
01742    {
01743       left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
01744       if(left==0)
01745       {
01746          if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
01747          AVI->track[AVI->aptr].audio_posc++;
01748          AVI->track[AVI->aptr].audio_posb = 0;
01749          continue;
01750       }
01751       if(bytes<left)
01752          todo = bytes;
01753       else
01754          todo = left;
01755       pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
01756       lseek(AVI->fdes, pos, SEEK_SET);
01757       if (avi_read(AVI->fdes,audbuf+nr,todo) != todo)
01758       {
01759          AVI_errno = AVI_ERR_READ;
01760          return -1;
01761       }
01762       bytes -= todo;
01763       nr    += todo;
01764       AVI->track[AVI->aptr].audio_posb += todo;
01765    }
01766 
01767    return nr;
01768 }
01769 
01770 long AVI_read_audio_chunk(avi_t *AVI, char *audbuf)
01771 {
01772    long pos, left;
01773 
01774    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01775    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
01776 
01777    if (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len == 0) return 0;
01778    left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
01779 
01780    if (audbuf == NULL) return left;
01781 
01782    if(left==0) return 0;
01783 
01784    pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
01785    lseek(AVI->fdes, pos, SEEK_SET);
01786    if (avi_read(AVI->fdes,audbuf,left) != left)
01787    {
01788       AVI_errno = AVI_ERR_READ;
01789       return -1;
01790    }
01791    AVI->track[AVI->aptr].audio_posc++;
01792    AVI->track[AVI->aptr].audio_posb = 0;
01793 
01794    return left;
01795 }
01796 
01797 /* AVI_read_data: Special routine for reading the next audio or video chunk
01798                   without having an index of the file. */
01799 
01800 int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
01801                               char *audbuf, long max_audbuf,
01802                               long *len)
01803 {
01804 
01805 /*
01806  * Return codes:
01807  *
01808  *    1 = video data read
01809  *    2 = audio data read
01810  *    0 = reached EOF
01811  *   -1 = video buffer too small
01812  *   -2 = audio buffer too small
01813  */
01814 
01815    off_t n;
01816    char data[8];
01817 
01818    if(AVI->mode==AVI_MODE_WRITE) return 0;
01819 
01820    while(1)
01821    {
01822       /* Read tag and length */
01823 
01824       if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
01825 
01826       /* if we got a list tag, ignore it */
01827 
01828       if(strncasecmp(data,"LIST",4) == 0)
01829       {
01830          lseek(AVI->fdes,4,SEEK_CUR);
01831          continue;
01832       }
01833 
01834       n = PAD_EVEN(str2ulong((unsigned char *)data+4));
01835 
01836       if(strncasecmp(data,AVI->video_tag,3) == 0)
01837       {
01838          *len = n;
01839          AVI->video_pos++;
01840          if(n>max_vidbuf)
01841          {
01842             lseek(AVI->fdes,n,SEEK_CUR);
01843             return -1;
01844          }
01845          if(avi_read(AVI->fdes,vidbuf,n) != n ) return 0;
01846          return 1;
01847       }
01848       else if(strncasecmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
01849       {
01850          *len = n;
01851          if(n>max_audbuf)
01852          {
01853             lseek(AVI->fdes,n,SEEK_CUR);
01854             return -2;
01855          }
01856          if(avi_read(AVI->fdes,audbuf,n) != n ) return 0;
01857          return 2;
01858          break;
01859       }
01860       else
01861          if(lseek(AVI->fdes,n,SEEK_CUR)<0)  return 0;
01862    }
01863 }
01864 
01865 /* AVI_print_error: Print most recent error (similar to perror) */
01866 
01867 char *(avi_errors[]) =
01868 {
01869   /*  0 */ "avilib - No Error",
01870   /*  1 */ "avilib - AVI file size limit reached",
01871   /*  2 */ "avilib - Error opening AVI file",
01872   /*  3 */ "avilib - Error reading from AVI file",
01873   /*  4 */ "avilib - Error writing to AVI file",
01874   /*  5 */ "avilib - Error writing index (file may still be useable)",
01875   /*  6 */ "avilib - Error closing AVI file",
01876   /*  7 */ "avilib - Operation (read/write) not permitted",
01877   /*  8 */ "avilib - Out of memory (malloc failed)",
01878   /*  9 */ "avilib - Not an AVI file",
01879   /* 10 */ "avilib - AVI file has no header list (corrupted?)",
01880   /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
01881   /* 12 */ "avilib - AVI file has no video data",
01882   /* 13 */ "avilib - operation needs an index",
01883   /* 14 */ "avilib - Unkown Error"
01884 };
01885 static int num_avi_errors = sizeof(avi_errors)/sizeof(char*);
01886 
01887 static char error_string[4096];
01888 
01889 void AVI_print_error(char *str)
01890 {
01891    int aerrno;
01892 
01893    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
01894 
01895    fprintf(stderr,"%s: %s\n",str,avi_errors[aerrno]);
01896 
01897    /* for the following errors, perror should report a more detailed reason: */
01898 
01899    if(AVI_errno == AVI_ERR_OPEN ||
01900       AVI_errno == AVI_ERR_READ ||
01901       AVI_errno == AVI_ERR_WRITE ||
01902       AVI_errno == AVI_ERR_WRITE_INDEX ||
01903       AVI_errno == AVI_ERR_CLOSE )
01904    {
01905       perror("REASON");
01906    }
01907 }
01908 
01909 char *AVI_strerror()
01910 {
01911    int aerrno;
01912 
01913    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
01914 
01915    if(AVI_errno == AVI_ERR_OPEN ||
01916       AVI_errno == AVI_ERR_READ ||
01917       AVI_errno == AVI_ERR_WRITE ||
01918       AVI_errno == AVI_ERR_WRITE_INDEX ||
01919       AVI_errno == AVI_ERR_CLOSE )
01920    {
01921       sprintf(error_string,"%s - %s",avi_errors[aerrno],strerror(errno));
01922       return error_string;
01923    }
01924    else
01925    {
01926       return avi_errors[aerrno];
01927    }
01928 }
01929 
01930 uint64_t AVI_max_size()
01931 {
01932   return((uint64_t) AVI_MAX_LEN);
01933 }
01934 
Generated on Sun May 8 08:41:22 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3