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 }