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