Coverage Report

Created: 2025-10-10 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/media_tools/avilib.c
Line
Count
Source
1
/*
2
 *  avilib.c
3
 *
4
 *  Copyright (C) Thomas ostreich - June 2001
5
 *  multiple audio track support Copyright (C) 2002 Thomas ostreich
6
 *
7
 *  Original code:
8
 *  Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
9
 *
10
 *  This file is part of transcode, a linux video stream processing tool
11
 *
12
 *  transcode is free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU Lesser General Public License as published by
14
 *  the Free Software Foundation; either version 2, or (at your option)
15
 *  any later version.
16
 *
17
 *  transcode is distributed in the hope that it will be useful,
18
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 *  GNU Lesser General Public License for more details.
21
 *
22
 *  You should have received a copy of the GNU Lesser General Public
23
 *  License aint with this library; see the file COPYING.  If not, write to
24
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25
 *
26
 */
27
28
#include <gpac/setup.h>
29
30
#ifndef GPAC_DISABLE_AVILIB
31
32
#include <gpac/internal/avilib.h>
33
34
35
#define INFO_LIST
36
37
// add a new riff chunk after XX MB
38
#define NEW_RIFF_THRES (1900*1024*1024)
39
40
// Maximum number of indices per stream
41
0
#define NR_IXNN_CHUNKS 96
42
43
44
#define DEBUG_ODML
45
#undef DEBUG_ODML
46
47
/* The following variable indicates the kind of error */
48
49
int AVI_errno = 0;
50
51
0
#define MAX_INFO_STRLEN 64
52
static char id_str[MAX_INFO_STRLEN];
53
54
0
#define FRAME_RATE_SCALE 1000000
55
56
/*******************************************************************
57
 *                                                                 *
58
 *    Utilities for writing an AVI File                            *
59
 *                                                                 *
60
 *******************************************************************/
61
62
static u32 avi_read(FILE *fd, char *buf, u32 len)
63
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
0
  for (j=0; j<AVI->anum; j++)
1773
0
  {
1774
0
    if(AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index);
1775
0
    if(AVI->track[j].audio_superindex) {
1776
0
      avisuperindex_chunk *asi = AVI->track[j].audio_superindex;
1777
0
      if (asi && asi->aIndex) gf_free(asi->aIndex);
1778
1779
0
      if (asi && asi->stdindex) {
1780
0
        for (j=0; j < NR_IXNN_CHUNKS; j++) {
1781
0
          if (asi->stdindex[j]->aIndex)
1782
0
            gf_free(asi->stdindex[j]->aIndex);
1783
0
          gf_free(asi->stdindex[j]);
1784
0
        }
1785
0
        gf_free(asi->stdindex);
1786
0
      }
1787
0
      gf_free(asi);
1788
0
    }
1789
0
  }
1790
1791
0
  if (AVI->bitmap_info_header)
1792
0
    gf_free(AVI->bitmap_info_header);
1793
0
  for (j = 0; j < AVI->anum; j++)
1794
0
    if (AVI->wave_format_ex[j])
1795
0
      gf_free(AVI->wave_format_ex[j]);
1796
0
  if (AVI->extradata)
1797
0
    gf_free(AVI->extradata);
1798
1799
0
  gf_free(AVI);
1800
0
  return ret;
1801
0
}
1802
1803
1804
0
#define ERR_EXIT(x) \
1805
0
{ \
1806
0
   if (hdrl_data) { gf_free(hdrl_data); hdrl_data=NULL; }\
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 = NULL;
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
          ERR_EXIT(AVI_ERR_READ)
1953
0
        }
1954
0
      }
1955
0
      else if(strnicmp(data,"movi",4) == 0)
1956
0
      {
1957
0
        AVI->movi_start = gf_ftell(AVI->fdes);
1958
0
        if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
1959
0
      }
1960
0
      else if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
1961
0
    }
1962
0
    else if(strnicmp(data,"idx1",4) == 0)
1963
0
    {
1964
      /* n must be a multiple of 16, but the reading does not
1965
         break if this is not the case */
1966
1967
0
      AVI->n_idx = AVI->max_idx = (u32) (n/16);
1968
0
      AVI->idx = (unsigned  char((*)[16]) ) gf_malloc((u32)n);
1969
0
      if(AVI->idx==0) {
1970
0
        ERR_EXIT(AVI_ERR_NO_MEM)
1971
0
      }
1972
0
      if(avi_read(AVI->fdes, (char *) AVI->idx, (u32) n) != n ) {
1973
0
        gf_free( AVI->idx);
1974
0
        AVI->idx=NULL;
1975
0
        AVI->n_idx = 0;
1976
0
        ERR_EXIT(AVI_ERR_READ)
1977
0
      }
1978
0
    }
1979
0
    else
1980
0
      gf_fseek(AVI->fdes,n,SEEK_CUR);
1981
0
  }
1982
1983
0
  if(!hdrl_data) ERR_EXIT(AVI_ERR_NO_HDRL)
1984
0
  if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
1985
1986
      /* Interpret the header list */
1987
1988
0
      for(i=0; i<hdrl_len;)
1989
0
      {
1990
0
        if (i+4>hdrl_len) ERR_EXIT(AVI_ERR_READ)
1991
1992
        /* List tags are completly ignored */
1993
#ifdef DEBUG_ODML
1994
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]));
1995
#endif
1996
1997
0
        if(strnicmp((char *)hdrl_data+i,"LIST",4)==0) {
1998
0
          i+= 12;
1999
0
          continue;
2000
0
        }
2001
2002
0
        if (i+8>hdrl_len) ERR_EXIT(AVI_ERR_READ)
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
0
          if (i+4>hdrl_len) ERR_EXIT(AVI_ERR_READ)
2015
#ifdef DEBUG_ODML
2016
          GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] TAG   %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]));
