Coverage Report

Created: 2023-11-19 06:24

/src/gpac/src/media_tools/avilib.c
Line
Count
Source (jump to first uncovered line)
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
0
{
64
0
  u32 r = 0;
65
66
0
  while (r < len) {
67
0
    s32 n = (s32) gf_fread(buf + r, len - r, fd);
68
0
    if (n == 0) break;
69
0
    if (n < 0) return r;
70
0
    r += n;
71
0
  }
72
73
0
  return r;
74
0
}
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
0
#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
0
{
107
0
  dst[0] = (n    )&0xff;
108
0
  dst[1] = (n>> 8)&0xff;
109
0
  dst[2] = (n>>16)&0xff;
110
0
  dst[3] = (n>>24)&0xff;
111
0
}
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
0
{
126
0
  u64 r = ((u32)str[0] | ((u32)str[1]<<8) | ((u32)str[2]<<16) | ((u32)str[3]<<24));
127
0
  u64 s = ((u32)str[4] | ((u32)str[5]<<8) | ((u32)str[6]<<16) | ((u32)str[7]<<24));
128
0
#ifdef __GNUC__
129
0
  return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffff);
130
#else
131
  return ((s<<32)&0xffffffff00000000)|(r&0xffffffff);
132
#endif
133
0
}
134
135
static u32 str2ulong(unsigned char *str)
136
0
{
137
0
  return ( (u32)str[0] | ((u32)str[1]<<8) | ((u32)str[2]<<16) | ((u32)str[3]<<24) );
138
0
}
139
static u32 str2ushort(unsigned char *str)
140
0
{
141
0
  return ( (u32)str[0] | ((u32)str[1]<<8) );
142
0
}
143
144
// bit 31 denotes a keyframe
145
static u32 str2ulong_len (unsigned char *str)
146
0
{
147
0
  return str2ulong(str) & 0x7fffffff;
148
0
}
149
150
151
// if bit 31 is 0, its a keyframe
152
static u32 str2ulong_key (unsigned char *str)
153
0
{
154
0
  u32 c = str2ulong(str);
155
0
  c &= 0x80000000;
156
0
  if (c == 0) return 0x10;
157
0
  else return 0;
158
0
}
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
0
{
165
0
  int s;
166
0
  s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
167
  //   if(s==0) s=1; /* avoid possible zero divisions */
168
0
  if(s<4) s=4; /* avoid possible zero divisions */
169
0
  return s;
170
0
}
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
0
{
544
0
  if(AVI->n_idx>=AVI->max_idx) {
545
0
    void *ptr = gf_realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
546
547
0
    if(ptr == 0) {
548
0
      AVI_errno = AVI_ERR_NO_MEM;
549
0
      return -1;
550
0
    }
551
0
    AVI->max_idx += 4096;
552
0
    AVI->idx = (unsigned char((*)[16]) ) ptr;
553
0
  }
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
0
  memcpy(AVI->idx[AVI->n_idx],tag,4);
560
0
  long2str(AVI->idx[AVI->n_idx]+ 4,flags);
561
0
  long2str(AVI->idx[AVI->n_idx]+ 8, (s32) pos);
562
0
  long2str(AVI->idx[AVI->n_idx]+12, (s32) len);
563
564
  /* Update counter */
565
566
0
  AVI->n_idx++;
567
568
0
  if(len>AVI->max_len) AVI->max_len=(u32) len;
569
570
0
  return 0;
571
0
}
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
0
{
1709
1710
0
  if (track + 1 > AVI->anum) return(-1);
1711
1712
  //this info is not written to file anyway
1713
0
  AVI->aptr=track;
1714
0
  return 0;
1715
0
}
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
0
{
1744
0
  int ret;
1745
0
  u32 j;
1746
1747
  /* If the file was open for writing, the header and index still have
1748
     to be written */
1749
1750
0
  if(AVI->mode == AVI_MODE_WRITE)
1751
0
    ret = avi_close_output_file(AVI);
1752
0
  else
1753
0
    ret = 0;
1754
1755
  /* Even if there happened an error, we first clean up */
1756
1757
0
  gf_fclose(AVI->fdes);
1758
0
  if(AVI->idx) gf_free(AVI->idx);
1759
0
  if(AVI->video_index) gf_free(AVI->video_index);
1760
0
  if(AVI->video_superindex) {
1761
0
    if(AVI->video_superindex->aIndex) gf_free(AVI->video_superindex->aIndex);
1762
0
    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
0
    gf_free(AVI->video_superindex);
1771
0
  }
1772
1773
0
  for (j=0; j<AVI->anum; j++)
1774
0
  {
1775
0
    if(AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index);
1776
0
    if(AVI->track[j].audio_superindex) {
1777
0
      avisuperindex_chunk *asi = AVI->track[j].audio_superindex;
1778
0
      if (asi->aIndex) gf_free(asi->aIndex);
1779
1780
0
      if (asi->stdindex) {
1781
0
        for (j=0; j < NR_IXNN_CHUNKS; j++) {
1782
0
          if (asi->stdindex[j]->aIndex)
1783
0
            gf_free(asi->stdindex[j]->aIndex);
1784
0
          gf_free(asi->stdindex[j]);
1785
0
        }
1786
0
        gf_free(asi->stdindex);
1787
0
      }
1788
0
      gf_free(asi);
1789
0
    }
1790
0
  }
1791
1792
0
  if (AVI->bitmap_info_header)
1793
0
    gf_free(AVI->bitmap_info_header);
1794
0
  for (j = 0; j < AVI->anum; j++)
1795
0
    if (AVI->wave_format_ex[j])
1796
0
      gf_free(AVI->wave_format_ex[j]);
1797
0
  if (AVI->extradata)
1798
0
    gf_free(AVI->extradata);
1799
1800
0
  gf_free(AVI);
1801
0
  return ret;
1802
0
}
1803
1804
1805
0
#define ERR_EXIT(x) \
1806
0
{ \
1807
0
   AVI_close(AVI); \
1808
0
   AVI_errno = x; \
1809
0
   return 0; \
1810
0
}
1811
1812
1813
avi_t *AVI_open_input_file(char *filename, int getIndex)
1814
0
{
1815
0
  avi_t *AVI;
1816
1817
  /* Create avi_t structure */
1818
1819
0
  AVI = (avi_t *) gf_malloc(sizeof(avi_t));
1820
0
  if(AVI==NULL)
1821
0
  {
1822
0
    AVI_errno = AVI_ERR_NO_MEM;
1823
0
    return 0;
1824
0
  }
1825
0
  memset((void *)AVI,0,sizeof(avi_t));
1826
1827
0
  AVI->mode = AVI_MODE_READ; /* open for reading */
1828
1829
  /* Open the file */
1830
1831
0
  AVI->fdes = gf_fopen(filename,"rb");
1832
0
  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
0
  AVI_errno = 0;
1840
0
  avi_parse_input_file(AVI, getIndex);
1841
1842
0
  if (AVI != NULL && !AVI_errno) {
1843
0
    AVI->aptr=0; //reset
1844
0
  }
1845
1846
0
  if (AVI_errno) return NULL;
1847
1848
0
  return AVI;
1849
0
}
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
0
{
1887
0
  int rate, scale, idx_type;
1888
0
  s64 n, i;
1889
0
  unsigned char *hdrl_data;
1890
0
  u64 header_offset=0;
1891
0
  int hdrl_len=0;
1892
0
  int nvi, nai[AVI_MAX_TRACKS], ioff;
1893
0
  u64 tot[AVI_MAX_TRACKS];
1894
0
  u32 j;
1895
0
  int lasttag = 0;
1896
0
  int vids_strh_seen = 0;
1897
0
  int vids_strf_seen = 0;
1898
0
  int auds_strh_seen = 0;
1899
  //  int auds_strf_seen = 0;
1900
0
  int num_stream = 0;
1901
0
  char data[256];
1902
0
  s64 oldpos=-1, newpos=-1;
1903
1904
0
  int aud_chunks = 0;
1905
0
  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
0
  if (avi_read(AVI->fdes,data,12) != 12 )
1912
0
    ERR_EXIT(AVI_ERR_READ)
1913
1914
0
  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
0
  hdrl_data = 0;
1922
1923
0
  while(1)
1924
0
  {
1925
0
    if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
1926
0
    newpos = gf_ftell(AVI->fdes);
1927
0
    if(oldpos==newpos) {
1928
      /* This is a broken AVI stream... */
1929
0
      return -1;
1930
0
    }
1931
0
    oldpos=newpos;
1932
1933
0
    n = str2ulong((unsigned char *)data+4);
1934
0
    n = PAD_EVEN(n);
1935
1936
0
    if(strnicmp(data,"LIST",4) == 0)
1937
0
    {
1938
0
      if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
1939
0
        n -= 4;
1940
0
      if(strnicmp(data,"hdrl",4) == 0)
1941
0
      {
1942
0
        if (n>0xFFFFFFFF) ERR_EXIT(AVI_ERR_READ)
1943
0
        hdrl_len = (u32) n;
1944
0
        hdrl_data = (unsigned char *) gf_malloc((u32)n);
1945
0
        if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM);
1946
1947
        // offset of header
1948
1949
0
        header_offset = gf_ftell(AVI->fdes);
1950
1951
0
        if( avi_read(AVI->fdes,(char *)hdrl_data, (u32) n) != n ) {
1952
0
          if (hdrl_data) gf_free(hdrl_data);
1953
0
          ERR_EXIT(AVI_ERR_READ)
1954
0
        }
1955
0
      }
1956
0
      else if(strnicmp(data,"movi",4) == 0)
1957
0
      {
1958
0
        AVI->movi_start = gf_ftell(AVI->fdes);
1959
0
        if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
1960
0
      }
1961
0
      else if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
1962
0
    }
1963
0
    else if(strnicmp(data,"idx1",4) == 0)
1964
0
    {
1965
      /* n must be a multiple of 16, but the reading does not
1966
         break if this is not the case */
1967
1968
0
      AVI->n_idx = AVI->max_idx = (u32) (n/16);
1969
0
      AVI->idx = (unsigned  char((*)[16]) ) gf_malloc((u32)n);
1970
0
      if(AVI->idx==0) {
1971
0
        if (hdrl_data) gf_free(hdrl_data);
1972
0
        ERR_EXIT(AVI_ERR_NO_MEM)
1973
0
      }
1974
0
      if(avi_read(AVI->fdes, (char *) AVI->idx, (u32) n) != n ) {
1975
0
        gf_free( AVI->idx);
1976
0
        AVI->idx=NULL;
1977
0
        AVI->n_idx = 0;
1978
0
        if (hdrl_data) gf_free(hdrl_data);
1979
0
        ERR_EXIT(AVI_ERR_READ)
1980
0
      }
1981
0
    }
1982
0
    else
1983
0
      gf_fseek(AVI->fdes,n,SEEK_CUR);
1984
0
  }
