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