2017
#endif
2018
0
          if(strnicmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
2019
0
          {
2020
0
            memcpy(AVI->compressor,hdrl_data+i+4,4);
2021
0
            AVI->compressor[4] = 0;
2022
2023
            // ThOe
2024
0
            AVI->v_codech_off = header_offset + i+4;
2025
2026
0
            scale = str2ulong(hdrl_data+i+20);
2027
0
            rate  = str2ulong(hdrl_data+i+24);
2028
0
            if(scale!=0) AVI->fps = (double)rate/(double)scale;
2029
0
            AVI->video_frames = str2ulong(hdrl_data+i+32);
2030
0
            AVI->video_strn = num_stream;
2031
0
            AVI->max_len = 0;
2032
0
            vids_strh_seen = 1;
2033
0
            lasttag = 1; /* vids */
2034
0
            memcpy(&AVI->video_stream_header, hdrl_data + i,
2035
0
                   sizeof(alAVISTREAMHEADER));
2036
0
          }
2037
0
          else if (strnicmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
2038
0
          {
2039
2040
            //inc audio tracks
2041
0
            AVI->aptr=AVI->anum;
2042
0
            ++AVI->anum;
2043
2044
0
            if(AVI->anum > AVI_MAX_TRACKS) {
2045
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] error - only %d audio tracks supported\n", AVI_MAX_TRACKS));
2046
0
              return(-1);
2047
0
            }
2048
2049
0
            AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
2050
0
            AVI->track[AVI->aptr].audio_strn = num_stream;
2051
2052
            // if samplesize==0 -> vbr
2053
0
            AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44);
2054
2055
0
            AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24);
2056
0
            memcpy(&AVI->stream_headers[AVI->aptr], hdrl_data + i,
2057
0
                   sizeof(alAVISTREAMHEADER));
2058
2059
            //     auds_strh_seen = 1;
2060
0
            lasttag = 2; /* auds */
2061
2062
            // ThOe
2063
0
            AVI->track[AVI->aptr].a_codech_off = header_offset + i;
2064
2065
0
          }
2066
0
          else if (strnicmp ((char*)hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) {
2067
0
            GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] AVILIB: error - DV AVI Type 1 no supported\n"));
2068
0
            return (-1);
2069
0
          }
2070
0
          else
2071
0
            lasttag = 0;
2072
0
          num_stream++;
2073
0
        }
2074
0
        else if(strnicmp((char*)hdrl_data+i,"dmlh",4) == 0) {
2075
2076
0
          if (i+12>hdrl_len) ERR_EXIT(AVI_ERR_READ)
2077
2078
0
          AVI->total_frames = str2ulong(hdrl_data+i+8);
2079
#ifdef DEBUG_ODML
2080
          GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] real number of frames %d\n", AVI->total_frames));
2081
#endif
2082
0
          i += 8;
2083
0
        }
2084
0
        else if(strnicmp((char *)hdrl_data+i,"strf",4)==0)
2085
0
        {
2086
0
          i += 8;
2087
0
          if(lasttag == 1)
2088
0
          {
2089
0
            alBITMAPINFOHEADER bih;
2090
2091
0
            memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER));
2092
0
            bih.bi_size = str2ulong((unsigned char *)&bih.bi_size);
2093
2094
0
            if (i + bih.bi_size > hdrl_len) ERR_EXIT(AVI_ERR_READ)
2095
2096
0
            AVI->bitmap_info_header = (alBITMAPINFOHEADER *) gf_malloc(bih.bi_size);
2097
0
            if (AVI->bitmap_info_header != NULL)
2098
0
              memcpy(AVI->bitmap_info_header, hdrl_data + i, bih.bi_size);
2099
2100
0
            AVI->width  = str2ulong(hdrl_data+i+4);
2101
0
            AVI->height = str2ulong(hdrl_data+i+8);
2102
0
            vids_strf_seen = 1;
2103
            //ThOe
2104
0
            AVI->v_codecf_off = header_offset + i+16;
2105
2106
0
            memcpy(AVI->compressor2, hdrl_data+i+16, 4);
2107
0
            AVI->compressor2[4] = 0;
2108
2109
0
            if (n>40) {
2110
0
              if (n>0xFFFFFFFF) ERR_EXIT(AVI_ERR_READ)
2111
0
              AVI->extradata_size = (u32) (n - 40);
2112
0
              AVI->extradata = gf_malloc(sizeof(u8)* AVI->extradata_size);
2113
0
              if (!AVI->extradata) ERR_EXIT(AVI_ERR_NO_MEM)
2114
0
              memcpy(AVI->extradata, hdrl_data + i + 40, AVI->extradata_size);
2115
0
            }
2116
2117
0
          }
2118
0
          else if(lasttag == 2)
2119
0
          {
2120
0
            alWAVEFORMATEX *wfe;
2121
0
            char *nwfe;
2122
0
            int wfes;
2123
2124
0
            if ((u32) (hdrl_len - i) < sizeof(alWAVEFORMATEX))
2125
0
              wfes = (int) (hdrl_len - i);
2126
0
            else
2127
0
              wfes = sizeof(alWAVEFORMATEX);
2128
0
            wfe = (alWAVEFORMATEX *)gf_malloc(sizeof(alWAVEFORMATEX));
2129
0
            if (wfe != NULL) {
2130
0
              memset(wfe, 0, sizeof(alWAVEFORMATEX));
2131
0
              memcpy(wfe, hdrl_data + i, wfes);
2132
0
              if (str2ushort((unsigned char *)&wfe->cb_size) != 0) {
2133
0
                nwfe = (char *)
2134
0
                       gf_realloc(wfe, sizeof(alWAVEFORMATEX) +
2135
0
                                  str2ushort((unsigned char *)&wfe->cb_size));
2136
0
                if (nwfe != 0) {
2137
0
                  s64 lpos = gf_ftell(AVI->fdes);
2138
0
                  gf_fseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX),
2139
0
                           SEEK_SET);
2140
0
                  wfe = (alWAVEFORMATEX *)nwfe;
2141
0
                  nwfe = &nwfe[sizeof(alWAVEFORMATEX)];
2142
0
                  avi_read(AVI->fdes, nwfe,
2143
0
                           str2ushort((unsigned char *)&wfe->cb_size));
2144
0
                  gf_fseek(AVI->fdes, lpos, SEEK_SET);
2145
0
                }
2146
0
              }
2147
0
              AVI->wave_format_ex[AVI->aptr] = wfe;
2148
0
            }
2149
2150
0
            AVI->track[AVI->aptr].a_fmt   = str2ushort(hdrl_data+i  );
2151
2152
            //ThOe
2153
0
            AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
2154
2155
0
            AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
2156
0
            AVI->track[AVI->aptr].a_rate  = str2ulong (hdrl_data+i+4);
2157
            //ThOe: read mp3bitrate
