Coverage Report

Created: 2025-12-14 06:51

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