4 * Copyright (C) Thomas Östreich - June 2001
5 * multiple audio track support Copyright (C) 2002 Thomas Östreich
8 * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
10 * This file is part of transcode, a linux video stream processing tool
12 * transcode is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
17 * transcode is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with GNU Make; see the file COPYING. If not, write to
24 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
33 /* The following variable indicates the kind of error */
37 #define MAX_INFO_STRLEN 64
38 static char id_str
[MAX_INFO_STRLEN
];
40 #define FRAME_RATE_SCALE 1000000
44 #define VERSION "0.00"
48 /* win32 wants a binary flag to open(); this sets it to null
49 on platforms that don't have it. */
53 /*******************************************************************
55 * Utilities for writing an AVI File *
57 *******************************************************************/
59 static size_t avi_read(int fd
, char *buf
, size_t len
)
65 n
= read (fd
, buf
+ r
, len
- r
);
75 static size_t avi_write (int fd
, char *buf
, size_t len
)
81 n
= write (fd
, buf
+ r
, len
- r
);
90 /* HEADERBYTES: The number of bytes to reserve for the header */
92 #define HEADERBYTES 2048
94 /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
95 the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */
97 #define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES)
99 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
102 /* Copy n into dst as a 4 byte, little endian number.
103 Should also work on big endian machines */
105 static void long2str(unsigned char *dst
, int n
)
108 dst
[1] = (n
>> 8)&0xff;
109 dst
[2] = (n
>>16)&0xff;
110 dst
[3] = (n
>>24)&0xff;
113 /* Convert a string of 4 or 2 bytes to a number,
114 also working on big endian machines */
116 static unsigned long str2ulong(unsigned char *str
)
118 return ( str
[0] | (str
[1]<<8) | (str
[2]<<16) | (str
[3]<<24) );
120 static unsigned long str2ushort(unsigned char *str
)
122 return ( str
[0] | (str
[1]<<8) );
125 /* Calculate audio sample size from number of bits and number of channels.
126 This may have to be adjusted for eg. 12 bits and stereo */
128 static int avi_sampsize(avi_t
*AVI
, int j
)
131 s
= ((AVI
->track
[j
].a_bits
+7)/8)*AVI
->track
[j
].a_chans
;
132 // if(s==0) s=1; /* avoid possible zero divisions */
133 if(s
<4) s
=4; /* avoid possible zero divisions */
137 /* Add a chunk (=tag and data) to the AVI file,
138 returns -1 on write error, 0 on success */
140 static int avi_add_chunk(avi_t
*AVI
, unsigned char *tag
, unsigned char *data
, int length
)
144 /* Copy tag and length int c, so that we need only 1 write system call
145 for these two values */
148 long2str(c
+4,length
);
150 /* Output tag, length and data, restore previous position
151 if the write fails */
153 length
= PAD_EVEN(length
);
155 if( avi_write(AVI
->fdes
,(char *)c
,8) != 8 ||
156 avi_write(AVI
->fdes
,(char *)data
,length
) != length
)
158 lseek(AVI
->fdes
,AVI
->pos
,SEEK_SET
);
159 AVI_errno
= AVI_ERR_WRITE
;
163 /* Update file position */
165 AVI
->pos
+= 8 + length
;
167 //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
172 static int avi_add_index_entry(avi_t
*AVI
, unsigned char *tag
, long flags
, unsigned long pos
, unsigned long len
)
176 if(AVI
->n_idx
>=AVI
->max_idx
) {
177 ptr
= realloc((void *)AVI
->idx
,(AVI
->max_idx
+4096)*16);
180 AVI_errno
= AVI_ERR_NO_MEM
;
183 AVI
->max_idx
+= 4096;
184 AVI
->idx
= (unsigned char((*)[16]) ) ptr
;
187 /* Add index entry */
189 // fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
191 memcpy(AVI
->idx
[AVI
->n_idx
],tag
,4);
192 long2str(AVI
->idx
[AVI
->n_idx
]+ 4,flags
);
193 long2str(AVI
->idx
[AVI
->n_idx
]+ 8, pos
);
194 long2str(AVI
->idx
[AVI
->n_idx
]+12, len
);
200 if(len
>AVI
->max_len
) AVI
->max_len
=len
;
206 AVI_open_output_file: Open an AVI File and write a bunch
207 of zero bytes as space for the header.
209 returns a pointer to avi_t on success, a zero pointer on error
212 avi_t
* AVI_open_output_file(char * filename
)
219 unsigned char AVI_header
[HEADERBYTES
];
221 /* Allocate the avi_t struct and zero it */
223 AVI
= (avi_t
*) malloc(sizeof(avi_t
));
226 AVI_errno
= AVI_ERR_NO_MEM
;
229 memset((void *)AVI
,0,sizeof(avi_t
));
231 /* Since Linux needs a long time when deleting big files,
232 we do not truncate the file when we open it.
233 Instead it is truncated when the AVI file is closed */
238 AVI
->fdes
= open(filename
, O_RDWR
|O_CREAT
|O_BINARY
, 0644 &~ mask
);
241 AVI_errno
= AVI_ERR_OPEN
;
246 /* Write out HEADERBYTES bytes, the header will go here
247 when we are finished with writing */
249 for (i
=0;i
<HEADERBYTES
;i
++) AVI_header
[i
] = 0;
250 i
= avi_write(AVI
->fdes
,(char *)AVI_header
,HEADERBYTES
);
251 if (i
!= HEADERBYTES
)
254 AVI_errno
= AVI_ERR_WRITE
;
259 AVI
->pos
= HEADERBYTES
;
260 AVI
->mode
= AVI_MODE_WRITE
; /* open for writing */
269 void AVI_set_video(avi_t
*AVI
, int width
, int height
, double fps
, char *compressor
)
271 /* may only be called if file is open for writing */
273 if(AVI
->mode
==AVI_MODE_READ
) return;
276 AVI
->height
= height
;
279 if(strncmp(compressor
, "RGB", 3)==0) {
280 memset(AVI
->compressor
, 0, 4);
282 memcpy(AVI
->compressor
,compressor
,4);
285 AVI
->compressor
[4] = 0;
287 avi_update_header(AVI
);
290 void AVI_set_audio(avi_t
*AVI
, int channels
, long rate
, int bits
, int format
, long mp3rate
)
292 /* may only be called if file is open for writing */
294 if(AVI
->mode
==AVI_MODE_READ
) return;
300 if(AVI
->anum
> AVI_MAX_TRACKS
) {
301 fprintf(stderr
, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS
);
305 AVI
->track
[AVI
->aptr
].a_chans
= channels
;
306 AVI
->track
[AVI
->aptr
].a_rate
= rate
;
307 AVI
->track
[AVI
->aptr
].a_bits
= bits
;
308 AVI
->track
[AVI
->aptr
].a_fmt
= format
;
309 AVI
->track
[AVI
->aptr
].mp3rate
= mp3rate
;
311 avi_update_header(AVI
);
315 if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
318 if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
321 if(nhb<=HEADERBYTES-2) { \
322 AVI_header[nhb ] = (n )&0xff; \
323 AVI_header[nhb+1] = (n>>8)&0xff; \
328 //ThOe write preliminary AVI file header: 0 frames, max vid/aud size
329 int avi_update_header(avi_t
*AVI
)
331 int njunk
, sampsize
, hasIndex
, ms_per_frame
, frate
, flag
;
332 int movi_len
, hdrl_start
, strl_start
, j
;
333 unsigned char AVI_header
[HEADERBYTES
];
337 movi_len
= AVI_MAX_LEN
- HEADERBYTES
+ 4;
339 //assume index will be written
342 if(AVI
->fps
< 0.001) {
346 frate
= (int) (FRAME_RATE_SCALE
*AVI
->fps
+ 0.5);
347 ms_per_frame
=(int) (1000000/AVI
->fps
+ 0.5);
350 /* Prepare the file header */
354 /* The RIFF header */
357 OUTLONG(movi_len
); // assume max size
360 /* Start the header list */
363 OUTLONG(0); /* Length of list in bytes, don't know yet */
364 hdrl_start
= nhb
; /* Store start position */
367 /* The main AVI header */
369 /* The Flags in AVI File header */
371 #define AVIF_HASINDEX 0x00000010 /* Index at end of file */
372 #define AVIF_MUSTUSEINDEX 0x00000020
373 #define AVIF_ISINTERLEAVED 0x00000100
374 #define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */
375 #define AVIF_WASCAPTUREFILE 0x00010000
376 #define AVIF_COPYRIGHTED 0x00020000
379 OUTLONG(56); /* # of bytes to follow */
380 OUTLONG(ms_per_frame
); /* Microseconds per frame */
382 // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */
384 OUTLONG(0); /* PaddingGranularity (whatever that might be) */
385 /* Other sources call it 'reserved' */
386 flag
= AVIF_ISINTERLEAVED
;
387 if(hasIndex
) flag
|= AVIF_HASINDEX
;
388 if(hasIndex
&& AVI
->must_use_index
) flag
|= AVIF_MUSTUSEINDEX
;
389 OUTLONG(flag
); /* Flags */
390 OUTLONG(0); // no frames yet
391 OUTLONG(0); /* InitialFrames */
393 OUTLONG(AVI
->anum
+1);
395 OUTLONG(0); /* SuggestedBufferSize */
396 OUTLONG(AVI
->width
); /* Width */
397 OUTLONG(AVI
->height
); /* Height */
398 /* MS calls the following 'reserved': */
399 OUTLONG(0); /* TimeScale: Unit used to measure time */
400 OUTLONG(0); /* DataRate: Data rate of playback */
401 OUTLONG(0); /* StartTime: Starting time of AVI data */
402 OUTLONG(0); /* DataLength: Size of AVI data chunk */
405 /* Start the video stream list ---------------------------------- */
408 OUTLONG(0); /* Length of list in bytes, don't know yet */
409 strl_start
= nhb
; /* Store start position */
412 /* The video stream header */
415 OUTLONG(56); /* # of bytes to follow */
416 OUT4CC ("vids"); /* Type */
417 OUT4CC (AVI
->compressor
); /* Handler */
418 OUTLONG(0); /* Flags */
419 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
420 OUTLONG(0); /* InitialFrames */
421 OUTLONG(FRAME_RATE_SCALE
); /* Scale */
422 OUTLONG(frate
); /* Rate: Rate/Scale == samples/second */
423 OUTLONG(0); /* Start */
424 OUTLONG(0); // no frames yet
425 OUTLONG(0); /* SuggestedBufferSize */
426 OUTLONG(-1); /* Quality */
427 OUTLONG(0); /* SampleSize */
428 OUTLONG(0); /* Frame */
429 OUTLONG(0); /* Frame */
430 // OUTLONG(0); /* Frame */
431 //OUTLONG(0); /* Frame */
433 /* The video stream format */
436 OUTLONG(40); /* # of bytes to follow */
437 OUTLONG(40); /* Size */
438 OUTLONG(AVI
->width
); /* Width */
439 OUTLONG(AVI
->height
); /* Height */
440 OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
441 OUT4CC (AVI
->compressor
); /* Compression */
443 OUTLONG(AVI
->width
*AVI
->height
*3); /* SizeImage (in bytes?) */
444 OUTLONG(0); /* XPelsPerMeter */
445 OUTLONG(0); /* YPelsPerMeter */
446 OUTLONG(0); /* ClrUsed: Number of colors used */
447 OUTLONG(0); /* ClrImportant: Number of colors important */
449 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
451 long2str(AVI_header
+strl_start
-4,nhb
-strl_start
);
454 /* Start the audio stream list ---------------------------------- */
456 for(j
=0; j
<AVI
->anum
; ++j
) {
458 sampsize
= avi_sampsize(AVI
, j
);
461 OUTLONG(0); /* Length of list in bytes, don't know yet */
462 strl_start
= nhb
; /* Store start position */
465 /* The audio stream header */
468 OUTLONG(56); /* # of bytes to follow */
473 OUTLONG(0); /* Format (Optionally) */
476 OUTLONG(0); /* Flags */
477 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
478 OUTLONG(0); /* InitialFrames */
481 OUTLONG(sampsize
/4); /* Scale */
482 OUTLONG(1000*AVI
->track
[j
].mp3rate
/8);
483 OUTLONG(0); /* Start */
484 OUTLONG(4*AVI
->track
[j
].audio_bytes
/sampsize
); /* Length */
485 OUTLONG(0); /* SuggestedBufferSize */
486 OUTLONG(-1); /* Quality */
489 OUTLONG(sampsize
/4); /* SampleSize */
491 OUTLONG(0); /* Frame */
492 OUTLONG(0); /* Frame */
493 // OUTLONG(0); /* Frame */
494 //OUTLONG(0); /* Frame */
496 /* The audio stream format */
499 OUTLONG(16); /* # of bytes to follow */
500 OUTSHRT(AVI
->track
[j
].a_fmt
); /* Format */
501 OUTSHRT(AVI
->track
[j
].a_chans
); /* Number of channels */
502 OUTLONG(AVI
->track
[j
].a_rate
); /* SamplesPerSec */
504 OUTLONG(1000*AVI
->track
[j
].mp3rate
/8);
507 OUTSHRT(sampsize
/4); /* BlockAlign */
510 OUTSHRT(AVI
->track
[j
].a_bits
); /* BitsPerSample */
512 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
514 long2str(AVI_header
+strl_start
-4,nhb
-strl_start
);
517 /* Finish header list */
519 long2str(AVI_header
+hdrl_start
-4,nhb
-hdrl_start
);
522 /* Calculate the needed amount of junk bytes, output junk */
524 njunk
= HEADERBYTES
- nhb
- 8 - 12;
526 /* Safety first: if njunk <= 0, somebody has played with
527 HEADERBYTES without knowing what (s)he did.
528 This is a fatal error */
532 fprintf(stderr
,"AVI_close_output_file: # of header bytes too small\n");
538 memset(AVI_header
+nhb
,0,njunk
);
540 //11/14/01 added id string
542 if(njunk
> strlen(id_str
)+8) {
543 sprintf(id_str
, "%s-%s", PACKAGE
, VERSION
);
544 memcpy(AVI_header
+nhb
, id_str
, strlen(id_str
));
549 /* Start the movi list */
552 OUTLONG(movi_len
); /* Length of list in bytes */
555 /* Output the header, truncate the file to the number of bytes
556 actually written, report an error if someting goes wrong */
558 if ( lseek(AVI
->fdes
,0,SEEK_SET
)<0 ||
559 avi_write(AVI
->fdes
,(char *)AVI_header
,HEADERBYTES
)!=HEADERBYTES
||
560 lseek(AVI
->fdes
,AVI
->pos
,SEEK_SET
)<0)
562 AVI_errno
= AVI_ERR_CLOSE
;
570 Write the header of an AVI file and close it.
571 returns 0 on success, -1 on write error.
574 static int avi_close_output_file(avi_t
*AVI
)
577 int ret
, njunk
, sampsize
, hasIndex
, ms_per_frame
, frate
, idxerror
, flag
;
578 unsigned long movi_len
;
579 int hdrl_start
, strl_start
, j
;
580 unsigned char AVI_header
[HEADERBYTES
];
588 /* Calculate length of movi list */
590 movi_len
= AVI
->pos
- HEADERBYTES
+ 4;
592 /* Try to ouput the index entries. This may fail e.g. if no space
593 is left on device. We will report this as an error, but we still
594 try to write the header correctly (so that the file still may be
595 readable in the most cases */
598 // fprintf(stderr, "pos=%lu, index_len=%ld \n", AVI->pos, AVI->n_idx*16);
599 ret
= avi_add_chunk(AVI
, (unsigned char *)"idx1", (void*)AVI
->idx
, AVI
->n_idx
*16);
601 //fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex);
605 AVI_errno
= AVI_ERR_WRITE_INDEX
;
608 /* Calculate Microseconds per frame */
610 if(AVI
->fps
< 0.001) {
614 frate
= (int) (FRAME_RATE_SCALE
*AVI
->fps
+ 0.5);
615 ms_per_frame
=(int) (1000000/AVI
->fps
+ 0.5);
618 /* Prepare the file header */
622 /* The RIFF header */
625 OUTLONG(AVI
->pos
- 8); /* # of bytes to follow */
628 /* Start the header list */
631 OUTLONG(0); /* Length of list in bytes, don't know yet */
632 hdrl_start
= nhb
; /* Store start position */
635 /* The main AVI header */
637 /* The Flags in AVI File header */
639 #define AVIF_HASINDEX 0x00000010 /* Index at end of file */
640 #define AVIF_MUSTUSEINDEX 0x00000020
641 #define AVIF_ISINTERLEAVED 0x00000100
642 #define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */
643 #define AVIF_WASCAPTUREFILE 0x00010000
644 #define AVIF_COPYRIGHTED 0x00020000
647 OUTLONG(56); /* # of bytes to follow */
648 OUTLONG(ms_per_frame
); /* Microseconds per frame */
650 // OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */
652 OUTLONG(0); /* PaddingGranularity (whatever that might be) */
653 /* Other sources call it 'reserved' */
654 flag
= AVIF_ISINTERLEAVED
;
655 if(hasIndex
) flag
|= AVIF_HASINDEX
;
656 if(hasIndex
&& AVI
->must_use_index
) flag
|= AVIF_MUSTUSEINDEX
;
657 OUTLONG(flag
); /* Flags */
658 OUTLONG(AVI
->video_frames
); /* TotalFrames */
659 OUTLONG(0); /* InitialFrames */
661 OUTLONG(AVI
->anum
+1);
662 // if (AVI->track[0].audio_bytes)
663 // { OUTLONG(2); } /* Streams */
665 // { OUTLONG(1); } /* Streams */
667 OUTLONG(0); /* SuggestedBufferSize */
668 OUTLONG(AVI
->width
); /* Width */
669 OUTLONG(AVI
->height
); /* Height */
670 /* MS calls the following 'reserved': */
671 OUTLONG(0); /* TimeScale: Unit used to measure time */
672 OUTLONG(0); /* DataRate: Data rate of playback */
673 OUTLONG(0); /* StartTime: Starting time of AVI data */
674 OUTLONG(0); /* DataLength: Size of AVI data chunk */
677 /* Start the video stream list ---------------------------------- */
680 OUTLONG(0); /* Length of list in bytes, don't know yet */
681 strl_start
= nhb
; /* Store start position */
684 /* The video stream header */
687 OUTLONG(56); /* # of bytes to follow */
688 OUT4CC ("vids"); /* Type */
689 OUT4CC (AVI
->compressor
); /* Handler */
690 OUTLONG(0); /* Flags */
691 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
692 OUTLONG(0); /* InitialFrames */
693 OUTLONG(FRAME_RATE_SCALE
); /* Scale */
694 OUTLONG(frate
); /* Rate: Rate/Scale == samples/second */
695 OUTLONG(0); /* Start */
696 OUTLONG(AVI
->video_frames
); /* Length */
697 OUTLONG(0); /* SuggestedBufferSize */
698 OUTLONG(-1); /* Quality */
699 OUTLONG(0); /* SampleSize */
700 OUTLONG(0); /* Frame */
701 OUTLONG(0); /* Frame */
702 // OUTLONG(0); /* Frame */
703 //OUTLONG(0); /* Frame */
705 /* The video stream format */
708 OUTLONG(40); /* # of bytes to follow */
709 OUTLONG(40); /* Size */
710 OUTLONG(AVI
->width
); /* Width */
711 OUTLONG(AVI
->height
); /* Height */
712 OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
713 OUT4CC (AVI
->compressor
); /* Compression */
715 OUTLONG(AVI
->width
*AVI
->height
*3); /* SizeImage (in bytes?) */
716 OUTLONG(0); /* XPelsPerMeter */
717 OUTLONG(0); /* YPelsPerMeter */
718 OUTLONG(0); /* ClrUsed: Number of colors used */
719 OUTLONG(0); /* ClrImportant: Number of colors important */
721 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
723 long2str(AVI_header
+strl_start
-4,nhb
-strl_start
);
725 /* Start the audio stream list ---------------------------------- */
727 for(j
=0; j
<AVI
->anum
; ++j
) {
729 //if (AVI->track[j].a_chans && AVI->track[j].audio_bytes)
732 sampsize
= avi_sampsize(AVI
, j
);
735 OUTLONG(0); /* Length of list in bytes, don't know yet */
736 strl_start
= nhb
; /* Store start position */
739 /* The audio stream header */
742 OUTLONG(56); /* # of bytes to follow */
747 OUTLONG(0); /* Format (Optionally) */
750 OUTLONG(0); /* Flags */
751 OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */
752 OUTLONG(0); /* InitialFrames */
755 OUTLONG(sampsize
/4); /* Scale */
756 OUTLONG(1000*AVI
->track
[j
].mp3rate
/8);
757 OUTLONG(0); /* Start */
758 OUTLONG(4*AVI
->track
[j
].audio_bytes
/sampsize
); /* Length */
759 OUTLONG(0); /* SuggestedBufferSize */
760 OUTLONG(-1); /* Quality */
763 OUTLONG(sampsize
/4); /* SampleSize */
765 OUTLONG(0); /* Frame */
766 OUTLONG(0); /* Frame */
767 // OUTLONG(0); /* Frame */
768 //OUTLONG(0); /* Frame */
770 /* The audio stream format */
773 OUTLONG(16); /* # of bytes to follow */
774 OUTSHRT(AVI
->track
[j
].a_fmt
); /* Format */
775 OUTSHRT(AVI
->track
[j
].a_chans
); /* Number of channels */
776 OUTLONG(AVI
->track
[j
].a_rate
); /* SamplesPerSec */
778 OUTLONG(1000*AVI
->track
[j
].mp3rate
/8);
781 OUTSHRT(sampsize
/4); /* BlockAlign */
784 OUTSHRT(AVI
->track
[j
].a_bits
); /* BitsPerSample */
786 /* Finish stream list, i.e. put number of bytes in the list to proper pos */
788 long2str(AVI_header
+strl_start
-4,nhb
-strl_start
);
791 /* Finish header list */
793 long2str(AVI_header
+hdrl_start
-4,nhb
-hdrl_start
);
796 // add INFO list --- (0.6.0pre4)
802 info_len
= MAX_INFO_STRLEN
+ 12;
807 // OUTLONG(MAX_INFO_STRLEN);
809 // sprintf(id_str, "\t");
810 // memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
811 // memcpy(AVI_header+nhb, id_str, strlen(id_str));
812 // nhb += MAX_INFO_STRLEN;
815 OUTLONG(MAX_INFO_STRLEN
);
817 sprintf(id_str
, "%s-%s", PACKAGE
, VERSION
);
818 memset(AVI_header
+nhb
, 0, MAX_INFO_STRLEN
);
819 memcpy(AVI_header
+nhb
, id_str
, strlen(id_str
));
820 nhb
+= MAX_INFO_STRLEN
;
823 // OUTLONG(MAX_INFO_STRLEN);
825 // calptr=time(NULL);
826 // sprintf(id_str, "\t%s %s", ctime(&calptr), "");
827 // memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
828 // memcpy(AVI_header+nhb, id_str, 25);
829 // nhb += MAX_INFO_STRLEN;
832 // ----------------------------
834 /* Calculate the needed amount of junk bytes, output junk */
836 njunk
= HEADERBYTES
- nhb
- 8 - 12;
838 /* Safety first: if njunk <= 0, somebody has played with
839 HEADERBYTES without knowing what (s)he did.
840 This is a fatal error */
844 fprintf(stderr
,"AVI_close_output_file: # of header bytes too small\n");
850 memset(AVI_header
+nhb
,0,njunk
);
854 /* Start the movi list */
857 OUTLONG(movi_len
); /* Length of list in bytes */
860 /* Output the header, truncate the file to the number of bytes
861 actually written, report an error if someting goes wrong */
863 if ( lseek(AVI
->fdes
,0,SEEK_SET
)<0 ||
864 avi_write(AVI
->fdes
,(char *)AVI_header
,HEADERBYTES
)!=HEADERBYTES
865 //|| ftruncate(AVI->fdes,AVI->pos)<0
868 AVI_errno
= AVI_ERR_CLOSE
;
872 if(idxerror
) return -1;
879 Add video or audio data to the file;
883 -1 Error, AVI_errno is set appropriatly;
887 static int avi_write_data(avi_t
*AVI
, char *data
, unsigned long length
, int audio
, int keyframe
)
891 unsigned char astr
[5];
893 /* Check for maximum file length */
895 if ( (AVI
->pos
+ 8 + length
+ 8 + (AVI
->n_idx
+1)*16) > AVI_MAX_LEN
) {
896 AVI_errno
= AVI_ERR_SIZELIM
;
900 /* Add index entry */
902 //set tag for current audio track
903 sprintf((char *)astr
, "0%1dwb", AVI
->aptr
+1);
906 n
= avi_add_index_entry(AVI
,astr
,0x00,AVI
->pos
,length
);
908 n
= avi_add_index_entry(AVI
,(unsigned char *) "00db",((keyframe
)?0x10:0x0),AVI
->pos
,length
);
912 /* Output tag and data */
915 n
= avi_add_chunk(AVI
,(unsigned char *) astr
, (unsigned char *)data
,length
);
917 n
= avi_add_chunk(AVI
,(unsigned char *)"00db",(unsigned char *)data
,length
);
924 int AVI_write_frame(avi_t
*AVI
, char *data
, long bytes
, int keyframe
)
928 if(AVI
->mode
==AVI_MODE_READ
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
932 if(avi_write_data(AVI
,data
,bytes
,0,keyframe
)) return -1;
935 AVI
->last_len
= bytes
;
940 int AVI_dup_frame(avi_t
*AVI
)
942 if(AVI
->mode
==AVI_MODE_READ
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
944 if(AVI
->last_pos
==0) return 0; /* No previous real frame */
945 if(avi_add_index_entry(AVI
,(unsigned char *)"00db",0x10,AVI
->last_pos
,AVI
->last_len
)) return -1;
947 AVI
->must_use_index
= 1;
951 int AVI_write_audio(avi_t
*AVI
, char *data
, long bytes
)
953 if(AVI
->mode
==AVI_MODE_READ
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
955 if( avi_write_data(AVI
,data
,bytes
,1,0) ) return -1;
956 AVI
->track
[AVI
->aptr
].audio_bytes
+= bytes
;
961 int AVI_append_audio(avi_t
*AVI
, char *data
, long bytes
)
967 if(AVI
->mode
==AVI_MODE_READ
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
969 // update last index entry:
972 length
= str2ulong(AVI
->idx
[AVI
->n_idx
]+12);
973 pos
= str2ulong(AVI
->idx
[AVI
->n_idx
]+8);
976 long2str(AVI
->idx
[AVI
->n_idx
]+12,length
+bytes
);
980 AVI
->track
[AVI
->aptr
].audio_bytes
+= bytes
;
982 //update chunk header
983 lseek(AVI
->fdes
, pos
+4, SEEK_SET
);
984 long2str(c
, length
+bytes
);
985 avi_write(AVI
->fdes
,(char *) c
, 4);
987 lseek(AVI
->fdes
, pos
+8+length
, SEEK_SET
);
989 i
=PAD_EVEN(length
+ bytes
);
992 avi_write(AVI
->fdes
, data
, bytes
);
993 AVI
->pos
= pos
+ 8 + i
;
999 long AVI_bytes_remain(avi_t
*AVI
)
1001 if(AVI
->mode
==AVI_MODE_READ
) return 0;
1003 return ( AVI_MAX_LEN
- (AVI
->pos
+ 8 + 16*AVI
->n_idx
));
1006 long AVI_bytes_written(avi_t
*AVI
)
1008 if(AVI
->mode
==AVI_MODE_READ
) return 0;
1010 return (AVI
->pos
+ 8 + 16*AVI
->n_idx
);
1013 int AVI_set_audio_track(avi_t
*AVI
, int track
)
1016 if(track
< 0 || track
+ 1 > AVI
->anum
) return(-1);
1018 //this info is not written to file anyway
1023 int AVI_get_audio_track(avi_t
*AVI
)
1029 /*******************************************************************
1031 * Utilities for reading video and audio from an AVI File *
1033 *******************************************************************/
1035 int AVI_close(avi_t
*AVI
)
1039 /* If the file was open for writing, the header and index still have
1042 if(AVI
->mode
== AVI_MODE_WRITE
)
1043 ret
= avi_close_output_file(AVI
);
1047 /* Even if there happened an error, we first clean up */
1050 if(AVI
->idx
) free(AVI
->idx
);
1051 if(AVI
->video_index
) free(AVI
->video_index
);
1053 //if(AVI->audio_index) free(AVI->audio_index);
1060 #define ERR_EXIT(x) \
1067 avi_t
*AVI_open_input_file(char *filename
, int getIndex
)
1071 /* Create avi_t structure */
1073 AVI
= (avi_t
*) malloc(sizeof(avi_t
));
1076 AVI_errno
= AVI_ERR_NO_MEM
;
1079 memset((void *)AVI
,0,sizeof(avi_t
));
1081 AVI
->mode
= AVI_MODE_READ
; /* open for reading */
1085 AVI
->fdes
= open(filename
,O_RDONLY
|O_BINARY
);
1088 AVI_errno
= AVI_ERR_OPEN
;
1093 avi_parse_input_file(AVI
, getIndex
);
1095 AVI
->aptr
=0; //reset
1100 avi_t
*AVI_open_fd(int fd
, int getIndex
)
1104 /* Create avi_t structure */
1106 AVI
= (avi_t
*) malloc(sizeof(avi_t
));
1109 AVI_errno
= AVI_ERR_NO_MEM
;
1112 memset((void *)AVI
,0,sizeof(avi_t
));
1114 AVI
->mode
= AVI_MODE_READ
; /* open for reading */
1119 avi_parse_input_file(AVI
, getIndex
);
1121 AVI
->aptr
=0; //reset
1126 int avi_parse_input_file(avi_t
*AVI
, int getIndex
)
1128 long i
, n
, rate
, scale
, idx_type
;
1129 unsigned char *hdrl_data
;
1130 long header_offset
=0, hdrl_len
=0;
1131 long nvi
, nai
[AVI_MAX_TRACKS
], ioff
;
1132 long tot
[AVI_MAX_TRACKS
];
1135 int vids_strh_seen
= 0;
1136 int vids_strf_seen
= 0;
1137 int auds_strh_seen
= 0;
1138 // int auds_strf_seen = 0;
1142 /* Read first 12 bytes and check that this is an AVI file */
1144 if( avi_read(AVI
->fdes
,data
,12) != 12 ) ERR_EXIT(AVI_ERR_READ
)
1146 if( strncasecmp(data
,"RIFF",4) !=0 ||
1147 strncasecmp(data
+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI
)
1149 /* Go through the AVI file and extract the header list,
1150 the start position of the 'movi' list and an optionally
1157 if( avi_read(AVI
->fdes
,data
,8) != 8 ) break; /* We assume it's EOF */
1159 n
= str2ulong((unsigned char *) data
+4);
1162 if(strncasecmp(data
,"LIST",4) == 0)
1164 if( avi_read(AVI
->fdes
,data
,4) != 4 ) ERR_EXIT(AVI_ERR_READ
)
1166 if(strncasecmp(data
,"hdrl",4) == 0)
1169 hdrl_data
= (unsigned char *) malloc(n
);
1170 if(hdrl_data
==0) ERR_EXIT(AVI_ERR_NO_MEM
);
1174 header_offset
= lseek(AVI
->fdes
,0,SEEK_CUR
);
1176 if( avi_read(AVI
->fdes
,(char *)hdrl_data
,n
) != n
) ERR_EXIT(AVI_ERR_READ
)
1178 else if(strncasecmp(data
,"movi",4) == 0)
1180 AVI
->movi_start
= lseek(AVI
->fdes
,0,SEEK_CUR
);
1181 lseek(AVI
->fdes
,n
,SEEK_CUR
);
1184 lseek(AVI
->fdes
,n
,SEEK_CUR
);
1186 else if(strncasecmp(data
,"idx1",4) == 0)
1188 /* n must be a multiple of 16, but the reading does not
1189 break if this is not the case */
1191 AVI
->n_idx
= AVI
->max_idx
= n
/16;
1192 AVI
->idx
= (unsigned char((*)[16]) ) malloc(n
);
1193 if(AVI
->idx
==0) ERR_EXIT(AVI_ERR_NO_MEM
)
1194 if(avi_read(AVI
->fdes
, (char *) AVI
->idx
, n
) != n
) ERR_EXIT(AVI_ERR_READ
)
1197 lseek(AVI
->fdes
,n
,SEEK_CUR
);
1200 if(!hdrl_data
) ERR_EXIT(AVI_ERR_NO_HDRL
)
1201 if(!AVI
->movi_start
) ERR_EXIT(AVI_ERR_NO_MOVI
)
1203 /* Interpret the header list */
1205 for(i
=0;i
<hdrl_len
;)
1207 /* List tags are completly ignored */
1209 if(strncasecmp((char *) hdrl_data
+i
, "LIST",4)==0) { i
+= 12; continue; }
1211 n
= str2ulong(hdrl_data
+i
+4);
1214 /* Interpret the tag and its args */
1216 if(strncasecmp((char *)hdrl_data
+i
,"strh",4)==0)
1219 if(strncasecmp((char *)hdrl_data
+i
,"vids",4) == 0 && !vids_strh_seen
)
1221 memcpy(AVI
->compressor
,hdrl_data
+i
+4,4);
1222 AVI
->compressor
[4] = 0;
1225 AVI
->v_codech_off
= header_offset
+ i
+4;
1227 scale
= str2ulong((unsigned char *)hdrl_data
+i
+20);
1228 rate
= str2ulong(hdrl_data
+i
+24);
1229 if(scale
!=0) AVI
->fps
= (double)rate
/(double)scale
;
1230 AVI
->video_frames
= str2ulong(hdrl_data
+i
+32);
1231 AVI
->video_strn
= num_stream
;
1234 lasttag
= 1; /* vids */
1236 else if (strncasecmp ((char *) hdrl_data
+i
,"auds",4) ==0 && ! auds_strh_seen
)
1240 AVI
->aptr
=AVI
->anum
;
1243 if(AVI
->anum
> AVI_MAX_TRACKS
) {
1244 fprintf(stderr
, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS
);
1248 AVI
->track
[AVI
->aptr
].audio_bytes
= str2ulong(hdrl_data
+i
+32)*avi_sampsize(AVI
, 0);
1249 AVI
->track
[AVI
->aptr
].audio_strn
= num_stream
;
1250 // auds_strh_seen = 1;
1251 lasttag
= 2; /* auds */
1254 AVI
->track
[AVI
->aptr
].a_codech_off
= header_offset
+ i
;
1261 else if(strncasecmp((char *) hdrl_data
+i
,"strf",4)==0)
1266 AVI
->width
= str2ulong(hdrl_data
+i
+4);
1267 AVI
->height
= str2ulong(hdrl_data
+i
+8);
1270 AVI
->v_codecf_off
= header_offset
+ i
+16;
1272 memcpy(AVI
->compressor2
, hdrl_data
+i
+16, 4);
1273 AVI
->compressor2
[4] = 0;
1276 else if(lasttag
== 2)
1278 AVI
->track
[AVI
->aptr
].a_fmt
= str2ushort(hdrl_data
+i
);
1281 AVI
->track
[AVI
->aptr
].a_codecf_off
= header_offset
+ i
;
1283 AVI
->track
[AVI
->aptr
].a_chans
= str2ushort(hdrl_data
+i
+2);
1284 AVI
->track
[AVI
->aptr
].a_rate
= str2ulong (hdrl_data
+i
+4);
1285 //ThOe: read mp3bitrate
1286 AVI
->track
[AVI
->aptr
].mp3rate
= 8*str2ulong(hdrl_data
+i
+8)/1000;
1288 AVI
->track
[AVI
->aptr
].a_bits
= str2ushort(hdrl_data
+i
+14);
1289 // auds_strf_seen = 1;
1304 if(!vids_strh_seen
|| !vids_strf_seen
) ERR_EXIT(AVI_ERR_NO_VIDS
)
1306 AVI
->video_tag
[0] = AVI
->video_strn
/10 + '0';
1307 AVI
->video_tag
[1] = AVI
->video_strn
%10 + '0';
1308 AVI
->video_tag
[2] = 'd';
1309 AVI
->video_tag
[3] = 'b';
1311 /* Audio tag is set to "99wb" if no audio present */
1312 if(!AVI
->track
[0].a_chans
) AVI
->track
[0].audio_strn
= 99;
1314 for(j
=0; j
<AVI
->anum
; ++j
) {
1315 AVI
->track
[j
].audio_tag
[0] = (j
+1)/10 + '0';
1316 AVI
->track
[j
].audio_tag
[1] = (j
+1)%10 + '0';
1317 AVI
->track
[j
].audio_tag
[2] = 'w';
1318 AVI
->track
[j
].audio_tag
[3] = 'b';
1321 lseek(AVI
->fdes
,AVI
->movi_start
,SEEK_SET
);
1323 /* get index if wanted */
1325 if(!getIndex
) return(0);
1327 /* if the file has an idx1, check if this is relative
1328 to the start of the file or to the start of the movi list */
1336 /* Search the first videoframe in the idx1 and look where
1337 it is in the file */
1339 for(i
=0;i
<AVI
->n_idx
;i
++)
1340 if( strncasecmp((char *) AVI
->idx
[i
],(char *) AVI
->video_tag
,3)==0 ) break;
1341 if(i
>=AVI
->n_idx
) ERR_EXIT(AVI_ERR_NO_VIDS
)
1343 pos
= str2ulong(AVI
->idx
[i
]+ 8);
1344 len
= str2ulong(AVI
->idx
[i
]+12);
1346 lseek(AVI
->fdes
,pos
,SEEK_SET
);
1347 if(avi_read(AVI
->fdes
,data
,8)!=8) ERR_EXIT(AVI_ERR_READ
)
1348 if( strncasecmp((char *)data
,(char *)AVI
->idx
[i
],4)==0 &&
1349 str2ulong((unsigned char *)data
+4)==len
)
1351 idx_type
= 1; /* Index from start of file */
1355 lseek(AVI
->fdes
,pos
+AVI
->movi_start
-4,SEEK_SET
);
1356 if(avi_read(AVI
->fdes
,data
,8)!=8) ERR_EXIT(AVI_ERR_READ
)
1357 if( strncasecmp((char *)data
,(char *)AVI
->idx
[i
],4)==0 && str2ulong((unsigned char *)data
+4)==len
)
1359 idx_type
= 2; /* Index from start of movi list */
1362 /* idx_type remains 0 if neither of the two tests above succeeds */
1367 /* we must search through the file to get the index */
1369 lseek(AVI
->fdes
, AVI
->movi_start
, SEEK_SET
);
1375 if( avi_read(AVI
->fdes
,data
,8) != 8 ) break;
1376 n
= str2ulong((unsigned char *)data
+4);
1378 /* The movi list may contain sub-lists, ignore them */
1380 if(strncasecmp(data
,"LIST",4)==0)
1382 lseek(AVI
->fdes
,4,SEEK_CUR
);
1386 /* Check if we got a tag ##db, ##dc or ##wb */
1388 if( ( (data
[2]=='d' || data
[2]=='D') &&
1389 (data
[3]=='b' || data
[3]=='B' || data
[3]=='c' || data
[3]=='C') )
1390 || ( (data
[2]=='w' || data
[2]=='W') &&
1391 (data
[3]=='b' || data
[3]=='B') ) )
1393 avi_add_index_entry(AVI
,(unsigned char *) data
,0,lseek(AVI
->fdes
,0,SEEK_CUR
)-8,n
);
1396 lseek(AVI
->fdes
,PAD_EVEN(n
),SEEK_CUR
);
1401 /* Now generate the video index and audio index arrays */
1404 for(j
=0; j
<AVI
->anum
; ++j
) nai
[j
] = 0;
1406 for(i
=0;i
<AVI
->n_idx
;i
++) {
1408 if(strncasecmp((char *)AVI
->idx
[i
],(char *) AVI
->video_tag
,3) == 0) nvi
++;
1410 for(j
=0; j
<AVI
->anum
; ++j
) if(strncasecmp((char *)AVI
->idx
[i
], AVI
->track
[j
].audio_tag
,4) == 0) nai
[j
]++;
1413 AVI
->video_frames
= nvi
;
1414 for(j
=0; j
<AVI
->anum
; ++j
) AVI
->track
[j
].audio_chunks
= nai
[j
];
1416 // fprintf(stderr, "chunks = %ld %d %s\n", AVI->track[0].audio_chunks, AVI->anum, AVI->track[0].audio_tag);
1418 if(AVI
->video_frames
==0) ERR_EXIT(AVI_ERR_NO_VIDS
);
1419 AVI
->video_index
= (video_index_entry
*) malloc(nvi
*sizeof(video_index_entry
));
1420 if(AVI
->video_index
==0) ERR_EXIT(AVI_ERR_NO_MEM
);
1422 for(j
=0; j
<AVI
->anum
; ++j
) {
1423 if(AVI
->track
[j
].audio_chunks
) {
1424 AVI
->track
[j
].audio_index
= (audio_index_entry
*) malloc(nai
[j
]*sizeof(audio_index_entry
));
1425 if(AVI
->track
[j
].audio_index
==0) ERR_EXIT(AVI_ERR_NO_MEM
);
1430 for(j
=0; j
<AVI
->anum
; ++j
) nai
[j
] = tot
[j
] = 0;
1432 ioff
= idx_type
== 1 ? 8 : AVI
->movi_start
+4;
1434 for(i
=0;i
<AVI
->n_idx
;i
++) {
1437 if(strncasecmp((char *)AVI
->idx
[i
],(char *)AVI
->video_tag
,3) == 0) {
1438 AVI
->video_index
[nvi
].key
= str2ulong(AVI
->idx
[i
]+ 4);
1439 AVI
->video_index
[nvi
].pos
= str2ulong(AVI
->idx
[i
]+ 8)+ioff
;
1440 AVI
->video_index
[nvi
].len
= str2ulong(AVI
->idx
[i
]+12);
1445 for(j
=0; j
<AVI
->anum
; ++j
) {
1447 if(strncasecmp((char *)AVI
->idx
[i
],AVI
->track
[j
].audio_tag
,4) == 0) {
1448 AVI
->track
[j
].audio_index
[nai
[j
]].pos
= str2ulong(AVI
->idx
[i
]+ 8)+ioff
;
1449 AVI
->track
[j
].audio_index
[nai
[j
]].len
= str2ulong(AVI
->idx
[i
]+12);
1450 AVI
->track
[j
].audio_index
[nai
[j
]].tot
= tot
[j
];
1451 tot
[j
] += AVI
->track
[j
].audio_index
[nai
[j
]].len
;
1458 for(j
=0; j
<AVI
->anum
; ++j
) AVI
->track
[j
].audio_bytes
= tot
[j
];
1460 /* Reposition the file */
1462 lseek(AVI
->fdes
,AVI
->movi_start
,SEEK_SET
);
1468 long AVI_video_frames(avi_t
*AVI
)
1470 return AVI
->video_frames
;
1472 int AVI_video_width(avi_t
*AVI
)
1476 int AVI_video_height(avi_t
*AVI
)
1480 double AVI_frame_rate(avi_t
*AVI
)
1484 char* AVI_video_compressor(avi_t
*AVI
)
1486 return AVI
->compressor2
;
1489 long AVI_max_video_chunk(avi_t
*AVI
)
1491 return AVI
->max_len
;
1494 int AVI_audio_tracks(avi_t
*AVI
)
1499 int AVI_audio_channels(avi_t
*AVI
)
1501 return AVI
->track
[AVI
->aptr
].a_chans
;
1504 long AVI_audio_mp3rate(avi_t
*AVI
)
1506 return AVI
->track
[AVI
->aptr
].mp3rate
;
1509 int AVI_audio_bits(avi_t
*AVI
)
1511 return AVI
->track
[AVI
->aptr
].a_bits
;
1514 int AVI_audio_format(avi_t
*AVI
)
1516 return AVI
->track
[AVI
->aptr
].a_fmt
;
1519 long AVI_audio_rate(avi_t
*AVI
)
1521 return AVI
->track
[AVI
->aptr
].a_rate
;
1524 long AVI_audio_bytes(avi_t
*AVI
)
1526 return AVI
->track
[AVI
->aptr
].audio_bytes
;
1529 long AVI_audio_chunks(avi_t
*AVI
)
1531 return AVI
->track
[AVI
->aptr
].audio_chunks
;
1534 long AVI_audio_codech_offset(avi_t
*AVI
)
1536 return AVI
->track
[AVI
->aptr
].a_codech_off
;
1539 long AVI_audio_codecf_offset(avi_t
*AVI
)
1541 return AVI
->track
[AVI
->aptr
].a_codecf_off
;
1544 long AVI_video_codech_offset(avi_t
*AVI
)
1546 return AVI
->v_codech_off
;
1549 long AVI_video_codecf_offset(avi_t
*AVI
)
1551 return AVI
->v_codecf_off
;
1554 long AVI_frame_size(avi_t
*AVI
, long frame
)
1556 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1557 if(!AVI
->video_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1559 if(frame
< 0 || frame
>= AVI
->video_frames
) return 0;
1560 return(AVI
->video_index
[frame
].len
);
1563 long AVI_audio_size(avi_t
*AVI
, long frame
)
1565 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1566 if(!AVI
->track
[AVI
->aptr
].audio_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1568 if(frame
< 0 || frame
>= AVI
->track
[AVI
->aptr
].audio_chunks
) return 0;
1569 return(AVI
->track
[AVI
->aptr
].audio_index
[frame
].len
);
1572 long AVI_get_video_position(avi_t
*AVI
, long frame
)
1574 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1575 if(!AVI
->video_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1577 if(frame
< 0 || frame
>= AVI
->video_frames
) return 0;
1578 return(AVI
->video_index
[frame
].pos
);
1582 int AVI_seek_start(avi_t
*AVI
)
1584 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1586 lseek(AVI
->fdes
,AVI
->movi_start
,SEEK_SET
);
1591 int AVI_set_video_position(avi_t
*AVI
, long frame
)
1593 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1594 if(!AVI
->video_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1596 if (frame
< 0 ) frame
= 0;
1597 AVI
->video_pos
= frame
;
1601 int AVI_set_audio_bitrate(avi_t
*AVI
, long bitrate
)
1603 if(AVI
->mode
==AVI_MODE_READ
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1605 AVI
->track
[AVI
->aptr
].mp3rate
= bitrate
;
1610 long AVI_read_frame(avi_t
*AVI
, char *vidbuf
, int *keyframe
)
1614 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1615 if(!AVI
->video_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1617 if(AVI
->video_pos
< 0 || AVI
->video_pos
>= AVI
->video_frames
) return -1;
1618 n
= AVI
->video_index
[AVI
->video_pos
].len
;
1620 *keyframe
= (AVI
->video_index
[AVI
->video_pos
].key
==0x10) ? 1:0;
1622 lseek(AVI
->fdes
, AVI
->video_index
[AVI
->video_pos
].pos
, SEEK_SET
);
1624 if (avi_read(AVI
->fdes
,vidbuf
,n
) != n
)
1626 AVI_errno
= AVI_ERR_READ
;
1635 int AVI_set_audio_position(avi_t
*AVI
, long byte
)
1639 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1640 if(!AVI
->track
[AVI
->aptr
].audio_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1642 if(byte
< 0) byte
= 0;
1644 /* Binary search in the audio chunks */
1647 n1
= AVI
->track
[AVI
->aptr
].audio_chunks
;
1652 if(AVI
->track
[AVI
->aptr
].audio_index
[n
].tot
>byte
)
1658 AVI
->track
[AVI
->aptr
].audio_posc
= n0
;
1659 AVI
->track
[AVI
->aptr
].audio_posb
= byte
- AVI
->track
[AVI
->aptr
].audio_index
[n0
].tot
;
1664 long AVI_read_audio(avi_t
*AVI
, char *audbuf
, long bytes
)
1666 long nr
, pos
, left
, todo
;
1668 if(AVI
->mode
==AVI_MODE_WRITE
) { AVI_errno
= AVI_ERR_NOT_PERM
; return -1; }
1669 if(!AVI
->track
[AVI
->aptr
].audio_index
) { AVI_errno
= AVI_ERR_NO_IDX
; return -1; }
1671 nr
= 0; /* total number of bytes read */
1675 left
= AVI
->track
[AVI
->aptr
].audio_index
[AVI
->track
[AVI
->aptr
].audio_posc
].len
- AVI
->track
[AVI
->aptr
].audio_posb
;
1678 if(AVI
->track
[AVI
->aptr
].audio_posc
>=AVI
->track
[AVI
->aptr
].audio_chunks
-1) return nr
;
1679 AVI
->track
[AVI
->aptr
].audio_posc
++;
1680 AVI
->track
[AVI
->aptr
].audio_posb
= 0;
1687 pos
= AVI
->track
[AVI
->aptr
].audio_index
[AVI
->track
[AVI
->aptr
].audio_posc
].pos
+ AVI
->track
[AVI
->aptr
].audio_posb
;
1688 lseek(AVI
->fdes
, pos
, SEEK_SET
);
1689 if (avi_read(AVI
->fdes
,audbuf
+nr
,todo
) != todo
)
1691 AVI_errno
= AVI_ERR_READ
;
1696 AVI
->track
[AVI
->aptr
].audio_posb
+= todo
;
1702 /* AVI_read_data: Special routine for reading the next audio or video chunk
1703 without having an index of the file. */
1705 int AVI_read_data(avi_t
*AVI
, char *vidbuf
, long max_vidbuf
,
1706 char *audbuf
, long max_audbuf
,
1713 * 1 = video data read
1714 * 2 = audio data read
1716 * -1 = video buffer too small
1717 * -2 = audio buffer too small
1723 if(AVI
->mode
==AVI_MODE_WRITE
) return 0;
1727 /* Read tag and length */
1729 if( avi_read(AVI
->fdes
,data
,8) != 8 ) return 0;
1731 /* if we got a list tag, ignore it */
1733 if(strncasecmp(data
,"LIST",4) == 0)
1735 lseek(AVI
->fdes
,4,SEEK_CUR
);
1739 n
= PAD_EVEN(str2ulong((unsigned char *)data
+4));
1741 if(strncasecmp(data
,AVI
->video_tag
,3) == 0)
1747 lseek(AVI
->fdes
,n
,SEEK_CUR
);
1750 if(avi_read(AVI
->fdes
,vidbuf
,n
) != n
) return 0;
1753 else if(strncasecmp(data
,AVI
->track
[AVI
->aptr
].audio_tag
,4) == 0)
1758 lseek(AVI
->fdes
,n
,SEEK_CUR
);
1761 if(avi_read(AVI
->fdes
,audbuf
,n
) != n
) return 0;
1766 if(lseek(AVI
->fdes
,n
,SEEK_CUR
)<0) return 0;
1770 /* AVI_print_error: Print most recent error (similar to perror) */
1772 char *(avi_errors
[]) =
1774 /* 0 */ "avilib - No Error",
1775 /* 1 */ "avilib - AVI file size limit reached",
1776 /* 2 */ "avilib - Error opening AVI file",
1777 /* 3 */ "avilib - Error reading from AVI file",
1778 /* 4 */ "avilib - Error writing to AVI file",
1779 /* 5 */ "avilib - Error writing index (file may still be useable)",
1780 /* 6 */ "avilib - Error closing AVI file",
1781 /* 7 */ "avilib - Operation (read/write) not permitted",
1782 /* 8 */ "avilib - Out of memory (malloc failed)",
1783 /* 9 */ "avilib - Not an AVI file",
1784 /* 10 */ "avilib - AVI file has no header list (corrupted?)",
1785 /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
1786 /* 12 */ "avilib - AVI file has no video data",
1787 /* 13 */ "avilib - operation needs an index",
1788 /* 14 */ "avilib - Unkown Error"
1790 static int num_avi_errors
= sizeof(avi_errors
)/sizeof(char*);
1792 static char error_string
[4096];
1794 void AVI_print_error(char *str
)
1798 aerrno
= (AVI_errno
>=0 && AVI_errno
<num_avi_errors
) ? AVI_errno
: num_avi_errors
-1;
1800 fprintf(stderr
,"%s: %s\n",str
,avi_errors
[aerrno
]);
1802 /* for the following errors, perror should report a more detailed reason: */
1804 if(AVI_errno
== AVI_ERR_OPEN
||
1805 AVI_errno
== AVI_ERR_READ
||
1806 AVI_errno
== AVI_ERR_WRITE
||
1807 AVI_errno
== AVI_ERR_WRITE_INDEX
||
1808 AVI_errno
== AVI_ERR_CLOSE
)
1814 char *AVI_strerror()
1818 aerrno
= (AVI_errno
>=0 && AVI_errno
<num_avi_errors
) ? AVI_errno
: num_avi_errors
-1;
1820 if(AVI_errno
== AVI_ERR_OPEN
||
1821 AVI_errno
== AVI_ERR_READ
||
1822 AVI_errno
== AVI_ERR_WRITE
||
1823 AVI_errno
== AVI_ERR_WRITE_INDEX
||
1824 AVI_errno
== AVI_ERR_CLOSE
)
1826 sprintf(error_string
,"%s - %s",avi_errors
[aerrno
],strerror(errno
));
1827 return error_string
;
1831 return avi_errors
[aerrno
];
1835 uint64_t AVI_max_size()
1837 return((uint64_t) AVI_MAX_LEN
);