2158
0
            AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
2159
            //:ThOe
2160
0
            AVI->track[AVI->aptr].a_bits  = str2ushort(hdrl_data+i+14);
2161
            //            auds_strf_seen = 1;
2162
0
          }
2163
0
        }
2164
0
        else if(strnicmp((char*)hdrl_data+i,"indx",4) == 0) {
2165
0
          char *a;
2166
2167
0
          if(lasttag == 1) // V I D E O
2168
0
          {
2169
2170
0
            a = (char*)hdrl_data+i;
2171
0
            int avail =(int) (hdrl_len-i);
2172
0
            if (avail<32) ERR_EXIT(AVI_ERR_READ)
2173
2174
0
            AVI->video_superindex = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk));
2175
0
            memset(AVI->video_superindex, 0, sizeof (avisuperindex_chunk));
2176
0
            memcpy (AVI->video_superindex->fcc, a, 4);
2177
0
            a += 4;
2178
0
            AVI->video_superindex->dwSize = str2ulong((unsigned char *)a);
2179
0
            a += 4;
2180
0
            AVI->video_superindex->wLongsPerEntry = str2ushort((unsigned char *)a);
2181
0
            a += 2;
2182
0
            AVI->video_superindex->bIndexSubType = *a;
2183
0
            a += 1;
2184
0
            AVI->video_superindex->bIndexType = *a;
2185
0
            a += 1;
2186
0
            AVI->video_superindex->nEntriesInUse = str2ulong((unsigned char *)a);
2187
0
            a += 4;
2188
0
            memcpy (AVI->video_superindex->dwChunkId, a, 4);
2189
0
            a += 4;
2190
2191
            // 3 * reserved
2192
0
            a += 4;
2193
0
            a += 4;
2194
0
            a += 4;
2195
2196
0
            if (AVI->video_superindex->bIndexSubType != 0) {
2197
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
2198
0
            }
2199
0
            avail -= 32;
2200
0
            if (AVI->video_superindex->nEntriesInUse >= GF_INT_MAX/16 ||
2201
0
              avail < (int) AVI->video_superindex->nEntriesInUse*16) {
2202
2203
0
                ERR_EXIT(AVI_ERR_READ)
2204
0
            }
2205
2206
0
            AVI->video_superindex->aIndex = (avisuperindex_entry*)
2207
0
                                            gf_malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (u32));
2208
2209
            // position of ix## chunks
2210
0
            for (j=0; j<AVI->video_superindex->nEntriesInUse; ++j) {
2211
0
              AVI->video_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
2212
0
              a += 8;
2213
0
              AVI->video_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
2214
0
              a += 4;
2215
0
              AVI->video_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
2216
0
              a += 4;
2217
2218
#ifdef DEBUG_ODML
2219
              GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
2220
                                                      (unsigned int long)AVI->video_superindex->aIndex[j].qwOffset,
2221
                                                      (unsigned long)AVI->video_superindex->aIndex[j].dwSize,
2222
                                                      (unsigned long)AVI->video_superindex->aIndex[j].dwDuration));
2223
#endif
2224
0
            }
2225
2226
2227
#ifdef DEBUG_ODML
2228
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] FOURCC \"%c%c%c%c\"\n", AVI->video_superindex->fcc[0], AVI->video_superindex->fcc[1],
2229
                                                    AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]));
2230
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize));
2231
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry));
2232
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType));
2233
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->video_superindex->bIndexType));
2234
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse));
2235
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] dwChunkId \"%c%c%c%c\"\n", AVI->video_superindex->dwChunkId[0], AVI->video_superindex->dwChunkId[1],
2236
                                                    AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]));
2237
#endif
2238
2239
0
            AVI->is_opendml = 1;
2240
2241
0
          }
2242
0
          else if(lasttag == 2) // A U D I O
2243
0
          {
2244
2245
0
            a = (char*) hdrl_data+i;
2246
0
            int avail = (int) (hdrl_len-i);
2247
0
            if (avail<32) ERR_EXIT(AVI_ERR_READ)
2248
2249
0
            GF_SAFEALLOC(AVI->track[AVI->aptr].audio_superindex, avisuperindex_chunk);
2250
0
            memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4);
2251
0
            a += 4;
2252
0
            AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong((unsigned char*)a);
2253
0
            a += 4;
2254
0
            AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort((unsigned char*)a);
2255
0
            a += 2;
2256
0
            AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a;
2257
0
            a += 1;
2258
0
            AVI->track[AVI->aptr].audio_superindex->bIndexType = *a;
2259
0
            a += 1;
2260
0
            AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong((unsigned char*)a);
2261
0
            a += 4;
2262
0
            memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4);
2263
0
            a += 4;
2264
2265
            // 3 * reserved
2266
0
            a += 4;
2267
0
            a += 4;
2268
0
            a += 4;
2269
2270
0
            if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {
2271
0
              GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
2272
0
            }
2273
2274
0
            avail -= 32;
2275
0
            if (AVI->track[AVI->aptr].audio_superindex->nEntriesInUse >= GF_INT_MAX/16
2276
0
              || avail < (int) AVI->track[AVI->aptr].audio_superindex->nEntriesInUse*16) {
2277
2278
0
                ERR_EXIT(AVI_ERR_READ)
2279
0
            }
2280
2281
0
            AVI->track[AVI->aptr].audio_superindex->aIndex = (avisuperindex_entry*)
2282
0
                    gf_malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry *
2283
0
                               AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (u32));
2284
2285
            // position of ix## chunks
2286
0
            for (j=0; j<AVI->track[AVI->aptr].audio_superindex->nEntriesInUse; ++j) {
2287
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
2288
0
              a += 8;
2289
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
2290
0
              a += 4;
2291
0
              AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
2292
0
              a += 4;
2293
2294
#ifdef DEBUG_ODML
2295
              GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
2296
                                                      (unsigned int long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset,
2297
                                                      (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize,
2298
                                                      (unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration));
2299
#endif
2300
0
            }
2301
2302
0
            AVI->track[AVI->aptr].audio_superindex->stdindex = NULL;
2303
2304
#ifdef DEBUG_ODML
2305
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc));
2306
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize));
2307
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry));
2308
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType));
2309
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType));
2310
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse));
2311
            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]));