1985
1986
0
  if(!hdrl_data) ERR_EXIT(AVI_ERR_NO_HDRL)
1987
0
  if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
1988
1989
      /* Interpret the header list */
1990
1991
0
      for(i=0; i<hdrl_len;)
1992
0
      {
1993
        /* List tags are completly ignored */
1994
1995
#ifdef DEBUG_ODML
1996
        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]));
1997
#endif
1998
1999
0
        if(strnicmp((char *)hdrl_data+i,"LIST",4)==0) {
2000
0
          i+= 12;
2001
0
          continue;
2002
0
        }
2003
2004
0
        n = str2ulong(hdrl_data+i+4);
2005
0
        n = PAD_EVEN(n);
2006
0
        if (i+n>hdrl_len) ERR_EXIT(AVI_ERR_READ)
2007
2008
2009
        /* Interpret the tag and its args */
2010
2011
0
        if(strnicmp((char *)hdrl_data+i,"strh",4)==0)
2012
0
        {
2013
0
          i += 8;
2014
#ifdef DEBUG_ODML
2015
          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]));
2016
#endif
2017
0
          if(strnicmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
2018
0
          {
2019
0
            memcpy(AVI->compressor,hdrl_data+i+4,4);
2020
0
            AVI->compressor[4] = 0;
2021
2022
            // ThOe
2023
0
            AVI->v_codech_off = header_offset + i+4;
2024
2025
0
            scale = str2ulong(hdrl_data+i+20);
2026
0
            rate  = str2ulong(hdrl_data+i+24);
2027
0
            if(scale!=0) AVI->fps = (double)rate/(double)scale;
2028
0
            AVI->video_frames = str2ulong(hdrl_data+i+32);
2029
0
            AVI->video_strn = num_stream;
2030
0
            AVI->max_len = 0;
2031
0
            vids_strh_seen = 1;
2032
0
            lasttag = 1; /* vids */
2033
0
            memcpy(&AVI->video_stream_header, hdrl_data + i,
2034
0
                   sizeof(alAVISTREAMHEADER));
2035
0
          }
2036
0
          else if (strnicmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
2037
0
          {
2038
2039
            //inc audio tracks
2040
0
            AVI->aptr=AVI->anum;
2041
0
            ++AVI->anum;
2042
2043
0
            if(AVI->anum > AVI_MAX_TRACKS) {
2044
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] error - only %d audio tracks supported\n", AVI_MAX_TRACKS));
2045
0
              return(-1);
2046
0
            }
2047
2048
0
            AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
2049
0
            AVI->track[AVI->aptr].audio_strn = num_stream;
2050
2051
            // if samplesize==0 -> vbr
2052
0
            AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44);
2053
2054
0
            AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24);
2055
0
            memcpy(&AVI->stream_headers[AVI->aptr], hdrl_data + i,
2056
0
                   sizeof(alAVISTREAMHEADER));
