1 /*
2  *  avilib.c
3  *
4  *  Copyright (C) Thomas �streich - June 2001
5  *  multiple audio track support Copyright (C) 2002 Thomas �streich
6  *
7  *  Original code:
8  *  Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
9  *
10  *  This file is part of transcode, a video stream processing tool
11  *
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)
15  *  any later version.
16  *
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.
21  *
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.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <unistd.h>
33 
34 #ifndef	O_BINARY
35 #define O_BINARY 0
36 #endif
37 
38 extern int lav_detect_endian(void);
39 
40 #include "avilib.h"
41 
42 #define INFO_LIST
43 
44 // add a new riff chunk after XX MB
45 //#define NEW_RIFF_THRES (1900*1024*1024)
46 #define NEW_RIFF_THRES (1900*1024*1024)
47 //#define NEW_RIFF_THRES (10*1024*1024)
48 
49 // Maximum number of indices per stream
50 #define NR_IXNN_CHUNKS 32
51 
52 #define DEBUG_ODML
53 #undef DEBUG_ODML
54 
55 /* The following variable indicates the kind of error */
56 
57 long AVI_errno = 0;
58 
59 #define MAX_INFO_STRLEN 64
60 static char id_str[MAX_INFO_STRLEN];
61 
62 #define FRAME_RATE_SCALE 1000000
63 
64 /*******************************************************************
65  *                                                                 *
66  *    Utilities for writing an AVI File                            *
67  *                                                                 *
68  *******************************************************************/
69 
avi_read(int fd,char * buf,size_t len)70 static ssize_t avi_read(int fd, char *buf, size_t len)
71 {
72    ssize_t n = 0;
73    ssize_t r = 0;
74 
75    while (r < len) {
76       n = read (fd, buf + r, len - r);
77       if (n == 0)
78 	  break;
79       if (n < 0) {
80 	  if (errno == EINTR)
81 	      continue;
82 	  else
83 	      break;
84       }
85 
86       r += n;
87    }
88 
89    return r;
90 }
91 
avi_write(int fd,char * buf,size_t len)92 static ssize_t avi_write (int fd, char *buf, size_t len)
93 {
94    ssize_t n = 0;
95    ssize_t r = 0;
96 
97    while (r < len) {
98       n = write (fd, buf + r, len - r);
99       if (n < 0)
100          return n;
101 
102       r += n;
103    }
104    return r;
105 }
106 
107 /* HEADERBYTES: The number of bytes to reserve for the header */
108 
109 #define HEADERBYTES 2048
110 
111 /* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below
112     the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */
113 
114 #define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES)
115 
116 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
117 
118 
119 /* Copy n into dst as a 4 or 2 byte, little endian number.
120    Should also work on big endian machines */
121 
long2str(unsigned char * dst,int32_t n)122 static void long2str(unsigned char *dst, int32_t n)
123 {
124    dst[0] = (n    )&0xff;
125    dst[1] = (n>> 8)&0xff;
126    dst[2] = (n>>16)&0xff;
127    dst[3] = (n>>24)&0xff;
128 }
129 
short2str(unsigned char * dst,int32_t n)130 static void short2str(unsigned char *dst, int32_t n)
131 {
132    dst[0] = (n    )&0xff;
133    dst[1] = (n>> 8)&0xff;
134 }
135 
136 /* Convert a string of 4 or 2 bytes to a number,
137    also working on big endian machines */
138 
str2ullong(unsigned char * str)139 static uint64_t str2ullong(unsigned char *str)
140 {
141    uint64_t r = (str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24));
142    uint64_t s = (str[4] | (str[5]<<8) | (str[6]<<16) | (str[7]<<24));
143    return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffffULL);
144 }
145 
str2ulong(unsigned char * str)146 static uint32_t str2ulong(unsigned char *str)
147 {
148    return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
149 }
str2ushort(unsigned char * str)150 static uint32_t str2ushort(unsigned char *str)
151 {
152    return ( str[0] | (str[1]<<8) );
153 }
154 
155 // bit 31 denotes a keyframe
str2ulong_len(unsigned char * str)156 static uint32_t str2ulong_len (unsigned char *str)
157 {
158    return str2ulong(str) & 0x7fffffff;
159 }
160 
161 
162 // if bit 31 is 0, its a keyframe
str2ulong_key(unsigned char * str)163 static uint32_t str2ulong_key (unsigned char *str)
164 {
165   uint32_t c = str2ulong(str);
166   c &= 0x80000000;
167   if (c == 0) return 0x10;
168   else return 0;
169 }
170 
171 /* Calculate audio sample size from number of bits and number of channels.
172    This may have to be adjusted for eg. 12 bits and stereo */
173 
avi_sampsize(avi_t * AVI,int j)174 static int avi_sampsize(avi_t *AVI, int j)
175 {
176    int s;
177    s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
178    //   if(s==0) s=1; /* avoid possible zero divisions */
179    if(s<4) s=4; /* avoid possible zero divisions */
180    return s;
181 }
182 
183 /* Add a chunk (=tag and data) to the AVI file,
184    returns -1 on write error, 0 on success */
185 
avi_add_chunk(avi_t * AVI,unsigned char * tag,unsigned char * data,int length)186 static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length)
187 {
188    unsigned char c[8];
189    char p=0;
190 
191    /* Copy tag and length int c, so that we need only 1 write system call
192       for these two values */
193 
194    memcpy(c,tag,4);
195    long2str(c+4,length);
196 
197    /* Output tag, length and data, restore previous position
198       if the write fails */
199 
200    if( avi_write(AVI->fdes,(char *)c,8) != 8 ||
201        avi_write(AVI->fdes,(char *)data,length) != length ||
202        avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte
203    {
204       lseek(AVI->fdes,AVI->pos,SEEK_SET);
205       AVI_errno = AVI_ERR_WRITE;
206       return -1;
207    }
208 
209    /* Update file position */
210 
211    AVI->pos += 8 + PAD_EVEN(length);
212 
213    //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag);
214 
215    return 0;
216 }
217 
218 #define OUTD(n) long2str(ix00+bl,n); bl+=4
219 #define OUTW(n) ix00[bl] = (n)&0xff; ix00[bl+1] = (n>>8)&0xff; bl+=2
220 #define OUTC(n) ix00[bl] = (n)&0xff; bl+=1
221 #define OUTS(s) memcpy(ix00+bl,s,4); bl+=4
222 
223 // this does the physical writeout of the ix## structure
avi_ixnn_entry(avi_t * AVI,avistdindex_chunk * ch,avisuperindex_entry * en)224 static int avi_ixnn_entry(avi_t *AVI, avistdindex_chunk *ch, avisuperindex_entry *en)
225 {
226     int bl, k;
227     unsigned int max = ch->nEntriesInUse * sizeof (uint32_t) * ch->wLongsPerEntry + 24; // header
228     char *ix00 = malloc (max);
229     char dfcc[5];
230     memcpy (dfcc, ch->fcc, 4);
231     dfcc[4] = 0;
232 
233     bl = 0;
234 
235     if (en) {
236 	en->qwOffset = AVI->pos;
237 	en->dwSize = max;
238 	//en->dwDuration = ch->nEntriesInUse -1; // NUMBER OF stream ticks == frames for video/samples for audio
239     }
240 
241 #ifdef DEBUG_ODML
242     //printf ("ODML Write %s: Entries %ld size %d \n", dfcc, ch->nEntriesInUse, max);
243 #endif
244 
245     //OUTS(ch->fcc);
246     //OUTD(max);
247     OUTW(ch->wLongsPerEntry);
248     OUTC(ch->bIndexSubType);
249     OUTC(ch->bIndexType);
250     OUTD(ch->nEntriesInUse);
251     OUTS(ch->dwChunkId);
252     OUTD(ch->qwBaseOffset&0xffffffff);
253     OUTD((ch->qwBaseOffset>>32)&0xffffffff);
254     OUTD(ch->dwReserved3);
255 
256     for (k = 0; k < ch->nEntriesInUse; k++) {
257 	OUTD(ch->aIndex[k].dwOffset);
258 	OUTD(ch->aIndex[k].dwSize);
259 
260     }
261     avi_add_chunk (AVI, ch->fcc, ix00, max);
262 
263     free(ix00);
264 
265     return 0;
266 }
267 #undef OUTS
268 #undef OUTW
269 #undef OUTD
270 #undef OUTC
271 
272 // inits a super index structure including its enclosed stdindex
avi_init_super_index(avi_t * AVI,unsigned char * idxtag,avisuperindex_chunk ** si)273 static int avi_init_super_index(avi_t *AVI, unsigned char *idxtag, avisuperindex_chunk **si)
274 {
275     int k;
276 
277     avisuperindex_chunk *sil = NULL;
278 
279     if ((sil = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk))) == NULL) {
280 	AVI_errno = AVI_ERR_NO_MEM;
281 	return -1;
282     }
283     memset(sil, 0, sizeof (avisuperindex_chunk));
284     memcpy (sil->fcc, "indx", 4);
285     sil->dwSize = 0; // size of this chunk
286     sil->wLongsPerEntry = 4;
287     sil->bIndexSubType = 0;
288     sil->bIndexType = AVI_INDEX_OF_INDEXES;
289     sil->nEntriesInUse = 0; // none are in use
290     memcpy (sil->dwChunkId, idxtag, 4);
291     memset (sil->dwReserved, 0, sizeof (sil->dwReserved));
292 
293     // NR_IXNN_CHUNKS == allow 32 indices which means 32 GB files -- arbitrary
294     sil->aIndex = malloc (sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t));
295     if (!sil->aIndex) {
296 	AVI_errno = AVI_ERR_NO_MEM;
297 	return -1;
298     }
299     memset (sil->aIndex, 0, sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (uint32_t));
300 
301     sil->stdindex = malloc (NR_IXNN_CHUNKS * sizeof (avistdindex_chunk *));
302     if (!sil->stdindex) {
303 	AVI_errno = AVI_ERR_NO_MEM;
304 	return -1;
305     }
306     for (k = 0; k < NR_IXNN_CHUNKS; k++) {
307 	sil->stdindex[k] = malloc (sizeof (avistdindex_chunk));
308 	memset(sil->stdindex[k], 0, sizeof (avistdindex_chunk));
309 	// gets rewritten later
310 	sil->stdindex[k]->qwBaseOffset = (uint64_t)k * NEW_RIFF_THRES;
311     }
312 
313     *si = sil;
314 
315     return 0;
316 }
317 
318 // fills an alloc'ed stdindex structure and mallocs some entries for the actual chunks
avi_add_std_index(avi_t * AVI,unsigned char * idxtag,unsigned char * strtag,avistdindex_chunk * stdil)319 static int avi_add_std_index(avi_t *AVI, unsigned char *idxtag, unsigned char *strtag,
320 	avistdindex_chunk *stdil)
321 {
322 
323     memcpy (stdil->fcc, idxtag, 4);
324     stdil->dwSize = 4096;
325     stdil->wLongsPerEntry = 2; //sizeof(avistdindex_entry)/sizeof(uint32_t);
326     stdil->bIndexSubType = 0;
327     stdil->bIndexType = AVI_INDEX_OF_CHUNKS;
328     stdil->nEntriesInUse = 0;
329 
330     // cp 00db ChunkId
331     memcpy(stdil->dwChunkId, strtag, 4);
332 
333     //stdil->qwBaseOffset = AVI->video_superindex->aIndex[ cur_std_idx ]->qwOffset;
334 
335     stdil->aIndex = malloc(stdil->dwSize * sizeof (uint32_t) * stdil->wLongsPerEntry);
336 
337     if (!stdil->aIndex) {
338 	AVI_errno = AVI_ERR_NO_MEM;
339 	return -1;
340     }
341 
342 
343     return 0;
344 }
345 
avi_add_odml_index_entry_core(avi_t * AVI,long flags,off_t pos,unsigned long len,avistdindex_chunk * si)346 static int avi_add_odml_index_entry_core(avi_t *AVI, long flags, off_t pos, unsigned long len, avistdindex_chunk *si)
347 {
348     int cur_chunk_idx;
349     // put new chunk into index
350     si->nEntriesInUse++;
351     cur_chunk_idx = si->nEntriesInUse-1;
352 
353     // need to fetch more memory
354     if (cur_chunk_idx >= si->dwSize) {
355 	si->dwSize += 4096;
356 	si->aIndex = realloc ( si->aIndex, si->dwSize * sizeof (uint32_t) * si->wLongsPerEntry);
357     }
358 
359     if(len>AVI->max_len) AVI->max_len=len;
360 
361     // if bit 31 is set, it is NOT a keyframe
362     if (flags != 0x10) {
363 	len |= 0x80000000;
364     }
365 
366     si->aIndex [ cur_chunk_idx ].dwSize = len;
367     si->aIndex [ cur_chunk_idx ].dwOffset =
368 	pos - si->qwBaseOffset + 8;
369 
370     //printf("ODML: POS: 0x%lX\n", si->aIndex [ cur_chunk_idx ].dwOffset);
371 
372     return 0;
373 }
374 
avi_add_odml_index_entry(avi_t * AVI,unsigned char * tag,long flags,off_t pos,unsigned long len)375 static int avi_add_odml_index_entry(avi_t *AVI, unsigned char *tag, long flags, off_t pos, unsigned long len)
376 {
377     char fcc[5];
378 
379     int audio = (strchr (tag, 'w')?1:0);
380     int video = !audio;
381 
382     unsigned int cur_std_idx;
383     int audtr;
384     off_t towrite = 0LL;
385 
386     if (video) {
387 
388 	if (!AVI->video_superindex) {
389 	    if (avi_init_super_index(AVI, "ix00", &AVI->video_superindex) < 0) return -1;
390              AVI->video_superindex->nEntriesInUse++;
391 	    cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
392 
393 	    if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
394 		return -1;
395 	} // init
396 
397     } // video
398 
399     if (audio) {
400 
401 	fcc[0] = 'i'; fcc[1] = 'x'; fcc[2] = tag[0]; fcc[3] = tag[1]; fcc[4] = '\0';
402 	if (!AVI->track[AVI->aptr].audio_superindex) {
403 
404 #ifdef DEBUG_ODML
405 	    printf("ODML: fcc = %s\n", fcc);
406 #endif
407 	    if (avi_init_super_index(AVI, fcc, &AVI->track[AVI->aptr].audio_superindex) < 0) return -1;
408 
409 
410 	    AVI->track[AVI->aptr].audio_superindex->nEntriesInUse++;
411 
412 	    snprintf(fcc, sizeof(fcc), "ix%02d", AVI->aptr+1);
413 	    if (avi_add_std_index (AVI, fcc, tag, AVI->track[AVI->aptr].audio_superindex->stdindex[
414 			AVI->track[AVI->aptr].audio_superindex->nEntriesInUse - 1 ]) < 0
415 	       ) return -1;
416 	} // init
417 
418     }
419 
420     towrite = 0;
421     if (AVI->video_superindex) {
422 
423 	cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
424 	towrite += AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
425 	    + 4+4+2+1+1+4+4+8+4;
426 	if (cur_std_idx == 0) {
427 	    towrite += AVI->n_idx*16 + 8;
428 	    towrite += HEADERBYTES;
429 	}
430     }
431 
432     for (audtr=0; audtr<AVI->anum; audtr++) {
433 	if (AVI->track[audtr].audio_superindex) {
434 	    cur_std_idx = AVI->track[audtr].audio_superindex->nEntriesInUse-1;
435 	    towrite += AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
436 		+ 4+4+2+1+1+4+4+8+4;
437 	}
438     }
439     towrite += len + (len&1) + 8;
440 
441     //printf("ODML: towrite = 0x%llX = %lld\n", towrite, towrite);
442 
443     if (AVI->video_superindex &&
444 	    (off_t)(AVI->pos+towrite) > (off_t)((off_t)NEW_RIFF_THRES*AVI->video_superindex->nEntriesInUse)) {
445 
446 	fprintf(stderr, "Adding a new RIFF chunk: %d\n", AVI->video_superindex->nEntriesInUse);
447 
448 	// rotate ALL indices
449 	AVI->video_superindex->nEntriesInUse++;
450 	cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
451 
452 	if (AVI->video_superindex->nEntriesInUse > NR_IXNN_CHUNKS) {
453 	    fprintf (stderr, "Internal error in avilib - redefine NR_IXNN_CHUNKS\n");
454 	    fprintf (stderr, "[avilib dump] cur_std_idx=%d NR_IXNN_CHUNKS=%d"
455 		    "POS=%lld towrite=%lld\n",
456 		    cur_std_idx,NR_IXNN_CHUNKS, AVI->pos, towrite);
457 	    return -1;
458 	}
459 
460 	if (avi_add_std_index (AVI, "ix00", "00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
461 	    return -1;
462 
463 	for (audtr = 0; audtr < AVI->anum; audtr++) {
464 	    char aud[5];
465 	    if (!AVI->track[audtr].audio_superindex) {
466 		// not initialized -> no index
467 		continue;
468 	    }
469 	    AVI->track[audtr].audio_superindex->nEntriesInUse++;
470 
471 	    snprintf(fcc, sizeof(fcc), "ix%02d", audtr+1);
472 	    snprintf(aud, sizeof(aud), "0%01dwb", audtr+1);
473 	    if (avi_add_std_index (AVI, fcc, aud, AVI->track[audtr].audio_superindex->stdindex[
474 			AVI->track[audtr].audio_superindex->nEntriesInUse - 1 ]) < 0
475 	       ) return -1;
476 	}
477 
478 	// write the new riff;
479 	if (cur_std_idx > 0) {
480 
481 	    // dump the _previous_ == already finished index
482 	    avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx - 1],
483 		    &AVI->video_superindex->aIndex[cur_std_idx - 1]);
484 	    AVI->video_superindex->aIndex[cur_std_idx - 1].dwDuration =
485 		AVI->video_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
486 
487 	    for (audtr = 0; audtr < AVI->anum; audtr++) {
488 
489 		if (!AVI->track[audtr].audio_superindex) {
490 		    // not initialized -> no index
491 		    continue;
492 		}
493 		avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1],
494 			&AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1]);
495 
496 		AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration =
497 		    AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
498 		if (AVI->track[audtr].a_fmt == 0x1) {
499 		    AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration *=
500 			AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
501 		}
502 	    }
503 
504 	    // XXX: dump idx1 structure
505 	    if (cur_std_idx == 1) {
506 		avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
507 		// qwBaseOffset will contain the start of the second riff chunk
508 	    }
509 	    // Fix the Offsets later at closing time
510 	    avi_add_chunk(AVI, (unsigned char *)"RIFF", "AVIXLIST\0\0\0\0movi", 16);
511 
512 	    AVI->video_superindex->stdindex[ cur_std_idx ]->qwBaseOffset = AVI->pos -16 -8;
513 #ifdef DEBUG_ODML
514 	    printf("ODML: RIFF No.%02d at Offset 0x%llX\n", cur_std_idx, AVI->pos -16 -8);
515 #endif
516 
517 	    for (audtr = 0; audtr < AVI->anum; audtr++) {
518 		if (AVI->track[audtr].audio_superindex)
519 		    AVI->track[audtr].audio_superindex->stdindex[ cur_std_idx ]->qwBaseOffset =
520 			AVI->pos -16 -8;
521 
522 	    }
523 
524 	    // now we can be sure
525 	    AVI->is_opendml++;
526 	}
527 
528     }
529 
530 
531     if (video) {
532 	avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
533 		AVI->video_superindex->stdindex[ AVI->video_superindex->nEntriesInUse-1 ]);
534 
535 	AVI->total_frames++;
536     } // video
537 
538     if (audio) {
539 	avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
540 		AVI->track[AVI->aptr].audio_superindex->stdindex[
541 		        AVI->track[AVI->aptr].audio_superindex->nEntriesInUse-1 ]);
542     }
543 
544 
545     return 0;
546 }
547 
548 // #undef NR_IXNN_CHUNKS
549 
avi_add_index_entry(avi_t * AVI,unsigned char * tag,long flags,unsigned long pos,unsigned long len)550 static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned long len)
551 {
552    void *ptr;
553 
554    if(AVI->n_idx>=AVI->max_idx) {
555      ptr = realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
556 
557      if(ptr == 0) {
558        AVI_errno = AVI_ERR_NO_MEM;
559        return -1;
560      }
561      AVI->max_idx += 4096;
562      AVI->idx = (unsigned char((*)[16]) ) ptr;
563    }
564 
565    /* Add index entry */
566 
567    //   fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len);
568 
569    memcpy(AVI->idx[AVI->n_idx],tag,4);
570    long2str(AVI->idx[AVI->n_idx]+ 4,flags);
571    long2str(AVI->idx[AVI->n_idx]+ 8, pos);
572    long2str(AVI->idx[AVI->n_idx]+12, len);
573 
574    /* Update counter */
575 
576    AVI->n_idx++;
577 
578    if(len>AVI->max_len) AVI->max_len=len;
579 
580    return 0;
581 }
582 
583 /* Returns 1 if more audio is in that video junk */
AVI_can_read_audio(avi_t * AVI)584 int AVI_can_read_audio(avi_t *AVI)
585 {
586    if(AVI->mode==AVI_MODE_WRITE) { return -1; }
587    if(!AVI->video_index)         { return -1; }
588    if(!AVI->track[AVI->aptr].audio_index)         { return -1; }
589 
590    // is it -1? the last ones got left out --tibit
591    //if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) {
592    if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks) {
593        return 0;
594    }
595 
596    if (AVI->video_pos >= AVI->video_frames) return 1;
597 
598    if (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos < AVI->video_index[AVI->video_pos].pos) return 1;
599    else return 0;
600 }
601 /*
602    AVI_open_output_file: Open an AVI File and write a bunch
603                          of zero bytes as space for the header.
604 
605    returns a pointer to avi_t on success, a zero pointer on error
606 */
607 
AVI_open_output_file(char * filename)608 avi_t* AVI_open_output_file(char * filename)
609 {
610    avi_t *AVI;
611    int i;
612 
613    unsigned char AVI_header[HEADERBYTES];
614 
615    /* Allocate the avi_t struct and zero it */
616 
617    AVI = (avi_t *) malloc(sizeof(avi_t));
618    if(AVI==0)
619    {
620       AVI_errno = AVI_ERR_NO_MEM;
621       return 0;
622    }
623    memset((void *)AVI,0,sizeof(avi_t));
624 
625    /* Since Linux needs a long time when deleting big files,
626       we do not truncate the file when we open it.
627       Instead it is truncated when the AVI file is closed */
628 
629    AVI->fdes = open(filename, O_RDWR|O_CREAT|O_BINARY, 0664);
630 
631    if (AVI->fdes < 0)
632    {
633       AVI_errno = AVI_ERR_OPEN;
634       free(AVI);
635       return 0;
636    }
637 
638    /* Write out HEADERBYTES bytes, the header will go here
639       when we are finished with writing */
640 
641    for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0;
642    i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES);
643    if (i != HEADERBYTES)
644    {
645       close(AVI->fdes);
646       AVI_errno = AVI_ERR_WRITE;
647       free(AVI);
648       return 0;
649    }
650 
651    AVI->pos  = HEADERBYTES;
652    AVI->mode = AVI_MODE_WRITE; /* open for writing */
653 
654    //init
655    AVI->anum = 0;
656    AVI->aptr = 0;
657 
658    return AVI;
659 }
660 
AVI_set_video(avi_t * AVI,int width,int height,double fps,char * compressor)661 void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor)
662 {
663    /* may only be called if file is open for writing */
664 
665    if(AVI->mode==AVI_MODE_READ) return;
666 
667    AVI->width  = width;
668    AVI->height = height;
669    AVI->fps    = fps;
670 
671    if(strncmp(compressor, "RGB", 3)==0) {
672      memset(AVI->compressor, 0, 4);
673    } else {
674      memcpy(AVI->compressor,compressor,4);
675    }
676 
677    AVI->compressor[4] = 0;
678 
679    avi_update_header(AVI);
680 }
681 
AVI_set_audio(avi_t * AVI,int channels,long rate,int bits,int format,long mp3rate)682 void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate)
683 {
684    /* may only be called if file is open for writing */
685 
686    if(AVI->mode==AVI_MODE_READ) return;
687 
688    //inc audio tracks
689    AVI->aptr=AVI->anum;
690    ++AVI->anum;
691 
692    if(AVI->anum > AVI_MAX_TRACKS) {
693      fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
694      exit(1);
695    }
696 
697    AVI->track[AVI->aptr].a_chans = channels;
698    AVI->track[AVI->aptr].a_rate  = rate;
699    AVI->track[AVI->aptr].a_bits  = bits;
700    AVI->track[AVI->aptr].a_fmt   = format;
701    AVI->track[AVI->aptr].mp3rate = mp3rate;
702 
703    avi_update_header(AVI);
704 }
705 
706 #define OUT4CC(s) \
707    if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
708 
709 #define OUTLONG(n) \
710    if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb,n); nhb += 4
711 
712 #define OUTSHRT(n) \
713    if(nhb<=HEADERBYTES-2) { \
714       AVI_header[nhb  ] = (n   )&0xff; \
715       AVI_header[nhb+1] = (n>>8)&0xff; \
716    } \
717    nhb += 2
718 
719 #define OUTCHR(n) \
720    if(nhb<=HEADERBYTES-1) { \
721       AVI_header[nhb  ] = (n   )&0xff; \
722    } \
723    nhb += 1
724 
725 #define OUTMEM(d, s) \
726    { \
727      unsigned int s_ = (s); \
728      if(nhb <= HEADERBYTES-s_) \
729         memcpy(AVI_header+nhb, (d), s_); \
730      nhb += s_; \
731    }
732 
733 
734 //ThOe write preliminary AVI file header: 0 frames, max vid/aud size
avi_update_header(avi_t * AVI)735 int avi_update_header(avi_t *AVI)
736 {
737    int njunk, sampsize, hasIndex, ms_per_frame, frate, flag;
738    int movi_len, hdrl_start, strl_start, j;
739    unsigned char AVI_header[HEADERBYTES];
740    long nhb;
741    unsigned long xd_size, xd_size_align2;
742 
743    //assume max size
744    movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
745 
746    //assume index will be written
747    hasIndex=1;
748 
749    if(AVI->fps < 0.001) {
750      frate=0;
751      ms_per_frame=0;
752    } else {
753      frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
754      ms_per_frame=(int) (1000000/AVI->fps + 0.5);
755    }
756 
757    /* Prepare the file header */
758 
759    nhb = 0;
760 
761    /* The RIFF header */
762 
763    OUT4CC ("RIFF");
764    OUTLONG(movi_len);    // assume max size
765    OUT4CC ("AVI ");
766 
767    /* Start the header list */
768 
769    OUT4CC ("LIST");
770    OUTLONG(0);        /* Length of list in bytes, don't know yet */
771    hdrl_start = nhb;  /* Store start position */
772    OUT4CC ("hdrl");
773 
774    /* The main AVI header */
775 
776    /* The Flags in AVI File header */
777 
778 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
779 #define AVIF_MUSTUSEINDEX       0x00000020
780 #define AVIF_ISINTERLEAVED      0x00000100
781 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
782 #define AVIF_WASCAPTUREFILE     0x00010000
783 #define AVIF_COPYRIGHTED        0x00020000
784 
785    OUT4CC ("avih");
786    OUTLONG(56);                 /* # of bytes to follow */
787    OUTLONG(ms_per_frame);       /* Microseconds per frame */
788    //ThOe ->0
789    //   OUTLONG(10000000);           /* MaxBytesPerSec, I hope this will never be used */
790    OUTLONG(0);
791    OUTLONG(0);                  /* PaddingGranularity (whatever that might be) */
792                                 /* Other sources call it 'reserved' */
793    flag = AVIF_ISINTERLEAVED;
794    if(hasIndex) flag |= AVIF_HASINDEX;
795    if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
796    OUTLONG(flag);               /* Flags */
797    OUTLONG(0);                  // no frames yet
798    OUTLONG(0);                  /* InitialFrames */
799 
800    OUTLONG(AVI->anum+1);
801 
802    OUTLONG(0);                  /* SuggestedBufferSize */
803    OUTLONG(AVI->width);         /* Width */
804    OUTLONG(AVI->height);        /* Height */
805                                 /* MS calls the following 'reserved': */
806    OUTLONG(0);                  /* TimeScale:  Unit used to measure time */
807    OUTLONG(0);                  /* DataRate:   Data rate of playback     */
808    OUTLONG(0);                  /* StartTime:  Starting time of AVI data */
809    OUTLONG(0);                  /* DataLength: Size of AVI data chunk    */
810 
811 
812    /* Start the video stream list ---------------------------------- */
813 
814    OUT4CC ("LIST");
815    OUTLONG(0);        /* Length of list in bytes, don't know yet */
816    strl_start = nhb;  /* Store start position */
817    OUT4CC ("strl");
818 
819    /* The video stream header */
820 
821    OUT4CC ("strh");
822    OUTLONG(56);                 /* # of bytes to follow */
823    OUT4CC ("vids");             /* Type */
824    OUT4CC (AVI->compressor);    /* Handler */
825    OUTLONG(0);                  /* Flags */
826    OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
827    OUTLONG(0);                  /* InitialFrames */
828    OUTLONG(FRAME_RATE_SCALE);              /* Scale */
829    OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
830    OUTLONG(0);                  /* Start */
831    OUTLONG(0);                  // no frames yet
832    OUTLONG(0);                  /* SuggestedBufferSize */
833    OUTLONG(-1);                 /* Quality */
834    OUTLONG(0);                  /* SampleSize */
835    OUTLONG(0);                  /* Frame */
836    OUTLONG(0);                  /* Frame */
837    //   OUTLONG(0);                  /* Frame */
838    //OUTLONG(0);                  /* Frame */
839 
840    /* The video stream format */
841 
842    xd_size        = AVI->extradata_size;
843    xd_size_align2 = (AVI->extradata_size+1) & ~1;
844 
845    OUT4CC ("strf");
846    OUTLONG(40 + xd_size_align2);/* # of bytes to follow */
847    OUTLONG(40 + xd_size);	/* Size */
848    OUTLONG(AVI->width);         /* Width */
849    OUTLONG(AVI->height);        /* Height */
850    OUTSHRT(1); OUTSHRT(24);     /* Planes, Count */
851    OUT4CC (AVI->compressor);    /* Compression */
852    // ThOe (*3)
853    OUTLONG(AVI->width*AVI->height*3);  /* SizeImage (in bytes?) */
854    OUTLONG(0);                  /* XPelsPerMeter */
855    OUTLONG(0);                  /* YPelsPerMeter */
856    OUTLONG(0);                  /* ClrUsed: Number of colors used */
857    OUTLONG(0);                  /* ClrImportant: Number of colors important */
858 
859    // write extradata
860    if (xd_size > 0 && AVI->extradata) {
861       OUTMEM(AVI->extradata, xd_size);
862       if (xd_size != xd_size_align2) {
863          OUTCHR(0);
864       }
865    }
866 
867    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
868 
869    long2str(AVI_header+strl_start-4,nhb-strl_start);
870 
871 
872    /* Start the audio stream list ---------------------------------- */
873 
874    for(j=0; j<AVI->anum; ++j) {
875 
876        sampsize = avi_sampsize(AVI, j);
877 
878        OUT4CC ("LIST");
879        OUTLONG(0);        /* Length of list in bytes, don't know yet */
880        strl_start = nhb;  /* Store start position */
881        OUT4CC ("strl");
882 
883        /* The audio stream header */
884 
885        OUT4CC ("strh");
886        OUTLONG(56);            /* # of bytes to follow */
887        OUT4CC ("auds");
888 
889        // -----------
890        // ThOe
891        OUTLONG(0);             /* Format (Optionally) */
892        // -----------
893 
894        OUTLONG(0);             /* Flags */
895        OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
896        OUTLONG(0);             /* InitialFrames */
897 
898        // ThOe /4
899        OUTLONG(sampsize/4);      /* Scale */
900        OUTLONG(1000*AVI->track[j].mp3rate/8);
901        OUTLONG(0);             /* Start */
902        OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   /* Length */
903        OUTLONG(0);             /* SuggestedBufferSize */
904        OUTLONG(-1);            /* Quality */
905 
906        // ThOe /4
907        OUTLONG(sampsize/4);    /* SampleSize */
908 
909        OUTLONG(0);             /* Frame */
910        OUTLONG(0);             /* Frame */
911        //       OUTLONG(0);             /* Frame */
912        //OUTLONG(0);             /* Frame */
913 
914        /* The audio stream format */
915 
916        OUT4CC ("strf");
917        OUTLONG(16);                   /* # of bytes to follow */
918        OUTSHRT(AVI->track[j].a_fmt);           /* Format */
919        OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
920        OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
921        // ThOe
922        OUTLONG(1000*AVI->track[j].mp3rate/8);
923        //ThOe (/4)
924 
925        OUTSHRT(sampsize/4);           /* BlockAlign */
926 
927 
928        OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
929 
930        /* Finish stream list, i.e. put number of bytes in the list to proper pos */
931 
932        long2str(AVI_header+strl_start-4,nhb-strl_start);
933    }
934 
935    /* Finish header list */
936 
937    long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
938 
939 
940    /* Calculate the needed amount of junk bytes, output junk */
941 
942    njunk = HEADERBYTES - nhb - 8 - 12;
943 
944    /* Safety first: if njunk <= 0, somebody has played with
945       HEADERBYTES without knowing what (s)he did.
946       This is a fatal error */
947 
948    if(njunk<=0)
949      {
950        fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
951        exit(1);
952      }
953 
954    OUT4CC ("JUNK");
955    OUTLONG(njunk);
956    memset(AVI_header+nhb,0,njunk);
957 
958    nhb += njunk;
959 
960    /* Start the movi list */
961 
962    OUT4CC ("LIST");
963    OUTLONG(movi_len); /* Length of list in bytes */
964    OUT4CC ("movi");
965 
966    /* Output the header, truncate the file to the number of bytes
967       actually written, report an error if someting goes wrong */
968 
969    if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
970         avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
971 	lseek(AVI->fdes,AVI->pos,SEEK_SET)<0)
972      {
973        AVI_errno = AVI_ERR_CLOSE;
974        return -1;
975      }
976 
977    return 0;
978 }
979 
valid_info_tag(char * c)980 static int valid_info_tag(char *c)
981 {
982     if      (!strncmp(c, "IARL", 4)) return 1;
983     else if (!strncmp(c, "IART", 4)) return 1;
984     else if (!strncmp(c, "ICMS", 4)) return 1;
985     else if (!strncmp(c, "ICMT", 4)) return 1;
986     else if (!strncmp(c, "ICOP", 4)) return 1;
987     else if (!strncmp(c, "ICRD", 4)) return 1;
988     else if (!strncmp(c, "ICRP", 4)) return 1;
989     else if (!strncmp(c, "IDIM", 4)) return 1;
990     else if (!strncmp(c, "IDPI", 4)) return 1;
991     else if (!strncmp(c, "IENG", 4)) return 1;
992     else if (!strncmp(c, "IGNR", 4)) return 1;
993     else if (!strncmp(c, "IKEY", 4)) return 1;
994     else if (!strncmp(c, "ILGT", 4)) return 1;
995     else if (!strncmp(c, "IMED", 4)) return 1;
996     else if (!strncmp(c, "INAM", 4)) return 1;
997     else if (!strncmp(c, "IPLT", 4)) return 1;
998     else if (!strncmp(c, "IPRD", 4)) return 1;
999     else if (!strncmp(c, "ISBJ", 4)) return 1;
1000     else if (!strncmp(c, "ISHP", 4)) return 1;
1001     else if (!strncmp(c, "ISRC", 4)) return 1;
1002     else if (!strncmp(c, "ISRF", 4)) return 1;
1003     else if (!strncmp(c, "ITCH", 4)) return 1;
1004     else return 0;
1005 
1006     return 0;
1007 }
1008 // see ../docs/avi_comments.txt
1009 // returns the length of written stream (-1 on error)
avi_parse_comments(int fd,char * buf,int space_left)1010 static int avi_parse_comments (int fd, char *buf, int space_left)
1011 {
1012     int len=0, readlen=0, k;
1013     char *data, *c, *d;
1014     struct stat st;
1015 
1016     // safety checks
1017     if (fd<=0 || !buf || space_left<=0)
1018 	return -1;
1019 
1020     memset (buf, 0, space_left);
1021     if (fstat (fd, &st) == -1) {
1022 	perror ("stat");
1023 	return -1;
1024     }
1025 
1026     if ( !(data = malloc(st.st_size*sizeof(char)+1)) ) {
1027 	fprintf(stderr, "malloc failed\n");
1028 	return -1;
1029     }
1030 
1031     readlen = avi_read ( fd, data, st.st_size);
1032 
1033     //printf("Read %d bytes from %d\n", readlen, fd);
1034 
1035     c = data;
1036     space_left--;
1037 
1038     while (len < space_left) {
1039 	if ( !c || *c == '\0')
1040 	    break; // eof;
1041 	else if (*c == '#') { // comment, ignore
1042 	    c = strchr(c, '\n')+1;
1043 	}
1044 	else if (*c == '\n') { // empty, ignore
1045 	    c++;
1046 	}
1047 	else if (*c == 'I') {
1048 
1049 	    // do not write ISFT -- this is written by transcode
1050 	    // and important for debugging.
1051 	    if (!valid_info_tag(c)) {
1052 		// skip this line
1053 		while (c && *c && *c != '\n' ) {
1054 		    c++;
1055 		}
1056 		continue;
1057 	    }
1058 
1059 	    // set d after TAG
1060 	    d = c+4;
1061 
1062 	    // find first non-blank (!space or !TAB)
1063 	    while ( d && *d && (*d == ' ' || *d == '	')) ++d;
1064 	    if (!d) break;
1065 
1066 	    // TAG without argument is fine but ignored
1067 	    if (*d == '\n' || *d == '\r') {
1068 		c = d+1;
1069 		if (*c == '\n') ++c;
1070 		continue;
1071 	    }
1072 
1073 	    k = 0;
1074 	    while (d[k] != '\r' && d[k] != '\n' && d[k] != '\0') ++k;
1075 	    if (k>=space_left) return len;
1076 
1077 	    // write TAG
1078 	    memcpy(buf+len,c,4);
1079 	    len += 4;
1080 
1081 	    // write length + '\0'
1082 	    long2str(buf+len, k+1); len += 4;
1083 
1084 	    // write comment string
1085 	    memcpy (buf+len, d, k);
1086 	    // must be null terminated
1087 	    *(buf+len+k+1) = '\0';
1088 
1089 	    // PAD
1090 	    if ((k+1)&1) {
1091 		k++;
1092 		*(buf+len+k+1) = '\0';
1093 	    }
1094 	    len += k+1;
1095 
1096 	    // advance c
1097 	    while (*c != '\n' && *c != '\0') ++c;
1098 	    if (*c != '\0') ++c;
1099 	    else break;
1100 
1101 	} else {
1102 
1103 	    // ignore junk lines
1104 	    while (c && *c && *c != '\n' ) {
1105 		if (*c == ' ' || *c == '	') { c++; break; }
1106 		c++;
1107 	    }
1108 	    if (!c) break;
1109 	}
1110 
1111     }
1112     free(data);
1113 
1114     return len;
1115 }
1116 
1117 //SLM
1118 #ifndef S_IRUSR
1119 #define S_IRWXU       00700       /* read, write, execute: owner */
1120 #define S_IRUSR       00400       /* read permission: owner */
1121 #define S_IWUSR       00200       /* write permission: owner */
1122 #define S_IXUSR       00100       /* execute permission: owner */
1123 #define S_IRWXG       00070       /* read, write, execute: group */
1124 #define S_IRGRP       00040       /* read permission: group */
1125 #define S_IWGRP       00020       /* write permission: group */
1126 #define S_IXGRP       00010       /* execute permission: group */
1127 #define S_IRWXO       00007       /* read, write, execute: other */
1128 #define S_IROTH       00004       /* read permission: other */
1129 #define S_IWOTH       00002       /* write permission: other */
1130 #define S_IXOTH       00001       /* execute permission: other */
1131 #endif
1132 
1133 /*
1134   Write the header of an AVI file and close it.
1135   returns 0 on success, -1 on write error.
1136 */
1137 
avi_close_output_file(avi_t * AVI)1138 static int avi_close_output_file(avi_t *AVI)
1139 {
1140 
1141    int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
1142    unsigned long movi_len;
1143    int hdrl_start, strl_start, j;
1144    unsigned char AVI_header[HEADERBYTES];
1145    long nhb;
1146    unsigned long xd_size, xd_size_align2;
1147 
1148 #ifdef INFO_LIST
1149    long info_len;
1150    long id_len, real_id_len;
1151    long info_start_pos;
1152 //   time_t calptr;
1153 #endif
1154 
1155    /* Calculate length of movi list */
1156 
1157    // dump the rest of the index
1158    if (AVI->is_opendml) {
1159        int cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
1160        int audtr;
1161 
1162 #ifdef DEBUG_ODML
1163        printf("ODML dump the rest indices\n");
1164 #endif
1165        avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx],
1166 	       &AVI->video_superindex->aIndex[cur_std_idx]);
1167 
1168        AVI->video_superindex->aIndex[cur_std_idx].dwDuration =
1169 	   AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
1170 
1171        for (audtr = 0; audtr < AVI->anum; audtr++) {
1172 	    if (!AVI->track[audtr].audio_superindex) {
1173 		// not initialized -> no index
1174 		continue;
1175 	    }
1176 	   avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx],
1177 		   &AVI->track[audtr].audio_superindex->aIndex[cur_std_idx]);
1178 	   AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration =
1179 	       AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
1180 	   if (AVI->track[audtr].a_fmt == 0x1) {
1181 	       AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration *=
1182 		   AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
1183 	   }
1184        }
1185        // The AVI->video_superindex->nEntriesInUse contains the offset
1186        AVI->video_superindex->stdindex[ cur_std_idx+1 ]->qwBaseOffset = AVI->pos;
1187    }
1188 
1189    if (AVI->is_opendml) {
1190        // Correct!
1191        movi_len = AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - HEADERBYTES+4 - AVI->n_idx*16 - 8;
1192    } else {
1193        movi_len = AVI->pos - HEADERBYTES + 4;
1194    }
1195 
1196 
1197    /* Try to ouput the index entries. This may fail e.g. if no space
1198       is left on device. We will report this as an error, but we still
1199       try to write the header correctly (so that the file still may be
1200       readable in the most cases */
1201 
1202    idxerror = 0;
1203    hasIndex = 1;
1204    if (!AVI->is_opendml) {
1205        //   fprintf(stderr, "pos=%lu, index_len=%ld             \n", AVI->pos, AVI->n_idx*16);
1206        ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
1207        hasIndex = (ret==0);
1208        //fprintf(stderr, "pos=%lu, index_len=%d\n", AVI->pos, hasIndex);
1209 
1210        if(ret) {
1211 	   idxerror = 1;
1212 	   AVI_errno = AVI_ERR_WRITE_INDEX;
1213        }
1214    }
1215 
1216    /* Calculate Microseconds per frame */
1217 
1218    if(AVI->fps < 0.001) {
1219      frate=0;
1220      ms_per_frame=0;
1221    } else {
1222      frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
1223      ms_per_frame=(int) (1000000/AVI->fps + 0.5);
1224    }
1225 
1226    /* Prepare the file header */
1227 
1228    nhb = 0;
1229 
1230    /* The RIFF header */
1231 
1232    OUT4CC ("RIFF");
1233    if (AVI->is_opendml) {
1234        OUTLONG(AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - 8);    /* # of bytes to follow */
1235    } else {
1236        OUTLONG(AVI->pos - 8);    /* # of bytes to follow */
1237    }
1238 
1239    OUT4CC ("AVI ");
1240 
1241    /* Start the header list */
1242 
1243    OUT4CC ("LIST");
1244    OUTLONG(0);        /* Length of list in bytes, don't know yet */
1245    hdrl_start = nhb;  /* Store start position */
1246    OUT4CC ("hdrl");
1247 
1248    /* The main AVI header */
1249 
1250    /* The Flags in AVI File header */
1251 
1252 #define AVIF_HASINDEX           0x00000010      /* Index at end of file */
1253 #define AVIF_MUSTUSEINDEX       0x00000020
1254 #define AVIF_ISINTERLEAVED      0x00000100
1255 #define AVIF_TRUSTCKTYPE        0x00000800      /* Use CKType to find key frames */
1256 #define AVIF_WASCAPTUREFILE     0x00010000
1257 #define AVIF_COPYRIGHTED        0x00020000
1258 
1259    OUT4CC ("avih");
1260    OUTLONG(56);                 /* # of bytes to follow */
1261    OUTLONG(ms_per_frame);       /* Microseconds per frame */
1262    //ThOe ->0
1263    //   OUTLONG(10000000);           /* MaxBytesPerSec, I hope this will never be used */
1264    OUTLONG(0);
1265    OUTLONG(0);                  /* PaddingGranularity (whatever that might be) */
1266                                 /* Other sources call it 'reserved' */
1267    flag = AVIF_ISINTERLEAVED;
1268    if(hasIndex) flag |= AVIF_HASINDEX;
1269    if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
1270    OUTLONG(flag);               /* Flags */
1271    OUTLONG(AVI->video_frames);  /* TotalFrames */
1272    OUTLONG(0);                  /* InitialFrames */
1273 
1274    OUTLONG(AVI->anum+1);
1275 //   if (AVI->track[0].audio_bytes)
1276 //      { OUTLONG(2); }           /* Streams */
1277 //   else
1278 //      { OUTLONG(1); }           /* Streams */
1279 
1280    OUTLONG(0);                  /* SuggestedBufferSize */
1281    OUTLONG(AVI->width);         /* Width */
1282    OUTLONG(AVI->height);        /* Height */
1283                                 /* MS calls the following 'reserved': */
1284    OUTLONG(0);                  /* TimeScale:  Unit used to measure time */
1285    OUTLONG(0);                  /* DataRate:   Data rate of playback     */
1286    OUTLONG(0);                  /* StartTime:  Starting time of AVI data */
1287    OUTLONG(0);                  /* DataLength: Size of AVI data chunk    */
1288 
1289 
1290    /* Start the video stream list ---------------------------------- */
1291 
1292    OUT4CC ("LIST");
1293    OUTLONG(0);        /* Length of list in bytes, don't know yet */
1294    strl_start = nhb;  /* Store start position */
1295    OUT4CC ("strl");
1296 
1297    /* The video stream header */
1298 
1299    OUT4CC ("strh");
1300    OUTLONG(56);                 /* # of bytes to follow */
1301    OUT4CC ("vids");             /* Type */
1302    OUT4CC (AVI->compressor);    /* Handler */
1303    OUTLONG(0);                  /* Flags */
1304    OUTLONG(0);                  /* Reserved, MS says: wPriority, wLanguage */
1305    OUTLONG(0);                  /* InitialFrames */
1306    OUTLONG(FRAME_RATE_SCALE);   /* Scale */
1307    OUTLONG(frate);              /* Rate: Rate/Scale == samples/second */
1308    OUTLONG(0);                  /* Start */
1309    OUTLONG(AVI->video_frames);  /* Length */
1310    OUTLONG(AVI->max_len);       /* SuggestedBufferSize */
1311    OUTLONG(0);                  /* Quality */
1312    OUTLONG(0);                  /* SampleSize */
1313    OUTLONG(0);                  /* Frame */
1314    OUTLONG(0);                  /* Frame */
1315    //OUTLONG(0);                  /* Frame */
1316    //OUTLONG(0);                  /* Frame */
1317 
1318    /* The video stream format */
1319 
1320    xd_size        = AVI->extradata_size;
1321    xd_size_align2 = (AVI->extradata_size+1) & ~1;
1322 
1323    OUT4CC ("strf");
1324    OUTLONG(40 + xd_size_align2);/* # of bytes to follow */
1325    OUTLONG(40 + xd_size);	/* Size */
1326    OUTLONG(AVI->width);         /* Width */
1327    OUTLONG(AVI->height);        /* Height */
1328    OUTSHRT(1); OUTSHRT(24);     /* Planes, Count */
1329    OUT4CC (AVI->compressor);    /* Compression */
1330    // ThOe (*3)
1331    OUTLONG(AVI->width*AVI->height*3);  /* SizeImage (in bytes?) */
1332    OUTLONG(0);                  /* XPelsPerMeter */
1333    OUTLONG(0);                  /* YPelsPerMeter */
1334    OUTLONG(0);                  /* ClrUsed: Number of colors used */
1335    OUTLONG(0);                  /* ClrImportant: Number of colors important */
1336 
1337    // write extradata if present
1338    if (xd_size > 0 && AVI->extradata) {
1339       OUTMEM(AVI->extradata, xd_size);
1340       if (xd_size != xd_size_align2) {
1341          OUTCHR(0);
1342       }
1343    }
1344 
1345    // dump index of indices for audio
1346    if (AVI->is_opendml) {
1347 
1348        int k;
1349 
1350        OUT4CC(AVI->video_superindex->fcc);
1351        OUTLONG(2+1+1+4+4+3*4 + AVI->video_superindex->nEntriesInUse * (8+4+4));
1352        OUTSHRT(AVI->video_superindex->wLongsPerEntry);
1353        OUTCHR(AVI->video_superindex->bIndexSubType);
1354        OUTCHR(AVI->video_superindex->bIndexType);
1355        OUTLONG(AVI->video_superindex->nEntriesInUse);
1356        OUT4CC(AVI->video_superindex->dwChunkId);
1357        OUTLONG(0);
1358        OUTLONG(0);
1359        OUTLONG(0);
1360 
1361 
1362        for (k = 0; k < AVI->video_superindex->nEntriesInUse; k++) {
1363 	   uint32_t r = (AVI->video_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff;
1364 	   uint32_t s = (AVI->video_superindex->aIndex[k].qwOffset) & 0xffffffff;
1365 
1366 	printf("VID NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld|\n",  k,
1367 		(unsigned long)AVI->video_superindex->nEntriesInUse,
1368 		AVI->video_superindex->dwChunkId[0],
1369 		AVI->video_superindex->dwChunkId[1],
1370 		AVI->video_superindex->dwChunkId[2],
1371 		AVI->video_superindex->dwChunkId[3],
1372 		(unsigned long long)AVI->video_superindex->aIndex[k].qwOffset,
1373 		(unsigned long)AVI->video_superindex->aIndex[k].dwSize,
1374 		(unsigned long)AVI->video_superindex->aIndex[k].dwDuration
1375 		);
1376 	   /*
1377 		*/
1378 
1379 	   OUTLONG(s);
1380 	   OUTLONG(r);
1381 	   OUTLONG(AVI->video_superindex->aIndex[k].dwSize);
1382 	   OUTLONG(AVI->video_superindex->aIndex[k].dwDuration);
1383        }
1384 
1385    }
1386 
1387    /* Finish stream list, i.e. put number of bytes in the list to proper pos */
1388 
1389    long2str(AVI_header+strl_start-4,nhb-strl_start);
1390 
1391    /* Start the audio stream list ---------------------------------- */
1392 
1393    for(j=0; j<AVI->anum; ++j) {
1394 
1395      //if (AVI->track[j].a_chans && AVI->track[j].audio_bytes)
1396        {
1397 	 unsigned long nBlockAlign = 0;
1398 	 unsigned long avgbsec = 0;
1399 	 unsigned long scalerate = 0;
1400 
1401 	 sampsize = avi_sampsize(AVI, j);
1402 	 sampsize = AVI->track[j].a_fmt==0x1?sampsize*4:sampsize;
1403 
1404 	 nBlockAlign = (AVI->track[j].a_rate<32000)?576:1152;
1405 	 /*
1406 	 printf("XXX sampsize (%d) block (%ld) rate (%ld) audio_bytes (%ld) mp3rate(%ld,%ld)\n",
1407 		 sampsize, nBlockAlign, AVI->track[j].a_rate,
1408 		 (long int)AVI->track[j].audio_bytes,
1409 		 1000*AVI->track[j].mp3rate/8, AVI->track[j].mp3rate);
1410 		 */
1411 
1412 	 if (AVI->track[j].a_fmt==0x1) {
1413 	     sampsize = (AVI->track[j].a_chans<2)?sampsize/2:sampsize;
1414 	     avgbsec = AVI->track[j].a_rate*sampsize/4;
1415 	     scalerate = AVI->track[j].a_rate*sampsize/4;
1416 	 } else  {
1417 	     avgbsec = 1000*AVI->track[j].mp3rate/8;
1418 	     scalerate = 1000*AVI->track[j].mp3rate/8;
1419 	 }
1420 
1421 	 OUT4CC ("LIST");
1422 	 OUTLONG(0);        /* Length of list in bytes, don't know yet */
1423 	 strl_start = nhb;  /* Store start position */
1424 	 OUT4CC ("strl");
1425 
1426 	 /* The audio stream header */
1427 
1428 	 OUT4CC ("strh");
1429 	 OUTLONG(56);            /* # of bytes to follow */
1430 	 OUT4CC ("auds");
1431 
1432 	 // -----------
1433 	 // ThOe
1434 	 OUTLONG(0);             /* Format (Optionally) */
1435 	   // -----------
1436 
1437 	 OUTLONG(0);             /* Flags */
1438 	 OUTLONG(0);             /* Reserved, MS says: wPriority, wLanguage */
1439 	 OUTLONG(0);             /* InitialFrames */
1440 
1441 	 // VBR
1442 	 if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
1443 	     OUTLONG(nBlockAlign);                   /* Scale */
1444 	     OUTLONG(AVI->track[j].a_rate);          /* Rate */
1445 	     OUTLONG(0);                             /* Start */
1446 	     OUTLONG(AVI->track[j].audio_chunks);    /* Length */
1447 	     OUTLONG(0);                      /* SuggestedBufferSize */
1448 	     OUTLONG(0);                             /* Quality */
1449 	     OUTLONG(0);                             /* SampleSize */
1450 	     OUTLONG(0);                             /* Frame */
1451 	     OUTLONG(0);                             /* Frame */
1452 	 } else {
1453 	     OUTLONG(sampsize/4);                    /* Scale */
1454 	     OUTLONG(scalerate);  /* Rate */
1455 	     OUTLONG(0);                             /* Start */
1456 	     OUTLONG(4*AVI->track[j].audio_bytes/sampsize);   /* Length */
1457 	     OUTLONG(0);                             /* SuggestedBufferSize */
1458 	     OUTLONG(0xffffffff);                             /* Quality */
1459 	     OUTLONG(sampsize/4);                    /* SampleSize */
1460 	     OUTLONG(0);                             /* Frame */
1461 	     OUTLONG(0);                             /* Frame */
1462 	 }
1463 
1464 	 /* The audio stream format */
1465 
1466 	 OUT4CC ("strf");
1467 
1468 	 if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
1469 
1470 	     OUTLONG(30);                            /* # of bytes to follow */ // mplayer writes 28
1471 	     OUTSHRT(AVI->track[j].a_fmt);           /* Format */                  // 2
1472 	     OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */      // 2
1473 	     OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */           // 4
1474 	     //ThOe/tibit
1475 	     OUTLONG(1000*AVI->track[j].mp3rate/8);  /* maybe we should write an avg. */ // 4
1476 	     OUTSHRT(nBlockAlign);                   /* BlockAlign */              // 2
1477 	     OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */           // 2
1478 
1479 	     OUTSHRT(12);                           /* cbSize */                   // 2
1480 	     OUTSHRT(1);                            /* wID */                      // 2
1481 	     OUTLONG(2);                            /* fdwFlags */                 // 4
1482 	     OUTSHRT(nBlockAlign);                  /* nBlockSize */               // 2
1483 	     OUTSHRT(1);                            /* nFramesPerBlock */          // 2
1484 	     OUTSHRT(0);                            /* nCodecDelay */              // 2
1485 
1486 	 } else if (AVI->track[j].a_fmt == 0x55 && !AVI->track[j].a_vbr) {
1487 
1488 	     OUTLONG(30);                            /* # of bytes to follow */
1489 	     OUTSHRT(AVI->track[j].a_fmt);           /* Format */
1490 	     OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
1491 	     OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
1492 	     //ThOe/tibit
1493 	     OUTLONG(1000*AVI->track[j].mp3rate/8);
1494 	     OUTSHRT(sampsize/4);                    /* BlockAlign */
1495 	     OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
1496 
1497 	     OUTSHRT(12);                           /* cbSize */
1498 	     OUTSHRT(1);                            /* wID */
1499 	     OUTLONG(2);                            /* fdwFlags */
1500 	     OUTSHRT(nBlockAlign);                  /* nBlockSize */
1501 	     OUTSHRT(1);                            /* nFramesPerBlock */
1502 	     OUTSHRT(0);                            /* nCodecDelay */
1503 
1504 	 } else {
1505 
1506 	     OUTLONG(18);                   /* # of bytes to follow */
1507 	     OUTSHRT(AVI->track[j].a_fmt);           /* Format */
1508 	     OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
1509 	     OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
1510 	     //ThOe/tibit
1511 	     OUTLONG(avgbsec);  /* Avg bytes/sec */
1512 	     OUTSHRT(sampsize/4);                    /* BlockAlign */
1513 	     OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
1514 	     OUTSHRT(0);                           /* cbSize */
1515 
1516 	 }
1517        }
1518        if (AVI->is_opendml) {
1519 
1520 	   int k ;
1521 
1522 	    if (!AVI->track[j].audio_superindex) {
1523 		// not initialized -> no index
1524 		continue;
1525 	    }
1526 
1527 	   OUT4CC(AVI->track[j].audio_superindex->fcc);    /* "indx" */
1528 	   OUTLONG(2+1+1+4+4+3*4 + AVI->track[j].audio_superindex->nEntriesInUse * (8+4+4));
1529 	   OUTSHRT(AVI->track[j].audio_superindex->wLongsPerEntry);
1530 	   OUTCHR(AVI->track[j].audio_superindex->bIndexSubType);
1531 	   OUTCHR(AVI->track[j].audio_superindex->bIndexType);
1532 	   OUTLONG(AVI->track[j].audio_superindex->nEntriesInUse);
1533 	   OUT4CC(AVI->track[j].audio_superindex->dwChunkId);
1534 	   OUTLONG(0); OUTLONG(0); OUTLONG(0);
1535 
1536 	   for (k = 0; k < AVI->track[j].audio_superindex->nEntriesInUse; k++) {
1537 	       uint32_t r = (AVI->track[j].audio_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff;
1538 	       uint32_t s = (AVI->track[j].audio_superindex->aIndex[k].qwOffset) & 0xffffffff;
1539 
1540 	       /*
1541 	       printf("AUD[%d] NrEntries %d/%ld (%c%c%c%c) |0x%llX|%ld|%ld| \n",  j, k,
1542 	               AVI->track[j].audio_superindex->nEntriesInUse,
1543 		       AVI->track[j].audio_superindex->dwChunkId[0], AVI->track[j].audio_superindex->dwChunkId[1],
1544 		       AVI->track[j].audio_superindex->dwChunkId[2], AVI->track[j].audio_superindex->dwChunkId[3],
1545 		       AVI->track[j].audio_superindex->aIndex[k].qwOffset,
1546 		       AVI->track[j].audio_superindex->aIndex[k].dwSize,
1547 		       AVI->track[j].audio_superindex->aIndex[k].dwDuration
1548 		     );
1549 		     */
1550 
1551 	       OUTLONG(s);
1552 	       OUTLONG(r);
1553 	       OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwSize);
1554 	       OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwDuration);
1555 	   }
1556        }
1557        /* Finish stream list, i.e. put number of bytes in the list to proper pos */
1558        long2str(AVI_header+strl_start-4,nhb-strl_start);
1559    }
1560 
1561    if (AVI->is_opendml) {
1562        OUT4CC("LIST");
1563        OUTLONG(16);
1564        OUT4CC("odml");
1565        OUT4CC("dmlh");
1566        OUTLONG(4);
1567        OUTLONG(AVI->total_frames);
1568    }
1569 
1570    /* Finish header list */
1571 
1572    long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
1573 
1574 
1575    // add INFO list --- (0.6.0pre4)
1576 
1577 #ifdef INFO_LIST
1578    OUT4CC ("LIST");
1579 
1580    info_start_pos = nhb;
1581    info_len = MAX_INFO_STRLEN + 12;
1582    OUTLONG(info_len); // rewritten later
1583    OUT4CC ("INFO");
1584 
1585    OUT4CC ("ISFT");
1586    //OUTLONG(MAX_INFO_STRLEN);
1587    memset(id_str, 0, MAX_INFO_STRLEN);
1588 
1589    snprintf(id_str, sizeof(id_str), "%s-%s", PACKAGE, VERSION);
1590    real_id_len = id_len = strlen(id_str)+1;
1591    if (id_len&1) id_len++;
1592 
1593    OUTLONG(real_id_len);
1594 
1595    memset(AVI_header+nhb, 0, id_len);
1596    memcpy(AVI_header+nhb, id_str, id_len);
1597    nhb += id_len;
1598 
1599    info_len = avi_parse_comments (AVI->comment_fd, AVI_header+nhb, HEADERBYTES - nhb - 8 - 12);
1600    if (info_len <= 0) info_len=0;
1601 
1602    // write correct len
1603    long2str(AVI_header+info_start_pos, info_len + id_len + 4+4+4);
1604 
1605    nhb += info_len;
1606 
1607 //   OUT4CC ("ICMT");
1608 //   OUTLONG(MAX_INFO_STRLEN);
1609 
1610 //   calptr=time(NULL);
1611 //   snprintf(id_str, sizeof(id_str), "\t%s %s", ctime(&calptr), "");
1612 //   memset(AVI_header+nhb, 0, MAX_INFO_STRLEN);
1613 //   memcpy(AVI_header+nhb, id_str, 25);
1614 //   nhb += MAX_INFO_STRLEN;
1615 #endif
1616 
1617    // ----------------------------
1618 
1619    /* Calculate the needed amount of junk bytes, output junk */
1620 
1621    njunk = HEADERBYTES - nhb - 8 - 12;
1622 
1623    /* Safety first: if njunk <= 0, somebody has played with
1624       HEADERBYTES without knowing what (s)he did.
1625       This is a fatal error */
1626 
1627    if(njunk<=0)
1628    {
1629       fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
1630       exit(1);
1631    }
1632 
1633    OUT4CC ("JUNK");
1634    OUTLONG(njunk);
1635    memset(AVI_header+nhb,0,njunk);
1636 
1637    nhb += njunk;
1638 
1639    /* Start the movi list */
1640 
1641    OUT4CC ("LIST");
1642    OUTLONG(movi_len); /* Length of list in bytes */
1643    OUT4CC ("movi");
1644 
1645    /* Output the header, truncate the file to the number of bytes
1646       actually written, report an error if someting goes wrong */
1647 
1648    if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
1649         avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
1650         ftruncate(AVI->fdes,AVI->pos)<0 )
1651    {
1652       AVI_errno = AVI_ERR_CLOSE;
1653       return -1;
1654    }
1655 
1656 
1657    // Fix up the empty additional RIFF and LIST chunks
1658    if (AVI->is_opendml) {
1659        int k = 0;
1660        char f[4];
1661        unsigned int len;
1662 
1663        for (k=1; k<AVI->video_superindex->nEntriesInUse; k++) {
1664 	    // the len of the RIFF Chunk
1665 	    lseek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET);
1666 	    len = AVI->video_superindex->stdindex[k+1]->qwBaseOffset -
1667 		  AVI->video_superindex->stdindex[k]->qwBaseOffset - 8;
1668 	    long2str(f, len);
1669 	    avi_write(AVI->fdes, f, 4);
1670 
1671 	    // len of the LIST/movi chunk
1672 	    lseek(AVI->fdes, 8, SEEK_CUR);
1673 	    len -= 12;
1674 	    long2str(f, len);
1675 	    avi_write(AVI->fdes, f, 4);
1676        }
1677    }
1678 
1679 
1680    if(idxerror) return -1;
1681 
1682    return 0;
1683 }
1684 
1685 /*
1686    AVI_write_data:
1687    Add video or audio data to the file;
1688 
1689    Return values:
1690     0    No error;
1691    -1    Error, AVI_errno is set appropriatly;
1692 
1693 */
1694 
avi_write_data(avi_t * AVI,char * data,unsigned long length,int audio,int keyframe)1695 static int avi_write_data(avi_t *AVI, char *data, unsigned long length, int audio, int keyframe)
1696 {
1697    int n = 0;
1698 
1699    unsigned char astr[5];
1700 
1701    // transcode core itself checks for the size -- unneeded and
1702    // does harm to xvid 2pass encodes where the first pass can get
1703    // _very_ large -- tibit.
1704 
1705 #if 0
1706    /* Check for maximum file length */
1707 
1708    if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) {
1709      AVI_errno = AVI_ERR_SIZELIM;
1710      return -1;
1711    }
1712 #endif
1713 
1714    /* Add index entry */
1715 
1716    //set tag for current audio track
1717    snprintf((char *)astr, sizeof(astr), "0%1dwb", (int)(AVI->aptr+1));
1718 
1719    if(audio) {
1720      if (!AVI->is_opendml) n = avi_add_index_entry(AVI,astr,0x10,AVI->pos,length);
1721      n += avi_add_odml_index_entry(AVI,astr,0x10,AVI->pos,length);
1722    } else {
1723      if (!AVI->is_opendml) n = avi_add_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
1724      n += avi_add_odml_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
1725    }
1726 
1727    if(n) return -1;
1728 
1729    /* Output tag and data */
1730 
1731    if(audio)
1732      n = avi_add_chunk(AVI,(unsigned char *)astr,data,length);
1733    else
1734      n = avi_add_chunk(AVI,(unsigned char *)"00db",data,length);
1735 
1736    if (n) return -1;
1737 
1738    return 0;
1739 }
1740 
AVI_write_frame(avi_t * AVI,char * data,long bytes,int keyframe)1741 int AVI_write_frame(avi_t *AVI, char *data, long bytes, int keyframe)
1742 {
1743   off_t pos;
1744 
1745   if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1746 
1747   pos = AVI->pos;
1748 
1749   if(avi_write_data(AVI,data,bytes,0,keyframe)) return -1;
1750 
1751   AVI->last_pos = pos;
1752   AVI->last_len = bytes;
1753   AVI->video_frames++;
1754   return 0;
1755 }
1756 
AVI_dup_frame(avi_t * AVI)1757 int AVI_dup_frame(avi_t *AVI)
1758 {
1759    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1760 
1761    if(AVI->last_pos==0) return 0; /* No previous real frame */
1762    if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
1763    AVI->video_frames++;
1764    AVI->must_use_index = 1;
1765    return 0;
1766 }
1767 
AVI_write_audio(avi_t * AVI,char * data,long bytes)1768 int AVI_write_audio(avi_t *AVI, char *data, long bytes)
1769 {
1770    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1771 
1772    if( avi_write_data(AVI,data,bytes,1,0) ) return -1;
1773    AVI->track[AVI->aptr].audio_bytes += bytes;
1774    AVI->track[AVI->aptr].audio_chunks++;
1775    return 0;
1776 }
1777 
1778 
AVI_append_audio(avi_t * AVI,char * data,long bytes)1779 int AVI_append_audio(avi_t *AVI, char *data, long bytes)
1780 {
1781 
1782     // won't work for >2gb
1783   long i, length, pos;
1784   unsigned char c[4];
1785 
1786   if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
1787 
1788   // update last index entry:
1789 
1790   --AVI->n_idx;
1791   length = str2ulong(AVI->idx[AVI->n_idx]+12);
1792   pos    = str2ulong(AVI->idx[AVI->n_idx]+8);
1793 
1794   //update;
1795   long2str(AVI->idx[AVI->n_idx]+12,length+bytes);
1796 
1797   ++AVI->n_idx;
1798 
1799   AVI->track[AVI->aptr].audio_bytes += bytes;
1800 
1801   //update chunk header
1802   lseek(AVI->fdes, pos+4, SEEK_SET);
1803   long2str(c, length+bytes);
1804   avi_write(AVI->fdes, (char *)c, 4);
1805 
1806   lseek(AVI->fdes, pos+8+length, SEEK_SET);
1807 
1808   i=PAD_EVEN(length + bytes);
1809 
1810   bytes = i - length;
1811   avi_write(AVI->fdes, data, bytes);
1812   AVI->pos = pos + 8 + i;
1813 
1814   return 0;
1815 }
1816 
1817 
AVI_bytes_remain(avi_t * AVI)1818 long AVI_bytes_remain(avi_t *AVI)
1819 {
1820    if(AVI->mode==AVI_MODE_READ) return 0;
1821 
1822    return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
1823 }
1824 
AVI_bytes_written(avi_t * AVI)1825 long AVI_bytes_written(avi_t *AVI)
1826 {
1827    if(AVI->mode==AVI_MODE_READ) return 0;
1828 
1829    return (AVI->pos + 8 + 16*AVI->n_idx);
1830 }
1831 
AVI_set_audio_track(avi_t * AVI,int track)1832 int AVI_set_audio_track(avi_t *AVI, int track)
1833 {
1834 
1835   if(track < 0 || track + 1 > AVI->anum) return(-1);
1836 
1837   //this info is not written to file anyway
1838   AVI->aptr=track;
1839   return 0;
1840 }
1841 
AVI_get_audio_track(avi_t * AVI)1842 int AVI_get_audio_track(avi_t *AVI)
1843 {
1844     return(AVI->aptr);
1845 }
1846 
AVI_set_audio_vbr(avi_t * AVI,long is_vbr)1847 void AVI_set_audio_vbr(avi_t *AVI, long is_vbr)
1848 {
1849     AVI->track[AVI->aptr].a_vbr = is_vbr;
1850 }
1851 
AVI_get_audio_vbr(avi_t * AVI)1852 long AVI_get_audio_vbr(avi_t *AVI)
1853 {
1854     return(AVI->track[AVI->aptr].a_vbr);
1855 }
1856 
AVI_set_comment_fd(avi_t * AVI,int fd)1857 void AVI_set_comment_fd(avi_t *AVI, int fd)
1858 {
1859     AVI->comment_fd = fd;
1860 }
AVI_get_comment_fd(avi_t * AVI)1861 int  AVI_get_comment_fd(avi_t *AVI)
1862 {
1863     return AVI->comment_fd;
1864 }
1865 
1866 
1867 /*******************************************************************
1868  *                                                                 *
1869  *    Utilities for reading video and audio from an AVI File       *
1870  *                                                                 *
1871  *******************************************************************/
1872 
AVI_close(avi_t * AVI)1873 int AVI_close(avi_t *AVI)
1874 {
1875    int ret;
1876    int j,k;
1877 
1878    /* If the file was open for writing, the header and index still have
1879       to be written */
1880 
1881    if(AVI->mode == AVI_MODE_WRITE)
1882       ret = avi_close_output_file(AVI);
1883    else
1884       ret = 0;
1885 
1886    /* Even if there happened an error, we first clean up */
1887 
1888    if (AVI->comment_fd>0)
1889        close(AVI->comment_fd);
1890    AVI->comment_fd = -1;
1891    close(AVI->fdes);
1892    if(AVI->idx) free(AVI->idx);
1893    if(AVI->video_index) free(AVI->video_index);
1894    if(AVI->video_superindex) {
1895        for (j = 0; j < NR_IXNN_CHUNKS; j++) {
1896 	   if (AVI->video_superindex->stdindex[j]) {
1897 	       if (AVI->video_superindex->stdindex[j]->aIndex) {
1898 		   free(AVI->video_superindex->stdindex[j]->aIndex);
1899 	       }
1900 	       free(AVI->video_superindex->stdindex[j]);
1901 	   }
1902        }
1903        if(AVI->video_superindex->stdindex) free(AVI->video_superindex->stdindex);
1904        if(AVI->video_superindex->aIndex) free(AVI->video_superindex->aIndex);
1905        free(AVI->video_superindex);
1906    }
1907 
1908    for (j=0; j<AVI->anum; j++)
1909    {
1910        if(AVI->track[j].audio_index) free(AVI->track[j].audio_index);
1911        if(AVI->track[j].audio_superindex) {
1912 	   // shortcut
1913 	   avisuperindex_chunk *a = AVI->track[j].audio_superindex;
1914 	   for (k = 0; k < NR_IXNN_CHUNKS; k++) {
1915 	       if (a->stdindex[k]) {
1916 		   if (a->stdindex[k]->aIndex) {
1917 		       free(a->stdindex[k]->aIndex);
1918 		   }
1919 		   free(a->stdindex[k]);
1920 	       }
1921 	   }
1922 	   if(a->stdindex) free(a->stdindex);
1923 	   if(a->aIndex) free(a->aIndex);
1924 	   free(a);
1925        }
1926    }
1927 
1928    if (AVI->bitmap_info_header)
1929      free(AVI->bitmap_info_header);
1930    for (j = 0; j < AVI->anum; j++)
1931      if (AVI->wave_format_ex[j])
1932        free(AVI->wave_format_ex[j]);
1933 
1934    free(AVI);
1935    AVI=NULL;
1936 
1937    return ret;
1938 }
1939 
1940 
1941 #define ERR_EXIT(x) \
1942 { \
1943    AVI_close(AVI); \
1944    AVI_errno = x; \
1945    return 0; \
1946 }
1947 
AVI_open_input_indexfile(char * filename,int getIndex,char * indexfile)1948 avi_t *AVI_open_input_indexfile(char *filename, int getIndex, char *indexfile)
1949 {
1950   avi_t *AVI=NULL;
1951 
1952   /* Create avi_t structure */
1953 
1954   AVI = (avi_t *) malloc(sizeof(avi_t));
1955   if(AVI==NULL)
1956     {
1957       AVI_errno = AVI_ERR_NO_MEM;
1958       return 0;
1959     }
1960   memset((void *)AVI,0,sizeof(avi_t));
1961 
1962   AVI->mode = AVI_MODE_READ; /* open for reading */
1963 
1964   /* Open the file */
1965 
1966   AVI->fdes = open(filename,O_RDONLY|O_BINARY);
1967   if(AVI->fdes < 0)
1968     {
1969       AVI_errno = AVI_ERR_OPEN;
1970       free(AVI);
1971       return 0;
1972     }
1973 
1974   AVI->index_file=strdup(indexfile);
1975   AVI_errno = 0;
1976   avi_parse_input_file(AVI, getIndex);
1977 
1978   if (AVI != NULL && !AVI_errno) {
1979       AVI->aptr=0; //reset
1980   }
1981 
1982   if (AVI_errno)
1983       return AVI=NULL;
1984   else
1985       return AVI;
1986 }
1987 
AVI_open_indexfd(int fd,int getIndex,char * indexfile)1988 avi_t *AVI_open_indexfd(int fd, int getIndex, char *indexfile)
1989 {
1990   avi_t *AVI=NULL;
1991 
1992   /* Create avi_t structure */
1993 
1994   AVI = (avi_t *) malloc(sizeof(avi_t));
1995   if(AVI==NULL)
1996     {
1997       AVI_errno = AVI_ERR_NO_MEM;
1998       return 0;
1999     }
2000   memset((void *)AVI,0,sizeof(avi_t));
2001 
2002   AVI->mode = AVI_MODE_READ; /* open for reading */
2003 
2004   // file alread open
2005   AVI->fdes = fd;
2006 
2007   AVI->index_file=strdup(indexfile);
2008   AVI_errno = 0;
2009   avi_parse_input_file(AVI, getIndex);
2010 
2011   if (AVI != NULL && !AVI_errno) {
2012       AVI->aptr=0; //reset
2013   }
2014 
2015   if (AVI_errno)
2016       return AVI=NULL;
2017   else
2018       return AVI;
2019 }
2020 
2021 
AVI_open_input_file(char * filename,int getIndex)2022 avi_t *AVI_open_input_file(char *filename, int getIndex)
2023 {
2024   avi_t *AVI=NULL;
2025 
2026   /* Create avi_t structure */
2027 
2028   AVI = (avi_t *) malloc(sizeof(avi_t));
2029   if(AVI==NULL)
2030     {
2031       AVI_errno = AVI_ERR_NO_MEM;
2032       return 0;
2033     }
2034   memset((void *)AVI,0,sizeof(avi_t));
2035 
2036   AVI->mode = AVI_MODE_READ; /* open for reading */
2037 
2038   /* Open the file */
2039 
2040   AVI->fdes = open(filename,O_RDONLY);
2041   if(AVI->fdes < 0)
2042     {
2043       AVI_errno = AVI_ERR_OPEN;
2044       free(AVI);
2045       return 0;
2046     }
2047 
2048   AVI_errno = 0;
2049   avi_parse_input_file(AVI, getIndex);
2050 
2051   if (AVI != NULL && !AVI_errno) {
2052       AVI->aptr=0; //reset
2053   }
2054 
2055   if (AVI_errno)
2056       return AVI=NULL;
2057   else
2058       return AVI;
2059 }
2060 
AVI_open_fd(int fd,int getIndex)2061 avi_t *AVI_open_fd(int fd, int getIndex)
2062 {
2063   avi_t *AVI=NULL;
2064 
2065   /* Create avi_t structure */
2066 
2067   AVI = (avi_t *) malloc(sizeof(avi_t));
2068   if(AVI==NULL)
2069     {
2070       AVI_errno = AVI_ERR_NO_MEM;
2071       return 0;
2072     }
2073   memset((void *)AVI,0,sizeof(avi_t));
2074 
2075   AVI->mode = AVI_MODE_READ; /* open for reading */
2076 
2077   // file alread open
2078   AVI->fdes = fd;
2079 
2080   AVI_errno = 0;
2081   avi_parse_input_file(AVI, getIndex);
2082 
2083   if (AVI != NULL && !AVI_errno) {
2084       AVI->aptr=0; //reset
2085   }
2086 
2087   if (AVI_errno)
2088       return AVI=NULL;
2089   else
2090       return AVI;
2091 }
2092 
2093 // transcode-0.6.8
2094 // reads a file generated by aviindex and builds the index out of it.
2095 
avi_parse_index_from_file(avi_t * AVI,char * filename)2096 int avi_parse_index_from_file(avi_t *AVI, char *filename)
2097 {
2098     char data[100]; // line buffer
2099     FILE *fd = NULL; // read from
2100     off_t pos, len, f_pos, tot_chunks[AVI_MAX_TRACKS];
2101     int key=0, type;
2102     int vid_chunks=0, aud_chunks[AVI_MAX_TRACKS];
2103     long line_count=0;
2104     char *c, d;
2105     int i,j;
2106 
2107     for (i=0; i<AVI_MAX_TRACKS; i++) aud_chunks[i] = 0;
2108     i=0;
2109 
2110     // already have an index -- may be incomplete
2111     if (AVI->video_index) {
2112 	free(AVI->video_index);
2113 	AVI->video_index = NULL;
2114     }
2115 
2116     for(j=0; j<AVI->anum; ++j) {
2117 	if(AVI->track[j].audio_index) {
2118 	    free(AVI->track[j].audio_index);
2119 	}
2120 	AVI->track[j].audio_index = NULL;
2121 	AVI->track[j].audio_chunks = 0;
2122     }
2123 
2124     if (!(fd = fopen(filename, "r"))) { perror ("avi_parse_index_from_file: fopen"); return -1; }
2125 
2126     // read header
2127     fgets(data, 100, fd);
2128 
2129     if ( strncasecmp(data, "AVIIDX1", 7) != 0) {
2130 	fprintf(stderr, "%s: Not an AVI index file\n", filename);
2131 	return -1;
2132     }
2133 
2134     // read comment
2135     fgets(data, 100, fd);
2136     f_pos = ftell(fd);
2137     while (fgets(data, 100, fd)) {
2138 	d = data[5] - '1';
2139 	if        (d == 0) {
2140 	    vid_chunks++;
2141 	} else if (d == 1 || d == 2 || d == 3 || d == 4 ||
2142 		   d == 5 || d == 6 || d == 7 || d == 8  ) {
2143 	    aud_chunks[d-1]++;
2144 	} else
2145 	    continue;
2146 
2147 	line_count++;
2148     }
2149 
2150     AVI->video_frames = vid_chunks;
2151     for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = aud_chunks[j];
2152 
2153     if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2154     AVI->video_index = (video_index_entry *) malloc(vid_chunks*sizeof(video_index_entry));
2155     if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2156 
2157     for(j=0; j<AVI->anum; ++j) {
2158 	if(AVI->track[j].audio_chunks) {
2159 	    AVI->track[j].audio_index = (audio_index_entry *) malloc(aud_chunks[j]*sizeof(audio_index_entry));
2160 	    if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2161 	}
2162     }
2163 
2164     // reset after header
2165     fseek(fd, f_pos, SEEK_SET);
2166 
2167     vid_chunks = 0;
2168     for(j=0; j<AVI->anum; ++j) aud_chunks[j] = tot_chunks[j] = 0;
2169 
2170     while (fgets(data, 100, fd)) {
2171 	// this is very slow
2172 	// sscanf(data, "%*s %d %*d %*d %lld %lld %d %*f", &type,  &pos, &len, &key);
2173 	c     = strchr (data, ' ');
2174 	type  = strtol(c+1, &c, 10);
2175 	//ch    = strtol(c+1, &c, 10);
2176 	c = strchr(c+1, ' ');
2177 	//chtype= strtol(c+1, &c, 10);
2178 	c = strchr(c+1, ' ');
2179 	pos   = strtoll(c+1, &c, 10);
2180 	len   = strtol(c+1, &c, 10);
2181 	key   = strtol(c+1, &c, 10);
2182 	//ms    = strtod(c+1, NULL);
2183 	i = type-1;
2184 
2185 	switch (i) {
2186 	    case 0: // video
2187 		AVI->video_index[vid_chunks].key = (off_t)(key?0x10:0);
2188 		AVI->video_index[vid_chunks].pos = pos+8;
2189 		AVI->video_index[vid_chunks].len = len;
2190 		vid_chunks++;
2191 		break;
2192 	    case 1: case 2: case 3: case 4:
2193 	    case 5: case 6: case 7: case 8:
2194 		j=i-1;
2195 		AVI->track[j].audio_index[aud_chunks[j]].pos = pos+8;
2196 		AVI->track[j].audio_index[aud_chunks[j]].len = len;
2197 		AVI->track[j].audio_index[aud_chunks[j]].tot = tot_chunks[j];
2198 		tot_chunks[j] += AVI->track[j].audio_index[aud_chunks[j]].len;
2199 		aud_chunks[j]++;
2200 		break;
2201 	    default:
2202 		continue;
2203 	}
2204 
2205     }
2206     for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot_chunks[j];
2207 
2208     fclose (fd);
2209 
2210     return 0;
2211 }
2212 
avi_parse_input_file(avi_t * AVI,int getIndex)2213 int avi_parse_input_file(avi_t *AVI, int getIndex)
2214 {
2215   long i, rate, scale, idx_type;
2216   off_t n;
2217   unsigned char *hdrl_data;
2218   long header_offset=0, hdrl_len=0;
2219   long nvi, nai[AVI_MAX_TRACKS], ioff;
2220   long tot[AVI_MAX_TRACKS];
2221   int j;
2222   int lasttag = 0;
2223   int vids_strh_seen = 0;
2224   int vids_strf_seen = 0;
2225   int auds_strh_seen = 0;
2226   //  int auds_strf_seen = 0;
2227   int num_stream = 0;
2228   char data[256];
2229   off_t oldpos=-1, newpos=-1;
2230 
2231   /* Read first 12 bytes and check that this is an AVI file */
2232 
2233    if( avi_read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
2234 
2235    if( strncasecmp(data  ,"RIFF",4) !=0 ||
2236        strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
2237 
2238    /* Go through the AVI file and extract the header list,
2239       the start position of the 'movi' list and an optionally
2240       present idx1 tag */
2241 
2242    hdrl_data = 0;
2243 
2244 
2245    while(1)
2246    {
2247       if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
2248       newpos = lseek(AVI->fdes,0,SEEK_CUR);
2249       if(oldpos==newpos) {
2250 	      /* This is a broken AVI stream... */
2251 	      return -1;
2252       }
2253       oldpos=newpos;
2254 
2255       n = str2ulong((unsigned char *)data+4);
2256       n = PAD_EVEN(n);
2257 
2258       if(strncasecmp(data,"LIST",4) == 0)
2259       {
2260          if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
2261          n -= 4;
2262          if(strncasecmp(data,"hdrl",4) == 0)
2263          {
2264             hdrl_len = n;
2265             hdrl_data = (unsigned char *) malloc(n);
2266             if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM);
2267 
2268 	    // offset of header
2269 
2270 	    header_offset = lseek(AVI->fdes,0,SEEK_CUR);
2271 
2272             if( avi_read(AVI->fdes,(char *)hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
2273          }
2274          else if(strncasecmp(data,"movi",4) == 0)
2275          {
2276             AVI->movi_start = lseek(AVI->fdes,0,SEEK_CUR);
2277             if (lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) break;
2278          }
2279          else
2280             if (lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) break;
2281       }
2282       else if(strncasecmp(data,"idx1",4) == 0)
2283       {
2284          /* n must be a multiple of 16, but the reading does not
2285             break if this is not the case */
2286 
2287          AVI->n_idx = AVI->max_idx = n/16;
2288          AVI->idx = (unsigned  char((*)[16]) ) malloc(n);
2289          if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
2290          if(avi_read(AVI->fdes, (char *) AVI->idx, n) != n ) {
2291 	     free ( AVI->idx); AVI->idx=NULL;
2292 	     AVI->n_idx = 0;
2293 	 }
2294       }
2295       else
2296          lseek(AVI->fdes,n,SEEK_CUR);
2297    }
2298 
2299    if(!hdrl_data      ) ERR_EXIT(AVI_ERR_NO_HDRL)
2300    if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
2301 
2302    /* Interpret the header list */
2303 
2304    for(i=0;i<hdrl_len;)
2305    {
2306       /* List tags are completly ignored */
2307 
2308 #ifdef DEBUG_ODML
2309       printf("TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]);
2310 #endif
2311 
2312       if(strncasecmp((char *)hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
2313 
2314       n = str2ulong(hdrl_data+i+4);
2315       n = PAD_EVEN(n);
2316 
2317 
2318       /* Interpret the tag and its args */
2319 
2320       if(strncasecmp((char *)hdrl_data+i,"strh",4)==0)
2321       {
2322          i += 8;
2323 #ifdef DEBUG_ODML
2324 	 printf("TAG   %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]);
2325 #endif
2326          if(strncasecmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
2327          {
2328             memcpy(AVI->compressor,hdrl_data+i+4,4);
2329             AVI->compressor[4] = 0;
2330 
2331 	    // ThOe
2332 	    AVI->v_codech_off = header_offset + i+4;
2333 
2334             scale = str2ulong(hdrl_data+i+20);
2335             rate  = str2ulong(hdrl_data+i+24);
2336             if(scale!=0) AVI->fps = (double)rate/(double)scale;
2337             AVI->video_frames = str2ulong(hdrl_data+i+32);
2338             AVI->video_strn = num_stream;
2339 	    AVI->max_len = 0;
2340             vids_strh_seen = 1;
2341             lasttag = 1; /* vids */
2342          }
2343          else if (strncasecmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
2344          {
2345 
2346 	   //inc audio tracks
2347 	   AVI->aptr=AVI->anum;
2348 	   ++AVI->anum;
2349 
2350 	   if(AVI->anum > AVI_MAX_TRACKS) {
2351 	     fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS);
2352 	     return(-1);
2353 	   }
2354 
2355 	   AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
2356 	   AVI->track[AVI->aptr].audio_strn = num_stream;
2357 
2358 	   // if samplesize==0 -> vbr
2359 	   AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44);
2360 
2361 	   AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24);
2362 
2363 	   //	   auds_strh_seen = 1;
2364 	   lasttag = 2; /* auds */
2365 
2366 	   // ThOe
2367 	   AVI->track[AVI->aptr].a_codech_off = header_offset + i;
2368 
2369          }
2370          else if (strncasecmp (hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) {
2371 	     fprintf(stderr, "AVILIB: error - DV AVI Type 1 no supported\n");
2372 	     return (-1);
2373 	 }
2374          else
2375             lasttag = 0;
2376          num_stream++;
2377       }
2378       else if(strncasecmp(hdrl_data+i,"dmlh",4) == 0) {
2379 	  AVI->total_frames = str2ulong(hdrl_data+i+8);
2380 #ifdef DEBUG_ODML
2381 	 fprintf(stderr, "real number of frames %d\n", AVI->total_frames);
2382 #endif
2383 	 i += 8;
2384       }
2385       else if(strncasecmp((char *)hdrl_data+i,"strf",4)==0)
2386       {
2387          i += 8;
2388          if(lasttag == 1)
2389          {
2390             alBITMAPINFOHEADER bih;
2391 
2392             memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER));
2393             AVI->bitmap_info_header = (alBITMAPINFOHEADER *)
2394               malloc(str2ulong((unsigned char *)&bih.bi_size));
2395             if (AVI->bitmap_info_header != NULL)
2396               memcpy(AVI->bitmap_info_header, hdrl_data + i,
2397                      str2ulong((unsigned char *)&bih.bi_size));
2398 
2399             AVI->width  = str2ulong(hdrl_data+i+4);
2400             AVI->height = str2ulong(hdrl_data+i+8);
2401                     vids_strf_seen = 1;
2402 	    //ThOe
2403 	    AVI->v_codecf_off = header_offset + i+16;
2404 
2405 	    memcpy(AVI->compressor2, hdrl_data+i+16, 4);
2406             AVI->compressor2[4] = 0;
2407 
2408          }
2409          else if(lasttag == 2)
2410          {
2411             alWAVEFORMATEX *wfe;
2412 	    char *nwfe;
2413             int wfes;
2414 
2415             if ((hdrl_len - i) < sizeof(alWAVEFORMATEX))
2416               wfes = hdrl_len - i;
2417             else
2418               wfes = sizeof(alWAVEFORMATEX);
2419             wfe = (alWAVEFORMATEX *)malloc(sizeof(alWAVEFORMATEX));
2420             if (wfe != NULL) {
2421               memset(wfe, 0, sizeof(alWAVEFORMATEX));
2422 	      memcpy(wfe, hdrl_data + i, wfes);
2423 	      if (str2ushort((unsigned char *)&wfe->cb_size) != 0) {
2424 		nwfe = (char *)
2425                   realloc(wfe, sizeof(alWAVEFORMATEX) +
2426                           str2ushort((unsigned char *)&wfe->cb_size));
2427 		if (nwfe != 0) {
2428 		  off_t lpos = lseek(AVI->fdes, 0, SEEK_CUR);
2429 		  lseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX),
2430 			SEEK_SET);
2431 		  wfe = (alWAVEFORMATEX *)nwfe;
2432 		  nwfe = &nwfe[sizeof(alWAVEFORMATEX)];
2433 		  avi_read(AVI->fdes, nwfe,
2434                            str2ushort((unsigned char *)&wfe->cb_size));
2435 		  lseek(AVI->fdes, lpos, SEEK_SET);
2436 		}
2437 	      }
2438 	      AVI->wave_format_ex[AVI->aptr] = wfe;
2439 	    }
2440 
2441             AVI->track[AVI->aptr].a_fmt   = str2ushort(hdrl_data+i  );
2442 
2443 	    //ThOe
2444 	    AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
2445 
2446             AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
2447             AVI->track[AVI->aptr].a_rate  = str2ulong (hdrl_data+i+4);
2448 	    //ThOe: read mp3bitrate
2449 	    AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
2450 	    //:ThOe
2451             AVI->track[AVI->aptr].a_bits  = str2ushort(hdrl_data+i+14);
2452 	    //            auds_strf_seen = 1;
2453          }
2454       }
2455       else if(strncasecmp(hdrl_data+i,"indx",4) == 0) {
2456 	 char *a;
2457 	 int j;
2458 
2459 	 if(lasttag == 1) // V I D E O
2460 	 {
2461 
2462 	    a = hdrl_data+i;
2463 
2464 	    AVI->video_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk));
2465 	    memcpy (AVI->video_superindex->fcc, a, 4);             a += 4;
2466 	    AVI->video_superindex->dwSize = str2ulong(a);          a += 4;
2467 	    AVI->video_superindex->wLongsPerEntry = str2ushort(a); a += 2;
2468 	    AVI->video_superindex->bIndexSubType = *a;             a += 1;
2469 	    AVI->video_superindex->bIndexType = *a;                a += 1;
2470 	    AVI->video_superindex->nEntriesInUse = str2ulong(a);   a += 4;
2471 	    memcpy (AVI->video_superindex->dwChunkId, a, 4);       a += 4;
2472 
2473 	    // 3 * reserved
2474 	    a += 4; a += 4; a += 4;
2475 
2476 	    if (AVI->video_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); }
2477 
2478 	    AVI->video_superindex->aIndex =
2479 	       malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (uint32_t));
2480 
2481 	    // position of ix## chunks
2482 	    for (j=0; j<AVI->video_superindex->nEntriesInUse; ++j) {
2483 	       AVI->video_superindex->aIndex[j].qwOffset = str2ullong (a);  a += 8;
2484 	       AVI->video_superindex->aIndex[j].dwSize = str2ulong (a);     a += 4;
2485 	       AVI->video_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4;
2486 
2487 #ifdef DEBUG_ODML
2488 	       printf("[%d] 0x%llx 0x%lx %lu\n", j,
2489 		       (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset,
2490 		       (unsigned long)AVI->video_superindex->aIndex[j].dwSize,
2491 		       (unsigned long)AVI->video_superindex->aIndex[j].dwDuration);
2492 #endif
2493 	    }
2494 
2495 
2496 #ifdef DEBUG_ODML
2497 	    printf("FOURCC \"%c%c%c%c\"\n", AVI->video_superindex->fcc[0], AVI->video_superindex->fcc[1],
2498 		                            AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]);
2499 	    printf("LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize);
2500 	    printf("wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry);
2501 	    printf("bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType);
2502 	    printf("bIndexType \"%d\"\n", AVI->video_superindex->bIndexType);
2503 	    printf("nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse);
2504 	    printf("dwChunkId \"%c%c%c%c\"\n", AVI->video_superindex->dwChunkId[0], AVI->video_superindex->dwChunkId[1],
2505 		                               AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]);
2506 	    printf("--\n");
2507 #endif
2508 
2509 	    AVI->is_opendml = 1;
2510 
2511 	 }
2512          else if(lasttag == 2) // A U D I O
2513          {
2514 
2515 	    a = hdrl_data+i;
2516 
2517 	    AVI->track[AVI->aptr].audio_superindex = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk));
2518 	    memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4);             a += 4;
2519 	    AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong(a);          a += 4;
2520 	    AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort(a); a += 2;
2521 	    AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a;             a += 1;
2522 	    AVI->track[AVI->aptr].audio_superindex->bIndexType = *a;                a += 1;
2523 	    AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong(a);   a += 4;
2524 	    memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4);       a += 4;
2525 
2526 	    // 3 * reserved
2527 	    a += 4; a += 4; a += 4;
2528 
2529 	    if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {fprintf(stderr, "Invalid Header, bIndexSubType != 0\n"); }
2530 
2531 	    AVI->track[AVI->aptr].audio_superindex->aIndex =
2532 	       malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry *
2533 		     AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (uint32_t));
2534 
2535 	    // position of ix## chunks
2536 	    for (j=0; j<AVI->track[AVI->aptr].audio_superindex->nEntriesInUse; ++j) {
2537 	       AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong (a);  a += 8;
2538 	       AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong (a);     a += 4;
2539 	       AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong (a); a += 4;
2540 
2541 #ifdef DEBUG_ODML
2542 	       printf("[%d] 0x%llx 0x%lx %lu\n", j,
2543 		       (unsigned long long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset,
2544 		       (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize,
2545 		       (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration);
2546 #endif
2547 	    }
2548 
2549 #ifdef DEBUG_ODML
2550 	    printf("FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc);
2551 	    printf("LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize);
2552 	    printf("wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry);
2553 	    printf("bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType);
2554 	    printf("bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType);
2555 	    printf("nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse);
2556 	    printf("dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]);
2557 	    printf("--\n");
2558 #endif
2559 
2560 	 }
2561 	 i += 8;
2562       }
2563       else if((strncasecmp(hdrl_data+i,"JUNK",4) == 0) ||
2564               (strncasecmp(hdrl_data+i,"strn",4) == 0) ||
2565               (strncasecmp(hdrl_data+i,"vprp",4) == 0)){
2566 	 i += 8;
2567 	 // do not reset lasttag
2568       } else
2569       {
2570          i += 8;
2571          lasttag = 0;
2572       }
2573       //printf("adding %ld bytes\n", (long int)n);
2574 
2575       i += n;
2576    }
2577 
2578    free(hdrl_data);
2579 
2580    if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
2581 
2582    AVI->video_tag[0] = AVI->video_strn/10 + '0';
2583    AVI->video_tag[1] = AVI->video_strn%10 + '0';
2584    AVI->video_tag[2] = 'd';
2585    AVI->video_tag[3] = 'b';
2586 
2587    /* Audio tag is set to "99wb" if no audio present */
2588    if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
2589 
2590    {
2591      int i=0;
2592      for(j=0; j<AVI->anum+1; ++j) {
2593        if (j == AVI->video_strn) continue;
2594        AVI->track[i].audio_tag[0] = j/10 + '0';
2595        AVI->track[i].audio_tag[1] = j%10 + '0';
2596        AVI->track[i].audio_tag[2] = 'w';
2597        AVI->track[i].audio_tag[3] = 'b';
2598        ++i;
2599      }
2600    }
2601 
2602    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2603 
2604    /* get index if wanted */
2605 
2606    if(AVI->index_file && !getIndex) {
2607        int ret;
2608 
2609        ret = avi_parse_index_from_file(AVI, AVI->index_file);
2610 
2611        /* Reposition the file */
2612 
2613        lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2614        AVI->video_pos = 0;
2615        return (ret);
2616 
2617    }
2618    if(!getIndex) return(0);
2619 
2620    /* if the file has an idx1, check if this is relative
2621       to the start of the file or to the start of the movi list */
2622 
2623    idx_type = 0;
2624 
2625    if(AVI->idx)
2626    {
2627       off_t pos, len;
2628 
2629       /* Search the first videoframe in the idx1 and look where
2630          it is in the file */
2631 
2632       for(i=0;i<AVI->n_idx;i++)
2633          if( strncasecmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
2634       if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
2635 
2636       pos = str2ulong(AVI->idx[i]+ 8);
2637       len = str2ulong(AVI->idx[i]+12);
2638 
2639       lseek(AVI->fdes,pos,SEEK_SET);
2640       if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2641       if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2642       {
2643          idx_type = 1; /* Index from start of file */
2644       }
2645       else
2646       {
2647          lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
2648          if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2649          if( strncasecmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2650          {
2651             idx_type = 2; /* Index from start of movi list */
2652          }
2653       }
2654       /* idx_type remains 0 if neither of the two tests above succeeds */
2655    }
2656 
2657 
2658    if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames)
2659    {
2660       /* we must search through the file to get the index */
2661 
2662       lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2663 
2664       AVI->n_idx = 0;
2665 
2666       while(1)
2667       {
2668          if( avi_read(AVI->fdes,data,8) != 8 ) break;
2669          n = str2ulong((unsigned char *)data+4);
2670 
2671          /* The movi list may contain sub-lists, ignore them */
2672 
2673          if(strncasecmp(data,"LIST",4)==0)
2674          {
2675             lseek(AVI->fdes,4,SEEK_CUR);
2676             continue;
2677          }
2678 
2679          /* Check if we got a tag ##db, ##dc or ##wb */
2680 
2681          if( ( (data[2]=='d' || data[2]=='D') &&
2682                (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
2683 	     || ( (data[2]=='w' || data[2]=='W') &&
2684 		  (data[3]=='b' || data[3]=='B') ) )
2685 	   {
2686 	   avi_add_index_entry(AVI,(unsigned char *)data,0, lseek(AVI->fdes,0,SEEK_CUR)-8,n);
2687          }
2688 
2689          lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2690       }
2691       idx_type = 1;
2692    }
2693 
2694    // ************************
2695    // OPENDML
2696    // ************************
2697 
2698    // read extended index chunks
2699    if (AVI->is_opendml) {
2700       uint64_t offset = 0;
2701       int hdrl_len = 4+4+2+1+1+4+4+8+4;
2702       char *en, *chunk_start;
2703       int k = 0, audtr = 0;
2704       uint32_t nrEntries = 0;
2705 
2706       AVI->video_index = NULL;
2707 
2708       nvi = 0;
2709       for(audtr=0; audtr<AVI->anum; ++audtr) nai[audtr] = tot[audtr] = 0;
2710 
2711       // ************************
2712       // VIDEO
2713       // ************************
2714 
2715       for (j=0; j<AVI->video_superindex->nEntriesInUse; j++) {
2716 
2717 	 // read from file
2718 	 chunk_start = en = malloc (AVI->video_superindex->aIndex[j].dwSize+hdrl_len);
2719 
2720 	 if (lseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) {
2721 	    fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__,
2722 		    (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset);
2723 	    free(chunk_start);
2724 	    continue;
2725 	 }
2726 
2727 	 if (avi_read(AVI->fdes, en, AVI->video_superindex->aIndex[j].dwSize+hdrl_len) <= 0) {
2728 	    fprintf(stderr, "(%s) cannot read from offset 0x%llx %ld bytes; broken (incomplete) file?\n",
2729 		  __FILE__, (unsigned long long)AVI->video_superindex->aIndex[j].qwOffset,
2730 		  (unsigned long)AVI->video_superindex->aIndex[j].dwSize+hdrl_len);
2731 	    free(chunk_start);
2732 	    continue;
2733 	 }
2734 
2735 	 nrEntries = str2ulong(en + 12);
2736 #ifdef DEBUG_ODML
2737 	 //printf("[%d:0] Video nrEntries %ld\n", j, nrEntries);
2738 #endif
2739 	 offset = str2ullong(en + 20);
2740 
2741 	 // skip header
2742 	 en += hdrl_len;
2743 	 nvi += nrEntries;
2744 	 AVI->video_index = (video_index_entry *) realloc (AVI->video_index, nvi * sizeof (video_index_entry));
2745 	 if (!AVI->video_index) {
2746 		 fprintf(stderr, "AVILIB: out of mem (size = %ld)\n", nvi * sizeof (video_index_entry));
2747 		 exit(1);
2748 	 }
2749 
2750 	 while (k < nvi) {
2751 
2752 	    AVI->video_index[k].pos = offset + str2ulong(en); en += 4;
2753 	    AVI->video_index[k].len = str2ulong_len(en);
2754 	    AVI->video_index[k].key = str2ulong_key(en); en += 4;
2755 
2756 	    // completely empty chunk
2757 	    if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) {
2758 		k--;
2759 		nvi--;
2760 	    }
2761 
2762 #ifdef DEBUG_ODML
2763 	    /*
2764 	    printf("[%d] POS 0x%llX len=%d key=%s offset (%llx) (%ld)\n", k,
2765 		  AVI->video_index[k].pos,
2766 		  (int)AVI->video_index[k].len,
2767 		  AVI->video_index[k].key?"yes":"no ", offset,
2768 		  AVI->video_superindex->aIndex[j].dwSize);
2769 		  */
2770 #endif
2771 
2772 	    k++;
2773 	 }
2774 
2775 	 free(chunk_start);
2776       }
2777 
2778       AVI->video_frames = nvi;
2779       // this should deal with broken 'rec ' odml files.
2780       if (AVI->video_frames == 0) {
2781 	  AVI->is_opendml=0;
2782 	  goto multiple_riff;
2783       }
2784 
2785       // ************************
2786       // AUDIO
2787       // ************************
2788 
2789       for(audtr=0; audtr<AVI->anum; ++audtr) {
2790 
2791 	 k = 0;
2792 	 if (!AVI->track[audtr].audio_superindex) {
2793 	       fprintf(stderr, "(%s) cannot read audio index for track %d\n", __FILE__, audtr);
2794 	       continue;
2795 	 }
2796 	 for (j=0; j<AVI->track[audtr].audio_superindex->nEntriesInUse; j++) {
2797 
2798 	    // read from file
2799 	    chunk_start = en = malloc (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len);
2800 
2801 	    if (lseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (off_t)-1) {
2802 	       fprintf(stderr, "(%s) cannot seek to 0x%llx\n", __FILE__, (unsigned long long)AVI->track[audtr].audio_superindex->aIndex[j].qwOffset);
2803 	       free(chunk_start);
2804 	       continue;
2805 	    }
2806 
2807 	    if (avi_read(AVI->fdes, en, AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len) <= 0) {
2808 	       fprintf(stderr, "(%s) cannot read from offset 0x%llx; broken (incomplete) file?\n",
2809 		     __FILE__,(unsigned long long) AVI->track[audtr].audio_superindex->aIndex[j].qwOffset);
2810 	       free(chunk_start);
2811 	       continue;
2812 	    }
2813 
2814 	    nrEntries = str2ulong(en + 12);
2815 	    //if (nrEntries > 50) nrEntries = 2; // XXX
2816 #ifdef DEBUG_ODML
2817 	    //printf("[%d:%d] Audio nrEntries %ld\n", j, audtr, nrEntries);
2818 #endif
2819 	    offset = str2ullong(en + 20);
2820 
2821 	    // skip header
2822 	    en += hdrl_len;
2823 	    nai[audtr] += nrEntries;
2824 	    AVI->track[audtr].audio_index = (audio_index_entry *) realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry));
2825 
2826 	    while (k < nai[audtr]) {
2827 
2828 	       AVI->track[audtr].audio_index[k].pos = offset + str2ulong(en); en += 4;
2829 	       AVI->track[audtr].audio_index[k].len = str2ulong_len(en); en += 4;
2830 	       AVI->track[audtr].audio_index[k].tot = tot[audtr];
2831 	       tot[audtr] += AVI->track[audtr].audio_index[k].len;
2832 
2833 #ifdef DEBUG_ODML
2834 	       /*
2835 		  printf("[%d:%d] POS 0x%llX len=%d offset (%llx) (%ld)\n", k, audtr,
2836 		  AVI->track[audtr].audio_index[k].pos,
2837 		  (int)AVI->track[audtr].audio_index[k].len,
2838 		  offset, AVI->track[audtr].audio_superindex->aIndex[j].dwSize);
2839 		  */
2840 #endif
2841 
2842 	       ++k;
2843 	    }
2844 
2845 	    free(chunk_start);
2846 	 }
2847 
2848 	 AVI->track[audtr].audio_chunks = nai[audtr];
2849 	 AVI->track[audtr].audio_bytes = tot[audtr];
2850       }
2851    } // is opendml
2852 
2853    else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) {
2854 
2855    // *********************
2856    // MULTIPLE RIFF CHUNKS (and no index)
2857    // *********************
2858 
2859       long aud_chunks = 0;
2860 multiple_riff:
2861 
2862       lseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2863 
2864       AVI->n_idx = 0;
2865 
2866       fprintf(stderr, "[avilib] Reconstructing index...");
2867 
2868       // Number of frames; only one audio track supported
2869       nvi = AVI->video_frames = AVI->total_frames;
2870       nai[0] = AVI->track[0].audio_chunks = AVI->total_frames;
2871       for(j=1; j<AVI->anum; ++j) AVI->track[j].audio_chunks = 0;
2872 
2873       AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
2874 
2875       if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2876 
2877       for(j=0; j<AVI->anum; ++j) {
2878 	  if(AVI->track[j].audio_chunks) {
2879 	      AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry));
2880 	      memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2881 	      if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2882 	  }
2883       }
2884 
2885       nvi = 0;
2886       for(j=0; j<AVI->anum; ++j) nai[j] = tot[j] = 0;
2887 
2888       aud_chunks = AVI->total_frames;
2889 
2890       while(1)
2891       {
2892 	 if (nvi >= AVI->total_frames) break;
2893 
2894          if( avi_read(AVI->fdes,data,8) != 8 ) break;
2895          n = str2ulong((unsigned char *)data+4);
2896 
2897 
2898 	 j=0;
2899 
2900 	 if (aud_chunks - nai[j] -1 <= 0) {
2901 	     aud_chunks += AVI->total_frames;
2902 	     AVI->track[j].audio_index = (audio_index_entry *)
2903 		 realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry));
2904 	     if (!AVI->track[j].audio_index) {
2905 		 fprintf(stderr, "Internal error in avilib -- no mem\n");
2906 		 AVI_errno = AVI_ERR_NO_MEM;
2907 		 return -1;
2908 	     }
2909 	 }
2910 
2911          /* Check if we got a tag ##db, ##dc or ##wb */
2912 
2913 	 // VIDEO
2914          if(
2915 	     (data[0]=='0' || data[1]=='0') &&
2916 	     (data[2]=='d' || data[2]=='D') &&
2917              (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) {
2918 
2919 	     AVI->video_index[nvi].key = 0x0;
2920 	     AVI->video_index[nvi].pos = lseek(AVI->fdes,0,SEEK_CUR);
2921 	     AVI->video_index[nvi].len = n;
2922 
2923 	     /*
2924 	     fprintf(stderr, "Frame %ld pos %lld len %lld key %ld\n",
2925 		     nvi, AVI->video_index[nvi].pos,  AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key);
2926 		     */
2927 	     nvi++;
2928 	     lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2929 	 }
2930 
2931 	 //AUDIO
2932 	 else if(
2933 		 (data[0]=='0' || data[1]=='1') &&
2934 		 (data[2]=='w' || data[2]=='W') &&
2935 	     (data[3]=='b' || data[3]=='B') ) {
2936 
2937 
2938 		AVI->track[j].audio_index[nai[j]].pos = lseek(AVI->fdes,0,SEEK_CUR);
2939 		AVI->track[j].audio_index[nai[j]].len = n;
2940 		AVI->track[j].audio_index[nai[j]].tot = tot[j];
2941 		tot[j] += AVI->track[j].audio_index[nai[j]].len;
2942 		nai[j]++;
2943 
2944 		lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2945 	 }
2946 	 else {
2947             lseek(AVI->fdes,-4,SEEK_CUR);
2948 	 }
2949 
2950       }
2951       if (nvi < AVI->total_frames) {
2952 	  fprintf(stderr, "\n[avilib] Uh? Some frames seems missing (%ld/%d)\n",
2953 		  nvi,  AVI->total_frames);
2954       }
2955 
2956 
2957       AVI->video_frames = nvi;
2958       AVI->track[0].audio_chunks = nai[0];
2959 
2960       for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2961       idx_type = 1;
2962       fprintf(stderr, "done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]);
2963 
2964    } // total_frames but no indx chunk (xawtv does this)
2965 
2966    else
2967 
2968    {
2969    // ******************
2970    // NO OPENDML
2971    // ******************
2972 
2973    /* Now generate the video index and audio index arrays */
2974 
2975    nvi = 0;
2976    for(j=0; j<AVI->anum; ++j) nai[j] = 0;
2977 
2978    for(i=0;i<AVI->n_idx;i++) {
2979 
2980      if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
2981 
2982      for(j=0; j<AVI->anum; ++j) if(strncasecmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
2983    }
2984 
2985    AVI->video_frames = nvi;
2986    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
2987 
2988 
2989    if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2990    AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry));
2991    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2992 
2993    for(j=0; j<AVI->anum; ++j) {
2994        if(AVI->track[j].audio_chunks) {
2995 	   AVI->track[j].audio_index = (audio_index_entry *) malloc((nai[j]+1)*sizeof(audio_index_entry));
2996 	   memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2997 	   if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2998        }
2999    }
3000 
3001    nvi = 0;
3002    for(j=0; j<AVI->anum; ++j) nai[j] = tot[j] = 0;
3003 
3004    ioff = idx_type == 1 ? 8 : AVI->movi_start+4;
3005 
3006    for(i=0;i<AVI->n_idx;i++) {
3007 
3008      //video
3009      if(strncasecmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
3010        AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
3011        AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
3012        AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
3013        nvi++;
3014      }
3015 
3016      //audio
3017      for(j=0; j<AVI->anum; ++j) {
3018 
3019        if(strncasecmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
3020 	 AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
3021 	 AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
3022 	 AVI->track[j].audio_index[nai[j]].tot = tot[j];
3023 	 tot[j] += AVI->track[j].audio_index[nai[j]].len;
3024 	 nai[j]++;
3025        }
3026      }
3027    }
3028 
3029 
3030    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
3031 
3032    } // is no opendml
3033 
3034    /* Reposition the file */
3035 
3036    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
3037    AVI->video_pos = 0;
3038 
3039    return(0);
3040 }
3041 
AVI_video_frames(avi_t * AVI)3042 long AVI_video_frames(avi_t *AVI)
3043 {
3044    return AVI->video_frames;
3045 }
AVI_video_width(avi_t * AVI)3046 int  AVI_video_width(avi_t *AVI)
3047 {
3048    return AVI->width;
3049 }
AVI_video_height(avi_t * AVI)3050 int  AVI_video_height(avi_t *AVI)
3051 {
3052    return AVI->height;
3053 }
AVI_frame_rate(avi_t * AVI)3054 double AVI_frame_rate(avi_t *AVI)
3055 {
3056    return AVI->fps;
3057 }
AVI_video_compressor(avi_t * AVI)3058 char* AVI_video_compressor(avi_t *AVI)
3059 {
3060    return AVI->compressor2;
3061 }
3062 
AVI_max_video_chunk(avi_t * AVI)3063 long AVI_max_video_chunk(avi_t *AVI)
3064 {
3065    return AVI->max_len;
3066 }
3067 
AVI_audio_tracks(avi_t * AVI)3068 int AVI_audio_tracks(avi_t *AVI)
3069 {
3070     return(AVI->anum);
3071 }
3072 
AVI_audio_channels(avi_t * AVI)3073 int AVI_audio_channels(avi_t *AVI)
3074 {
3075    return AVI->track[AVI->aptr].a_chans;
3076 }
3077 
AVI_audio_mp3rate(avi_t * AVI)3078 long AVI_audio_mp3rate(avi_t *AVI)
3079 {
3080    return AVI->track[AVI->aptr].mp3rate;
3081 }
3082 
AVI_audio_padrate(avi_t * AVI)3083 long AVI_audio_padrate(avi_t *AVI)
3084 {
3085    return AVI->track[AVI->aptr].padrate;
3086 }
3087 
AVI_audio_bits(avi_t * AVI)3088 int AVI_audio_bits(avi_t *AVI)
3089 {
3090    return AVI->track[AVI->aptr].a_bits;
3091 }
3092 
AVI_audio_format(avi_t * AVI)3093 int AVI_audio_format(avi_t *AVI)
3094 {
3095    return AVI->track[AVI->aptr].a_fmt;
3096 }
3097 
AVI_audio_rate(avi_t * AVI)3098 long AVI_audio_rate(avi_t *AVI)
3099 {
3100    return AVI->track[AVI->aptr].a_rate;
3101 }
3102 
AVI_audio_bytes(avi_t * AVI)3103 long AVI_audio_bytes(avi_t *AVI)
3104 {
3105    return AVI->track[AVI->aptr].audio_bytes;
3106 }
3107 
AVI_audio_chunks(avi_t * AVI)3108 long AVI_audio_chunks(avi_t *AVI)
3109 {
3110    return AVI->track[AVI->aptr].audio_chunks;
3111 }
3112 
AVI_audio_codech_offset(avi_t * AVI)3113 long AVI_audio_codech_offset(avi_t *AVI)
3114 {
3115    return AVI->track[AVI->aptr].a_codech_off;
3116 }
3117 
AVI_audio_codecf_offset(avi_t * AVI)3118 long AVI_audio_codecf_offset(avi_t *AVI)
3119 {
3120    return AVI->track[AVI->aptr].a_codecf_off;
3121 }
3122 
AVI_video_codech_offset(avi_t * AVI)3123 long  AVI_video_codech_offset(avi_t *AVI)
3124 {
3125     return AVI->v_codech_off;
3126 }
3127 
AVI_video_codecf_offset(avi_t * AVI)3128 long  AVI_video_codecf_offset(avi_t *AVI)
3129 {
3130     return AVI->v_codecf_off;
3131 }
3132 
AVI_frame_size(avi_t * AVI,long frame)3133 long AVI_frame_size(avi_t *AVI, long frame)
3134 {
3135    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3136    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3137 
3138    if(frame < 0 || frame >= AVI->video_frames) return 0;
3139    return(AVI->video_index[frame].len);
3140 }
3141 
AVI_audio_size(avi_t * AVI,long frame)3142 long AVI_audio_size(avi_t *AVI, long frame)
3143 {
3144   if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3145   if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3146 
3147   if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1;
3148   return(AVI->track[AVI->aptr].audio_index[frame].len);
3149 }
3150 
AVI_get_video_position(avi_t * AVI,long frame)3151 long AVI_get_video_position(avi_t *AVI, long frame)
3152 {
3153    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3154    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3155 
3156    if(frame < 0 || frame >= AVI->video_frames) return 0;
3157    return(AVI->video_index[frame].pos);
3158 }
3159 
3160 
AVI_seek_start(avi_t * AVI)3161 int AVI_seek_start(avi_t *AVI)
3162 {
3163    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3164 
3165    lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
3166    AVI->video_pos = 0;
3167    return 0;
3168 }
3169 
AVI_set_video_position(avi_t * AVI,long frame)3170 int AVI_set_video_position(avi_t *AVI, long frame)
3171 {
3172    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3173    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3174 
3175    if (frame < 0 ) frame = 0;
3176    AVI->video_pos = frame;
3177    return 0;
3178 }
3179 
AVI_set_audio_bitrate(avi_t * AVI,long bitrate)3180 int AVI_set_audio_bitrate(avi_t *AVI, long bitrate)
3181 {
3182    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3183 
3184    AVI->track[AVI->aptr].mp3rate = bitrate;
3185    return 0;
3186 }
3187 
3188 
AVI_read_frame(avi_t * AVI,char * vidbuf,int * keyframe)3189 long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe)
3190 {
3191    long n;
3192 
3193    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3194    if(!AVI->video_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3195 
3196    if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
3197    n = AVI->video_index[AVI->video_pos].len;
3198 
3199    *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
3200 
3201    if (vidbuf == NULL) {
3202      AVI->video_pos++;
3203      return n;
3204    }
3205 
3206    lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
3207 
3208    if (avi_read(AVI->fdes,vidbuf,n) != n)
3209    {
3210       AVI_errno = AVI_ERR_READ;
3211       return -1;
3212    }
3213 
3214    AVI->video_pos++;
3215 
3216    return n;
3217 }
3218 
AVI_get_audio_position_index(avi_t * AVI)3219 long AVI_get_audio_position_index(avi_t *AVI)
3220 {
3221    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3222    if(!AVI->track[AVI->aptr].audio_index) { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3223 
3224    return (AVI->track[AVI->aptr].audio_posc);
3225 }
3226 
AVI_set_audio_position_index(avi_t * AVI,long indexpos)3227 int AVI_set_audio_position_index(avi_t *AVI, long indexpos)
3228 {
3229    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3230    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3231    if(indexpos > AVI->track[AVI->aptr].audio_chunks)     { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3232 
3233    AVI->track[AVI->aptr].audio_posc = indexpos;
3234    AVI->track[AVI->aptr].audio_posb = 0;
3235 
3236    return 0;
3237 }
3238 
3239 
AVI_set_audio_position(avi_t * AVI,long byte)3240 int AVI_set_audio_position(avi_t *AVI, long byte)
3241 {
3242    long n0, n1, n;
3243 
3244    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3245    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3246 
3247    if(byte < 0) byte = 0;
3248 
3249    /* Binary search in the audio chunks */
3250 
3251    n0 = 0;
3252    n1 = AVI->track[AVI->aptr].audio_chunks;
3253 
3254    while(n0<n1-1)
3255    {
3256       n = (n0+n1)/2;
3257       if(AVI->track[AVI->aptr].audio_index[n].tot>byte)
3258          n1 = n;
3259       else
3260          n0 = n;
3261    }
3262 
3263    AVI->track[AVI->aptr].audio_posc = n0;
3264    AVI->track[AVI->aptr].audio_posb = byte - AVI->track[AVI->aptr].audio_index[n0].tot;
3265 
3266    return 0;
3267 }
3268 
AVI_read_audio(avi_t * AVI,char * audbuf,long bytes)3269 long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes)
3270 {
3271    long nr, left, todo;
3272    off_t pos;
3273 
3274    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3275    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3276 
3277    nr = 0; /* total number of bytes read */
3278 
3279    if (bytes==0) {
3280      AVI->track[AVI->aptr].audio_posc++;
3281      AVI->track[AVI->aptr].audio_posb = 0;
3282       lseek(AVI->fdes, 0LL, SEEK_CUR);
3283    }
3284    while(bytes>0)
3285    {
3286        off_t ret;
3287       left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
3288       if(left==0)
3289       {
3290          if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
3291          AVI->track[AVI->aptr].audio_posc++;
3292          AVI->track[AVI->aptr].audio_posb = 0;
3293          continue;
3294       }
3295       if(bytes<left)
3296          todo = bytes;
3297       else
3298          todo = left;
3299       pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3300       lseek(AVI->fdes, pos, SEEK_SET);
3301       if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != todo)
3302       {
3303 	 fprintf(stderr, "XXX pos = %lld, ret = %lld, todo = %ld\n", pos, ret, todo);
3304          AVI_errno = AVI_ERR_READ;
3305          return -1;
3306       }
3307       bytes -= todo;
3308       nr    += todo;
3309       AVI->track[AVI->aptr].audio_posb += todo;
3310    }
3311 
3312    return nr;
3313 }
3314 
AVI_read_audio_chunk(avi_t * AVI,char * audbuf)3315 long AVI_read_audio_chunk(avi_t *AVI, char *audbuf)
3316 {
3317    long left;
3318    off_t pos;
3319 
3320    if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
3321    if(!AVI->track[AVI->aptr].audio_index)         { AVI_errno = AVI_ERR_NO_IDX;   return -1; }
3322 
3323    if (AVI->track[AVI->aptr].audio_posc+1>AVI->track[AVI->aptr].audio_chunks) return -1;
3324 
3325    left = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb;
3326 
3327    if (audbuf == NULL) return left;
3328 
3329    if(left==0) {
3330        AVI->track[AVI->aptr].audio_posc++;
3331        AVI->track[AVI->aptr].audio_posb = 0;
3332        return 0;
3333    }
3334 
3335    pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3336    lseek(AVI->fdes, pos, SEEK_SET);
3337    if (avi_read(AVI->fdes,audbuf,left) != left)
3338    {
3339       AVI_errno = AVI_ERR_READ;
3340       return -1;
3341    }
3342    AVI->track[AVI->aptr].audio_posc++;
3343    AVI->track[AVI->aptr].audio_posb = 0;
3344 
3345    return left;
3346 }
3347 
3348 /* AVI_read_data: Special routine for reading the next audio or video chunk
3349                   without having an index of the file. */
3350 
AVI_read_data(avi_t * AVI,char * vidbuf,long max_vidbuf,char * audbuf,long max_audbuf,long * len)3351 int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
3352                               char *audbuf, long max_audbuf,
3353                               long *len)
3354 {
3355 
3356 /*
3357  * Return codes:
3358  *
3359  *    1 = video data read
3360  *    2 = audio data read
3361  *    0 = reached EOF
3362  *   -1 = video buffer too small
3363  *   -2 = audio buffer too small
3364  */
3365 
3366    off_t n;
3367    char data[8];
3368 
3369    if(AVI->mode==AVI_MODE_WRITE) return 0;
3370 
3371    while(1)
3372    {
3373       /* Read tag and length */
3374 
3375       if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
3376 
3377       /* if we got a list tag, ignore it */
3378 
3379       if(strncasecmp(data,"LIST",4) == 0)
3380       {
3381          lseek(AVI->fdes,4,SEEK_CUR);
3382          continue;
3383       }
3384 
3385       n = PAD_EVEN(str2ulong((unsigned char *)data+4));
3386 
3387       if(strncasecmp(data,AVI->video_tag,3) == 0)
3388       {
3389          *len = n;
3390          AVI->video_pos++;
3391          if(n>max_vidbuf)
3392          {
3393             lseek(AVI->fdes,n,SEEK_CUR);
3394             return -1;
3395          }
3396          if(avi_read(AVI->fdes,vidbuf,n) != n ) return 0;
3397          return 1;
3398       }
3399       else if(strncasecmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
3400       {
3401          *len = n;
3402          if(n>max_audbuf)
3403          {
3404             lseek(AVI->fdes,n,SEEK_CUR);
3405             return -2;
3406          }
3407          if(avi_read(AVI->fdes,audbuf,n) != n ) return 0;
3408          return 2;
3409          break;
3410       }
3411       else
3412          if(lseek(AVI->fdes,n,SEEK_CUR)<0)  return 0;
3413    }
3414 }
3415 
3416 /* AVI_print_error: Print most recent error (similar to perror) */
3417 
3418 char *(avi_errors[]) =
3419 {
3420   /*  0 */ "avilib - No Error",
3421   /*  1 */ "avilib - AVI file size limit reached",
3422   /*  2 */ "avilib - Error opening AVI file",
3423   /*  3 */ "avilib - Error reading from AVI file",
3424   /*  4 */ "avilib - Error writing to AVI file",
3425   /*  5 */ "avilib - Error writing index (file may still be useable)",
3426   /*  6 */ "avilib - Error closing AVI file",
3427   /*  7 */ "avilib - Operation (read/write) not permitted",
3428   /*  8 */ "avilib - Out of memory (malloc failed)",
3429   /*  9 */ "avilib - Not an AVI file",
3430   /* 10 */ "avilib - AVI file has no header list (corrupted?)",
3431   /* 11 */ "avilib - AVI file has no MOVI list (corrupted?)",
3432   /* 12 */ "avilib - AVI file has no video data",
3433   /* 13 */ "avilib - operation needs an index",
3434   /* 14 */ "avilib - Unkown Error"
3435 };
3436 static int num_avi_errors = sizeof(avi_errors)/sizeof(char*);
3437 
3438 static char error_string[4096];
3439 
AVI_print_error(char * str)3440 void AVI_print_error(char *str)
3441 {
3442    int aerrno;
3443 
3444    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
3445 
3446    if (aerrno != 0)
3447        fprintf(stderr,"%s: %s\n",str,avi_errors[aerrno]);
3448 
3449    /* for the following errors, perror should report a more detailed reason: */
3450 
3451    if(AVI_errno == AVI_ERR_OPEN ||
3452       AVI_errno == AVI_ERR_READ ||
3453       AVI_errno == AVI_ERR_WRITE ||
3454       AVI_errno == AVI_ERR_WRITE_INDEX ||
3455       AVI_errno == AVI_ERR_CLOSE )
3456    {
3457       perror("REASON");
3458    }
3459 }
3460 
AVI_strerror(void)3461 char *AVI_strerror(void)
3462 {
3463    int aerrno;
3464 
3465    aerrno = (AVI_errno>=0 && AVI_errno<num_avi_errors) ? AVI_errno : num_avi_errors-1;
3466 
3467    if(AVI_errno == AVI_ERR_OPEN ||
3468       AVI_errno == AVI_ERR_READ ||
3469       AVI_errno == AVI_ERR_WRITE ||
3470       AVI_errno == AVI_ERR_WRITE_INDEX ||
3471       AVI_errno == AVI_ERR_CLOSE )
3472    {
3473       snprintf(error_string, sizeof(error_string), "%s - %s",avi_errors[aerrno],strerror(errno));
3474       return error_string;
3475    }
3476    else
3477    {
3478       return avi_errors[aerrno];
3479    }
3480 }
3481 
AVI_max_size(void)3482 uint64_t AVI_max_size(void)
3483 {
3484   return((uint64_t) AVI_MAX_LEN);
3485 }
3486 
3487 #if 0
3488 
3489 // This expression is a compile-time constraint.  It will force a
3490 // compiler error, if the condition (the correct size of the struct
3491 // wave_header) is not met.  The reason that this may fail is
3492 // structure padding.  If it happens, the code should be changed to
3493 // use a byte array for the raw data, instead of doing the fixup
3494 // in-place.
3495 typedef char struct_packing_constraint [
3496     44 == sizeof(struct wave_header) ? 1 : -1];
3497 #endif
3498 
AVI_read_wave_header(int fd,struct wave_header * wave)3499 int AVI_read_wave_header( int fd, struct wave_header * wave )
3500 {
3501     char buf[44];
3502     // read raw data
3503     if( avi_read (fd, buf, 44) != 44)
3504     {
3505 	AVI_errno = AVI_ERR_READ;
3506 	return -1;
3507     }
3508 
3509     memcpy(&wave->riff.id      ,buf+0, 4);
3510     memcpy(&wave->riff.len     ,buf+4, 4);
3511     memcpy(&wave->riff.wave_id ,buf+8, 4);
3512 
3513     memcpy(&wave->format.id    ,buf+12, 4);
3514     memcpy(&wave->format.len   ,buf+16, 4);
3515 
3516     memcpy(&wave->common.wFormatTag       ,buf+20, 2);
3517     memcpy(&wave->common.wChannels        ,buf+22, 2);
3518     memcpy(&wave->common.dwSamplesPerSec  ,buf+24, 4);
3519     memcpy(&wave->common.dwAvgBytesPerSec ,buf+28, 4);
3520     memcpy(&wave->common.wBlockAlign      ,buf+32, 2);
3521     memcpy(&wave->common.wBitsPerSample   ,buf+34, 2);
3522 
3523     memcpy(&wave->data.id  ,buf+36, 4);
3524     memcpy(&wave->data.len ,buf+40, 4);
3525 
3526 
3527     /*
3528     fprintf(stderr, "RIFF: %c%c%c%c| (%d) (%d)\n",
3529 	    wave->riff.id[0], wave->riff.id[1], wave->riff.id[2], wave->riff.id[3],
3530 	    sizeof (*wave), sizeof (struct wave_header));
3531     fprintf(stderr, "WAVE: %c%c%c%c|\n",
3532 	    wave->riff.wave_id[0], wave->riff.wave_id[1], wave->riff.wave_id[2], wave->riff.wave_id[3]);
3533     fprintf(stderr, "fmt : %c%c%c%c|\n",
3534 	    wave->format.id[0], wave->format.id[1], wave->format.id[2], wave->format.id[3]);
3535     fprintf(stderr, "data: %c%c%c%c|\n",
3536 	    wave->data.id[0], wave->data.id[1], wave->data.id[2], wave->data.id[3]);
3537 	    */
3538 
3539     if( strncasecmp(wave->riff.id     , "RIFF",4) != 0 ||
3540 	strncasecmp(wave->riff.wave_id, "WAVE",4) != 0 ||
3541 	strncasecmp(wave->format.id   , "fmt ",4) != 0 )
3542     {
3543 	AVI_errno = AVI_ERR_NO_AVI;
3544 	return -1;
3545     }
3546 
3547 #define x_FIXUP(field) \
3548     ((field) = (sizeof(field) == 4 ? str2ulong((unsigned char*)&(field)) \
3549 				   : str2ushort((unsigned char*)&(field))))
3550 
3551     if (lav_detect_endian())
3552         {
3553         x_FIXUP(wave->riff.len);
3554         x_FIXUP(wave->format.len);
3555         x_FIXUP(wave->common.wFormatTag);
3556         x_FIXUP(wave->common.wChannels);
3557         x_FIXUP(wave->common.dwSamplesPerSec);
3558         x_FIXUP(wave->common.dwAvgBytesPerSec);
3559         x_FIXUP(wave->common.wBlockAlign);
3560         x_FIXUP(wave->common.wBitsPerSample);
3561         x_FIXUP(wave->data.len);
3562 	}
3563 
3564 #undef x_FIXUP
3565 
3566     return 0;
3567 }
3568 
AVI_write_wave_header(int fd,const struct wave_header * wave)3569 int AVI_write_wave_header( int fd, const struct wave_header * wave )
3570 {
3571     char buf[44];
3572     struct wave_header buffer = *wave;
3573 
3574 #define x_FIXUP(field) \
3575     ((sizeof(field) == 4 ? long2str((unsigned char*)&(field),(field)) \
3576 			 : short2str((unsigned char*)&(field),(field))))
3577 
3578     if (lav_detect_endian())
3579         {
3580         x_FIXUP(buffer.riff.len);
3581         x_FIXUP(buffer.format.len);
3582         x_FIXUP(buffer.common.wFormatTag);
3583         x_FIXUP(buffer.common.wChannels);
3584         x_FIXUP(buffer.common.dwSamplesPerSec);
3585         x_FIXUP(buffer.common.dwAvgBytesPerSec);
3586         x_FIXUP(buffer.common.wBlockAlign);
3587         x_FIXUP(buffer.common.wBitsPerSample);
3588         x_FIXUP(buffer.data.len);
3589 	}
3590 
3591 #undef x_FIXUP
3592 
3593     memcpy(buf+ 0, &buffer.riff.id, 4);
3594     memcpy(buf+ 4, &buffer.riff.len, 4);
3595     memcpy(buf+ 8, &buffer.riff.wave_id, 4);
3596 
3597     memcpy(buf+12, &buffer.format.id, 4);
3598     memcpy(buf+16, &buffer.format.len, 4);
3599 
3600     memcpy(buf+20, &buffer.common.wFormatTag, 2);
3601     memcpy(buf+22, &buffer.common.wChannels, 2);
3602     memcpy(buf+24, &buffer.common.dwSamplesPerSec, 4);
3603     memcpy(buf+28, &buffer.common.dwAvgBytesPerSec, 4);
3604     memcpy(buf+32, &buffer.common.wBlockAlign, 2);
3605     memcpy(buf+34, &buffer.common.wBitsPerSample, 2);
3606 
3607     memcpy(buf+36, &buffer.data.id, 4);
3608     memcpy(buf+40, &buffer.data.len, 4);
3609 
3610 
3611     // write raw data
3612     if( avi_write (fd, buf, sizeof(buf)) != sizeof(buf) )
3613     {
3614 	AVI_errno = AVI_ERR_WRITE;
3615 	return -1;
3616     }
3617 
3618     return 0;
3619 }
3620 
AVI_read_wave_pcm_data(int fd,void * buffer,size_t buflen)3621 size_t AVI_read_wave_pcm_data( int fd, void * buffer, size_t buflen )
3622 {
3623     int doneread = avi_read(fd, buffer, buflen);
3624     char * bufptr = buffer;
3625     size_t i;
3626     char tmp;
3627 
3628     if (lav_detect_endian())
3629        {
3630        for ( i=0; i<doneread; i+=2 )
3631 	   {
3632 	   tmp = bufptr[i];
3633 	   bufptr[i] = bufptr[i+1];
3634 	   bufptr[i+1] = tmp;
3635 	   }
3636         }
3637     return doneread;
3638 }
3639 
AVI_write_wave_pcm_data(int fd,const void * data,size_t datalen)3640 size_t AVI_write_wave_pcm_data( int fd, const void * data, size_t datalen )
3641 {
3642     size_t totalwritten = 0;
3643     const char * inptr = data;
3644     char buffer[2048];
3645     size_t i, buflen, donewritten;
3646 
3647     if (lav_detect_endian())
3648        {
3649        while (datalen > 0)
3650            {
3651 	   buflen = datalen;
3652 	   if( buflen > sizeof(buffer) )
3653 	       buflen = sizeof(buffer);
3654 
3655 	   for ( i=0; i<buflen; i+=2 )
3656 	       {
3657 	       buffer[i]   = inptr[i+1];
3658 	       buffer[i+1] = inptr[i];
3659 	       }
3660 	   donewritten = avi_write(fd, buffer, buflen);
3661 	   totalwritten += donewritten;
3662 	   if ( buflen != donewritten )
3663 	       {
3664 	       AVI_errno = AVI_ERR_WRITE;
3665 	       return totalwritten;
3666 	       }
3667 	    datalen -= buflen;
3668 	    inptr += buflen;
3669 	    }
3670         }
3671     else
3672         {
3673         totalwritten = avi_write(fd, (char *)data, datalen);
3674         if ( datalen != totalwritten )
3675 	    AVI_errno = AVI_ERR_WRITE;
3676         }
3677     return totalwritten;
3678 }
3679