2312
#endif
2313
2314
0
          }
2315
0
          i += 8;
2316
0
        }
2317
0
        else if((strnicmp((char*)hdrl_data+i,"JUNK",4) == 0) ||
2318
0
                (strnicmp((char*)hdrl_data+i,"strn",4) == 0) ||
2319
0
                (strnicmp((char*)hdrl_data+i,"vprp",4) == 0)) {
2320
0
          i += 8;
2321
          // do not reset lasttag
2322
0
        } else
2323
0
        {
2324
0
          i += 8;
2325
0
          lasttag = 0;
2326
0
        }
2327
        //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] adding %ld bytes\n", (int int)n));
2328
2329
0
        i += (u32) n;
2330
0
      }
2331
2332
0
  gf_free(hdrl_data);
2333
0
  hdrl_data = NULL;
2334
2335
0
  if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
2336
2337
0
    AVI->video_tag[0] = AVI->video_strn/10 + '0';
2338
0
  AVI->video_tag[1] = AVI->video_strn%10 + '0';
2339
0
  AVI->video_tag[2] = 'd';
2340
0
  AVI->video_tag[3] = 'b';
2341
2342
  /* Audio tag is set to "99wb" if no audio present */
2343
0
  if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
2344
2345
0
  {
2346
0
    int tk=0;
2347
0
    for(j=0; j<AVI->anum+1; ++j) {
2348
0
      if (j == AVI->video_strn) continue;
2349
0
      AVI->track[tk].audio_tag[0] = j/10 + '0';
2350
0
      AVI->track[tk].audio_tag[1] = j%10 + '0';
2351
0
      AVI->track[tk].audio_tag[2] = 'w';
2352
0
      AVI->track[tk].audio_tag[3] = 'b';
2353
0
      ++tk;
2354
0
    }
2355
0
  }
2356
2357
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2358
2359
0
  if(!getIndex) return(0);
2360
2361
  /* if the file has an idx1, check if this is relative
2362
     to the start of the file or to the start of the movi list */
2363
2364
0
  idx_type = 0;
2365
2366
0
  if(AVI->idx)
2367
0
  {
2368
0
    s64 pos, len;
2369
2370
    /* Search the first videoframe in the idx1 and look where
2371
       it is in the file */
2372
2373
0
    for(i=0; i<AVI->n_idx; i++)
2374
0
      if( strnicmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
2375
0
    if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
2376
2377
0
      pos = str2ulong(AVI->idx[i]+ 8);
2378
0
    len = str2ulong(AVI->idx[i]+12);
2379
2380
0
    gf_fseek(AVI->fdes,pos,SEEK_SET);
2381
0
    if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2382
0
      if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2383
0
      {
2384
0
        idx_type = 1; /* Index from start of file */
2385
0
      }
2386
0
      else
2387
0
      {
2388
0
        gf_fseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
2389
0
        if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
2390
0
          if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
2391
0
          {
2392
0
            idx_type = 2; /* Index from start of movi list */
2393
0
          }
2394
0
      }
2395
    /* idx_type remains 0 if neither of the two tests above succeeds */
2396
0
  }
2397
2398
2399
0
  if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames)
