avilib.c
Go to the documentation of this file.
00001 /*******************************************************************************#
00002 #           guvcview              http://guvcview.berlios.de                    #
00003 #                                                                               #
00004 #           Paulo Assis <pj.assis@gmail.com>                                    #
00005 #                                                                               #
00006 # This program is free software; you can redistribute it and/or modify          #
00007 # it under the terms of the GNU General Public License as published by          #
00008 # the Free Software Foundation; either version 2 of the License, or             #
00009 # (at your option) any later version.                                           #
00010 #                                                                               #
00011 # This program is distributed in the hope that it will be useful,               #
00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of                #
00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 #
00014 # GNU General Public License for more details.                                  #
00015 #                                                                               #
00016 # You should have received a copy of the GNU General Public License             #
00017 # along with this program; if not, write to the Free Software                   #
00018 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA     #
00019 #                                                                               #
00020 ********************************************************************************/
00021 /*******************************************************************************#
00022 #   Some utilities for writing and reading AVI files.                           # 
00023 #   These are not intended to serve for a full blown                            #
00024 #   AVI handling software (this would be much too complex)                      #
00025 #   The only intention is to write out MJPEG encoded                            #
00026 #   AVIs with sound and to be able to read them back again.                     #
00027 #   These utilities should work with other types of codecs too, however.        #
00028 #                                                                               #
00029 #   Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>                       #
00030 ********************************************************************************/
00031 /*  Paulo Assis (6-4-2008): removed reading functions, cleaned build wranings  */
00032 
00033 #include <stdio.h>
00034 #include <fcntl.h>
00035 #include <unistd.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <errno.h>
00039 #include <time.h>
00040 //#include <glib.h>
00041 //#include <glib/gstdio.h>
00042 //#include "config.h"
00043 #include "avilib.h"
00044 #include "defs.h"
00045 
00046 /* The following variable indicates the kind of error */
00047 
00048 long AVI_errno = 0;
00049 
00050 /*******************************************************************
00051  *                                                                 *
00052  *    Utilities for writing an AVI File                            *
00053  *                                                                 *
00054  *******************************************************************/
00055 
00056 #define INFO_LIST
00057 
00058 #define MAX_INFO_STRLEN 64
00059 static char id_str[MAX_INFO_STRLEN];
00060 
00061 #ifndef PACKAGE
00062 #define PACKAGE "guvcview"
00063 #endif
00064 #ifndef VERSION
00065 #define VERSION "0.9"
00066 #endif
00067 
00068 /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
00069     the 2GB limit (Remember: 2*10^9 is smaller than 2 GB - using 1900*1024*1024) */
00070 
00071 ULONG AVI_MAX_LEN = AVI_MAX_SIZE;
00072 
00073 ULONG AVI_set_MAX_LEN(ULONG len) 
00074 {
00075         /*clip to max size*/
00076         if(len > AVI_MAX_SIZE) {len = AVI_MAX_SIZE; }
00077         else { AVI_MAX_LEN = len; }
00078         
00079         return (AVI_MAX_LEN);
00080 }
00081 
00082 /* HEADERBYTES: The number of bytes to reserve for the header */
00083 
00084 #define HEADERBYTES 2048
00085 
00086 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
00087 
00088 
00089 /* Copy n into dst as a 4 byte, little endian number.
00090    Should also work on big endian machines */
00091 
00092 static void long2str(unsigned char *dst, int n)
00093 {
00094         dst[0] = (n    )&0xff;
00095         dst[1] = (n>> 8)&0xff;
00096         dst[2] = (n>>16)&0xff;
00097         dst[3] = (n>>24)&0xff;
00098 }
00099 
00100 /* Convert a string of 4 or 2 bytes to a number,
00101    also working on big endian machines */
00102 
00103 static unsigned long str2ulong(BYTE *str)
00104 {
00105         return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
00106 }
00107 //~ static unsigned long str2ushort(BYTE *str)
00108 //~ {
00109    //~ return ( str[0] | (str[1]<<8) );
00110 //~ }
00111 
00112 /* Calculate audio sample size from number of bits and number of channels.
00113    This may have to be adjusted for eg. 12 bits and stereo */
00114 
00115 static int avi_sampsize(struct avi_t *AVI, int j)
00116 {
00117         int s;
00118         if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12) 
00119         {
00120                 s = 4;
00121         } 
00122         else 
00123         {
00124                 s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
00125                 if(s<4) s=4; /* avoid possible zero divisions */
00126         }
00127         return s;
00128 }
00129 
00130 static ssize_t avi_write (int fd, BYTE *buf, size_t len)
00131 {
00132         ssize_t n = 0;
00133         ssize_t r = 0;
00134 
00135         while ((size_t)r < len) 
00136         {
00137                 n = write (fd, buf + r, len - r);
00138                 if (n < 0)
00139                         return n;
00140 
00141                 r += n;
00142         }
00143         return r;
00144 }
00145 
00146 /* Add a chunk (=tag and data) to the AVI file,
00147    returns -1 on write error, 0 on success */
00148 
00149 static int avi_add_chunk(struct avi_t *AVI, BYTE *tag, BYTE *data, int length)
00150 {
00151         BYTE c[8];
00152         BYTE p=0;
00153         /* Copy tag and length int c, so that we need only 1 write system call
00154         for these two values */
00155 
00156         memcpy(c,tag,4);
00157         long2str(c+4,length);
00158 
00159         /* Output tag, length and data, restore previous position
00160         if the write fails */
00161 
00162         if( avi_write(AVI->fdes,c,8) != 8 ||
00163                 avi_write(AVI->fdes,data,length) != length ||
00164                 avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte
00165         {
00166                 lseek(AVI->fdes,AVI->pos,SEEK_SET);
00167                 AVI_errno = AVI_ERR_WRITE;
00168                 return -1;
00169         }
00170 
00171         /* Update file position */
00172         AVI->pos += 8 + PAD_EVEN(length);
00173    
00174         //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
00175    
00176         return 0;
00177 }
00178 
00179 static int avi_add_index_entry(struct avi_t *AVI, BYTE *tag, long flags, long pos, long len)
00180 {
00181         void *ptr;
00182 
00183         if(AVI->n_idx>=AVI->max_idx)
00184         {
00185         ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
00186         if(ptr == 0)
00187         {
00188                 AVI_errno = AVI_ERR_NO_MEM;
00189                 return -1;
00190         }
00191                 AVI->max_idx += 4096;
00192                 AVI->idx = (BYTE((*)[16]) ) ptr;
00193         }
00194 
00195         /* Add index entry */
00196 
00197         memcpy(AVI->idx[AVI->n_idx],tag,4);
00198         long2str(AVI->idx[AVI->n_idx]+ 4,flags);
00199         long2str(AVI->idx[AVI->n_idx]+ 8,pos);
00200         long2str(AVI->idx[AVI->n_idx]+12,len);
00201 
00202         /* Update counter */
00203 
00204         AVI->n_idx++;
00205 
00206         if(len>AVI->max_len) AVI->max_len=len;
00207         
00208         return 0;
00209 }
00210 
00211 //SLM
00212 #ifndef S_IRUSR
00213 #define S_IRWXU       00700       /* read, write, execute: owner */
00214 #define S_IRUSR       00400       /* read permission: owner */
00215 #define S_IWUSR       00200       /* write permission: owner */
00216 #define S_IXUSR       00100       /* execute permission: owner */
00217 #define S_IRWXG       00070       /* read, write, execute: group */
00218 #define S_IRGRP       00040       /* read permission: group */
00219 #define S_IWGRP       00020       /* write permission: group */
00220 #define S_IXGRP       00010       /* execute permission: group */
00221 #define S_IRWXO       00007       /* read, write, execute: other */
00222 #define S_IROTH       00004       /* read permission: other */
00223 #define S_IWOTH       00002       /* write permission: other */
00224 #define S_IXOTH       00001       /* execute permission: other */
00225 #endif
00226 
00227 
00228 #define OUT4CC(s) \
00229    if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
00230 
00231 #define OUTLONG(n) \
00232    if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
00233 
00234 #define OUTSHRT(n) \
00235    if(nhb<=HEADERBYTES-2) { \
00236       AVI_header[nhb  ] = (n   )&0xff; \
00237       AVI_header[nhb+1] = (n>>8)&0xff; \
00238    } \
00239    nhb += 2
00240 
00241 #define OUTCHR(n) \
00242    if(nhb<=HEADERBYTES-1) { \
00243       AVI_header[nhb  ] = (n   )&0xff; \
00244    } \
00245    nhb += 1
00246 
00247 #define OUTMEM(d, s) \
00248    { \
00249      unsigned int s_ = (s); \
00250      if(nhb <= HEADERBYTES-s_) \
00251         memcpy(AVI_header+nhb, (d), s_); \
00252      nhb += s_; \
00253    }
00254 
00255 //ThOe write preliminary AVI file header: 0 frames, max vid/aud size
00256 static int avi_update_header(struct avi_t *AVI)
00257 {
00258         int njunk, sampsize, hasIndex, ms_per_frame, frate, flag;
00259         int movi_len, hdrl_start, strl_start, j;
00260         BYTE AVI_header[HEADERBYTES];
00261         long nhb;
00262         ULONG xd_size, xd_size_align2;
00263 
00264         //assume max size
00265         movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
00266 
00267         //assume index will be written
00268         hasIndex=1;
00269 
00270         if(AVI->fps < 0.001) 
00271         {
00272                 frate=0;
00273                 ms_per_frame=0;
00274         }
00275         else 
00276         {
00277                 frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
00278                 ms_per_frame=(int) (1000000/AVI->fps + 0.5);
00279         }
00280 
00281         /* Prepare the file header */
00282 
00283         nhb = 0;
00284 
00285         /* The RIFF header */
00286 
00287         OUT4CC ("RIFF");
00288         OUTLONG(movi_len);    // assume max size
00289         OUT4CC ("AVI ");
00290 
00291         /* Start the header list */
00292 
00293         OUT4CC ("LIST");
00294         OUTLONG(0);        /* Length of list in bytes, don't know yet */
00295         hdrl_start = nhb;  /* Store start position */
00296         OUT4CC ("hdrl");
00297 
00298         /* The main AVI header */
00299 
00300         /* The Flags in AVI File header */
00301 
00302 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
00303 #define AVIF_MUSTUSEINDEX       0x00000020
00304 #define AVIF_ISINTERLEAVED      0x00000100
00305 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
00306 #define AVIF_WASCAPTUREFILE     0x00010000
00307 #define AVIF_COPYRIGHTED        0x00020000
00308 
00309         OUT4CC ("avih");
00310         OUTLONG(56);                    /* # of bytes to follow */
00311         OUTLONG(ms_per_frame);          /* Microseconds per frame */
00312         //ThOe ->0 
00313         //OUTLONG(10000000);            /* MaxBytesPerSec, I hope this will never be used */
00314         OUTLONG(0);
00315         OUTLONG(0);                     /* PaddingGranularity (whatever that might be) */
00316                                         /* Other sources call it 'reserved' */
00317         //flag = AVIF_ISINTERLEAVED;
00318         flag = AVIF_WASCAPTUREFILE;
00319         /*do not force index yet -only when closing*/
00320         /*this should prevent bad avi files even if it is not closed properly*/
00321         //if(hasIndex) flag |= AVIF_HASINDEX;
00322         //if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
00323         OUTLONG(flag);                  /* Flags */
00324         OUTLONG(0);                     // no frames yet
00325         OUTLONG(0);                     /* InitialFrames */
00326 
00327         OUTLONG(AVI->anum+1);           /*streams audio + video*/
00328 
00329         OUTLONG(0);                     /* SuggestedBufferSize */
00330         OUTLONG(AVI->width);            /* Width */
00331         OUTLONG(AVI->height);           /* Height */
00332                                         /* MS calls the following 'reserved': */
00333         OUTLONG(0);                     /* TimeScale:  Unit used to measure time */
00334         OUTLONG(0);                     /* DataRate:   Data rate of playback     */
00335         OUTLONG(0);                     /* StartTime:  Starting time of AVI data */
00336         OUTLONG(0);                     /* DataLength: Size of AVI data chunk    */
00337 
00338 
00339         /* Start the video stream list ---------------------------------- */
00340 
00341         OUT4CC ("LIST");
00342         OUTLONG(0);        /* Length of list in bytes, don't know yet */
00343         strl_start = nhb;  /* Store start position */
00344         OUT4CC ("strl");
00345 
00346         /* The video stream header */
00347 
00348         OUT4CC ("strh");
00349         OUTLONG(64);                 /* # of bytes to follow */
00350         OUT4CC ("vids");             /* Type */
00351         OUT4CC (AVI->compressor);    /* Handler */
00352         OUTLONG(0);                  /* Flags */
00353         OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
00354         OUTLONG(0);                  /* InitialFrames */
00355         OUTLONG(FRAME_RATE_SCALE);   /* Scale */
00356         OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
00357         OUTLONG(0);                  /* Start */
00358         OUTLONG(0);                  // no frames yet
00359         OUTLONG(0);                  /* SuggestedBufferSize */
00360         OUTLONG(-1);                 /* Quality */
00361         OUTLONG(0);                  /* SampleSize */
00362         OUTLONG(0);                  /* Frame */
00363         OUTLONG(0);                  /* Frame */
00364         OUTLONG(0);                  /* Frame */
00365         OUTLONG(0);                  /* Frame */
00366 
00367         /* The video stream format */
00368 
00369         xd_size        = AVI->extradata_size;
00370         xd_size_align2 = (AVI->extradata_size+1) & ~1;
00371 
00372         OUT4CC ("strf");
00373         OUTLONG(40 + xd_size_align2);/* # of bytes to follow */
00374         OUTLONG(40 + xd_size);       /* Size */
00375         OUTLONG(AVI->width);         /* Width */
00376         OUTLONG(AVI->height);        /* Height */
00377         OUTSHRT(1);                  /* Planes */
00378         OUTSHRT(24);                 /*Count - bitsperpixel - 1,4,8 or 24  32*/
00379         if(strncmp(AVI->compressor,"DIB",3)==0) {OUTLONG (0); }    /* Compression */
00380         else { OUT4CC (AVI->compressor); }
00381         //OUT4CC (AVI->compressor);
00382         
00383         // ThOe (*3)
00384         OUTLONG(AVI->width*AVI->height);  /* SizeImage (in bytes?) */
00385         //OUTLONG(AVI->width*AVI->height*3);  /* SizeImage */
00386         OUTLONG(0);                  /* XPelsPerMeter */
00387         OUTLONG(0);                  /* YPelsPerMeter */
00388         OUTLONG(0);                  /* ClrUsed: Number of colors used */
00389         OUTLONG(0);                  /* ClrImportant: Number of colors important */
00390 
00391         // write extradata
00392         if (xd_size > 0 && AVI->extradata) 
00393         {
00394                 OUTMEM(AVI->extradata, xd_size);
00395                 if (xd_size != xd_size_align2) 
00396                 {
00397                         OUTCHR(0);
00398                 }
00399         }
00400 
00401         /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00402 
00403         long2str(AVI_header+strl_start-4,nhb-strl_start);
00404 
00405    
00406         /* Start the audio stream list ---------------------------------- */
00407         /* only 1 audio stream => AVI->anum=1*/
00408         for(j=0; j<AVI->anum; ++j) 
00409         {
00410 
00411                 sampsize = avi_sampsize(AVI, j);
00412                 //sampsize = avi_sampsize(AVI);
00413        
00414                 OUT4CC ("LIST");
00415                 OUTLONG(0);        /* Length of list in bytes, don't know yet */
00416                 strl_start = nhb;  /* Store start position */
00417                 OUT4CC ("strl");
00418        
00419                 /* The audio stream header */
00420        
00421                 OUT4CC ("strh");
00422                 OUTLONG(64);            /* # of bytes to follow */
00423                 OUT4CC ("auds");
00424        
00425                 // -----------
00426                 // ThOe
00427                 OUT4CC ("\0\0\0\0");             /* Format (Optionally) */
00428                 // -----------
00429        
00430                 OUTLONG(0);             /* Flags */
00431                 OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
00432                 OUTLONG(0);             /* InitialFrames */
00433        
00434                 // ThOe /4
00435                 OUTLONG(sampsize/4);      /* Scale */
00436                 OUTLONG(1000*AVI->track[j].mpgrate/8);
00437                 OUTLONG(0);             /* Start */
00438                 OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   /* Length */
00439                 OUTLONG(0);             /* SuggestedBufferSize */
00440                 OUTLONG(-1);            /* Quality */
00441        
00442                 // ThOe /4
00443                 OUTLONG(sampsize/4);    /* SampleSize */
00444        
00445                 OUTLONG(0);             /* Frame */
00446                 OUTLONG(0);             /* Frame */
00447                 OUTLONG(0);             /* Frame */
00448                 OUTLONG(0);             /* Frame */
00449        
00450                 /* The audio stream format */
00451        
00452                 OUT4CC ("strf");
00453                 OUTLONG(16);                   /* # of bytes to follow */
00454                 OUTSHRT(AVI->track[j].a_fmt);           /* Format */
00455                 OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
00456                 OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
00457                 // ThOe
00458                 OUTLONG(1000*AVI->track[j].mpgrate/8);
00459                 //ThOe (/4)
00460        
00461                 OUTSHRT(sampsize/4);           /* BlockAlign */
00462        
00463        
00464                 OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
00465        
00466                 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00467        
00468                 long2str(AVI_header+strl_start-4,nhb-strl_start);
00469         }
00470    
00471         /* Finish header list */
00472    
00473         long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00474    
00475    
00476         /* Calculate the needed amount of junk bytes, output junk */
00477    
00478         njunk = HEADERBYTES - nhb - 8 - 12;
00479    
00480         /* Safety first: if njunk <= 0, somebody has played with
00481         HEADERBYTES without knowing what (s)he did.
00482         This is a fatal error */
00483    
00484         if(njunk<=0)
00485         {
00486                 fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
00487                 exit(1);
00488         }
00489    
00490         OUT4CC ("JUNK");
00491         OUTLONG(njunk);
00492         memset(AVI_header+nhb,0,njunk);
00493    
00494         nhb += njunk;
00495 
00496         /* Start the movi list */
00497 
00498         OUT4CC ("LIST");
00499         OUTLONG(movi_len); /* Length of list in bytes */
00500         OUT4CC ("movi");
00501 
00502         /* Output the header, truncate the file to the number of bytes
00503         actually written, report an error if someting goes wrong */
00504 
00505    
00506         if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
00507                 avi_write(AVI->fdes,AVI_header,HEADERBYTES)!=HEADERBYTES ||
00508                 lseek(AVI->fdes,AVI->pos,SEEK_SET)<0)
00509         {
00510                 AVI_errno = AVI_ERR_CLOSE;
00511                 return -1;
00512         }
00513 
00514         return 0;
00515 }
00516 
00517 /*
00518    first function to get called
00519    
00520    AVI_open_output_file: Open an AVI File and write a bunch
00521                          of zero bytes as space for the header.
00522                          Creates a mutex.
00523 
00524    returns a pointer to avi_t on success, a zero pointer on error
00525 */
00526 
00527 int AVI_open_output_file(struct avi_t *AVI, const char * filename)
00528 {
00529         int i;
00530         BYTE AVI_header[HEADERBYTES];
00531         //int mask = 0; 
00532    
00533         /*resets AVI struct*/ 
00534         memset((void *)AVI,0,sizeof(struct avi_t));
00535         /*create a new mutex*/
00536         AVI->closed = 0; /*opened - recordind*/
00537         
00538         /* Since Linux needs a long time when deleting big files,
00539         we do not truncate the file when we open it.
00540         Instead it is truncated when the AVI file is closed */
00541         AVI->fdes = open(filename, O_RDWR|O_CREAT,
00542                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00543         
00544         //AVI->fdes = open(filename,O_RDWR|O_CREAT|O_BINARY,0644 &~mask);
00545         if (AVI->fdes < 0)
00546         {
00547                 AVI_errno = AVI_ERR_OPEN;
00548                 //free(AVI);
00549                 return -1;
00550         }
00551 
00552         /* Write out HEADERBYTES bytes, the header will go here
00553         when we are finished with writing */
00554 
00555         for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0;
00556         i = avi_write(AVI->fdes,AVI_header,HEADERBYTES);
00557         if (i != HEADERBYTES)
00558         {
00559                 close(AVI->fdes);
00560                 AVI_errno = AVI_ERR_WRITE;
00561                 //free(AVI);
00562                 return -2;
00563         }
00564 
00565         AVI->pos  = HEADERBYTES;
00566         AVI->mode = AVI_MODE_WRITE; /* open for writing */
00567 
00568         //init
00569         AVI->anum = 0;
00570         AVI->aptr = 0;
00571         
00572         return 0;
00573 }
00574 
00575 void AVI_set_video(struct avi_t *AVI, int width, int height, double fps, char *compressor)
00576 {
00577         /* may only be called if file is open for writing */
00578 
00579         if(AVI->mode==AVI_MODE_READ) return;
00580 
00581                 AVI->width  = width;
00582                 AVI->height = height;
00583                 AVI->fps    = fps; /* just in case avi doesn't close properly */
00584                            /* it will be set at close                 */
00585                 if(strncmp(compressor, "RGB", 3)==0) 
00586                 {
00587                         memset(AVI->compressor, 0, 4);
00588                 } 
00589                 else 
00590                 {
00591                         memcpy(AVI->compressor,compressor,4);
00592                 }
00593    
00594                 AVI->compressor[4] = 0;
00595                 avi_update_header(AVI);
00596 
00597 }
00598 
00599 void AVI_set_audio(struct avi_t *AVI, int channels, long rate, int mpgrate, int bits, int format)
00600 {
00601         /* may only be called if file is open for writing */
00602 
00603         if(AVI->mode==AVI_MODE_READ) return;
00604 
00605                 //inc audio tracks
00606                 AVI->aptr=AVI->anum;
00607                 ++AVI->anum;
00608 
00609                 if(AVI->anum > AVI_MAX_TRACKS) 
00610                 {
00611                         fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
00612                         exit(1);
00613                 }
00614    
00615                 AVI->track[AVI->aptr].audio_bytes = 0;
00616                 AVI->track[AVI->aptr].a_chans = channels;
00617                 AVI->track[AVI->aptr].a_rate  = rate;
00618                 AVI->track[AVI->aptr].a_bits  = bits;
00619                 AVI->track[AVI->aptr].a_fmt   = format;
00620                 AVI->track[AVI->aptr].mpgrate = mpgrate;
00621 
00622                 avi_update_header(AVI);
00623 }
00624 
00625 /*
00626   Write the header of an AVI file and close it.
00627   returns 0 on success, -1 on write error.
00628 */
00629 
00630 static int avi_close_output_file(struct avi_t *AVI)
00631 {
00632 
00633         int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
00634         ULONG movi_len;
00635         int hdrl_start, strl_start, j;
00636         BYTE AVI_header[HEADERBYTES];
00637         long nhb;
00638         ULONG xd_size, xd_size_align2;
00639         /* Calculate length of movi list */
00640 
00641         movi_len = AVI->pos - HEADERBYTES + 4;
00642     
00643 #ifdef INFO_LIST
00644         long info_len;
00645         time_t rawtime;
00646 #endif
00647     
00648         /* Try to ouput the index entries. This may fail e.g. if no space
00649         is left on device. We will report this as an error, but we still
00650         try to write the header correctly (so that the file still may be
00651         readable in the most cases */
00652 
00653         idxerror = 0;
00654         hasIndex = 1;
00655                 
00656         ret = avi_add_chunk(AVI,(BYTE *)"idx1",(void *)AVI->idx,AVI->n_idx*16);
00657         hasIndex = (ret==0);
00658         
00659         if(ret)
00660         {
00661                 idxerror = 1;
00662                 AVI_errno = AVI_ERR_WRITE_INDEX;
00663         }
00664 
00665         /* Calculate Microseconds per frame */
00666 
00667         if(AVI->fps < 0.001) 
00668         {
00669                 frate=0;
00670                 ms_per_frame = 0;
00671         }
00672         else
00673         {
00674                 frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
00675                 ms_per_frame=(int) (1000000/AVI->fps + 0.5);
00676         }
00677 
00678         /* Prepare the file header */
00679 
00680         nhb = 0;
00681 
00682         /* The RIFF header */
00683 
00684         OUT4CC ("RIFF");
00685         OUTLONG(AVI->pos - 8);    /* # of bytes to follow */
00686         OUT4CC ("AVI ");
00687 
00688         /* Start the header list */
00689 
00690         OUT4CC ("LIST");
00691         OUTLONG(0);        /* Length of list in bytes, don't know yet */
00692         hdrl_start = nhb;  /* Store start position */
00693         OUT4CC ("hdrl");
00694 
00695         /* The main AVI header */
00696 
00697         /* The Flags in AVI File header */
00698 
00699 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
00700 #define AVIF_MUSTUSEINDEX       0x00000020
00701 #define AVIF_ISINTERLEAVED      0x00000100
00702 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
00703 #define AVIF_WASCAPTUREFILE     0x00010000
00704 #define AVIF_COPYRIGHTED        0x00020000
00705 
00706         OUT4CC ("avih");
00707         OUTLONG(56);                    /* # of bytes to follow */
00708         OUTLONG(ms_per_frame);          /* Microseconds per frame */
00709         //ThOe ->0
00710         //OUTLONG(10000000);            /* MaxBytesPerSec, I hope this will never be used */
00711         OUTLONG(0);
00712         OUTLONG(0);                     /* PaddingGranularity (whatever that might be) */
00713                                         /* Other sources call it 'reserved' */
00714         flag = AVIF_WASCAPTUREFILE;
00715         if(hasIndex) flag |= AVIF_HASINDEX;
00716         if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
00717         OUTLONG(flag);                  /* Flags */
00718         OUTLONG(AVI->video_frames);     /* TotalFrames */
00719         OUTLONG(0);                     /* InitialFrames */
00720         OUTLONG(AVI->anum+1);           /* streams audio + video */
00721         
00722         OUTLONG(0);                     /* SuggestedBufferSize */
00723         OUTLONG(AVI->width);            /* Width */
00724         OUTLONG(AVI->height);           /* Height */
00725                                         /* MS calls the following 'reserved': */
00726         OUTLONG(0);                     /* TimeScale:  Unit used to measure time */
00727         OUTLONG(0);                     /* DataRate:   Data rate of playback     */
00728         OUTLONG(0);                     /* StartTime:  Starting time of AVI data */
00729         OUTLONG(0);                     /* DataLength: Size of AVI data chunk    */
00730 
00731 
00732         /* Start the video stream list ---------------------------------- */
00733 
00734         OUT4CC ("LIST");
00735         OUTLONG(0);        /* Length of list in bytes, don't know yet */
00736         strl_start = nhb;  /* Store start position */
00737         OUT4CC ("strl");
00738 
00739         /* The video stream header */
00740 
00741         OUT4CC ("strh");
00742         OUTLONG(64);                 /* # of bytes to follow */
00743         OUT4CC ("vids");             /* Type */
00744         OUT4CC (AVI->compressor);    /* Handler */              
00745         OUTLONG(0);                  /* Flags */
00746         OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
00747         OUTLONG(0);                  /* InitialFrames */
00748         OUTLONG(FRAME_RATE_SCALE);   /* Scale */
00749         OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
00750         OUTLONG(0);                  /* Start */
00751         OUTLONG(AVI->video_frames);  /* Length */
00752         OUTLONG(AVI->max_len);       /* SuggestedBufferSize */
00753         OUTLONG(-1);                 /* Quality */
00754         OUTLONG(0);                  /* SampleSize */
00755         OUTLONG(0);                  /* Frame */
00756         OUTLONG(0);                  /* Frame */
00757         OUTLONG(0);                  /* Frame */
00758         OUTLONG(0);                  /* Frame */
00759 
00760         /* The video stream format i- this is a BITMAPINFO structure*/
00761   
00762         xd_size        = AVI->extradata_size;
00763         //printf("extra size=%d\n",xd_size);
00764         xd_size_align2 = (AVI->extradata_size+1) & ~1;
00765         
00766         OUT4CC ("strf");
00767         OUTLONG(40 + xd_size_align2);      /* # of bytes to follow (biSize) ?????*/
00768         OUTLONG(40 + xd_size);             /* biSize */
00769         OUTLONG(AVI->width);               /* biWidth */
00770         OUTLONG(AVI->height);              /* biHeight */
00771         OUTSHRT(1);                        /* Planes - allways 1 */ 
00772         OUTSHRT(24);                       /*Count - bitsperpixel - 1,4,8 or 24  32*/   
00773         if(strncmp(AVI->compressor,"DIB",3)==0) {OUTLONG (0); }    /* Compression */
00774         else { OUT4CC (AVI->compressor); }    
00775         //OUT4CC (AVI->compressor);
00776         // ThOe (*3)
00777         OUTLONG(AVI->width*AVI->height);  /* SizeImage (in bytes?) should be biSizeImage = ((((biWidth * biBitCount) + 31) & ~31) >> 3) * biHeight*/
00778         OUTLONG(0);                       /* XPelsPerMeter */
00779         OUTLONG(0);                       /* YPelsPerMeter */
00780         OUTLONG(0);                       /* ClrUsed: Number of colors used */
00781         OUTLONG(0);                       /* ClrImportant: Number of colors important */
00782 
00783         // write extradata if present
00784         if (xd_size > 0 && AVI->extradata) 
00785         {
00786                 OUTMEM(AVI->extradata, xd_size);
00787                 if (xd_size != xd_size_align2) 
00788                 {
00789                         OUTCHR(0);
00790                 }
00791         }
00792         
00793         /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00794 
00795         long2str(AVI_header+strl_start-4,nhb-strl_start);
00796    
00797         /* Start the audio stream list ---------------------------------- */
00798 
00799         for(j=0; j<AVI->anum; ++j) 
00800         {
00801 
00802                 ULONG nBlockAlign = 0;
00803                 ULONG avgbsec = 0;
00804                 ULONG scalerate = 0;
00805            
00806                 sampsize = avi_sampsize(AVI, j);
00807                 sampsize = AVI->track[j].a_fmt==0x1?sampsize*4:sampsize;
00808 
00809                 nBlockAlign = (AVI->track[j].a_rate<32000)?576:1152;
00810                 /*
00811                 printf("XXX sampsize (%d) block (%ld) rate (%ld) audio_bytes (%ld) mp3rate(%ld,%ld)\n", 
00812                  sampsize, nBlockAlign, AVI->track[j].a_rate, 
00813                  (long int)AVI->track[j].audio_bytes, 
00814                  1000*AVI->track[j].mp3rate/8, AVI->track[j].mp3rate);
00815                  */
00816            
00817                 if (AVI->track[j].a_fmt==0x1) {
00818                         sampsize = (AVI->track[j].a_chans<2)?sampsize/2:sampsize;
00819                         avgbsec = AVI->track[j].a_rate*sampsize/4;
00820                         scalerate = AVI->track[j].a_rate*sampsize/4;
00821                 } 
00822                 else
00823                 {
00824                         avgbsec = 1000*AVI->track[j].mpgrate/8;
00825                         scalerate = 1000*AVI->track[j].mpgrate/8;
00826                 }
00827 
00828                 OUT4CC ("LIST");
00829                 OUTLONG(0);        /* Length of list in bytes, don't know yet */
00830                 strl_start = nhb;  /* Store start position */
00831                 OUT4CC ("strl");
00832 
00833                 /* The audio stream header */
00834          
00835                 OUT4CC ("strh");
00836                 OUTLONG(64);            /* # of bytes to follow */
00837                 OUT4CC ("auds");
00838          
00839                 // -----------
00840                 // ThOe
00841                 OUT4CC ("\0\0\0\0");             /* Format (Optionally) */
00842                 // -----------
00843            
00844                 OUTLONG(0);             /* Flags */
00845                 OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
00846                 OUTLONG(0);             /* InitialFrames */
00847          
00848                 // VBR 
00849                 if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12 && AVI->track[j].a_vbr) 
00850                 {
00851                         OUTLONG(nBlockAlign);                   /* Scale */
00852                         OUTLONG(AVI->track[j].a_rate);          /* Rate */
00853                         OUTLONG(0);                             /* Start */
00854                         OUTLONG(AVI->track[j].audio_chunks);    /* Length */
00855                         OUTLONG(0);                             /* SuggestedBufferSize */
00856                         OUTLONG(0);                             /* Quality */
00857                         OUTLONG(0);                             /* SampleSize */
00858                         OUTLONG(0);                             /* Frame */
00859                         OUTLONG(0);                             /* Frame */
00860                         OUTLONG(0);                             /* Frame */
00861                         OUTLONG(0);                             /* Frame */
00862                 } 
00863                 else 
00864                 {
00865                         OUTLONG(sampsize/4);                    /* Scale */
00866                         OUTLONG(scalerate);                     /* Rate */
00867                         OUTLONG(0);                             /* Start */
00868                         OUTLONG(4*AVI->track[j].audio_bytes/sampsize);  /* Length */
00869                         OUTLONG(0);                             /* SuggestedBufferSize */
00870                         OUTLONG(0xffffffff);                    /* Quality */
00871                         OUTLONG(sampsize/4);                    /* SampleSize */
00872                         OUTLONG(0);                             /* Frame */
00873                         OUTLONG(0);                             /* Frame */
00874                         OUTLONG(0);                             /* Frame */
00875                         OUTLONG(0);                             /* Frame */
00876                 }
00877          
00878                 /* The audio stream format */
00879 
00880                 OUT4CC ("strf");
00881 
00882                 if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12 && AVI->track[j].a_vbr) 
00883                 {
00884 
00885                         OUTLONG(30);                            /* # of bytes to follow */ // mplayer writes 28
00886                         OUTSHRT(AVI->track[j].a_fmt);           /* Format */                  // 2
00887                         OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */      // 2
00888                         OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */           // 4
00889                         //ThOe/tibit
00890                         OUTLONG(1000*AVI->track[j].mpgrate/8);  /* maybe we should write an avg. */ // 4
00891                         OUTSHRT(nBlockAlign);                   /* BlockAlign */              // 2
00892                         OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */           // 2
00893 
00894                         OUTSHRT(12);                            /* cbSize */                   // 2
00895                         OUTSHRT(1);                             /* wID */                      // 2
00896                         OUTLONG(2);                             /* fdwFlags */                 // 4
00897                         OUTSHRT(nBlockAlign);                   /* nBlockSize */               // 2
00898                         OUTSHRT(1);                             /* nFramesPerBlock */          // 2
00899                         OUTSHRT(0);                             /* nCodecDelay */              // 2
00900                 } 
00901                 else if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12 && !AVI->track[j].a_vbr) 
00902                 {
00903                         OUTLONG(30);                            /* # of bytes to follow (30)*/
00904                         OUTSHRT(AVI->track[j].a_fmt);           /* Format */
00905                         OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
00906                         OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
00907                         //ThOe/tibit
00908                         OUTLONG(1000*AVI->track[j].mpgrate/8);
00909                         OUTSHRT(sampsize/4);                    /* BlockAlign */
00910                         OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
00911 
00912                         OUTSHRT(12);                            /* cbSize */
00913                         OUTSHRT(1);                             /* wID */
00914                         OUTLONG(2);                             /* fdwFlags */
00915                         OUTSHRT(nBlockAlign);                   /* nBlockSize */
00916                         OUTSHRT(1);                             /* nFramesPerBlock */
00917                         OUTSHRT(0);                             /* nCodecDelay */
00918                 } 
00919                 else
00920                 {
00921                         OUTLONG(18);                            /* # of bytes to follow (18)*/
00922                         OUTSHRT(AVI->track[j].a_fmt);           /* Format */
00923                         OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
00924                         OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
00925                         //ThOe/tibit
00926                         OUTLONG(avgbsec);                       /* Avg bytes/sec */
00927                         OUTSHRT(sampsize/4);                    /* BlockAlign */
00928                         OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
00929                         OUTSHRT(0);                             /* cbSize */
00930                 }
00931 
00932                 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
00933 
00934                 long2str(AVI_header+strl_start-4,nhb-strl_start);
00935 
00936         }
00937 
00938         /* Finish header list */
00939 
00940         long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00941     
00942         // add INFO list --- (0.6.0pre4)
00943 
00944 #ifdef INFO_LIST
00945         OUT4CC ("LIST");
00946    
00947         //FIXME
00948         info_len = MAX_INFO_STRLEN + 12;
00949         OUTLONG(info_len);
00950         OUT4CC ("INFO");
00951 
00952         OUT4CC ("INAM");
00953         OUTLONG(MAX_INFO_STRLEN);
00954 
00955         sprintf(id_str, "\t");
00956         memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00957         memcpy(AVI_header+nhb, id_str, strlen(id_str));
00958         nhb += MAX_INFO_STRLEN;
00959 
00960         OUT4CC ("ISFT");
00961         OUTLONG(MAX_INFO_STRLEN);
00962 
00963         sprintf(id_str, "%s-%s", PACKAGE, VERSION);
00964         memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00965         memcpy(AVI_header+nhb, id_str, strlen(id_str));
00966         nhb += MAX_INFO_STRLEN;
00967 
00968         OUT4CC ("ICMT");
00969         OUTLONG(MAX_INFO_STRLEN);
00970 
00971         time(&rawtime); 
00972         sprintf(id_str, "\t%s %s", ctime(&rawtime), "");
00973         memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
00974         memcpy(AVI_header+nhb, id_str, 25);
00975         nhb += MAX_INFO_STRLEN;
00976 #endif
00977     
00978 
00979         /* Calculate the needed amount of junk bytes, output junk */
00980 
00981         njunk = HEADERBYTES - nhb - 8 - 12;
00982 
00983         /* Safety first: if njunk <= 0, somebody has played with
00984         HEADERBYTES without knowing what (s)he did.
00985         This is a fatal error */
00986 
00987         if(njunk<=0)
00988         {
00989                 fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
00990                 exit(1);
00991         }
00992 
00993         OUT4CC ("JUNK");
00994         OUTLONG(njunk);
00995         memset(AVI_header+nhb,0,njunk);
00996         nhb += njunk;
00997 
00998         /* Start the movi list */
00999 
01000         OUT4CC ("LIST");
01001         OUTLONG(movi_len); /* Length of list in bytes */
01002         OUT4CC ("movi");
01003 
01004         /* Output the header, truncate the file to the number of bytes
01005         actually written, report an error if someting goes wrong */
01006 
01007         if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
01008                 avi_write(AVI->fdes,AVI_header,HEADERBYTES)!=HEADERBYTES ||
01009                 ftruncate(AVI->fdes,AVI->pos)<0 )   
01010         {
01011                 AVI_errno = AVI_ERR_CLOSE;
01012                 return -1;
01013         }
01014         
01015         if(idxerror) return -1;
01016 
01017         return 0;
01018 }
01019 /*
01020    avi_write_data:
01021    Add video or audio data to the file;
01022 
01023    Return values:
01024     0    No error;
01025    -1    Error, AVI_errno is set appropriatly;
01026 
01027 */
01028 
01029 static int avi_write_data(struct avi_t *AVI, BYTE *data, long length, int audio, int keyframe)
01030 {
01031         int ret=0;
01032         int n=0;
01033         char astr[5];
01034         /* Check for maximum file length */
01035 
01036         if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN )
01037         {
01038                 AVI_errno = AVI_ERR_SIZELIM;
01039                 ret=1;
01040       
01041                 /*if it is bigger than max size (1900Mb) + extra size (20 Mb) return imediatly*/
01042                 /*else still write the data but will return an error                          */ 
01043                 if ((AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > (AVI_MAX_LEN + AVI_EXTRA_SIZE)) return (-1);
01044         }
01045 
01046         //set tag for current audio track
01047         snprintf((char *)astr, sizeof(astr), "0%1dwb", (int)(AVI->aptr+1));
01048         
01049         /* Add index entry */
01050         if(audio)
01051                 n = avi_add_index_entry(AVI,(BYTE *) astr,0x00,AVI->pos,length);
01052         else
01053                 n = avi_add_index_entry(AVI,(BYTE *) "00dc",((keyframe)?0x10:0x0),AVI->pos,length);
01054 
01055         if(n) return(-1);
01056 
01057         /* Output tag and data */
01058         if(audio)
01059                 n = avi_add_chunk(AVI,(BYTE *) astr,data,length);
01060         else
01061                 n = avi_add_chunk(AVI,(BYTE *)"00dc",data,length);
01062 
01063         if (n) return(-1);
01064 
01065         return ret;
01066 }
01067 
01068 int AVI_write_frame(struct avi_t *AVI, BYTE *data, long bytes, int keyframe)
01069 {
01070         int ret=0;
01071         off_t pos;
01072 
01073         if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01074 
01075         pos = AVI->pos;
01076         ret = avi_write_data(AVI,data,bytes,0, keyframe);
01077         
01078         if(!(ret < 0)) 
01079           {
01080             AVI->last_pos = pos;
01081             AVI->last_len = bytes;
01082             AVI->video_frames++;
01083           }
01084         return ret;
01085 }
01086 
01087 int AVI_dup_frame(struct avi_t *AVI)
01088 {
01089         if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01090 
01091         if(AVI->last_pos==0) return 0; /* No previous real frame */
01092 
01093                 if(avi_add_index_entry(AVI,(BYTE *) "00dc",0x10,AVI->last_pos,AVI->last_len)) return -1;
01094                 AVI->video_frames++;
01095                 AVI->must_use_index = 1;
01096         return 0;
01097 }
01098 
01099 int AVI_write_audio(struct avi_t *AVI, BYTE *data, long bytes)
01100 {
01101         int ret=0;
01102         if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01103 
01104                 ret = avi_write_data(AVI,data,bytes,1,0);
01105    
01106                 if(!(ret<0)) 
01107                 {
01108                         AVI->track[AVI->aptr].audio_bytes += bytes;
01109                         AVI->track[AVI->aptr].audio_chunks++;
01110                 }
01111         return ret;
01112 }
01113 
01114 
01115 /*doesn't check for size limit - called when closing avi*/
01116 int AVI_append_audio(struct avi_t *AVI, BYTE *data, long bytes)
01117 {  
01118         // won't work for >2gb
01119         long i, length, pos;
01120         BYTE c[4];
01121 
01122         if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
01123   
01124         // update last index entry:
01125                 --AVI->n_idx;
01126                 length = str2ulong(AVI->idx[AVI->n_idx]+12);
01127                 pos    = str2ulong(AVI->idx[AVI->n_idx]+8);
01128 
01129                 //update;
01130                 long2str(AVI->idx[AVI->n_idx]+12,length+bytes);
01131 
01132                 ++AVI->n_idx;
01133 
01134                 AVI->track[AVI->aptr].audio_bytes += bytes;
01135 
01136                 //update chunk header
01137                 //xio_lseek(AVI->fdes, pos+4, SEEK_SET);
01138                 lseek(AVI->fdes, pos+4, SEEK_SET);      
01139                 long2str(c, length+bytes);     
01140                 avi_write(AVI->fdes, c, 4);
01141 
01142                 //xio_lseek(AVI->fdes, pos+8+length, SEEK_SET);
01143                 lseek(AVI->fdes, pos+8+length, SEEK_SET);
01144                 i=PAD_EVEN(length + bytes);
01145 
01146                 bytes = i - length;
01147                 avi_write(AVI->fdes, data, bytes);
01148                 AVI->pos = pos + 8 + i;
01149         
01150         return 0;
01151 }
01152 
01153 
01154 ULONG AVI_bytes_remain(struct avi_t *AVI)
01155 {
01156         if(AVI->mode==AVI_MODE_READ) return 0;
01157 
01158         return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
01159 }
01160 
01161 ULONG AVI_bytes_written(struct avi_t *AVI)
01162 {
01163         if(AVI->mode==AVI_MODE_READ) return 0;
01164 
01165         return (AVI->pos + 8 + 16*AVI->n_idx);
01166 }
01167 
01168 int AVI_set_audio_track(struct avi_t *AVI, int track)
01169 {
01170         if(track < 0 || track + 1 > AVI->anum) return(-1);
01171 
01172         //this info is not written to file anyway
01173         AVI->aptr=track;
01174         return 0;
01175 }
01176 
01177 void AVI_set_audio_vbr(struct avi_t *AVI, long is_vbr)
01178 {
01179         AVI->track[AVI->aptr].a_vbr = is_vbr;
01180 }
01181 
01182 
01183 /*******************************************************************
01184  *                                                                 *
01185  *    Utilities for reading video and audio from an AVI File       *
01186  *                                                                 *
01187  *******************************************************************/
01188 
01189 int AVI_close(struct avi_t *AVI)
01190 {
01191         int ret,j;
01192 
01193         /* If the file was open for writing, the header and index still have
01194         to be written */
01195         
01196                 AVI->closed = 1; /*closed - not recording*/
01197                 if(AVI->mode == AVI_MODE_WRITE)
01198                         ret = avi_close_output_file(AVI);
01199                 else
01200                         ret = 0;
01201 
01202                 /* Even if there happened a error, we first clean up */
01203                 close(AVI->fdes);
01204                 if(AVI->idx) free(AVI->idx);
01205                 if(AVI->video_index) free(AVI->video_index);
01206                 for (j=0; j<AVI->anum; j++) 
01207                 {
01208                         AVI->track[j].audio_bytes=0;  
01209                         if(AVI->track[j].audio_index) free(AVI->track[j].audio_index);
01210                 }
01211         /*free the mutex*/
01212         return ret;
01213 }
01214 
01215 
01216 #define ERR_EXIT(x) \
01217 { \
01218    AVI_close(AVI); \
01219    AVI_errno = x; \
01220    return 0; \
01221 }
01222 
01223 int AVI_getErrno() 
01224 {
01225         return AVI_errno;
01226 }
01227 
01228 /* AVI_print_error: Print most recent error (similar to perror) */
01229 
01230 char *(avi_errors[]) =
01231 {
01232   /*  0 */ "avilib - No Error",
01233   /*  1 */ "avilib - AVI file size limit reached",
01234   /*  2 */ "avilib - Error opening AVI file",
01235   /*  3 */ "avilib - Error reading from AVI file",
01236   /*  4 */ "avilib - Error writing to AVI file",
01237   /*  5 */ "avilib - Error writing index (file may still be useable)",
01238   /*  6 */ "avilib - Error closing AVI file",
01239   /*  7 */ "avilib - Operation (read/write) not permitted",
01240   /*  8 */ "avilib - Out of memory (malloc failed)",
01241   /*  9 */ "avilib - Not an AVI file",
01242   /* 10 */ "avilib - AVI file has no header list (corrupted?)",
01243   /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
01244   /* 12 */ "avilib - AVI file has no video data",
01245   /* 13 */ "avilib - operation needs an index",
01246   /* 14 */ "avilib - Unkown Error"
01247 };
01248 static int num_avi_errors = sizeof(avi_errors)/sizeof(char*);
01249 
01250 static char error_string[4096];
01251 
01252 void AVI_print_error(char *str)
01253 {
01254         int aerrno;
01255 
01256         aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
01257 
01258         fprintf(stderr,"%s: %s\n",str,avi_errors[aerrno]);
01259 
01260         /* for the following errors, perror should report a more detailed reason: */
01261 
01262         if(AVI_errno == AVI_ERR_OPEN ||
01263                 AVI_errno == AVI_ERR_READ ||
01264                 AVI_errno == AVI_ERR_WRITE ||
01265                 AVI_errno == AVI_ERR_WRITE_INDEX ||
01266                 AVI_errno == AVI_ERR_CLOSE )
01267         {
01268                 perror("REASON");
01269         }
01270 }
01271 
01272 char *AVI_strerror()
01273 {
01274         int aerrno;
01275 
01276         aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
01277 
01278         if(AVI_errno == AVI_ERR_OPEN ||
01279                 AVI_errno == AVI_ERR_READ ||
01280                 AVI_errno == AVI_ERR_WRITE ||
01281                 AVI_errno == AVI_ERR_WRITE_INDEX ||
01282                 AVI_errno == AVI_ERR_CLOSE )
01283         {
01284                 sprintf(error_string,"%s - %s",avi_errors[aerrno],strerror(errno));
01285                 return error_string;
01286         }
01287         else
01288         {
01289                 return avi_errors[aerrno];
01290         }
01291 }


corobot_camera
Author(s):
autogenerated on Wed Aug 26 2015 11:09:42