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