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