2400
0
  {
2401
    /* we must search through the file to get the index */
2402
2403
0
    gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2404
2405
0
    AVI->n_idx = 0;
2406
2407
0
    while(1)
2408
0
    {
2409
0
      if( avi_read(AVI->fdes,data,8) != 8 ) break;
2410
0
      n = str2ulong((unsigned char *)data+4);
2411
2412
      /* The movi list may contain sub-lists, ignore them */
2413
2414
0
      if(strnicmp(data,"LIST",4)==0)
2415
0
      {
2416
0
        gf_fseek(AVI->fdes,4,SEEK_CUR);
2417
0
        continue;
2418
0
      }
2419
2420
      /* Check if we got a tag ##db, ##dc or ##wb */
2421
2422
0
      if( ( (data[2]=='d' || data[2]=='D') &&
2423
0
              (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
2424
0
              || ( (data[2]=='w' || data[2]=='W') &&
2425
0
                   (data[3]=='b' || data[3]=='B') ) )
2426
0
      {
2427
0
        u64 __pos = gf_ftell(AVI->fdes) - 8;
2428
0
        avi_add_index_entry(AVI,(unsigned char *)data,0,__pos,n);
2429
0
      }
2430
2431
0
      gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2432
0
    }
2433
0
    idx_type = 1;
2434
0
  }
2435
2436
  // ************************
2437
  // OPENDML
2438
  // ************************
2439
2440
  // read extended index chunks
2441
0
  if (AVI->is_opendml) {
2442
0
    u64 offset = 0;
2443
0
    hdrl_len = 4+4+2+1+1+4+4+8+4;
2444
0
    char *en, *chunk_start;
2445
0
    int k = 0;
2446
0
    u32 audtr = 0;
2447
0
    u32 nrEntries = 0;
2448
2449
0
    AVI->video_index = NULL;
2450
2451
0
    nvi = 0;
2452
0
    for(audtr=0; audtr<AVI->anum; ++audtr) {
2453
0
      nai[audtr] = 0;
2454
0
      tot[audtr] = 0;
2455
0
    }
2456
2457
    // ************************
2458
    // VIDEO
2459
    // ************************
2460
2461
0
    for (j=0; j<AVI->video_superindex->nEntriesInUse; j++) {
2462
2463
      // read from file
2464
0
      u32 chunk_size = (u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len);
2465
0
      if (!chunk_size)
2466
0
        continue;
2467
0
      chunk_start = en = (char*) gf_malloc(chunk_size);
2468
2469
0
      if (gf_fseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
2470
0
        gf_free(chunk_start);
2471
0
        continue;
2472
0
      }
2473
2474
0
      if (avi_read(AVI->fdes, en, (u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) ) <= 0) {
2475
0
        gf_free(chunk_start);
2476
0
        continue;
2477
0
      }
2478
2479
0
      nrEntries = str2ulong((unsigned char*)en + 12);
2480
#ifdef DEBUG_ODML
2481
      //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:0] Video nrEntries %ld\n", j, nrEntries));
2482
#endif
2483
0
      offset = str2ullong((unsigned char*)en + 20);
2484
2485
      // skip header
2486
0
      en += hdrl_len;
2487
0
      nvi += nrEntries;
2488
0
      AVI->video_index = (video_index_entry *) gf_realloc (AVI->video_index, nvi * sizeof (video_index_entry));
2489
0
      if (!AVI->video_index) {
2490
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] out of mem (size = %ld)\n", nvi * sizeof (video_index_entry)));
2491
0
        exit(1);
2492
0
      }
2493
2494
0
      while (k < nvi) {
2495
2496
0
        if (en-chunk_start+8 > chunk_size)
2497
0
          break;
2498
2499
0
        AVI->video_index[k].pos = offset + str2ulong((unsigned char*)en);
2500
0
        en += 4;
2501
0
        AVI->video_index[k].len = str2ulong_len((unsigned char*)en);
2502
0
        AVI->video_index[k].key = str2ulong_key((unsigned char*)en);
2503
0
        en += 4;
2504
2505
        // completely empty chunk
2506
0
        if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) {
2507
0
          k--;
2508
0
          nvi--;
2509
0
        }
2510
2511
#ifdef DEBUG_ODML
2512
        /*
2513
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] POS 0x%llX len=%d key=%s offset (%llx) (%ld)\n", k,
2514
          AVI->video_index[k].pos,
2515
          (int)AVI->video_index[k].len,
2516
          AVI->video_index[k].key?"yes":"no ", offset,
2517
          AVI->video_superindex->aIndex[j].dwSize));
2518
          */
2519
#endif
2520
2521
0
        k++;
2522
0
      }
2523
2524
0
      gf_free(chunk_start);
2525
0
    }
2526
2527
0
    AVI->video_frames = nvi;
2528
    // this should deal with broken 'rec ' odml files.
2529
0
    if (AVI->video_frames == 0) {
2530
0
      AVI->is_opendml=0;
2531
0
      goto multiple_riff;
2532
0
    }
2533
2534
    // ************************
2535
    // AUDIO
2536
    // ************************
2537
2538
0
    for(audtr=0; audtr<AVI->anum; ++audtr) {
2539
2540
0
      k = 0;
2541
0
      if (!AVI->track[audtr].audio_superindex) {
2542
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] (%s) cannot read audio index for track %d\n", __FILE__, audtr));
2543
0
        continue;
2544
0
      }
2545
0
      for (j=0; j<AVI->track[audtr].audio_superindex->nEntriesInUse; j++) {
2546
2547
        // read from file
2548
0
        chunk_start = en = (char*)gf_malloc ((u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len));
2549
2550
0
        if (gf_fseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
2551
0
          gf_free(chunk_start);
2552
0
          continue;
2553
0
        }
2554
2555
0
        if (avi_read(AVI->fdes, en, (u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len)) <= 0) {
2556
0
          gf_free(chunk_start);
2557
0
          continue;
2558
0
        }
2559
2560
0
        nrEntries = str2ulong((unsigned char*)en + 12);
2561
        //if (nrEntries > 50) nrEntries = 2; // XXX
2562
#ifdef DEBUG_ODML
2563
        //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:%d] Audio nrEntries %ld\n", j, audtr, nrEntries));
2564
#endif
2565
0
        offset = str2ullong((unsigned char*)en + 20);
2566
2567
        // skip header
2568
0
        en += hdrl_len;
2569
0
        nai[audtr] += nrEntries;
2570
0
        AVI->track[audtr].audio_index = (audio_index_entry *) gf_realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry));
2571
2572
0
        while (k < nai[audtr]) {
2573
2574
0
          AVI->track[audtr].audio_index[k].pos = offset + str2ulong((unsigned char*)en);
2575
0
          en += 4;
2576
0
          AVI->track[audtr].audio_index[k].len = str2ulong_len((unsigned char*)en);
2577
0
          en += 4;
2578
0
          AVI->track[audtr].audio_index[k].tot = tot[audtr];
2579
0
          tot[audtr] += AVI->track[audtr].audio_index[k].len;
2580
2581
#ifdef DEBUG_ODML
2582
          /*
2583
          GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d:%d] POS 0x%llX len=%d offset (%llx) (%ld)\n", k, audtr,
2584
            AVI->track[audtr].audio_index[k].pos,
2585
            (int)AVI->track[audtr].audio_index[k].len,
2586
            offset, AVI->track[audtr].audio_superindex->aIndex[j].dwSize));
2587
            */
2588
#endif
2589
2590
0
          ++k;
2591
0
        }
2592
2593
0
        gf_free(chunk_start);
2594
0
      }
2595
2596
0
      AVI->track[audtr].audio_chunks = nai[audtr];
2597
0
      AVI->track[audtr].audio_bytes = tot[audtr];
2598
0
    }
2599
0
  } // is opendml
2600
2601
0
  else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) {
2602
2603
    // *********************
2604
    // MULTIPLE RIFF CHUNKS (and no index)
2605
    // *********************
2606
2607
0
multiple_riff:
2608
2609
0
    gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
2610
2611
0
    AVI->n_idx = 0;
2612
2613
0
    GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Reconstructing index..."));
2614
2615
    // Number of frames; only one audio track supported
2616
0
    nvi = AVI->video_frames = AVI->total_frames;
2617
0
    nai[0] = AVI->track[0].audio_chunks = AVI->total_frames;
2618
0
    for(j=1; j<AVI->anum; ++j) AVI->track[j].audio_chunks = 0;
2619
2620
0
    AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
2621
2622
0
    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2623
2624
0
    for(j=0; j<AVI->anum; ++j) {
2625
0
      if(AVI->track[j].audio_chunks) {
2626
0
        if (AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index);
2627
0
        AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
2628
0
        memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2629
0
        if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2630
0
      }
2631
0
    }
2632
2633
0
    nvi = 0;
2634
0
    for(j=0; j<AVI->anum; ++j) {
2635
0
      nai[j] = 0;
2636
0
      tot[j] = 0;
2637
0
    }
2638
2639
0
    aud_chunks = AVI->total_frames;
2640
2641
0
    while(1)
2642
0
    {
2643
0
      if (nvi >= AVI->total_frames) break;
2644
2645
0
      if( avi_read(AVI->fdes,data,8) != 8 ) break;
2646
0
      n = str2ulong((unsigned char *)data+4);
2647
2648
2649
0
      j=0;
2650
2651
0
      if (aud_chunks - nai[j] -1 <= 0) {
2652
0
        aud_chunks += AVI->total_frames;
2653
0
        AVI->track[j].audio_index = (audio_index_entry *)
2654
0
                                    gf_realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry));
2655
2656
0
        if (!AVI->track[j].audio_index) {
2657
0
          GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Internal error in avilib -- no mem\n"));
2658
0
          AVI_errno = AVI_ERR_NO_MEM;
2659
0
          return -1;
2660
0
        }
2661
2662
0
        if (AVI->anum <= j)
2663
0
          AVI->anum = j+1;
2664
0
      }