2057
2058
            //     auds_strh_seen = 1;
2059
0
            lasttag = 2; /* auds */
2060
2061
            // ThOe
2062
0
            AVI->track[AVI->aptr].a_codech_off = header_offset + i;
2063
2064
0
          }
2065
0
          else if (strnicmp ((char*)hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) {
2066
0
            GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] AVILIB: error - DV AVI Type 1 no supported\n"));
2067
0
            return (-1);
2068
0
          }
2069
0
          else
2070
0
            lasttag = 0;
2071
0
          num_stream++;
2072
0
        }
2073
0
        else if(strnicmp((char*)hdrl_data+i,"dmlh",4) == 0) {
2074
0
          AVI->total_frames = str2ulong(hdrl_data+i+8);
2075
#ifdef DEBUG_ODML
2076
          GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] real number of frames %d\n", AVI->total_frames));
2077
#endif
2078
0
          i += 8;
2079
0
        }
2080
0
        else if(strnicmp((char *)hdrl_data+i,"strf",4)==0)
2081
0
        {
2082
0
          i += 8;
2083
0
          if(lasttag == 1)
2084
0
          {
2085
0
            alBITMAPINFOHEADER bih;
2086
2087
0
            memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER));
2088
0
            bih.bi_size = str2ulong((unsigned char *)&bih.bi_size);
2089
2090
0
            if (i + bih.bi_size > hdrl_len) ERR_EXIT(AVI_ERR_READ)
2091
2092
0
            AVI->bitmap_info_header = (alBITMAPINFOHEADER *) gf_malloc(bih.bi_size);
2093
0
            if (AVI->bitmap_info_header != NULL)
2094
0
              memcpy(AVI->bitmap_info_header, hdrl_data + i, bih.bi_size);
2095
2096
0
            AVI->width  = str2ulong(hdrl_data+i+4);
2097
0
            AVI->height = str2ulong(hdrl_data+i+8);
2098
0
            vids_strf_seen = 1;
2099
            //ThOe
2100
0
            AVI->v_codecf_off = header_offset + i+16;
2101
2102
0
            memcpy(AVI->compressor2, hdrl_data+i+16, 4);
2103
0
            AVI->compressor2[4] = 0;
2104
2105
0
            if (n>40) {
2106
0
              if (n>0xFFFFFFFF) ERR_EXIT(AVI_ERR_READ)
2107
0
              AVI->extradata_size = (u32) (n - 40);
2108
0
              AVI->extradata = gf_malloc(sizeof(u8)* AVI->extradata_size);
2109
0
              if (!AVI->extradata) ERR_EXIT(AVI_ERR_NO_MEM)
2110
0
              memcpy(AVI->extradata, hdrl_data + i + 40, AVI->extradata_size);
2111
0
            }
2112
2113
0
          }
2114
0
          else if(lasttag == 2)
2115
0
          {
2116
0
            alWAVEFORMATEX *wfe;
2117
0
            char *nwfe;
2118
0
            int wfes;
2119
2120
0
            if ((u32) (hdrl_len - i) < sizeof(alWAVEFORMATEX))
2121
0
              wfes = (int) (hdrl_len - i);
2122
0
            else
2123
0
              wfes = sizeof(alWAVEFORMATEX);
2124
0
            wfe = (alWAVEFORMATEX *)gf_malloc(sizeof(alWAVEFORMATEX));
2125
0
            if (wfe != NULL) {
2126
0
              memset(wfe, 0, sizeof(alWAVEFORMATEX));
2127
0
              memcpy(wfe, hdrl_data + i, wfes);
2128
0
              if (str2ushort((unsigned char *)&wfe->cb_size) != 0) {
2129
0
                nwfe = (char *)
2130
0
                       gf_realloc(wfe, sizeof(alWAVEFORMATEX) +
2131
0
                                  str2ushort((unsigned char *)&wfe->cb_size));
2132
0
                if (nwfe != 0) {
2133
0
                  s64 lpos = gf_ftell(AVI->fdes);
2134
0
                  gf_fseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX),
2135
0
                           SEEK_SET);
2136
0
                  wfe = (alWAVEFORMATEX *)nwfe;
2137
0
                  nwfe = &nwfe[sizeof(alWAVEFORMATEX)];
2138
0
                  avi_read(AVI->fdes, nwfe,
2139
0
                           str2ushort((unsigned char *)&wfe->cb_size));
2140
0
                  gf_fseek(AVI->fdes, lpos, SEEK_SET);
2141
0
                }
2142
0
              }
2143
0
              AVI->wave_format_ex[AVI->aptr] = wfe;
2144
0
            }
2145
2146
0
            AVI->track[AVI->aptr].a_fmt   = str2ushort(hdrl_data+i  );
2147
2148
            //ThOe
2149
0
            AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
2150
2151
0
            AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
2152
0
            AVI->track[AVI->aptr].a_rate  = str2ulong (hdrl_data+i+4);
2153
            //ThOe: read mp3bitrate
2154
0
            AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
2155
            //:ThOe
2156
0
            AVI->track[AVI->aptr].a_bits  = str2ushort(hdrl_data+i+14);
2157
            //            auds_strf_seen = 1;
2158
0
          }
2159
0
        }
2160
0
        else if(strnicmp((char*)hdrl_data+i,"indx",4) == 0) {
2161
0
          char *a;
2162
2163
0
          if(lasttag == 1) // V I D E O
2164
0
          {
2165
2166
0
            a = (char*)hdrl_data+i;
2167
0
            int avail =(int) (hdrl_len-i);
2168
0
            if (avail<32) ERR_EXIT(AVI_ERR_READ)
2169
2170
0
            AVI->video_superindex = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk));
2171
0
            memset(AVI->video_superindex, 0, sizeof (avisuperindex_chunk));
2172
0
            memcpy (AVI->video_superindex->fcc, a, 4);
2173
0
            a += 4;
2174
0
            AVI->video_superindex->dwSize = str2ulong((unsigned char *)a);
2175
0
            a += 4;
2176
0
            AVI->video_superindex->wLongsPerEntry = str2ushort((unsigned char *)a);
2177
0
            a += 2;
2178
0
            AVI->video_superindex->bIndexSubType = *a;
2179
0
            a += 1;
2180
0
            AVI->video_superindex->bIndexType = *a;
2181
0
            a += 1;
2182
0
            AVI->video_superindex->nEntriesInUse = str2ulong((unsigned char *)a);
2183
0
            a += 4;
2184
0
            memcpy (AVI->video_superindex->dwChunkId, a, 4);
2185
0
            a += 4;
2186
2187
            // 3 * reserved
2188
0
            a += 4;
2189
0
            a += 4;
2190
0
            a += 4;
2191
2192
0
            if (AVI->video_superindex->bIndexSubType != 0) {
2193
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
2194
0
            }
2195
0
            avail -= 32;
2196
0
            if (avail < (int) AVI->video_superindex->nEntriesInUse*16) ERR_EXIT(AVI_ERR_READ)
