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