00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
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 
00041 
00042 
00043 #include "avilib.h"
00044 #include "defs.h"
00045 
00046 
00047 
00048 long AVI_errno = 0;
00049 
00050 
00051 
00052 
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 
00069 
00070 
00071 ULONG AVI_MAX_LEN = AVI_MAX_SIZE;
00072 
00073 ULONG AVI_set_MAX_LEN(ULONG len) 
00074 {
00075         
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 
00083 
00084 #define HEADERBYTES 2048
00085 
00086 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
00087 
00088 
00089 
00090 
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 
00101 
00102 
00103 static unsigned long str2ulong(BYTE *str)
00104 {
00105         return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
00106 }
00107 
00108 
00109    
00110 
00111 
00112 
00113 
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; 
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 
00147 
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         
00154 
00155 
00156         memcpy(c,tag,4);
00157         long2str(c+4,length);
00158 
00159         
00160 
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)) 
00165         {
00166                 lseek(AVI->fdes,AVI->pos,SEEK_SET);
00167                 AVI_errno = AVI_ERR_WRITE;
00168                 return -1;
00169         }
00170 
00171         
00172         AVI->pos += 8 + PAD_EVEN(length);
00173    
00174         
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         
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         
00203 
00204         AVI->n_idx++;
00205 
00206         if(len>AVI->max_len) AVI->max_len=len;
00207         
00208         return 0;
00209 }
00210 
00211 
00212 #ifndef S_IRUSR
00213 #define S_IRWXU       00700       
00214 #define S_IRUSR       00400       
00215 #define S_IWUSR       00200       
00216 #define S_IXUSR       00100       
00217 #define S_IRWXG       00070       
00218 #define S_IRGRP       00040       
00219 #define S_IWGRP       00020       
00220 #define S_IXGRP       00010       
00221 #define S_IRWXO       00007       
00222 #define S_IROTH       00004       
00223 #define S_IWOTH       00002       
00224 #define S_IXOTH       00001       
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 
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         
00265         movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
00266 
00267         
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         
00282 
00283         nhb = 0;
00284 
00285         
00286 
00287         OUT4CC ("RIFF");
00288         OUTLONG(movi_len);    
00289         OUT4CC ("AVI ");
00290 
00291         
00292 
00293         OUT4CC ("LIST");
00294         OUTLONG(0);        
00295         hdrl_start = nhb;  
00296         OUT4CC ("hdrl");
00297 
00298         
00299 
00300         
00301 
00302 #define AVIF_HASINDEX           0x00000010      
00303 #define AVIF_MUSTUSEINDEX       0x00000020
00304 #define AVIF_ISINTERLEAVED      0x00000100
00305 #define AVIF_TRUSTCKTYPE        0x00000800      
00306 #define AVIF_WASCAPTUREFILE     0x00010000
00307 #define AVIF_COPYRIGHTED        0x00020000
00308 
00309         OUT4CC ("avih");
00310         OUTLONG(56);                    
00311         OUTLONG(ms_per_frame);          
00312         
00313         
00314         OUTLONG(0);
00315         OUTLONG(0);                     
00316                                         
00317         
00318         flag = AVIF_WASCAPTUREFILE;
00319         
00320         
00321         
00322         
00323         OUTLONG(flag);                  
00324         OUTLONG(0);                     
00325         OUTLONG(0);                     
00326 
00327         OUTLONG(AVI->anum+1);           
00328 
00329         OUTLONG(0);                     
00330         OUTLONG(AVI->width);            
00331         OUTLONG(AVI->height);           
00332                                         
00333         OUTLONG(0);                     
00334         OUTLONG(0);                     
00335         OUTLONG(0);                     
00336         OUTLONG(0);                     
00337 
00338 
00339         
00340 
00341         OUT4CC ("LIST");
00342         OUTLONG(0);        
00343         strl_start = nhb;  
00344         OUT4CC ("strl");
00345 
00346         
00347 
00348         OUT4CC ("strh");
00349         OUTLONG(64);                 
00350         OUT4CC ("vids");             
00351         OUT4CC (AVI->compressor);    
00352         OUTLONG(0);                  
00353         OUTLONG(0);                  
00354         OUTLONG(0);                  
00355         OUTLONG(FRAME_RATE_SCALE);   
00356         OUTLONG(frate);              
00357         OUTLONG(0);                  
00358         OUTLONG(0);                  
00359         OUTLONG(0);                  
00360         OUTLONG(-1);                 
00361         OUTLONG(0);                  
00362         OUTLONG(0);                  
00363         OUTLONG(0);                  
00364         OUTLONG(0);                  
00365         OUTLONG(0);                  
00366 
00367         
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);
00374         OUTLONG(40 + xd_size);       
00375         OUTLONG(AVI->width);         
00376         OUTLONG(AVI->height);        
00377         OUTSHRT(1);                  
00378         OUTSHRT(24);                 
00379         if(strncmp(AVI->compressor,"DIB",3)==0) {OUTLONG (0); }    
00380         else { OUT4CC (AVI->compressor); }
00381         
00382         
00383         
00384         OUTLONG(AVI->width*AVI->height);  
00385         
00386         OUTLONG(0);                  
00387         OUTLONG(0);                  
00388         OUTLONG(0);                  
00389         OUTLONG(0);                  
00390 
00391         
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         
00402 
00403         long2str(AVI_header+strl_start-4,nhb-strl_start);
00404 
00405    
00406         
00407         
00408         for(j=0; j<AVI->anum; ++j) 
00409         {
00410 
00411                 sampsize = avi_sampsize(AVI, j);
00412                 
00413        
00414                 OUT4CC ("LIST");
00415                 OUTLONG(0);        
00416                 strl_start = nhb;  
00417                 OUT4CC ("strl");
00418        
00419                 
00420        
00421                 OUT4CC ("strh");
00422                 OUTLONG(64);            
00423                 OUT4CC ("auds");
00424        
00425                 
00426                 
00427                 OUT4CC ("\0\0\0\0");             
00428                 
00429        
00430                 OUTLONG(0);             
00431                 OUTLONG(0);             
00432                 OUTLONG(0);             
00433        
00434                 
00435                 OUTLONG(sampsize/4);      
00436                 OUTLONG(1000*AVI->track[j].mpgrate/8);
00437                 OUTLONG(0);             
00438                 OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   
00439                 OUTLONG(0);             
00440                 OUTLONG(-1);            
00441        
00442                 
00443                 OUTLONG(sampsize/4);    
00444        
00445                 OUTLONG(0);             
00446                 OUTLONG(0);             
00447                 OUTLONG(0);             
00448                 OUTLONG(0);             
00449        
00450                 
00451        
00452                 OUT4CC ("strf");
00453                 OUTLONG(16);                   
00454                 OUTSHRT(AVI->track[j].a_fmt);           
00455                 OUTSHRT(AVI->track[j].a_chans);         
00456                 OUTLONG(AVI->track[j].a_rate);          
00457                 
00458                 OUTLONG(1000*AVI->track[j].mpgrate/8);
00459                 
00460        
00461                 OUTSHRT(sampsize/4);           
00462        
00463        
00464                 OUTSHRT(AVI->track[j].a_bits);          
00465        
00466                 
00467        
00468                 long2str(AVI_header+strl_start-4,nhb-strl_start);
00469         }
00470    
00471         
00472    
00473         long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00474    
00475    
00476         
00477    
00478         njunk = HEADERBYTES - nhb - 8 - 12;
00479    
00480         
00481 
00482 
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         
00497 
00498         OUT4CC ("LIST");
00499         OUTLONG(movi_len); 
00500         OUT4CC ("movi");
00501 
00502         
00503 
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 
00519 
00520 
00521 
00522 
00523 
00524 
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         
00532    
00533          
00534         memset((void *)AVI,0,sizeof(struct avi_t));
00535         
00536         AVI->closed = 0; 
00537         
00538         
00539 
00540 
00541         AVI->fdes = open(filename, O_RDWR|O_CREAT,
00542                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00543         
00544         
00545         if (AVI->fdes < 0)
00546         {
00547                 AVI_errno = AVI_ERR_OPEN;
00548                 
00549                 return -1;
00550         }
00551 
00552         
00553 
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                 
00562                 return -2;
00563         }
00564 
00565         AVI->pos  = HEADERBYTES;
00566         AVI->mode = AVI_MODE_WRITE; 
00567 
00568         
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         
00578 
00579         if(AVI->mode==AVI_MODE_READ) return;
00580 
00581                 AVI->width  = width;
00582                 AVI->height = height;
00583                 AVI->fps    = fps; 
00584                            
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         
00602 
00603         if(AVI->mode==AVI_MODE_READ) return;
00604 
00605                 
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 
00627 
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         
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         
00649 
00650 
00651 
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         
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         
00679 
00680         nhb = 0;
00681 
00682         
00683 
00684         OUT4CC ("RIFF");
00685         OUTLONG(AVI->pos - 8);    
00686         OUT4CC ("AVI ");
00687 
00688         
00689 
00690         OUT4CC ("LIST");
00691         OUTLONG(0);        
00692         hdrl_start = nhb;  
00693         OUT4CC ("hdrl");
00694 
00695         
00696 
00697         
00698 
00699 #define AVIF_HASINDEX           0x00000010      
00700 #define AVIF_MUSTUSEINDEX       0x00000020
00701 #define AVIF_ISINTERLEAVED      0x00000100
00702 #define AVIF_TRUSTCKTYPE        0x00000800      
00703 #define AVIF_WASCAPTUREFILE     0x00010000
00704 #define AVIF_COPYRIGHTED        0x00020000
00705 
00706         OUT4CC ("avih");
00707         OUTLONG(56);                    
00708         OUTLONG(ms_per_frame);          
00709         
00710         
00711         OUTLONG(0);
00712         OUTLONG(0);                     
00713                                         
00714         flag = AVIF_WASCAPTUREFILE;
00715         if(hasIndex) flag |= AVIF_HASINDEX;
00716         if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
00717         OUTLONG(flag);                  
00718         OUTLONG(AVI->video_frames);     
00719         OUTLONG(0);                     
00720         OUTLONG(AVI->anum+1);           
00721         
00722         OUTLONG(0);                     
00723         OUTLONG(AVI->width);            
00724         OUTLONG(AVI->height);           
00725                                         
00726         OUTLONG(0);                     
00727         OUTLONG(0);                     
00728         OUTLONG(0);                     
00729         OUTLONG(0);                     
00730 
00731 
00732         
00733 
00734         OUT4CC ("LIST");
00735         OUTLONG(0);        
00736         strl_start = nhb;  
00737         OUT4CC ("strl");
00738 
00739         
00740 
00741         OUT4CC ("strh");
00742         OUTLONG(64);                 
00743         OUT4CC ("vids");             
00744         OUT4CC (AVI->compressor);                  
00745         OUTLONG(0);                  
00746         OUTLONG(0);                  
00747         OUTLONG(0);                  
00748         OUTLONG(FRAME_RATE_SCALE);   
00749         OUTLONG(frate);              
00750         OUTLONG(0);                  
00751         OUTLONG(AVI->video_frames);  
00752         OUTLONG(AVI->max_len);       
00753         OUTLONG(-1);                 
00754         OUTLONG(0);                  
00755         OUTLONG(0);                  
00756         OUTLONG(0);                  
00757         OUTLONG(0);                  
00758         OUTLONG(0);                  
00759 
00760         
00761   
00762         xd_size        = AVI->extradata_size;
00763         
00764         xd_size_align2 = (AVI->extradata_size+1) & ~1;
00765         
00766         OUT4CC ("strf");
00767         OUTLONG(40 + xd_size_align2);      
00768         OUTLONG(40 + xd_size);             
00769         OUTLONG(AVI->width);               
00770         OUTLONG(AVI->height);              
00771         OUTSHRT(1);                         
00772         OUTSHRT(24);                          
00773         if(strncmp(AVI->compressor,"DIB",3)==0) {OUTLONG (0); }    
00774         else { OUT4CC (AVI->compressor); }    
00775         
00776         
00777         OUTLONG(AVI->width*AVI->height);  
00778         OUTLONG(0);                       
00779         OUTLONG(0);                       
00780         OUTLONG(0);                       
00781         OUTLONG(0);                       
00782 
00783         
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         
00794 
00795         long2str(AVI_header+strl_start-4,nhb-strl_start);
00796    
00797         
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 
00812 
00813 
00814 
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);        
00830                 strl_start = nhb;  
00831                 OUT4CC ("strl");
00832 
00833                 
00834          
00835                 OUT4CC ("strh");
00836                 OUTLONG(64);            
00837                 OUT4CC ("auds");
00838          
00839                 
00840                 
00841                 OUT4CC ("\0\0\0\0");             
00842                 
00843            
00844                 OUTLONG(0);             
00845                 OUTLONG(0);             
00846                 OUTLONG(0);             
00847          
00848                 
00849                 if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12 && AVI->track[j].a_vbr) 
00850                 {
00851                         OUTLONG(nBlockAlign);                   
00852                         OUTLONG(AVI->track[j].a_rate);          
00853                         OUTLONG(0);                             
00854                         OUTLONG(AVI->track[j].audio_chunks);    
00855                         OUTLONG(0);                             
00856                         OUTLONG(0);                             
00857                         OUTLONG(0);                             
00858                         OUTLONG(0);                             
00859                         OUTLONG(0);                             
00860                         OUTLONG(0);                             
00861                         OUTLONG(0);                             
00862                 } 
00863                 else 
00864                 {
00865                         OUTLONG(sampsize/4);                    
00866                         OUTLONG(scalerate);                     
00867                         OUTLONG(0);                             
00868                         OUTLONG(4*AVI->track[j].audio_bytes/sampsize);  
00869                         OUTLONG(0);                             
00870                         OUTLONG(0xffffffff);                    
00871                         OUTLONG(sampsize/4);                    
00872                         OUTLONG(0);                             
00873                         OUTLONG(0);                             
00874                         OUTLONG(0);                             
00875                         OUTLONG(0);                             
00876                 }
00877          
00878                 
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);                             
00886                         OUTSHRT(AVI->track[j].a_fmt);                             
00887                         OUTSHRT(AVI->track[j].a_chans);               
00888                         OUTLONG(AVI->track[j].a_rate);                     
00889                         
00890                         OUTLONG(1000*AVI->track[j].mpgrate/8);   
00891                         OUTSHRT(nBlockAlign);                                 
00892                         OUTSHRT(AVI->track[j].a_bits);                     
00893 
00894                         OUTSHRT(12);                                               
00895                         OUTSHRT(1);                                                   
00896                         OUTLONG(2);                                              
00897                         OUTSHRT(nBlockAlign);                                  
00898                         OUTSHRT(1);                                       
00899                         OUTSHRT(0);                                           
00900                 } 
00901                 else if (AVI->track[j].a_fmt == ISO_FORMAT_MPEG12 && !AVI->track[j].a_vbr) 
00902                 {
00903                         OUTLONG(30);                            
00904                         OUTSHRT(AVI->track[j].a_fmt);           
00905                         OUTSHRT(AVI->track[j].a_chans);         
00906                         OUTLONG(AVI->track[j].a_rate);          
00907                         
00908                         OUTLONG(1000*AVI->track[j].mpgrate/8);
00909                         OUTSHRT(sampsize/4);                    
00910                         OUTSHRT(AVI->track[j].a_bits);          
00911 
00912                         OUTSHRT(12);                            
00913                         OUTSHRT(1);                             
00914                         OUTLONG(2);                             
00915                         OUTSHRT(nBlockAlign);                   
00916                         OUTSHRT(1);                             
00917                         OUTSHRT(0);                             
00918                 } 
00919                 else
00920                 {
00921                         OUTLONG(18);                            
00922                         OUTSHRT(AVI->track[j].a_fmt);           
00923                         OUTSHRT(AVI->track[j].a_chans);         
00924                         OUTLONG(AVI->track[j].a_rate);          
00925                         
00926                         OUTLONG(avgbsec);                       
00927                         OUTSHRT(sampsize/4);                    
00928                         OUTSHRT(AVI->track[j].a_bits);          
00929                         OUTSHRT(0);                             
00930                 }
00931 
00932                 
00933 
00934                 long2str(AVI_header+strl_start-4,nhb-strl_start);
00935 
00936         }
00937 
00938         
00939 
00940         long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
00941     
00942         
00943 
00944 #ifdef INFO_LIST
00945         OUT4CC ("LIST");
00946    
00947         
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         
00980 
00981         njunk = HEADERBYTES - nhb - 8 - 12;
00982 
00983         
00984 
00985 
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         
00999 
01000         OUT4CC ("LIST");
01001         OUTLONG(movi_len); 
01002         OUT4CC ("movi");
01003 
01004         
01005 
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 
01021 
01022 
01023 
01024 
01025 
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         
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                 
01042                  
01043                 if ((AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > (AVI_MAX_LEN + AVI_EXTRA_SIZE)) return (-1);
01044         }
01045 
01046         
01047         snprintf((char *)astr, sizeof(astr), "0%1dwb", (int)(AVI->aptr+1));
01048         
01049         
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         
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; 
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 
01116 int AVI_append_audio(struct avi_t *AVI, BYTE *data, long bytes)
01117 {  
01118         
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         
01125                 --AVI->n_idx;
01126                 length = str2ulong(AVI->idx[AVI->n_idx]+12);
01127                 pos    = str2ulong(AVI->idx[AVI->n_idx]+8);
01128 
01129                 
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                 
01137                 
01138                 lseek(AVI->fdes, pos+4, SEEK_SET);      
01139                 long2str(c, length+bytes);     
01140                 avi_write(AVI->fdes, c, 4);
01141 
01142                 
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         
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 
01186 
01187 
01188 
01189 int AVI_close(struct avi_t *AVI)
01190 {
01191         int ret,j;
01192 
01193         
01194 
01195         
01196                 AVI->closed = 1; 
01197                 if(AVI->mode == AVI_MODE_WRITE)
01198                         ret = avi_close_output_file(AVI);
01199                 else
01200                         ret = 0;
01201 
01202                 
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         
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 
01229 
01230 char *(avi_errors[]) =
01231 {
01232    "avilib - No Error",
01233    "avilib - AVI file size limit reached",
01234    "avilib - Error opening AVI file",
01235    "avilib - Error reading from AVI file",
01236    "avilib - Error writing to AVI file",
01237    "avilib - Error writing index (file may still be useable)",
01238    "avilib - Error closing AVI file",
01239    "avilib - Operation (read/write) not permitted",
01240    "avilib - Out of memory (malloc failed)",
01241    "avilib - Not an AVI file",
01242    "avilib - AVI file has no header list (corrupted?)",
01243    "avilib - AVI file has no MOVI list (corrupted?)",
01244    "avilib - AVI file has no video data",
01245    "avilib - operation needs an index",
01246    "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         
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 }