2197
2198
0
            AVI->video_superindex->aIndex = (avisuperindex_entry*)
2199
0
                                            gf_malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (u32));
2200
2201
            // position of ix## chunks
2202
0
            for (j=0; j<AVI->video_superindex->nEntriesInUse; ++j) {
2203
0
              AVI->video_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
2204
0
              a += 8;
2205
0
              AVI->video_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
2206
0
              a += 4;
2207
0
              AVI->video_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
2208
0
              a += 4;
2209
2210
#ifdef DEBUG_ODML
2211
              GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
2212
                                                      (unsigned int long)AVI->video_superindex->aIndex[j].qwOffset,
2213
                                                      (unsigned long)AVI->video_superindex->aIndex[j].dwSize,
2214
                                                      (unsigned long)AVI->video_superindex->aIndex[j].dwDuration));
2215
#endif
2216
0
            }
2217
2218
2219
#ifdef DEBUG_ODML
2220
            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],
2221
                                                    AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]));
2222
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize));
2223
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry));
2224
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType));
2225
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->video_superindex->bIndexType));
2226
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse));
2227
            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],
2228
                                                    AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]));
2229
#endif
2230
2231
0
            AVI->is_opendml = 1;
2232
2233
0
          }
2234
0
          else if(lasttag == 2) // A U D I O
2235
0
          {
2236
2237
0
            a = (char*) hdrl_data+i;
2238
0
            int avail = (int) (hdrl_len-i);
2239
0
            if (avail<32) ERR_EXIT(AVI_ERR_READ)
2240
2241
0
            AVI->track[AVI->aptr].audio_superindex = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk));
2242
0
            memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4);
2243
0
            a += 4;
2244
0
            AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong((unsigned char*)a);
2245
0
            a += 4;
2246
0
            AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort((unsigned char*)a);
2247
0
            a += 2;
2248
0
            AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a;
2249
0
            a += 1;
2250
0
            AVI->track[AVI->aptr].audio_superindex->bIndexType = *a;
2251
0
            a += 1;
2252
0
            AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong((unsigned char*)a);
2253
0
            a += 4;
2254
0
            memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4);
2255
0
            a += 4;
2256
2257
            // 3 * reserved
2258
0
            a += 4;
2259
0
            a += 4;
2260
0
            a += 4;
2261
2262
0
            if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {
2263
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
2264
0
            }
2265
2266
0
            avail -= 32;
2267
0
            if (avail < (int) AVI->track[AVI->aptr].audio_superindex->nEntriesInUse*16) ERR_EXIT(AVI_ERR_READ)
2268
2269
0
            AVI->track[AVI->aptr].audio_superindex->aIndex = (avisuperindex_entry*)
2270
0
                    gf_malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry *
2271
0
                               AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (u32));
2272
2273
            // position of ix## chunks
2274
0
            for (j=0; j<AVI->track[AVI->aptr].audio_superindex->nEntriesInUse; ++j) {
2275
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
2276
0
              a += 8;
2277
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
2278
0
              a += 4;
2279
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
2280
0
              a += 4;
2281
2282
#ifdef DEBUG_ODML
2283
              GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
2284
                                                      (unsigned int long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset,
2285
                                                      (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize,
2286
                                                      (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration));
2287
#endif
2288
0
            }
2289
2290
0
            AVI->track[AVI->aptr].audio_superindex->stdindex = NULL;
2291
2292
#ifdef DEBUG_ODML
2293
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc));
2294
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize));
2295
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry));
2296
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType));
2297
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType));
2298
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse));
2299
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]));
2300
#endif
2301
2302
0
          }
2303
0
          i += 8;
2304
0
        }
2305
0
        else if((strnicmp((char*)hdrl_data+i,"JUNK",4) == 0) ||
2306
0
                (strnicmp((char*)hdrl_data+i,"strn",4) == 0) ||
2307
0
                (strnicmp((char*)hdrl_data+i,"vprp",4) == 0)) {
2308
0
          i += 8;
2309
          // do not reset lasttag
2310
0
        } else
2311
0
        {
2312
0
          i += 8;
2313
0
          lasttag = 0;
2314
0
        }
2315
        //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] adding %ld bytes\n", (int int)n));
2316
2317
0
        i += (u32) n;
2318
0
      }
2319
2320
0
  gf_free(hdrl_data);
2321
2322
0
  if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
2323
2324
0
    AVI->video_tag[0] = AVI->video_strn/10 + '0';
2325
0
  AVI->video_tag[1] = AVI->video_strn%10 + '0';
2326
0
  AVI->video_tag[2] = 'd';
2327
0
  AVI->video_tag[3] = 'b';
2328
2329
  /* Audio tag is set to "99wb" if no audio present */
2330
0
  if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
2331
2332
0
  {
2333
0
    int tk=0;
2334
0
    for(j=0; j<AVI->anum+1; ++j) {
2335
0
      if (j == AVI->video_strn) continue;
2336
0
      AVI->track[tk].audio_tag[0] = j/10 + '0';
2337
0
      AVI->track[tk].audio_tag[1] = j%10 + '0';
2338
0
      AVI->track[tk].audio_tag[2] = 'w';
2339
0
      AVI->track[tk].audio_tag[3] = 'b';
2340
0
      ++tk;
2341
0
    }
2342
0
  }
2343
2344
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2345
2346
0
  if(!getIndex) return(0);
2347
2348
  /* if the file has an idx1, check if this is relative
2349
     to the start of the file or to the start of the movi list */
2350
2351
0
  idx_type = 0;
2352
2353
0
  if(AVI->idx)
2354
0
  {
2355
0
    s64 pos, len;
2356
2357
    /* Search the first videoframe in the idx1 and look where
2358
       it is in the file */
2359
2360
0
    for(i=0; i<AVI->n_idx; i++)
2361
0
      if( strnicmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
2362
0
    if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
2363
2364
0
      pos = str2ulong(AVI->idx[i]+ 8);
2365
0
    len = str2ulong(AVI->idx[i]+12);
2366
2367
0
    gf_fseek(AVI->fdes,pos,SEEK_SET);
2368
0
    if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2369
0
      if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2370
0
      {
2371
0
        idx_type = 1; /* Index from start of file */
2372
0
      }
2373
0
      else
2374
0
      {
2375
0
        gf_fseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
2376
0
        if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2377
0
          if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2378
0
          {
2379
0
            idx_type = 2; /* Index from start of movi list */
2380
0
          }
2381
0
      }
2382
    /* idx_type remains 0 if neither of the two tests above succeeds */
2383
0
  }
2384
2385
2386
0
  if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames)