2665
2666
      /* Check if we got a tag ##db, ##dc or ##wb */
2667
2668
      // VIDEO
2669
0
      if(
2670
0
          (data[0]=='0' || data[1]=='0') &&
2671
0
          (data[2]=='d' || data[2]=='D') &&
2672
0
          (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) {
2673
2674
0
        AVI->video_index[nvi].key = 0x0;
2675
0
        AVI->video_index[nvi].pos = gf_ftell(AVI->fdes);
2676
0
        AVI->video_index[nvi].len = (u32) n;
2677
2678
        /*
2679
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Frame %ld pos %"LLD" len %"LLD" key %ld\n",
2680
            nvi, AVI->video_index[nvi].pos,  AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key));
2681
            */
2682
0
        nvi++;
2683
0
        gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2684
0
      }
2685
2686
      //AUDIO
2687
0
      else if(
2688
0
          (data[0]=='0' || data[1]=='1') &&
2689
0
          (data[2]=='w' || data[2]=='W') &&
2690
0
          (data[3]=='b' || data[3]=='B') ) {
2691
2692
2693
0
        AVI->track[j].audio_index[nai[j]].pos = gf_ftell(AVI->fdes);
2694
0
        AVI->track[j].audio_index[nai[j]].len = (u32) n;
2695
0
        AVI->track[j].audio_index[nai[j]].tot = tot[j];
2696
0
        tot[j] += AVI->track[j].audio_index[nai[j]].len;
2697
0
        nai[j]++;
2698
2699
0
        gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
2700
0
      }
2701
0
      else {
2702
0
        gf_fseek(AVI->fdes,-4,SEEK_CUR);
2703
0
      }
2704
2705
0
    }
2706
0
    if (nvi < AVI->total_frames) {
2707
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[avilib] Uh? Some frames seems missing (%ld/%d)\n",
2708
0
              nvi,  AVI->total_frames));
2709
0
    }
2710
2711
2712
0
    AVI->video_frames = nvi;
2713
0
    AVI->track[0].audio_chunks = nai[0];
2714
2715
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2716
0
    GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]));
2717
2718
0
  } // total_frames but no indx chunk (xawtv does this)
2719
2720
0
  else
2721
2722
0
  {
2723
    // ******************
2724
    // NO OPENDML
2725
    // ******************
2726
2727
    /* Now generate the video index and audio index arrays */
2728
2729
0
    nvi = 0;
2730
0
    for(j=0; j<AVI->anum; ++j) nai[j] = 0;
2731
2732
0
    for(i=0; i<AVI->n_idx; i++) {
2733
2734
0
      if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
2735
2736
0
      for(j=0; j<AVI->anum; ++j) if(strnicmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
2737
0
    }
2738
2739
0
    AVI->video_frames = nvi;
2740
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
2741
2742
2743
0
    if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
2744
0
    AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
2745
0
    if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2746
2747
0
    for(j=0; j<AVI->anum; ++j) {
2748
0
      if(AVI->track[j].audio_chunks) {
2749
0
        if (AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index);
2750
0
        AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
2751
0
        memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
2752
0
        if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
2753
0
      }
2754
0
    }
2755
2756
0
    nvi = 0;
2757
0
    for(j=0; j<AVI->anum; ++j) {
2758
0
      nai[j] = 0;
2759
0
      tot[j] = 0;
2760
0
    }
2761
2762
0
    ioff = idx_type == 1 ? 8 : (u32)AVI->movi_start+4;
2763
2764
0
    for(i=0; i<AVI->n_idx; i++) {
2765
2766
      //video
2767
0
      if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
2768
0
        AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
2769
0
        AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
2770
0
        AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
2771
0
        nvi++;
2772
0
      }
2773
2774
      //audio
2775
0
      for(j=0; j<AVI->anum; ++j) {
2776
2777
0
        if(strnicmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
2778
0
          AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
2779
0
          AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
2780
0
          AVI->track[j].audio_index[nai[j]].tot = tot[j];
2781
0
          tot[j] += AVI->track[j].audio_index[nai[j]].len;
2782
0
          nai[j]++;
2783
0
        }
2784
0
      }
2785
0
    }
2786
2787
2788
0
    for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
2789
2790
0
  } // is no opendml
2791
2792
  /* Reposition the file */
2793
2794
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2795
0
  AVI->video_pos = 0;
2796
2797
0
  return(0);
