LCOV - code coverage report
Current view: top level - media_tools - avilib.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 846 1088 77.8 %
Date: 2021-04-29 23:48:07 Functions: 39 42 92.9 %

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

Generated by: LCOV version 1.13