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