2387
0
  {
2388
    /* we must search through the file to get the index */
2389
2390
0
    gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2391
2392
0
    AVI->n_idx = 0;
2393
2394
0
    while(1)
2395
0
    {
2396
0
      if( avi_read(AVI->fdes,data,8) != 8 ) break;
2397
0
      n = str2ulong((unsigned char *)data+4);
2398
2399
      /* The movi list may contain sub-lists, ignore them */
2400
2401
0
      if(strnicmp(data,"LIST",4)==0)
2402
0
      {
2403
0
        gf_fseek(AVI->fdes,4,SEEK_CUR);
2404
0
        continue;
2405
0
      }
2406
2407
      /* Check if we got a tag ##db, ##dc or ##wb */
2408
2409
0
      if( ( (data[2]=='d' || data[2]=='D') &&
2410
0
              (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
2411
0
              || ( (data[2]=='w' || data[2]=='W') &&
2412
0
                   (data[3]=='b' || data[3]=='B') ) )
2413
0
      {
2414
0
        u64 __pos = gf_ftell(AVI->fdes) - 8;
2415
0
        avi_add_index_entry(AVI,(unsigned char *)data,0,__pos,n);
2416
0
      }
2417
2418
0
      gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2419
0
    }
2420
0
    idx_type = 1;
2421
0
  }
2422
2423
  // ************************
2424
  // OPENDML
2425
  // ************************
2426
2427
  // read extended index chunks
2428
0
  if (AVI->is_opendml) {
2429
0
    u64 offset = 0;
2430
0
    hdrl_len = 4+4+2+1+1+4+4+8+4;
2431
0
    char *en, *chunk_start;
2432
0
    int k = 0;
2433
0
    u32 audtr = 0;
2434
0
    u32 nrEntries = 0;
2435
2436
0
    AVI->video_index = NULL;
2437
2438
0
    nvi = 0;
2439
0
    for(audtr=0; audtr<AVI->anum; ++audtr) {
2440
0
      nai[audtr] = 0;
2441
0
      tot[audtr] = 0;
2442
0
    }
2443
2444
    // ************************
2445
    // VIDEO
2446
    // ************************
2447
2448
0
    for (j=0; j<AVI->video_superindex->nEntriesInUse; j++) {
2449
2450
      // read from file
2451
0
      chunk_start = en = (char*) gf_malloc ((u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) );
2452
2453
0
      if (gf_fseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
2454
0
        gf_free(chunk_start);
2455
0
        continue;
2456
0
      }
2457
2458
0
      if (avi_read(AVI->fdes, en, (u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) ) <= 0) {
2459
0
        gf_free(chunk_start);
2460
0
        continue;
2461
0
      }
2462
2463
0
      nrEntries = str2ulong((unsigned char*)en + 12);
2464
#ifdef DEBUG_ODML
2465
      //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:0] Video nrEntries %ld\n", j, nrEntries));
2466
#endif
2467
0
      offset = str2ullong((unsigned char*)en + 20);
2468
2469
      // skip header
2470
0
      en += hdrl_len;
2471
0
      nvi += nrEntries;
2472
0
      AVI->video_index = (video_index_entry *) gf_realloc (AVI->video_index, nvi * sizeof (video_index_entry));
2473
0
      if (!AVI->video_index) {
2474
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] out of mem (size = %ld)\n", nvi * sizeof (video_index_entry)));
2475
0
        exit(1);
2476
0
      }
2477
2478
0
      while (k < nvi) {
2479
2480
0
        AVI->video_index[k].pos = offset + str2ulong((unsigned char*)en);
2481
0
        en += 4;
2482
0
        AVI->video_index[k].len = str2ulong_len((unsigned char*)en);
2483
0
        AVI->video_index[k].key = str2ulong_key((unsigned char*)en);
2484
0
        en += 4;
2485
2486
        // completely empty chunk
2487
0
        if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) {
2488
0
          k--;
2489
0
          nvi--;
2490
0
        }
2491
2492
#ifdef DEBUG_ODML
2493
        /*
2494
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] POS 0x%llX len=%d key=%s offset (%llx) (%ld)\n", k,
2495
          AVI->video_index[k].pos,
2496
          (int)AVI->video_index[k].len,
2497
          AVI->video_index[k].key?"yes":"no ", offset,
2498
          AVI->video_superindex->aIndex[j].dwSize));
2499
          */
2500
#endif
2501
2502
0
        k++;
2503
0
      }
2504
2505
0
      gf_free(chunk_start);
2506
0
    }
2507
2508
0
    AVI->video_frames = nvi;
2509
    // this should deal with broken 'rec ' odml files.
2510
0
    if (AVI->video_frames == 0) {
2511
0
      AVI->is_opendml=0;
2512
0
      goto multiple_riff;
2513
0
    }
2514
2515
    // ************************
2516
    // AUDIO
2517
    // ************************
2518
2519
0
    for(audtr=0; audtr<AVI->anum; ++audtr) {
2520
2521
0
      k = 0;
2522
0
      if (!AVI->track[audtr].audio_superindex) {
2523
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] (%s) cannot read audio index for track %d\n", __FILE__, audtr));
2524
0
        continue;
2525
0
      }
2526
0
      for (j=0; j<AVI->track[audtr].audio_superindex->nEntriesInUse; j++) {
2527
2528
        // read from file
2529
0
        chunk_start = en = (char*)gf_malloc ((u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len));
2530
2531
0
        if (gf_fseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
2532
0
          gf_free(chunk_start);
2533
0
          continue;
2534
0
        }
2535
2536
0
        if (avi_read(AVI->fdes, en, (u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len)) <= 0) {
2537
0
          gf_free(chunk_start);
2538
0
          continue;
2539
0
        }
2540
2541
0
        nrEntries = str2ulong((unsigned char*)en + 12);
2542
        //if (nrEntries > 50) nrEntries = 2; // XXX
2543
#ifdef DEBUG_ODML
2544
        //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:%d] Audio nrEntries %ld\n", j, audtr, nrEntries));
2545
#endif
2546
0
        offset = str2ullong((unsigned char*)en + 20);
2547
2548
        // skip header
2549
0
        en += hdrl_len;
2550
0
        nai[audtr] += nrEntries;
2551
0
        AVI->track[audtr].audio_index = (audio_index_entry *) gf_realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry));
2552
2553
0
        while (k < nai[audtr]) {
2554
2555
0
          AVI->track[audtr].audio_index[k].pos = offset + str2ulong((unsigned char*)en);
2556
0
          en += 4;
2557
0
          AVI->track[audtr].audio_index[k].len = str2ulong_len((unsigned char*)en);
2558
0
          en += 4;
2559
0
          AVI->track[audtr].audio_index[k].tot = tot[audtr];
2560
0
          tot[audtr] += AVI->track[audtr].audio_index[k].len;
2561
2562
#ifdef DEBUG_ODML
2563
          /*
2564
          GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:%d] POS 0x%llX len=%d offset (%llx) (%ld)\n", k, audtr,
2565
            AVI->track[audtr].audio_index[k].pos,
2566
            (int)AVI->track[audtr].audio_index[k].len,
2567
            offset, AVI->track[audtr].audio_superindex->aIndex[j].dwSize));
2568
            */
2569
#endif
2570
2571
0
          ++k;
2572
0
        }