2798
0
}
2799
2800
int AVI_video_frames(avi_t *AVI)
2801
0
{
2802
0
  return AVI->video_frames;
2803
0
}
2804
int  AVI_video_width(avi_t *AVI)
2805
0
{
2806
0
  return AVI->width;
2807
0
}
2808
int  AVI_video_height(avi_t *AVI)
2809
0
{
2810
0
  return AVI->height;
2811
0
}
2812
double AVI_frame_rate(avi_t *AVI)
2813
0
{
2814
0
  return AVI->fps;
2815
0
}
2816
char* AVI_video_compressor(avi_t *AVI)
2817
0
{
2818
0
  return AVI->compressor2;
2819
0
}
2820
2821
#if 0
2822
int AVI_max_video_chunk(avi_t *AVI)
2823
{
2824
  return AVI->max_len;
2825
}
2826
#endif
2827
2828
int AVI_audio_tracks(avi_t *AVI)
2829
0
{
2830
0
  return(AVI->anum);
2831
0
}
2832
2833
int AVI_audio_channels(avi_t *AVI)
2834
0
{
2835
0
  return AVI->track[AVI->aptr].a_chans;
2836
0
}
2837
2838
int AVI_audio_mp3rate(avi_t *AVI)
2839
0
{
2840
0
  return AVI->track[AVI->aptr].mp3rate;
2841
0
}
2842
2843
#if 0 //unused
2844
int AVI_audio_padrate(avi_t *AVI)
2845
{
2846
  return AVI->track[AVI->aptr].padrate;
2847
}
2848
#endif
2849
2850
int AVI_audio_bits(avi_t *AVI)
2851
0
{
2852
0
  return AVI->track[AVI->aptr].a_bits;
2853
0
}
2854
2855
int AVI_audio_format(avi_t *AVI)
2856
0
{
2857
0
  return AVI->track[AVI->aptr].a_fmt;
2858
0
}
2859
2860
int AVI_audio_rate(avi_t *AVI)
2861
0
{
2862
0
  return AVI->track[AVI->aptr].a_rate;
2863
0
}
2864
2865
2866
int AVI_frame_size(avi_t *AVI, int frame)
2867
0
{
2868
0
  if(AVI->mode==AVI_MODE_WRITE) {
2869
0
    AVI_errno = AVI_ERR_NOT_PERM;
2870
0
    return -1;
2871
0
  }
2872
0
  if(!AVI->video_index)         {
2873
0
    AVI_errno = AVI_ERR_NO_IDX;
2874
0
    return -1;
2875
0
  }
2876
2877
0
  if(frame < 0 || frame >= AVI->video_frames) return 0;
2878
0
  return (u32) (AVI->video_index[frame].len);
2879
0
}
2880
2881
int AVI_audio_size(avi_t *AVI, int frame)
2882
0
{
2883
0
  if(AVI->mode==AVI_MODE_WRITE) {
2884
0
    AVI_errno = AVI_ERR_NOT_PERM;
2885
0
    return -1;
2886
0
  }
2887
0
  if(!AVI->track[AVI->aptr].audio_index)         {
2888
0
    AVI_errno = AVI_ERR_NO_IDX;
2889
0
    return -1;
2890
0
  }
2891
2892
0
  if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1;
2893
0
  return (u32) (AVI->track[AVI->aptr].audio_index[frame].len);
2894
0
}
2895
2896
u64 AVI_get_video_position(avi_t *AVI, int frame)
2897
0
{
2898
0
  if(AVI->mode==AVI_MODE_WRITE) {
2899
0
    AVI_errno = AVI_ERR_NOT_PERM;
2900
0
    return (u64) -1;
2901
0
  }
2902
0
  if(!AVI->video_index)         {
2903
0
    AVI_errno = AVI_ERR_NO_IDX;
2904
0
    return (u64) -1;
2905
0
  }
2906
2907
0
  if(frame < 0 || frame >= AVI->video_frames) return 0;
2908
0
  return(AVI->video_index[frame].pos);
2909
0
}
2910
2911
2912
int AVI_seek_start(avi_t *AVI)
2913
0
{
2914
0
  if(AVI->mode==AVI_MODE_WRITE) {
2915
0
    AVI_errno = AVI_ERR_NOT_PERM;
2916
0
    return -1;
2917
0
  }
2918
2919
0
  gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
2920
0
  AVI->video_pos = 0;
2921
0
  return 0;
2922
0
}
2923
2924
int AVI_set_video_position(avi_t *AVI, int frame)
2925
0
{
2926
0
  if(AVI->mode==AVI_MODE_WRITE) {
2927
0
    AVI_errno = AVI_ERR_NOT_PERM;
2928
0
    return -1;
2929
0
  }
2930
0
  if(!AVI->video_index)         {
2931
0
    AVI_errno = AVI_ERR_NO_IDX;
2932
0
    return -1;
2933
0
  }
2934
2935
0
  if (frame < 0 ) frame = 0;
2936
0
  AVI->video_pos = frame;
2937
0
  return 0;
2938
0
}
2939
2940
#if 0 //unused
2941
int AVI_set_audio_bitrate(avi_t *AVI, int bitrate)
2942
{
2943
  if(AVI->mode==AVI_MODE_READ) {
2944
    AVI_errno = AVI_ERR_NOT_PERM;
2945
    return -1;
2946
  }
2947
2948
  AVI->track[AVI->aptr].mp3rate = bitrate;
2949
  return 0;
2950
}
2951
#endif
2952
2953
int AVI_read_frame(avi_t *AVI, u8 *vidbuf, int *keyframe)
2954
0
{
2955
0
  int n;
2956
2957
0
  if(AVI->mode==AVI_MODE_WRITE) {
2958
0
    AVI_errno = AVI_ERR_NOT_PERM;
2959
0
    return -1;
2960
0
  }
2961
0
  if(!AVI->video_index)         {
2962
0
    AVI_errno = AVI_ERR_NO_IDX;
2963
0
    return -1;
2964
0
  }
2965
2966
0
  if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
2967
0
  n = (u32) AVI->video_index[AVI->video_pos].len;
2968
2969
0
  *keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
2970
2971
0
  if (vidbuf == NULL) {
2972
0
    AVI->video_pos++;
2973
0
    return n;
2974
0
  }
2975
2976
0
  gf_fseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
2977
0
  AVI->video_pos++;
2978
2979
0
  if (avi_read(AVI->fdes,vidbuf,n) != (u32) n)
2980
0
  {
2981
0
    AVI_errno = AVI_ERR_READ;
2982
0
    return -1;
2983
0
  }
2984
2985
0
  return n;
2986
0
}
2987
2988
#if 0 //unused
2989
int AVI_get_audio_position_index(avi_t *AVI)
2990
{
2991
  if(AVI->mode==AVI_MODE_WRITE) {
2992
    AVI_errno = AVI_ERR_NOT_PERM;
2993
    return -1;
2994
  }
2995
  if(!AVI->track[AVI->aptr].audio_index) {
2996
    AVI_errno = AVI_ERR_NO_IDX;
2997
    return -1;
2998
  }
2999
3000
  return (AVI->track[AVI->aptr].audio_posc);
3001
}
3002
3003
int AVI_set_audio_position_index(avi_t *AVI, int indexpos)
3004
{
3005
  if(AVI->mode==AVI_MODE_WRITE) {
3006
    AVI_errno = AVI_ERR_NOT_PERM;
3007
    return -1;
3008
  }
3009
  if(!AVI->track[AVI->aptr].audio_index)         {
3010
    AVI_errno = AVI_ERR_NO_IDX;
3011
    return -1;
3012
  }
3013
  if(indexpos > AVI->track[AVI->aptr].audio_chunks)     {
3014
    AVI_errno = AVI_ERR_NO_IDX;
3015
    return -1;
3016
  }
3017
3018
  AVI->track[AVI->aptr].audio_posc = indexpos;
3019
  AVI->track[AVI->aptr].audio_posb = 0;
3020
3021
  return 0;
3022
}
3023
#endif
3024
3025
3026
int AVI_set_audio_position(avi_t *AVI, int byte)
3027
0
{
3028
0
  int n0, n1;
3029
3030
0
  if(AVI->mode==AVI_MODE_WRITE) {
3031
0
    AVI_errno = AVI_ERR_NOT_PERM;
3032
0
    return -1;
3033
0
  }
3034
0
  if(!AVI->track[AVI->aptr].audio_index)         {
3035
0
    AVI_errno = AVI_ERR_NO_IDX;
3036
0
    return -1;
3037
0
  }
3038
3039
0
  if(byte < 0) byte = 0;
3040
3041
  /* Binary search in the audio chunks */
3042
3043
0
  n0 = 0;
3044
0
  n1 = AVI->track[AVI->aptr].audio_chunks;
3045
3046
0
  while(n0<n1-1)
3047
0
  {
3048
0
    int n = (n0+n1)/2;
3049
0
    if(AVI->track[AVI->aptr].audio_index[n].tot>(u32) byte)
3050
0
      n1 = n;
3051
0
    else
3052
0
      n0 = n;
3053
0
  }
3054
3055
0
  AVI->track[AVI->aptr].audio_posc = n0;
3056
0
  AVI->track[AVI->aptr].audio_posb = (u32) (byte - AVI->track[AVI->aptr].audio_index[n0].tot);
3057
3058
0
  return 0;
3059
0
}
3060
3061
3062
int AVI_read_audio(avi_t *AVI, u8 *audbuf, int bytes, int *continuous)
3063
0
{
3064
0
  int nr;
3065
0
  u32 todo;
3066
0
  s64 pos;
3067
3068
0
  if(AVI->mode==AVI_MODE_WRITE) {
3069
0
    AVI_errno = AVI_ERR_NOT_PERM;
3070
0
    return -1;
3071
0
  }
3072
0
  if(!AVI->track[AVI->aptr].audio_index)         {
3073
0
    AVI_errno = AVI_ERR_NO_IDX;
3074
0
    return -1;
3075
0
  }
3076
3077
0
  nr = 0; /* total number of bytes read */
3078
3079
0
  if (bytes==0) {
3080
0
    AVI->track[AVI->aptr].audio_posc++;
3081
0
    AVI->track[AVI->aptr].audio_posb = 0;
3082
0
  }
3083
3084
0
  *continuous = 1;
3085
0
  while(bytes>0)
3086
0
  {
3087
0
    s64 ret;
3088
0
    u32 left = (u32) (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb);
3089
0
    if(left==0)
3090
0
    {
3091
0
      if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
3092
0
      AVI->track[AVI->aptr].audio_posc++;
3093
0
      AVI->track[AVI->aptr].audio_posb = 0;
3094
0
      *continuous = 0;
3095
0
      continue;
3096
0
    }
3097
0
    if((u32)bytes<left)
3098
0
      todo = bytes;
3099
0
    else
3100
0
      todo = left;
3101
0
    pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
3102
0
    gf_fseek(AVI->fdes, pos, SEEK_SET);
3103
0
    AVI->track[AVI->aptr].audio_posb += (int)todo;
3104
0
    if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != (s64)todo)
3105
0
    {
3106
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] XXX pos = "LLD", ret = "LLD", todo = %ld\n", pos, ret, todo));
3107
0
      AVI_errno = AVI_ERR_READ;
3108
0
      return -1;
3109
0
    }
