Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

libavi.c

00001 /*****************************************************************************
00002  * libavi.c : LibAVI
00003  *****************************************************************************
00004  * Copyright (C) 2001 the VideoLAN team
00005  * $Id: libavi.c 11664 2005-07-09 06:17:09Z courmisch $
00006  * Authors: Laurent Aimar <[email protected]>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00021  *****************************************************************************/
00022 
00023 #include <stdlib.h>                                      /* malloc(), free() */
00024 
00025 #include <vlc/vlc.h>
00026 #include <vlc/input.h>
00027 #include "codecs.h"                                      /* BITMAPINFOHEADER */
00028 
00029 #include "libavi.h"
00030 
00031 #define AVI_DEBUG 1
00032 
00033 #define FREE( p ) \
00034     if( p ) {free( p ); p = NULL; }
00035 
00036 #define __EVEN( x ) ( (x)&0x01 ? (x)+1 : (x) )
00037 
00038 static vlc_fourcc_t GetFOURCC( byte_t *p_buff )
00039 {
00040     return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
00041 }
00042 
00043 #define AVI_ChunkFree( a, b ) _AVI_ChunkFree( (a), (avi_chunk_t*)(b) )
00044 void    _AVI_ChunkFree( stream_t *, avi_chunk_t *p_chk );
00045 
00046 /****************************************************************************
00047  *
00048  * Basics functions to manipulates chunks
00049  *
00050  ****************************************************************************/
00051 static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk )
00052 {
00053     uint8_t  *p_peek;
00054     int i_peek;
00055 
00056     memset( p_chk, 0, sizeof( avi_chunk_t ) );
00057 
00058     if( ( i_peek = stream_Peek( s, &p_peek, 8 ) ) < 8 )
00059     {
00060         return VLC_EGENERIC;
00061     }
00062 
00063     p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );
00064     p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );
00065     p_chk->common.i_chunk_pos    = stream_Tell( s );
00066 
00067     p_chk->common.p_father = NULL;
00068     p_chk->common.p_next = NULL;
00069     p_chk->common.p_first = NULL;
00070     p_chk->common.p_next = NULL;
00071 
00072 #ifdef AVI_DEBUG
00073     msg_Dbg( (vlc_object_t*)s,
00074              "found Chunk fourcc:%8.8x (%4.4s) size:"I64Fd" pos:"I64Fd,
00075              p_chk->common.i_chunk_fourcc,
00076              (char*)&p_chk->common.i_chunk_fourcc,
00077              p_chk->common.i_chunk_size,
00078              p_chk->common.i_chunk_pos );
00079 #endif
00080     return VLC_SUCCESS;
00081 }
00082 
00083 static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk )
00084 {
00085     avi_chunk_t chk;
00086 
00087     if( !p_chk )
00088     {
00089         if( AVI_ChunkReadCommon( s, &chk ) )
00090         {
00091             return VLC_EGENERIC;
00092         }
00093         p_chk = &chk;
00094     }
00095 
00096     if( p_chk->common.p_father )
00097     {
00098         if( p_chk->common.p_father->common.i_chunk_pos +
00099                 __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 <
00100             p_chk->common.i_chunk_pos +
00101                 __EVEN( p_chk->common.i_chunk_size ) + 8 )
00102         {
00103             return VLC_EGENERIC;
00104         }
00105     }
00106     return stream_Seek( s, p_chk->common.i_chunk_pos +
00107                                  __EVEN( p_chk->common.i_chunk_size ) + 8 );
00108 }
00109 
00110 /****************************************************************************
00111  *
00112  * Functions to read chunks
00113  *
00114  ****************************************************************************/
00115 static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
00116 {
00117     avi_chunk_t *p_chk;
00118     uint8_t *p_peek;
00119     vlc_bool_t b_seekable;
00120 
00121     if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 8 )
00122     {
00123         /* empty box */
00124         msg_Warn( (vlc_object_t*)s, "empty list chunk" );
00125         return VLC_EGENERIC;
00126     }
00127     if( stream_Peek( s, &p_peek, 12 ) < 12 )
00128     {
00129         msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" );
00130         return VLC_EGENERIC;
00131     }
00132 
00133     stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );
00134 
00135     p_container->list.i_type = GetFOURCC( p_peek + 8 );
00136 
00137     if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
00138         p_container->list.i_type == AVIFOURCC_movi )
00139     {
00140         msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" );
00141         if( b_seekable )
00142         {
00143             return AVI_NextChunk( s, p_container );
00144         }
00145         return VLC_SUCCESS; /* point at begining of LIST-movi */
00146     }
00147 
00148     if( stream_Read( s, NULL, 12 ) != 12 )
00149     {
00150         msg_Warn( (vlc_object_t*)s, "cannot enter chunk" );
00151         return VLC_EGENERIC;
00152     }
00153 
00154 #ifdef AVI_DEBUG
00155     msg_Dbg( (vlc_object_t*)s,
00156              "found LIST chunk: \'%4.4s\'",
00157              (char*)&p_container->list.i_type );
00158 #endif
00159     msg_Dbg( (vlc_object_t*)s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );
00160     for( ; ; )
00161     {
00162         p_chk = malloc( sizeof( avi_chunk_t ) );
00163         memset( p_chk, 0, sizeof( avi_chunk_t ) );
00164         if( !p_container->common.p_first )
00165         {
00166             p_container->common.p_first = p_chk;
00167         }
00168         else
00169         {
00170             p_container->common.p_last->common.p_next = p_chk;
00171         }
00172         p_container->common.p_last = p_chk;
00173 
00174         if( AVI_ChunkRead( s, p_chk, p_container ) )
00175         {
00176             break;
00177         }
00178         if( p_chk->common.p_father->common.i_chunk_size > 0 &&
00179            ( stream_Tell( s ) >=
00180               (off_t)p_chk->common.p_father->common.i_chunk_pos +
00181                (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
00182         {
00183             break;
00184         }
00185 
00186         /* If we can't seek then stop when we 've found LIST-movi */
00187         if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
00188             p_chk->list.i_type == AVIFOURCC_movi &&
00189             ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
00190         {
00191             break;
00192         }
00193 
00194     }
00195     msg_Dbg( (vlc_object_t*)s, "</list \'%4.4s\'>", (char*)&p_container->list.i_type );
00196 
00197     return VLC_SUCCESS;
00198 }
00199 
00200 #define AVI_READCHUNK_ENTER \
00201     int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \
00202     uint8_t  *p_read, *p_buff;    \
00203     if( !( p_read = p_buff = malloc(i_read ) ) ) \
00204     { \
00205         return VLC_EGENERIC; \
00206     } \
00207     i_read = stream_Read( s, p_read, i_read ); \
00208     if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) \
00209     { \
00210         return VLC_EGENERIC; \
00211     }\
00212     p_read += 8; \
00213     i_read -= 8
00214 
00215 #define AVI_READCHUNK_EXIT( code ) \
00216     free( p_buff ); \
00217     if( i_read < 0 ) \
00218     { \
00219         msg_Warn( (vlc_object_t*)s, "not enough data" ); \
00220     } \
00221     return code
00222 
00223 #define AVI_READ1BYTE( i_byte ) \
00224     i_byte = *p_read; \
00225     p_read++; \
00226     i_read--
00227 
00228 #define AVI_READ2BYTES( i_word ) \
00229     i_word = GetWLE( p_read ); \
00230     p_read += 2; \
00231     i_read -= 2
00232 
00233 #define AVI_READ4BYTES( i_dword ) \
00234     i_dword = GetDWLE( p_read ); \
00235     p_read += 4; \
00236     i_read -= 4
00237 
00238 #define AVI_READ8BYTES( i_dword ) \
00239     i_dword = GetQWLE( p_read ); \
00240     p_read += 8; \
00241     i_read -= 8
00242 
00243 #define AVI_READFOURCC( i_dword ) \
00244     i_dword = GetFOURCC( p_read ); \
00245     p_read += 4; \
00246     i_read -= 4
00247 
00248 static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk )
00249 {
00250     AVI_READCHUNK_ENTER;
00251 
00252     AVI_READ4BYTES( p_chk->avih.i_microsecperframe);
00253     AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );
00254     AVI_READ4BYTES( p_chk->avih.i_reserved1 );
00255     AVI_READ4BYTES( p_chk->avih.i_flags );
00256     AVI_READ4BYTES( p_chk->avih.i_totalframes );
00257     AVI_READ4BYTES( p_chk->avih.i_initialframes );
00258     AVI_READ4BYTES( p_chk->avih.i_streams );
00259     AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );
00260     AVI_READ4BYTES( p_chk->avih.i_width );
00261     AVI_READ4BYTES( p_chk->avih.i_height );
00262     AVI_READ4BYTES( p_chk->avih.i_scale );
00263     AVI_READ4BYTES( p_chk->avih.i_rate );
00264     AVI_READ4BYTES( p_chk->avih.i_start );
00265     AVI_READ4BYTES( p_chk->avih.i_length );
00266 #ifdef AVI_DEBUG
00267     msg_Dbg( (vlc_object_t*)s,
00268              "avih: streams:%d flags:%s%s%s%s %dx%d",
00269              p_chk->avih.i_streams,
00270              p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
00271              p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
00272              p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
00273              p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
00274              p_chk->avih.i_width, p_chk->avih.i_height );
00275 #endif
00276     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00277 }
00278 
00279 static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk )
00280 {
00281     AVI_READCHUNK_ENTER;
00282 
00283     AVI_READFOURCC( p_chk->strh.i_type );
00284     AVI_READFOURCC( p_chk->strh.i_handler );
00285     AVI_READ4BYTES( p_chk->strh.i_flags );
00286     AVI_READ4BYTES( p_chk->strh.i_reserved1 );
00287     AVI_READ4BYTES( p_chk->strh.i_initialframes );
00288     AVI_READ4BYTES( p_chk->strh.i_scale );
00289     AVI_READ4BYTES( p_chk->strh.i_rate );
00290     AVI_READ4BYTES( p_chk->strh.i_start );
00291     AVI_READ4BYTES( p_chk->strh.i_length );
00292     AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );
00293     AVI_READ4BYTES( p_chk->strh.i_quality );
00294     AVI_READ4BYTES( p_chk->strh.i_samplesize );
00295 #ifdef AVI_DEBUG
00296     msg_Dbg( (vlc_object_t*)s,
00297              "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",
00298              (char*)&p_chk->strh.i_type,
00299              p_chk->strh.i_handler,
00300              p_chk->strh.i_samplesize,
00301              ( p_chk->strh.i_scale ?
00302                 (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );
00303 #endif
00304 
00305     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00306 }
00307 
00308 static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk )
00309 {
00310     avi_chunk_t *p_strh;
00311 
00312     AVI_READCHUNK_ENTER;
00313     if( p_chk->common.p_father == NULL )
00314     {
00315         msg_Err( (vlc_object_t*)s, "malformed avi file" );
00316         AVI_READCHUNK_EXIT( VLC_EGENERIC );
00317     }
00318     if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0 ) ) )
00319     {
00320         msg_Err( (vlc_object_t*)s, "malformed avi file" );
00321         AVI_READCHUNK_EXIT( VLC_EGENERIC );
00322     }
00323 
00324     switch( p_strh->strh.i_type )
00325     {
00326         case( AVIFOURCC_auds ):
00327             p_chk->strf.auds.i_cat = AUDIO_ES;
00328             p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );
00329             AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );
00330             AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );
00331             AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );
00332             AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );
00333             AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );
00334             AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );
00335             if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM
00336                  && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )
00337             {
00338                 AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );
00339                 /* prevent segfault */
00340                 if( p_chk->strf.auds.p_wf->cbSize >
00341                         p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )
00342                 {
00343                     p_chk->strf.auds.p_wf->cbSize =
00344                         p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );
00345                 }
00346                 if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
00347                 {
00348                     /* Found an extensible header atm almost nothing uses that. */
00349                     msg_Warn( (vlc_object_t*)s, "WAVE_FORMAT_EXTENSIBLE or "
00350                               "vorbis audio dectected: not supported" );
00351                 }
00352             }
00353             else
00354             {
00355                 p_chk->strf.auds.p_wf->cbSize = 0;
00356             }
00357             if( p_chk->strf.auds.p_wf->cbSize > 0 )
00358             {
00359                 memcpy( &p_chk->strf.auds.p_wf[1] ,
00360                         p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourrc+size */
00361                         p_chk->strf.auds.p_wf->cbSize );
00362             }
00363 #ifdef AVI_DEBUG
00364             msg_Dbg( (vlc_object_t*)s,
00365                      "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkb/s",
00366                      p_chk->strf.auds.p_wf->wFormatTag,
00367                      p_chk->strf.auds.p_wf->nChannels,
00368                      p_chk->strf.auds.p_wf->nSamplesPerSec,
00369                      p_chk->strf.auds.p_wf->wBitsPerSample,
00370                      p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1024 );
00371 #endif
00372             break;
00373         case( AVIFOURCC_vids ):
00374             p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */
00375             p_chk->strf.vids.i_cat = VIDEO_ES;
00376             p_chk->strf.vids.p_bih = malloc( p_chk->common.i_chunk_size );
00377             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );
00378             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );
00379             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );
00380             AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );
00381             AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );
00382             AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );
00383             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );
00384             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );
00385             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );
00386             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );
00387             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );
00388             if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )
00389             {
00390                 p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;
00391             }
00392             if( p_chk->strf.vids.p_bih->biSize - sizeof(BITMAPINFOHEADER) > 0 )
00393             {
00394                 memcpy( &p_chk->strf.vids.p_bih[1],
00395                         p_buff + 8 + sizeof(BITMAPINFOHEADER), /* 8=fourrc+size */
00396                         p_chk->common.i_chunk_size -sizeof(BITMAPINFOHEADER) );
00397             }
00398 #ifdef AVI_DEBUG
00399             msg_Dbg( (vlc_object_t*)s,
00400                      "strf: video:%4.4s %dx%d planes:%d %dbpp",
00401                      (char*)&p_chk->strf.vids.p_bih->biCompression,
00402                      p_chk->strf.vids.p_bih->biWidth,
00403                      p_chk->strf.vids.p_bih->biHeight,
00404                      p_chk->strf.vids.p_bih->biPlanes,
00405                      p_chk->strf.vids.p_bih->biBitCount );
00406 #endif
00407             break;
00408         default:
00409             msg_Warn( (vlc_object_t*)s, "unknown stream type" );
00410             p_chk->strf.common.i_cat = UNKNOWN_ES;
00411             break;
00412     }
00413     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00414 }
00415 static void AVI_ChunkFree_strf( avi_chunk_t *p_chk )
00416 {
00417     avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;
00418     if( p_strf->common.i_cat == AUDIO_ES )
00419     {
00420         FREE( p_strf->auds.p_wf );
00421     }
00422     else if( p_strf->common.i_cat == VIDEO_ES )
00423     {
00424         FREE( p_strf->vids.p_bih );
00425     }
00426 }
00427 
00428 static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk )
00429 {
00430     AVI_READCHUNK_ENTER;
00431     p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );
00432     memcpy( p_chk->strd.p_data,
00433             p_buff + 8,
00434             p_chk->common.i_chunk_size );
00435     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00436 }
00437 
00438 static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk )
00439 {
00440     unsigned int i_count, i_index;
00441 
00442     AVI_READCHUNK_ENTER;
00443 
00444     i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;
00445 
00446     p_chk->idx1.i_entry_count = i_count;
00447     p_chk->idx1.i_entry_max   = i_count;
00448     if( i_count > 0 )
00449     {
00450         p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );
00451 
00452         for( i_index = 0; i_index < i_count ; i_index++ )
00453         {
00454             AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );
00455             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );
00456             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );
00457             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );
00458         }
00459     }
00460     else
00461     {
00462         p_chk->idx1.entry = NULL;
00463     }
00464 #ifdef AVI_DEBUG
00465     msg_Dbg( (vlc_object_t*)s, "idx1: index entry:%d", i_count );
00466 #endif
00467     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00468 }
00469 
00470 static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk )
00471 {
00472     p_chk->idx1.i_entry_count = 0;
00473     p_chk->idx1.i_entry_max   = 0;
00474     FREE( p_chk->idx1.entry )
00475 }
00476 
00477 
00478 
00479 static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk )
00480 {
00481     unsigned int i_count, i;
00482     int32_t      i_dummy;
00483     avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
00484 
00485     AVI_READCHUNK_ENTER;
00486 
00487     AVI_READ2BYTES( p_indx->i_longsperentry );
00488     AVI_READ1BYTE ( p_indx->i_indexsubtype );
00489     AVI_READ1BYTE ( p_indx->i_indextype );
00490     AVI_READ4BYTES( p_indx->i_entriesinuse );
00491 
00492     AVI_READ4BYTES( p_indx->i_id );
00493     p_indx->idx.std     = NULL;
00494     p_indx->idx.field   = NULL;
00495     p_indx->idx.super   = NULL;
00496 
00497     if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == 0 )
00498     {
00499         AVI_READ8BYTES( p_indx->i_baseoffset );
00500         AVI_READ4BYTES( i_dummy );
00501 
00502         i_count = __MIN( p_indx->i_entriesinuse, i_read / 8 );
00503         p_indx->i_entriesinuse = i_count;
00504         p_indx->idx.std = calloc( sizeof( indx_std_entry_t ), i_count );
00505 
00506         for( i = 0; i < i_count; i++ )
00507         {
00508             AVI_READ4BYTES( p_indx->idx.std[i].i_offset );
00509             AVI_READ4BYTES( p_indx->idx.std[i].i_size );
00510         }
00511     }
00512     else if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
00513     {
00514         AVI_READ8BYTES( p_indx->i_baseoffset );
00515         AVI_READ4BYTES( i_dummy );
00516 
00517         i_count = __MIN( p_indx->i_entriesinuse, i_read / 12 );
00518         p_indx->i_entriesinuse = i_count;
00519         p_indx->idx.field = calloc( sizeof( indx_field_entry_t ), i_count );
00520         for( i = 0; i < i_count; i++ )
00521         {
00522             AVI_READ4BYTES( p_indx->idx.field[i].i_offset );
00523             AVI_READ4BYTES( p_indx->idx.field[i].i_size );
00524             AVI_READ4BYTES( p_indx->idx.field[i].i_offsetfield2 );
00525         }
00526     }
00527     else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
00528     {
00529         p_indx->i_baseoffset = 0;
00530         AVI_READ4BYTES( i_dummy );
00531         AVI_READ4BYTES( i_dummy );
00532         AVI_READ4BYTES( i_dummy );
00533 
00534         i_count = __MIN( p_indx->i_entriesinuse, i_read / 16 );
00535         p_indx->i_entriesinuse = i_count;
00536         p_indx->idx.super = calloc( sizeof( indx_super_entry_t ), i_count );
00537 
00538         for( i = 0; i < i_count; i++ )
00539         {
00540             AVI_READ8BYTES( p_indx->idx.super[i].i_offset );
00541             AVI_READ4BYTES( p_indx->idx.super[i].i_size );
00542             AVI_READ4BYTES( p_indx->idx.super[i].i_duration );
00543         }
00544     }
00545     else
00546     {
00547         msg_Warn( (vlc_object_t*)s, "unknow type/subtype index" );
00548     }
00549 
00550 #ifdef AVI_DEBUG
00551     msg_Dbg( (vlc_object_t*)s, "indx: type=%d subtype=%d entry=%d", p_indx->i_indextype, p_indx->i_indexsubtype, p_indx->i_entriesinuse );
00552 #endif
00553     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00554 }
00555 static void AVI_ChunkFree_indx( avi_chunk_t *p_chk )
00556 {
00557     avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
00558 
00559     FREE( p_indx->idx.std );
00560     FREE( p_indx->idx.field );
00561     FREE( p_indx->idx.super );
00562 }
00563 
00564 
00565 
00566 static struct
00567 {
00568     vlc_fourcc_t i_fourcc;
00569     char *psz_type;
00570 } AVI_strz_type[] =
00571 {
00572     { AVIFOURCC_IARL, "archive location" },
00573     { AVIFOURCC_IART, "artist" },
00574     { AVIFOURCC_ICMS, "commisioned" },
00575     { AVIFOURCC_ICMT, "comments" },
00576     { AVIFOURCC_ICOP, "copyright" },
00577     { AVIFOURCC_ICRD, "creation date" },
00578     { AVIFOURCC_ICRP, "cropped" },
00579     { AVIFOURCC_IDIM, "dimensions" },
00580     { AVIFOURCC_IDPI, "dots per inch" },
00581     { AVIFOURCC_IENG, "engineer" },
00582     { AVIFOURCC_IGNR, "genre" },
00583     { AVIFOURCC_IKEY, "keywords" },
00584     { AVIFOURCC_ILGT, "lightness" },
00585     { AVIFOURCC_IMED, "medium" },
00586     { AVIFOURCC_INAM, "name" },
00587     { AVIFOURCC_IPLT, "palette setting" },
00588     { AVIFOURCC_IPRD, "product" },
00589     { AVIFOURCC_ISBJ, "subject" },
00590     { AVIFOURCC_ISFT, "software" },
00591     { AVIFOURCC_ISHP, "sharpness" },
00592     { AVIFOURCC_ISRC, "source" },
00593     { AVIFOURCC_ISRF, "source form" },
00594     { AVIFOURCC_ITCH, "technician" },
00595     { AVIFOURCC_ISMP, "time code" },
00596     { AVIFOURCC_IDIT, "digitalization time" },
00597     { AVIFOURCC_strn, "stream name" },
00598     { 0,              "???" }
00599 };
00600 static int AVI_ChunkRead_strz( stream_t *s, avi_chunk_t *p_chk )
00601 {
00602     int i_index;
00603     avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
00604     AVI_READCHUNK_ENTER;
00605 
00606     for( i_index = 0;; i_index++)
00607     {
00608         if( !AVI_strz_type[i_index].i_fourcc ||
00609             AVI_strz_type[i_index].i_fourcc == p_strz->i_chunk_fourcc )
00610         {
00611             break;
00612         }
00613     }
00614     p_strz->p_type = strdup( AVI_strz_type[i_index].psz_type );
00615     p_strz->p_str = malloc( i_read + 1);
00616 
00617     if( p_strz->i_chunk_size )
00618     {
00619         memcpy( p_strz->p_str, p_read, i_read );
00620     }
00621     p_strz->p_str[i_read] = 0;
00622 
00623 #ifdef AVI_DEBUG
00624     msg_Dbg( (vlc_object_t*)s, "%4.4s: %s : %s",
00625              (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str);
00626 #endif
00627     AVI_READCHUNK_EXIT( VLC_SUCCESS );
00628 }
00629 static void AVI_ChunkFree_strz( avi_chunk_t *p_chk )
00630 {
00631     avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
00632     FREE( p_strz->p_type );
00633     FREE( p_strz->p_str );
00634 }
00635 
00636 static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk )
00637 {
00638     return AVI_NextChunk( s, p_chk );
00639 }
00640 static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk )
00641 {
00642 
00643 }
00644 
00645 static struct
00646 {
00647     vlc_fourcc_t i_fourcc;
00648     int   (*AVI_ChunkRead_function)( stream_t *s, avi_chunk_t *p_chk );
00649     void  (*AVI_ChunkFree_function)( avi_chunk_t *p_chk );
00650 } AVI_Chunk_Function [] =
00651 {
00652     { AVIFOURCC_RIFF, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
00653     { AVIFOURCC_LIST, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
00654     { AVIFOURCC_avih, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
00655     { AVIFOURCC_strh, AVI_ChunkRead_strh, AVI_ChunkFree_nothing },
00656     { AVIFOURCC_strf, AVI_ChunkRead_strf, AVI_ChunkFree_strf },
00657     { AVIFOURCC_strd, AVI_ChunkRead_strd, AVI_ChunkFree_nothing },
00658     { AVIFOURCC_idx1, AVI_ChunkRead_idx1, AVI_ChunkFree_idx1 },
00659     { AVIFOURCC_indx, AVI_ChunkRead_indx, AVI_ChunkFree_indx },
00660     { AVIFOURCC_JUNK, AVI_ChunkRead_nothing, AVI_ChunkFree_nothing },
00661 
00662     { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00663     { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00664     { AVIFOURCC_IART, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00665     { AVIFOURCC_ICMS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00666     { AVIFOURCC_ICMT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00667     { AVIFOURCC_ICOP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00668     { AVIFOURCC_ICRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00669     { AVIFOURCC_ICRP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00670     { AVIFOURCC_IDIM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00671     { AVIFOURCC_IDPI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00672     { AVIFOURCC_IENG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00673     { AVIFOURCC_IGNR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00674     { AVIFOURCC_IKEY, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00675     { AVIFOURCC_ILGT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00676     { AVIFOURCC_IMED, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00677     { AVIFOURCC_INAM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00678     { AVIFOURCC_IPLT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00679     { AVIFOURCC_IPRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00680     { AVIFOURCC_ISBJ, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00681     { AVIFOURCC_ISFT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00682     { AVIFOURCC_ISHP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00683     { AVIFOURCC_ISRC, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00684     { AVIFOURCC_ISRF, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00685     { AVIFOURCC_ITCH, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00686     { AVIFOURCC_ISMP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00687     { AVIFOURCC_IDIT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00688     { AVIFOURCC_strn, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
00689     { 0,           NULL,               NULL }
00690 };
00691 
00692 static int AVI_ChunkFunctionFind( vlc_fourcc_t i_fourcc )
00693 {
00694     unsigned int i_index;
00695     for( i_index = 0; ; i_index++ )
00696     {
00697         if( ( AVI_Chunk_Function[i_index].i_fourcc == i_fourcc )||
00698             ( AVI_Chunk_Function[i_index].i_fourcc == 0 ) )
00699         {
00700             return i_index;
00701         }
00702     }
00703 }
00704 
00705 int  _AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father )
00706 {
00707     int i_index;
00708 
00709     if( !p_chk )
00710     {
00711         return VLC_EGENERIC;
00712     }
00713 
00714     if( AVI_ChunkReadCommon( s, p_chk ) )
00715     {
00716         msg_Warn( (vlc_object_t*)s, "cannot read one chunk" );
00717         return VLC_EGENERIC;
00718     }
00719     if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) )
00720     {
00721         msg_Warn( (vlc_object_t*)s, "found null fourcc chunk (corrupted file?)" );
00722         return VLC_EGENERIC;
00723     }
00724     p_chk->common.p_father = p_father;
00725 
00726     i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
00727     if( AVI_Chunk_Function[i_index].AVI_ChunkRead_function )
00728     {
00729         return AVI_Chunk_Function[i_index].AVI_ChunkRead_function( s, p_chk );
00730     }
00731     else if( ((char*)&p_chk->common.i_chunk_fourcc)[0] == 'i' &&
00732              ((char*)&p_chk->common.i_chunk_fourcc)[1] == 'x' )
00733     {
00734         p_chk->common.i_chunk_fourcc = AVIFOURCC_indx;
00735         return AVI_ChunkRead_indx( s, p_chk );
00736     }
00737     msg_Warn( (vlc_object_t*)s, "unknown chunk (not loaded)" );
00738     return AVI_NextChunk( s, p_chk );
00739 }
00740 
00741 void _AVI_ChunkFree( stream_t *s,
00742                      avi_chunk_t *p_chk )
00743 {
00744     int i_index;
00745     avi_chunk_t *p_child, *p_next;
00746 
00747     if( !p_chk )
00748     {
00749         return;
00750     }
00751 
00752     /* Free all child chunk */
00753     p_child = p_chk->common.p_first;
00754     while( p_child )
00755     {
00756         p_next = p_child->common.p_next;
00757         AVI_ChunkFree( s, p_child );
00758         free( p_child );
00759         p_child = p_next;
00760     }
00761 
00762     i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
00763     if( AVI_Chunk_Function[i_index].AVI_ChunkFree_function )
00764     {
00765 #ifdef AVI_DEBUG
00766         msg_Dbg( (vlc_object_t*)s, "free chunk %4.4s",
00767                  (char*)&p_chk->common.i_chunk_fourcc );
00768 #endif
00769         AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_chk);
00770     }
00771     else
00772     {
00773         msg_Warn( (vlc_object_t*)s, "unknown chunk (not unloaded)" );
00774     }
00775     p_chk->common.p_first = NULL;
00776     p_chk->common.p_last  = NULL;
00777 
00778     return;
00779 }
00780 
00781 static void AVI_ChunkDumpDebug_level( vlc_object_t *p_obj,
00782                                       avi_chunk_t  *p_chk, int i_level )
00783 {
00784     char str[1024];
00785     int i;
00786     avi_chunk_t *p_child;
00787 
00788     memset( str, ' ', sizeof( str ) );
00789     for( i = 1; i < i_level; i++ )
00790     {
00791         str[i * 5] = '|';
00792     }
00793     if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF||
00794         p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST )
00795     {
00796         sprintf( str + i_level * 5,
00797                  "%c %4.4s-%4.4s size:"I64Fu" pos:"I64Fu,
00798                  i_level ? '+' : '*',
00799                  (char*)&p_chk->common.i_chunk_fourcc,
00800                  (char*)&p_chk->list.i_type,
00801                  p_chk->common.i_chunk_size,
00802                  p_chk->common.i_chunk_pos );
00803     }
00804     else
00805     {
00806         sprintf( str + i_level * 5,
00807                  "+ %4.4s size:"I64Fu" pos:"I64Fu,
00808                  (char*)&p_chk->common.i_chunk_fourcc,
00809                  p_chk->common.i_chunk_size,
00810                  p_chk->common.i_chunk_pos );
00811     }
00812     msg_Dbg( p_obj, "%s", str );
00813 
00814     p_child = p_chk->common.p_first;
00815     while( p_child )
00816     {
00817         AVI_ChunkDumpDebug_level( p_obj, p_child, i_level + 1 );
00818         p_child = p_child->common.p_next;
00819     }
00820 }
00821 
00822 int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root )
00823 {
00824     avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root;
00825     avi_chunk_t      *p_chk;
00826     vlc_bool_t b_seekable;
00827 
00828     stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );
00829 
00830     p_list->i_chunk_pos  = 0;
00831     p_list->i_chunk_size = stream_Size( s );
00832     p_list->i_chunk_fourcc = AVIFOURCC_LIST;
00833     p_list->p_father = NULL;
00834     p_list->p_next  = NULL;
00835     p_list->p_first = NULL;
00836     p_list->p_last  = NULL;
00837 
00838     p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
00839 
00840     for( ; ; )
00841     {
00842         p_chk = malloc( sizeof( avi_chunk_t ) );
00843         memset( p_chk, 0, sizeof( avi_chunk_t ) );
00844         if( !p_root->common.p_first )
00845         {
00846             p_root->common.p_first = p_chk;
00847         }
00848         else
00849         {
00850             p_root->common.p_last->common.p_next = p_chk;
00851         }
00852         p_root->common.p_last = p_chk;
00853 
00854         if( AVI_ChunkRead( s, p_chk, p_root ) ||
00855            ( stream_Tell( s ) >=
00856               (off_t)p_chk->common.p_father->common.i_chunk_pos +
00857                (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
00858         {
00859             break;
00860         }
00861         /* If we can't seek then stop when we 've found first RIFF-AVI */
00862         if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF &&
00863             p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable )
00864         {
00865             break;
00866         }
00867     }
00868 
00869     AVI_ChunkDumpDebug_level( (vlc_object_t*)s, p_root, 0 );
00870     return VLC_SUCCESS;
00871 }
00872 
00873 void AVI_ChunkFreeRoot( stream_t *s,
00874                         avi_chunk_t  *p_chk )
00875 {
00876     AVI_ChunkFree( s, p_chk );
00877 }
00878 
00879 
00880 int  _AVI_ChunkCount( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc )
00881 {
00882     int i_count;
00883     avi_chunk_t *p_child;
00884 
00885     if( !p_chk )
00886     {
00887         return 0;
00888     }
00889 
00890     i_count = 0;
00891     p_child = p_chk->common.p_first;
00892     while( p_child )
00893     {
00894         if( p_child->common.i_chunk_fourcc == i_fourcc ||
00895             ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST &&
00896               p_child->list.i_type == i_fourcc ) )
00897         {
00898             i_count++;
00899         }
00900         p_child = p_child->common.p_next;
00901     }
00902     return i_count;
00903 }
00904 
00905 void *_AVI_ChunkFind( avi_chunk_t *p_chk,
00906                       vlc_fourcc_t i_fourcc, int i_number )
00907 {
00908     avi_chunk_t *p_child;
00909     if( !p_chk )
00910     {
00911         return NULL;
00912     }
00913     p_child = p_chk->common.p_first;
00914 
00915     while( p_child )
00916     {
00917         if( p_child->common.i_chunk_fourcc == i_fourcc ||
00918             ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST &&
00919               p_child->list.i_type == i_fourcc ) )
00920         {
00921             if( i_number == 0 )
00922             {
00923                 /* We found it */
00924                 return p_child;
00925             }
00926 
00927             i_number--;
00928         }
00929         p_child = p_child->common.p_next;
00930     }
00931     return NULL;
00932 }
00933 
00934 

Generated on Tue Dec 20 10:14:31 2005 for vlc-0.8.4a by  doxygen 1.4.2