2573
2574
0
        gf_free(chunk_start);
2575
0
      }
2576
2577
0
      AVI->track[audtr].audio_chunks = nai[audtr];
2578
0
      AVI->track[audtr].audio_bytes = tot[audtr];
2579
0
    }
2580
0
  } // is opendml
2581
2582
0
  else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) {
2583
2584
    // *********************
2585
    // MULTIPLE RIFF CHUNKS (and no index)
2586
    // *********************
2587
2588
0
multiple_riff:
2589
2590
0
    gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2591
2592
0
    AVI->n_idx = 0;
2593
2594
0
    GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Reconstructing index..."));
2595
2596
    // Number of frames; only one audio track supported
2597
0
    nvi = AVI->video_frames = AVI->total_frames;
2598
0
    nai[0] = AVI->track[0].audio_chunks = AVI->total_frames;
2599
0
    for(j=1; j<AVI->anum; ++j) AVI->track[j].audio_chunks = 0;
2600
2601
0
    AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
2602
2603
0
    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2604
2605
0
    for(j=0; j<AVI->anum; ++j) {
2606
0
      if(AVI->track[j].audio_chunks) {
2607
0
        AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
2608
0
        memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2609
0
        if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2610
0
      }
2611
0
    }
2612
2613
0
    nvi = 0;
2614
0
    for(j=0; j<AVI->anum; ++j) {
2615
0
      nai[j] = 0;
2616
0
      tot[j] = 0;
2617
0
    }
2618
2619
0
    aud_chunks = AVI->total_frames;
2620
2621
0
    while(1)
2622
0
    {
2623
0
      if (nvi >= AVI->total_frames) break;
2624
2625
0
      if( avi_read(AVI->fdes,data,8) != 8 ) break;
2626
0
      n = str2ulong((unsigned char *)data+4);
2627
2628
2629
0
      j=0;
2630
2631
0
      if (aud_chunks - nai[j] -1 <= 0) {
2632
0
        aud_chunks += AVI->total_frames;
2633
0
        AVI->track[j].audio_index = (audio_index_entry *)
2634
0
                                    gf_realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry));
2635
0
        if (!AVI->track[j].audio_index) {
2636
0
          GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Internal error in avilib -- no mem\n"));
2637
0
          AVI_errno = AVI_ERR_NO_MEM;
2638
0
          return -1;
2639
0
        }
2640
0
      }
2641
2642
      /* Check if we got a tag ##db, ##dc or ##wb */
2643
2644
      // VIDEO
2645
0
      if(
2646
0
          (data[0]=='0' || data[1]=='0') &&
2647
0
          (data[2]=='d' || data[2]=='D') &&
2648
0
          (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) {
2649
2650
0
        AVI->video_index[nvi].key = 0x0;
2651
0
        AVI->video_index[nvi].pos = gf_ftell(AVI->fdes);
2652
0
        AVI->video_index[nvi].len = (u32) n;
2653
2654
        /*
2655
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Frame %ld pos %"LLD" len %"LLD" key %ld\n",
2656
            nvi, AVI->video_index[nvi].pos,  AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key));
2657
            */
2658
0
        nvi++;
2659
0
        gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2660
0
      }
2661
2662
      //AUDIO
2663
0
      else if(
2664
0
          (data[0]=='0' || data[1]=='1') &&
2665
0
          (data[2]=='w' || data[2]=='W') &&
2666
0
          (data[3]=='b' || data[3]=='B') ) {
2667
2668
2669
0
        AVI->track[j].audio_index[nai[j]].pos = gf_ftell(AVI->fdes);
2670
0
        AVI->track[j].audio_index[nai[j]].len = (u32) n;
2671
0
        AVI->track[j].audio_index[nai[j]].tot = tot[j];
2672
0
        tot[j] += AVI->track[j].audio_index[nai[j]].len;
2673
0
        nai[j]++;
2674
2675
0
        gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2676
0
      }
2677
0
      else {
2678
0
        gf_fseek(AVI->fdes,-4,SEEK_CUR);
2679
0
      }
2680
2681
0
    }
2682
0
    if (nvi < AVI->total_frames) {
2683
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[avilib] Uh? Some frames seems missing (%ld/%d)\n",
2684
0
              nvi,  AVI->total_frames));
2685
0
    }
2686
2687
2688
0
    AVI->video_frames = nvi;
2689
0
    AVI->track[0].audio_chunks = nai[0];
2690
2691
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2692
0
    GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]));
2693
2694
0
  } // total_frames but no indx chunk (xawtv does this)
2695
2696
0
  else
2697
2698
0
  {
2699
    // ******************
2700
    // NO OPENDML
2701
    // ******************
2702
2703
    /* Now generate the video index and audio index arrays */
2704
2705
0
    nvi = 0;
2706
0
    for(j=0; j<AVI->anum; ++j) nai[j] = 0;
2707
2708
0
    for(i=0; i<AVI->n_idx; i++) {
2709
2710
0
      if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
2711
2712
0
      for(j=0; j<AVI->anum; ++j) if(strnicmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
2713
0
    }
2714
2715
0
    AVI->video_frames = nvi;
2716
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
2717
2718
2719
0
    if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2720
0
    AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
2721
0
    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2722
2723
0
    for(j=0; j<AVI->anum; ++j) {
2724
0
      if(AVI->track[j].audio_chunks) {
2725
0
        AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
2726
0
        memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2727
0
        if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2728
0
      }
2729
0
    }
2730
2731
0
    nvi = 0;
2732
0
    for(j=0; j<AVI->anum; ++j) {
2733
0
      nai[j] = 0;
2734
0
      tot[j] = 0;
2735
0
    }
2736
2737
0
    ioff = idx_type == 1 ? 8 : (u32)AVI->movi_start+4;
2738
2739
0
    for(i=0; i<AVI->n_idx; i++) {
2740
2741
      //video
2742
0
      if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
2743
0
        AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
2744
0
        AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
2745
0
        AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
2746
0
        nvi++;
2747
0
      }
2748
2749
      //audio
2750
0
      for(j=0; j<AVI->anum; ++j) {
2751
2752
0
        if(strnicmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
2753
0
          AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
2754
0
          AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
2755
0
          AVI->track[j].audio_index[nai[j]].tot = tot[j];
2756
0
          tot[j] += AVI->track[j].audio_index[nai[j]].len;
2757
0
          nai[j]++;
2758
0
        }
2759
0
      }
2760
0
    }
2761
2762
2763
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2764
2765
0
  } // is no opendml
2766
2767
  /* Reposition the file */
2768
2769
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2770
0
  AVI->video_pos = 0;
2771
2772
0
  return(0);
