$search
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 }