3110
0
    bytes -= todo;
3111
0
    nr    += todo;
3112
0
  }
3113
3114
0
  return nr;
3115
0
}
3116
3117
3118
#if 0 //unused
3119
/* AVI_read_data: Special routine for reading the next audio or video chunk
3120
                  without having an index of the file. */
3121
3122
int AVI_read_data(avi_t *AVI, char *vidbuf, int max_vidbuf,
3123
                  char *audbuf, int max_audbuf,
3124
                  int *len)
3125
{
3126
3127
  /*
3128
   * Return codes:
3129
   *
3130
   *    1 = video data read
3131
   *    2 = audio data read
3132
   *    0 = reached EOF
3133
   *   -1 = video buffer too small
3134
   *   -2 = audio buffer too small
3135
   */
3136
3137
  s64 n;
3138
  char data[8];
3139
3140
  if(AVI->mode==AVI_MODE_WRITE) return 0;
3141
3142
  while(1)
3143
  {
3144
    /* Read tag and length */
3145
3146
    if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
3147
3148
    /* if we got a list tag, ignore it */
3149
3150
    if(strnicmp(data,"LIST",4) == 0)
3151
    {
3152
      gf_fseek(AVI->fdes,4,SEEK_CUR);
3153
      continue;
3154
    }
3155
3156
    n = PAD_EVEN(str2ulong((unsigned char *)data+4));
3157
3158
    if(strnicmp(data,AVI->video_tag,3) == 0)
3159
    {
3160
      *len = (u32) n;
3161
      AVI->video_pos++;
3162
      if(n>max_vidbuf)
3163
      {
3164
        gf_fseek(AVI->fdes,n,SEEK_CUR);
3165
        return -1;
3166
      }
3167
      if(avi_read(AVI->fdes,vidbuf, (u32) n) != n ) return 0;
3168
      return 1;
3169
    }
3170
    else if(strnicmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
3171
    {
3172
      *len = (u32) n;
3173
      if(n>max_audbuf)
3174
      {
3175
        gf_fseek(AVI->fdes,n,SEEK_CUR);
3176
        return -2;
3177
      }
3178
      if(avi_read(AVI->fdes,audbuf, (u32) n) != n ) return 0;
3179
      return 2;
3180
      break;
3181
    }
3182
    else if(gf_fseek(AVI->fdes,n,SEEK_CUR) == (u64) -1)  return 0;
3183
  }
3184
}
3185
3186
u64 AVI_max_size(void)
3187
{
3188
  return((u64) AVI_MAX_LEN);
3189
}
3190
#endif
3191
3192
3193
#endif /*GPAC_DISABLE_AVILIB*/