2773
0
}
2774
2775
int AVI_video_frames(avi_t *AVI)
2776
0
{
2777
0
  return AVI->video_frames;
2778
0
}
2779
int  AVI_video_width(avi_t *AVI)
2780
0
{
2781
0
  return AVI->width;
2782
0
}
2783
int  AVI_video_height(avi_t *AVI)
2784
0
{
2785
0
  return AVI->height;
2786
0
}
2787
double AVI_frame_rate(avi_t *AVI)
2788
0
{
2789
0
  return AVI->fps;
2790
0
}
2791
char* AVI_video_compressor(avi_t *AVI)
2792
0
{
2793
0
  return AVI->compressor2;
2794
0
}
2795
2796
#if 0
2797
int AVI_max_video_chunk(avi_t *AVI)
2798
{
2799
  return AVI->max_len;
2800
}
2801
#endif
2802
2803
int AVI_audio_tracks(avi_t *AVI)
2804
0
{
2805
0
  return(AVI->anum);
2806
0
}
2807
2808
int AVI_audio_channels(avi_t *AVI)
2809
0
{
2810
0
  return AVI->track[AVI->aptr].a_chans;
2811
0
}
2812
2813
int AVI_audio_mp3rate(avi_t *AVI)
2814
0
{
2815
0
  return AVI->track[AVI->aptr].mp3rate;
2816
0
}
2817
2818
#if 0 //unused
2819
int AVI_audio_padrate(avi_t *AVI)
2820
{
2821
  return AVI->track[AVI->aptr].padrate;
2822
}
2823
#endif
2824
2825
int AVI_audio_bits(avi_t *AVI)
2826
0
{
2827
0
  return AVI->track[AVI->aptr].a_bits;
2828
0
}
2829
2830
int AVI_audio_format(avi_t *AVI)
2831
0
{
2832
0
  return AVI->track[AVI->aptr].a_fmt;
2833
0
}
2834
2835
int AVI_audio_rate(avi_t *AVI)
2836
0
{
2837
0
  return AVI->track[AVI->aptr].a_rate;
2838
0
}
2839
2840
2841
int AVI_frame_size(avi_t *AVI, int frame)
2842
0
{
2843
0
  if(AVI->mode==AVI_MODE_WRITE) {
2844
0
    AVI_errno = AVI_ERR_NOT_PERM;
2845
0
    return -1;
2846
0
  }
2847
0
  if(!AVI->video_index)         {
2848
0
    AVI_errno = AVI_ERR_NO_IDX;
2849
0
    return -1;
2850
0
  }
2851
2852
0
  if(frame < 0 || frame >= AVI->video_frames) return 0;
2853
0
  return (u32) (AVI->video_index[frame].len);
2854
0
}
2855
2856
int AVI_audio_size(avi_t *AVI, int frame)
2857
0
{
2858
0
  if(AVI->mode==AVI_MODE_WRITE) {
2859
0
    AVI_errno = AVI_ERR_NOT_PERM;
2860
0
    return -1;
2861
0
  }
2862
0
  if(!AVI->track[AVI->aptr].audio_index)         {
2863
0
    AVI_errno = AVI_ERR_NO_IDX;
2864
0
    return -1;
2865
0
  }
2866
2867
0
  if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1;
2868
0
  return (u32) (AVI->track[AVI->aptr].audio_index[frame].len);
2869
0
}
2870
2871
u64 AVI_get_video_position(avi_t *AVI, int frame)
2872
0
{
2873
0
  if(AVI->mode==AVI_MODE_WRITE) {
2874
0
    AVI_errno = AVI_ERR_NOT_PERM;
2875
0
    return (u64) -1;
2876
0
  }
2877
0
  if(!AVI->video_index)         {
2878
0
    AVI_errno = AVI_ERR_NO_IDX;
2879
0
    return (u64) -1;
2880
0
  }
2881
2882
0
  if(frame < 0 || frame >= AVI->video_frames) return 0;
2883
0
  return(AVI->video_index[frame].pos);
2884
0
}
2885
2886
2887
int AVI_seek_start(avi_t *AVI)
2888
0
{
2889
0
  if(AVI->mode==AVI_MODE_WRITE) {
2890
0
    AVI_errno = AVI_ERR_NOT_PERM;
2891
0
    return -1;
2892
0
  }
2893
2894
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2895
0
  AVI->video_pos = 0;
2896
0
  return 0;
2897
0
}
2898
2899
int AVI_set_video_position(avi_t *AVI, int frame)
2900
0
{
2901
0
  if(AVI->mode==AVI_MODE_WRITE) {
2902
0
    AVI_errno = AVI_ERR_NOT_PERM;
2903
0
    return -1;
2904
0
  }
2905
0
  if(!AVI->video_index)         {
2906
0
    AVI_errno = AVI_ERR_NO_IDX;
2907
0
    return -1;
2908
0
  }
2909
2910
0
  if (frame < 0 ) frame = 0;
2911
0
  AVI->video_pos = frame;
2912
0
  return 0;
2913
0
}
2914
2915
#if 0 //unused
2916
int AVI_set_audio_bitrate(avi_t *AVI, int bitrate)
2917
{
2918
  if(AVI->mode==AVI_MODE_READ) {
2919
    AVI_errno = AVI_ERR_NOT_PERM;
2920
    return -1;
2921
  }
2922
2923
  AVI->track[AVI->aptr].mp3rate = bitrate;
2924
  return 0;
2925
}
2926
#endif
2927
2928
int AVI_read_frame(avi_t *AVI, u8 *vidbuf, int *keyframe)
2929
0
{
2930
0
  int n;
2931
2932
0
  if(AVI->mode==AVI_MODE_WRITE) {
2933
0
    AVI_errno = AVI_ERR_NOT_PERM;
2934
0
    return -1;
2935
0
  }
2936
0
  if(!AVI->video_index)         {
2937
0
    AVI_errno = AVI_ERR_NO_IDX;
2938
0
    return -1;
2939
0
  }
2940
2941
0
  if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
2942
0
  n = (u32) AVI->video_index[AVI->video_pos].len;
2943
2944
0
  *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
2945
2946
0
  if (vidbuf == NULL) {
2947
0
    AVI->video_pos++;
2948
0
    return n;
2949
0
  }
2950
2951
0
  gf_fseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
2952
0
  AVI->video_pos++;
2953
2954
0
  if (avi_read(AVI->fdes,vidbuf,n) != (u32) n)
2955
0
  {
2956
0
    AVI_errno = AVI_ERR_READ;
2957
0
    return -1;
2958
0
  }
2959
2960
0
  return n;
2961
0
}
2962
2963
#if 0 //unused
2964
int AVI_get_audio_position_index(avi_t *AVI)
2965
{
2966
  if(AVI->mode==AVI_MODE_WRITE) {
2967
    AVI_errno = AVI_ERR_NOT_PERM;
2968
    return -1;
2969
  }
2970
  if(!AVI->track[AVI->aptr].audio_index) {
2971
    AVI_errno = AVI_ERR_NO_IDX;
2972
    return -1;
2973
  }
2974
2975
  return (AVI->track[AVI->aptr].audio_posc);
2976
}
2977
2978
int AVI_set_audio_position_index(avi_t *AVI, int indexpos)
2979
{
2980
  if(AVI->mode==AVI_MODE_WRITE) {
2981
    AVI_errno = AVI_ERR_NOT_PERM;
2982
    return -1;
2983
  }
2984
  if(!AVI->track[AVI->aptr].audio_index)         {
2985
    AVI_errno = AVI_ERR_NO_IDX;
2986
    return -1;
2987
  }
2988
  if(indexpos > AVI->track[AVI->aptr].audio_chunks)     {
2989
    AVI_errno = AVI_ERR_NO_IDX;
2990
    return -1;
2991
  }
2992
2993
  AVI->track[AVI->aptr].audio_posc = indexpos;
2994
  AVI->track[AVI->aptr].audio_posb = 0;
2995
2996
  return 0;
2997
}
2998
#endif
2999
3000
3001
int AVI_set_audio_position(avi_t *AVI, int byte)
3002
0
{
3003
0
  int n0, n1;
3004
3005
0
  if(AVI->mode==AVI_MODE_WRITE) {
3006
0
    AVI_errno = AVI_ERR_NOT_PERM;
3007
0
    return -1;
3008
0
  }
3009
0
  if(!AVI->track[AVI->aptr].audio_index)         {
3010
0
    AVI_errno = AVI_ERR_NO_IDX;
3011
0
    return -1;
3012
0
  }
3013
3014
0
  if(byte < 0) byte = 0;
3015
3016
  /* Binary search in the audio chunks */
3017
3018
0
  n0 = 0;
3019
0
  n1 = AVI->track[AVI->aptr].audio_chunks;
3020
3021
0
  while(n0<n1-1)
3022
0
  {
3023
0
    int n = (n0+n1)/2;
3024
0
    if(AVI->track[AVI->aptr].audio_index[n].tot>(u32) byte)
3025
0
      n1 = n;
3026
0
    else
3027
0
      n0 = n;
3028
0
  }
3029
3030
0
  AVI->track[AVI->aptr].audio_posc = n0;
3031
0
  AVI->track[AVI->aptr].audio_posb = (u32) (byte - AVI->track[AVI->aptr].audio_index[n0].tot);
3032
3033
0
  return 0;
3034
0
}
3035
3036
3037
int AVI_read_audio(avi_t *AVI, u8 *audbuf, int bytes, int *continuous)
3038
0
{
3039
0
  int nr;
3040
0
  u32 todo;
3041
0
  s64 pos;
3042
3043
0
  if(AVI->mode==AVI_MODE_WRITE) {
3044
0
    AVI_errno = AVI_ERR_NOT_PERM;
3045
0
    return -1;
3046
0
  }
3047
0
  if(!AVI->track[AVI->aptr].audio_index)         {
3048
0
    AVI_errno = AVI_ERR_NO_IDX;
3049
0
    return -1;
3050
0
  }
3051
3052
0
  nr = 0; /* total number of bytes read */
3053
3054
0
  if (bytes==0) {
3055
0
    AVI->track[AVI->aptr].audio_posc++;
3056
0
    AVI->track[AVI->aptr].audio_posb = 0;
3057
0
  }
3058
3059
0
  *continuous = 1;
3060
0
  while(bytes>0)
3061
0
  {
3062
0
    s64 ret;
3063
0
    u32 left = (u32) (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb);
3064
0
    if(left==0)
3065
0
    {
3066
0
      if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
3067
0
      AVI->track[AVI->aptr].audio_posc++;
3068
0
      AVI->track[AVI->aptr].audio_posb = 0;
3069
0
      *continuous = 0;
3070
0
      continue;
3071
0
    }
3072
0
    if((u32)bytes<left)
3073
0
      todo = bytes;
3074
0
    else
3075
0
      todo = left;
3076
0
    pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3077
0
    gf_fseek(AVI->fdes, pos, SEEK_SET);
3078
0
    AVI->track[AVI->aptr].audio_posb += (int)todo;
3079
0
    if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != (s64)todo)
3080
0
    {
3081
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] XXX pos = "LLD", ret = "LLD", todo = %ld\n", pos, ret, todo));
3082
0
      AVI_errno = AVI_ERR_READ;
3083
0
      return -1;
3084
0
    }
