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