3085
0
    bytes -= todo;
3086
0
    nr    += todo;
3087
0
  }
3088
3089
0
  return nr;
3090
0
}
3091
3092
3093
#if 0 //unused
3094
/* AVI_read_data: Special routine for reading the next audio or video chunk
3095
                  without having an index of the file. */
3096
3097
int AVI_read_data(avi_t *AVI, char *vidbuf, int max_vidbuf,
3098
                  char *audbuf, int max_audbuf,
3099
                  int *len)
3100
{
3101
3102
  /*
3103
   * Return codes:
3104
   *
3105
   *    1 = video data read
3106
   *    2 = audio data read
3107
   *    0 = reached EOF
3108
   *   -1 = video buffer too small
3109
   *   -2 = audio buffer too small
3110
   */
3111
3112
  s64 n;
3113
  char data[8];
3114
3115
  if(AVI->mode==AVI_MODE_WRITE) return 0;
3116
3117
  while(1)
3118
  {
3119
    /* Read tag and length */
3120
3121
    if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
3122
3123
    /* if we got a list tag, ignore it */
3124
3125
    if(strnicmp(data,"LIST",4) == 0)
3126
    {
3127
      gf_fseek(AVI->fdes,4,SEEK_CUR);
3128
      continue;
3129
    }
3130
3131
    n = PAD_EVEN(str2ulong((unsigned char *)data+4));
3132
3133
    if(strnicmp(data,AVI->video_tag,3) == 0)
3134
    {
3135
      *len = (u32) n;
3136
      AVI->video_pos++;
3137
      if(n>max_vidbuf)
3138
      {
3139
        gf_fseek(AVI->fdes,n,SEEK_CUR);
3140
        return -1;
3141
      }
3142
      if(avi_read(AVI->fdes,vidbuf, (u32) n) != n ) return 0;
3143
      return 1;
3144
    }
3145
    else if(strnicmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
3146
    {
3147
      *len = (u32) n;
3148
      if(n>max_audbuf)
3149
      {
3150
        gf_fseek(AVI->fdes,n,SEEK_CUR);
3151
        return -2;
3152
      }
3153
      if(avi_read(AVI->fdes,audbuf, (u32) n) != n ) return 0;
3154
      return 2;
3155
      break;
3156
    }
3157
    else if(gf_fseek(AVI->fdes,n,SEEK_CUR) == (u64) -1)  return 0;
3158
  }
3159
}
3160
3161
u64 AVI_max_size(void)
3162
{
3163
  return((u64) AVI_MAX_LEN);
3164
}
3165
#endif
3166
3167
3168
#endif /*GPAC_DISABLE_AVILIB*/