libavi.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:30k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * libavi.c : LibAVI
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 the VideoLAN team
  5.  * $Id: ffbb3f9b16a66c295799a31d9d793c1549a9ef40 $
  6.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21.  *****************************************************************************/
  22. #ifdef HAVE_CONFIG_H
  23. # include "config.h"
  24. #endif
  25. #include <vlc_common.h>
  26. #include <vlc_demux.h>
  27. #include <vlc_codecs.h>                                /* BITMAPINFOHEADER */
  28. #include "libavi.h"
  29. #define AVI_DEBUG 1
  30. #define __EVEN( x ) (((x) + 1) & ~1)
  31. static vlc_fourcc_t GetFOURCC( const uint8_t *p_buff )
  32. {
  33.     return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
  34. }
  35. #define AVI_ChunkFree( a, b ) _AVI_ChunkFree( (a), (avi_chunk_t*)(b) )
  36. void    _AVI_ChunkFree( stream_t *, avi_chunk_t *p_chk );
  37. /****************************************************************************
  38.  *
  39.  * Basics functions to manipulates chunks
  40.  *
  41.  ****************************************************************************/
  42. static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk )
  43. {
  44.     const uint8_t *p_peek;
  45.     int i_peek;
  46.     memset( p_chk, 0, sizeof( avi_chunk_t ) );
  47.     if( ( i_peek = stream_Peek( s, &p_peek, 8 ) ) < 8 )
  48.     {
  49.         return VLC_EGENERIC;
  50.     }
  51.     p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );
  52.     p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );
  53.     p_chk->common.i_chunk_pos    = stream_Tell( s );
  54.     p_chk->common.p_father = NULL;
  55.     p_chk->common.p_next = NULL;
  56.     p_chk->common.p_first = NULL;
  57.     p_chk->common.p_next = NULL;
  58. #ifdef AVI_DEBUG
  59.     msg_Dbg( (vlc_object_t*)s,
  60.              "found Chunk fourcc:%8.8x (%4.4s) size:%"PRId64" pos:%"PRId64,
  61.              p_chk->common.i_chunk_fourcc,
  62.              (char*)&p_chk->common.i_chunk_fourcc,
  63.              p_chk->common.i_chunk_size,
  64.              p_chk->common.i_chunk_pos );
  65. #endif
  66.     return VLC_SUCCESS;
  67. }
  68. static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk )
  69. {
  70.     avi_chunk_t chk;
  71.     if( !p_chk )
  72.     {
  73.         if( AVI_ChunkReadCommon( s, &chk ) )
  74.         {
  75.             return VLC_EGENERIC;
  76.         }
  77.         p_chk = &chk;
  78.     }
  79.     if( p_chk->common.p_father )
  80.     {
  81.         if( p_chk->common.p_father->common.i_chunk_pos +
  82.                 __EVEN( p_chk->common.p_father->common.i_chunk_size ) + 8 <
  83.             p_chk->common.i_chunk_pos +
  84.                 __EVEN( p_chk->common.i_chunk_size ) + 8 )
  85.         {
  86.             return VLC_EGENERIC;
  87.         }
  88.     }
  89.     return stream_Seek( s, p_chk->common.i_chunk_pos +
  90.                                  __EVEN( p_chk->common.i_chunk_size ) + 8 );
  91. }
  92. /****************************************************************************
  93.  *
  94.  * Functions to read chunks
  95.  *
  96.  ****************************************************************************/
  97. static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
  98. {
  99.     avi_chunk_t *p_chk;
  100.     const uint8_t *p_peek;
  101.     bool b_seekable;
  102.     if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 8 )
  103.     {
  104.         /* empty box */
  105.         msg_Warn( (vlc_object_t*)s, "empty list chunk" );
  106.         return VLC_EGENERIC;
  107.     }
  108.     if( stream_Peek( s, &p_peek, 12 ) < 12 )
  109.     {
  110.         msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" );
  111.         return VLC_EGENERIC;
  112.     }
  113.     stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );
  114.     p_container->list.i_type = GetFOURCC( p_peek + 8 );
  115.     /* XXX fixed for on2 hack */
  116.     if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f )
  117.     {
  118.         p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF;
  119.         p_container->list.i_type = AVIFOURCC_AVI;
  120.     }
  121.     if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
  122.         p_container->list.i_type == AVIFOURCC_movi )
  123.     {
  124.         msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" );
  125.         if( b_seekable )
  126.         {
  127.             return AVI_NextChunk( s, p_container );
  128.         }
  129.         return VLC_SUCCESS; /* point at begining of LIST-movi */
  130.     }
  131.     if( stream_Read( s, NULL, 12 ) != 12 )
  132.     {
  133.         msg_Warn( (vlc_object_t*)s, "cannot enter chunk" );
  134.         return VLC_EGENERIC;
  135.     }
  136. #ifdef AVI_DEBUG
  137.     msg_Dbg( (vlc_object_t*)s,
  138.              "found LIST chunk: '%4.4s'",
  139.              (char*)&p_container->list.i_type );
  140. #endif
  141.     msg_Dbg( (vlc_object_t*)s, "<list '%4.4s'>", (char*)&p_container->list.i_type );
  142.     for( ; ; )
  143.     {
  144.         p_chk = malloc( sizeof( avi_chunk_t ) );
  145.         memset( p_chk, 0, sizeof( avi_chunk_t ) );
  146.         if( !p_container->common.p_first )
  147.         {
  148.             p_container->common.p_first = p_chk;
  149.         }
  150.         else
  151.         {
  152.             p_container->common.p_last->common.p_next = p_chk;
  153.         }
  154.         p_container->common.p_last = p_chk;
  155.         if( AVI_ChunkRead( s, p_chk, p_container ) )
  156.         {
  157.             break;
  158.         }
  159.         if( p_chk->common.p_father->common.i_chunk_size > 0 &&
  160.            ( stream_Tell( s ) >
  161.               (off_t)p_chk->common.p_father->common.i_chunk_pos +
  162.                (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
  163.         {
  164.             break;
  165.         }
  166.         /* If we can't seek then stop when we 've found LIST-movi */
  167.         if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
  168.             p_chk->list.i_type == AVIFOURCC_movi &&
  169.             ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
  170.         {
  171.             break;
  172.         }
  173.     }
  174.     msg_Dbg( (vlc_object_t*)s, "</list '%4.4s'>", (char*)&p_container->list.i_type );
  175.     return VLC_SUCCESS;
  176. }
  177. #define AVI_READCHUNK_ENTER 
  178.     int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; 
  179.     uint8_t  *p_read, *p_buff;    
  180.     if( !( p_read = p_buff = malloc(i_read ) ) ) 
  181.     { 
  182.         return VLC_EGENERIC; 
  183.     } 
  184.     i_read = stream_Read( s, p_read, i_read ); 
  185.     if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) 
  186.     { 
  187.         free( p_buff ); 
  188.         return VLC_EGENERIC; 
  189.     }
  190.     p_read += 8; 
  191.     i_read -= 8
  192. #define AVI_READ( res, func, size ) 
  193.     if( i_read < size ) { 
  194.         free( p_buff); 
  195.         return VLC_EGENERIC; 
  196.     } 
  197.     i_read -= size; 
  198.     res = func( p_read ); 
  199.     p_read += size 
  200. #define AVI_READCHUNK_EXIT( code ) 
  201.     free( p_buff ); 
  202.     return code
  203. static inline uint8_t GetB( uint8_t *ptr )
  204. {
  205.     return *ptr;
  206. }
  207. #define AVI_READ1BYTE( i_byte ) 
  208.     AVI_READ( i_byte, GetB, 1 )
  209. #define AVI_READ2BYTES( i_word ) 
  210.     AVI_READ( i_word, GetWLE, 2 )
  211. #define AVI_READ4BYTES( i_dword ) 
  212.     AVI_READ( i_dword, GetDWLE, 4 )
  213. #define AVI_READ8BYTES( i_qword ) 
  214.     AVI_READ( i_qword, GetQWLE, 8 )
  215. #define AVI_READFOURCC( i_dword ) 
  216.     AVI_READ( i_dword, GetFOURCC, 4 )
  217. static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk )
  218. {
  219.     AVI_READCHUNK_ENTER;
  220.     p_chk->common.i_chunk_fourcc = AVIFOURCC_avih;
  221.     AVI_READ4BYTES( p_chk->avih.i_microsecperframe);
  222.     AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );
  223.     AVI_READ4BYTES( p_chk->avih.i_reserved1 );
  224.     AVI_READ4BYTES( p_chk->avih.i_flags );
  225.     AVI_READ4BYTES( p_chk->avih.i_totalframes );
  226.     AVI_READ4BYTES( p_chk->avih.i_initialframes );
  227.     AVI_READ4BYTES( p_chk->avih.i_streams );
  228.     AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );
  229.     AVI_READ4BYTES( p_chk->avih.i_width );
  230.     AVI_READ4BYTES( p_chk->avih.i_height );
  231.     AVI_READ4BYTES( p_chk->avih.i_scale );
  232.     AVI_READ4BYTES( p_chk->avih.i_rate );
  233.     AVI_READ4BYTES( p_chk->avih.i_start );
  234.     AVI_READ4BYTES( p_chk->avih.i_length );
  235. #ifdef AVI_DEBUG
  236.     msg_Dbg( (vlc_object_t*)s,
  237.              "avih: streams:%d flags:%s%s%s%s %dx%d",
  238.              p_chk->avih.i_streams,
  239.              p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
  240.              p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
  241.              p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
  242.              p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
  243.              p_chk->avih.i_width, p_chk->avih.i_height );
  244. #endif
  245.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  246. }
  247. static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk )
  248. {
  249.     AVI_READCHUNK_ENTER;
  250.     AVI_READFOURCC( p_chk->strh.i_type );
  251.     AVI_READFOURCC( p_chk->strh.i_handler );
  252.     AVI_READ4BYTES( p_chk->strh.i_flags );
  253.     AVI_READ4BYTES( p_chk->strh.i_reserved1 );
  254.     AVI_READ4BYTES( p_chk->strh.i_initialframes );
  255.     AVI_READ4BYTES( p_chk->strh.i_scale );
  256.     AVI_READ4BYTES( p_chk->strh.i_rate );
  257.     AVI_READ4BYTES( p_chk->strh.i_start );
  258.     AVI_READ4BYTES( p_chk->strh.i_length );
  259.     AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );
  260.     AVI_READ4BYTES( p_chk->strh.i_quality );
  261.     AVI_READ4BYTES( p_chk->strh.i_samplesize );
  262. #ifdef AVI_DEBUG
  263.     msg_Dbg( (vlc_object_t*)s,
  264.              "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",
  265.              (char*)&p_chk->strh.i_type,
  266.              p_chk->strh.i_handler,
  267.              p_chk->strh.i_samplesize,
  268.              ( p_chk->strh.i_scale ?
  269.                 (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );
  270. #endif
  271.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  272. }
  273. static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk )
  274. {
  275.     avi_chunk_t *p_strh;
  276.     AVI_READCHUNK_ENTER;
  277.     if( p_chk->common.p_father == NULL )
  278.     {
  279.         msg_Err( (vlc_object_t*)s, "malformed avi file" );
  280.         AVI_READCHUNK_EXIT( VLC_EGENERIC );
  281.     }
  282.     if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0 ) ) )
  283.     {
  284.         msg_Err( (vlc_object_t*)s, "malformed avi file" );
  285.         AVI_READCHUNK_EXIT( VLC_EGENERIC );
  286.     }
  287.     switch( p_strh->strh.i_type )
  288.     {
  289.         case( AVIFOURCC_auds ):
  290.             p_chk->strf.auds.i_cat = AUDIO_ES;
  291.             p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );
  292.             AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );
  293.             AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );
  294.             AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );
  295.             AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );
  296.             AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );
  297.             AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );
  298.             if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM
  299.                  && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )
  300.             {
  301.                 AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );
  302.                 /* prevent segfault */
  303.                 if( p_chk->strf.auds.p_wf->cbSize >
  304.                         p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )
  305.                 {
  306.                     p_chk->strf.auds.p_wf->cbSize =
  307.                         p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );
  308.                 }
  309.                 if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
  310.                 {
  311.                     /* Found an extensible header atm almost nothing uses that. */
  312.                     msg_Warn( (vlc_object_t*)s, "WAVE_FORMAT_EXTENSIBLE or "
  313.                               "vorbis audio dectected: not supported" );
  314.                 }
  315.             }
  316.             else
  317.             {
  318.                 p_chk->strf.auds.p_wf->cbSize = 0;
  319.             }
  320.             if( p_chk->strf.auds.p_wf->cbSize > 0 )
  321.             {
  322.                 memcpy( &p_chk->strf.auds.p_wf[1] ,
  323.                         p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourrc+size */
  324.                         p_chk->strf.auds.p_wf->cbSize );
  325.             }
  326. #ifdef AVI_DEBUG
  327.             msg_Dbg( (vlc_object_t*)s,
  328.                      "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkb/s",
  329.                      p_chk->strf.auds.p_wf->wFormatTag,
  330.                      p_chk->strf.auds.p_wf->nChannels,
  331.                      p_chk->strf.auds.p_wf->nSamplesPerSec,
  332.                      p_chk->strf.auds.p_wf->wBitsPerSample,
  333.                      p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1024 );
  334. #endif
  335.             break;
  336.         case( AVIFOURCC_vids ):
  337.             p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */
  338.             p_chk->strf.vids.i_cat = VIDEO_ES;
  339.             p_chk->strf.vids.p_bih = malloc( p_chk->common.i_chunk_size );
  340.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );
  341.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );
  342.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );
  343.             AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );
  344.             AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );
  345.             AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );
  346.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );
  347.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );
  348.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );
  349.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );
  350.             AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );
  351.             if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )
  352.             {
  353.                 p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;
  354.             }
  355.             if( p_chk->common.i_chunk_size - sizeof(BITMAPINFOHEADER) > 0 )
  356.             {
  357.                 memcpy( &p_chk->strf.vids.p_bih[1],
  358.                         p_buff + 8 + sizeof(BITMAPINFOHEADER), /* 8=fourrc+size */
  359.                         p_chk->common.i_chunk_size -sizeof(BITMAPINFOHEADER) );
  360.             }
  361. #ifdef AVI_DEBUG
  362.             msg_Dbg( (vlc_object_t*)s,
  363.                      "strf: video:%4.4s %"PRIu32"x%"PRIu32" planes:%d %dbpp",
  364.                      (char*)&p_chk->strf.vids.p_bih->biCompression,
  365.                      (uint32_t)p_chk->strf.vids.p_bih->biWidth,
  366.                      (uint32_t)p_chk->strf.vids.p_bih->biHeight,
  367.                      p_chk->strf.vids.p_bih->biPlanes,
  368.                      p_chk->strf.vids.p_bih->biBitCount );
  369. #endif
  370.             break;
  371.         default:
  372.             msg_Warn( (vlc_object_t*)s, "unknown stream type" );
  373.             p_chk->strf.common.i_cat = UNKNOWN_ES;
  374.             break;
  375.     }
  376.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  377. }
  378. static void AVI_ChunkFree_strf( avi_chunk_t *p_chk )
  379. {
  380.     avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;
  381.     if( p_strf->common.i_cat == AUDIO_ES )
  382.     {
  383.         FREENULL( p_strf->auds.p_wf );
  384.     }
  385.     else if( p_strf->common.i_cat == VIDEO_ES )
  386.     {
  387.         FREENULL( p_strf->vids.p_bih );
  388.     }
  389. }
  390. static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk )
  391. {
  392.     AVI_READCHUNK_ENTER;
  393.     p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );
  394.     memcpy( p_chk->strd.p_data, p_buff + 8, p_chk->common.i_chunk_size );
  395.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  396. }
  397. static void AVI_ChunkFree_strd( avi_chunk_t *p_chk )
  398. {
  399.     free( p_chk->strd.p_data );
  400. }
  401. static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk )
  402. {
  403.     unsigned int i_count, i_index;
  404.     AVI_READCHUNK_ENTER;
  405.     i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;
  406.     p_chk->idx1.i_entry_count = i_count;
  407.     p_chk->idx1.i_entry_max   = i_count;
  408.     if( i_count > 0 )
  409.     {
  410.         p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );
  411.         for( i_index = 0; i_index < i_count ; i_index++ )
  412.         {
  413.             AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );
  414.             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );
  415.             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );
  416.             AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );
  417.         }
  418.     }
  419.     else
  420.     {
  421.         p_chk->idx1.entry = NULL;
  422.     }
  423. #ifdef AVI_DEBUG
  424.     msg_Dbg( (vlc_object_t*)s, "idx1: index entry:%d", i_count );
  425. #endif
  426.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  427. }
  428. static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk )
  429. {
  430.     p_chk->idx1.i_entry_count = 0;
  431.     p_chk->idx1.i_entry_max   = 0;
  432.     FREENULL( p_chk->idx1.entry );
  433. }
  434. static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk )
  435. {
  436.     unsigned int i_count, i;
  437.     int32_t      i_dummy;
  438.     avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
  439.     AVI_READCHUNK_ENTER;
  440.     AVI_READ2BYTES( p_indx->i_longsperentry );
  441.     AVI_READ1BYTE ( p_indx->i_indexsubtype );
  442.     AVI_READ1BYTE ( p_indx->i_indextype );
  443.     AVI_READ4BYTES( p_indx->i_entriesinuse );
  444.     AVI_READ4BYTES( p_indx->i_id );
  445.     p_indx->idx.std     = NULL;
  446.     p_indx->idx.field   = NULL;
  447.     p_indx->idx.super   = NULL;
  448.     if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == 0 )
  449.     {
  450.         AVI_READ8BYTES( p_indx->i_baseoffset );
  451.         AVI_READ4BYTES( i_dummy );
  452.         i_count = __MIN( p_indx->i_entriesinuse, i_read / 8 );
  453.         p_indx->i_entriesinuse = i_count;
  454.         p_indx->idx.std = calloc( i_count, sizeof( indx_std_entry_t ) );
  455.         for( i = 0; i < i_count; i++ )
  456.         {
  457.             AVI_READ4BYTES( p_indx->idx.std[i].i_offset );
  458.             AVI_READ4BYTES( p_indx->idx.std[i].i_size );
  459.         }
  460.     }
  461.     else if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
  462.     {
  463.         AVI_READ8BYTES( p_indx->i_baseoffset );
  464.         AVI_READ4BYTES( i_dummy );
  465.         i_count = __MIN( p_indx->i_entriesinuse, i_read / 12 );
  466.         p_indx->i_entriesinuse = i_count;
  467.         p_indx->idx.field = calloc( i_count, sizeof( indx_field_entry_t ) );
  468.         for( i = 0; i < i_count; i++ )
  469.         {
  470.             AVI_READ4BYTES( p_indx->idx.field[i].i_offset );
  471.             AVI_READ4BYTES( p_indx->idx.field[i].i_size );
  472.             AVI_READ4BYTES( p_indx->idx.field[i].i_offsetfield2 );
  473.         }
  474.     }
  475.     else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
  476.     {
  477.         p_indx->i_baseoffset = 0;
  478.         AVI_READ4BYTES( i_dummy );
  479.         AVI_READ4BYTES( i_dummy );
  480.         AVI_READ4BYTES( i_dummy );
  481.         i_count = __MIN( p_indx->i_entriesinuse, i_read / 16 );
  482.         p_indx->i_entriesinuse = i_count;
  483.         p_indx->idx.super = calloc( i_count, sizeof( indx_super_entry_t ) );
  484.         for( i = 0; i < i_count; i++ )
  485.         {
  486.             AVI_READ8BYTES( p_indx->idx.super[i].i_offset );
  487.             AVI_READ4BYTES( p_indx->idx.super[i].i_size );
  488.             AVI_READ4BYTES( p_indx->idx.super[i].i_duration );
  489.         }
  490.     }
  491.     else
  492.     {
  493.         msg_Warn( (vlc_object_t*)s, "unknow type/subtype index" );
  494.     }
  495. #ifdef AVI_DEBUG
  496.     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 );
  497. #endif
  498.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  499. }
  500. static void AVI_ChunkFree_indx( avi_chunk_t *p_chk )
  501. {
  502.     avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
  503.     FREENULL( p_indx->idx.std );
  504.     FREENULL( p_indx->idx.field );
  505.     FREENULL( p_indx->idx.super );
  506. }
  507. static const struct
  508. {
  509.     vlc_fourcc_t i_fourcc;
  510.     const char *psz_type;
  511. } AVI_strz_type[] =
  512. {
  513.     { AVIFOURCC_IARL, "archive location" },
  514.     { AVIFOURCC_IART, "artist" },
  515.     { AVIFOURCC_ICMS, "commisioned" },
  516.     { AVIFOURCC_ICMT, "comments" },
  517.     { AVIFOURCC_ICOP, "copyright" },
  518.     { AVIFOURCC_ICRD, "creation date" },
  519.     { AVIFOURCC_ICRP, "cropped" },
  520.     { AVIFOURCC_IDIM, "dimensions" },
  521.     { AVIFOURCC_IDPI, "dots per inch" },
  522.     { AVIFOURCC_IENG, "engineer" },
  523.     { AVIFOURCC_IGNR, "genre" },
  524.     { AVIFOURCC_IKEY, "keywords" },
  525.     { AVIFOURCC_ILGT, "lightness" },
  526.     { AVIFOURCC_IMED, "medium" },
  527.     { AVIFOURCC_INAM, "name" },
  528.     { AVIFOURCC_IPLT, "palette setting" },
  529.     { AVIFOURCC_IPRD, "product" },
  530.     { AVIFOURCC_ISBJ, "subject" },
  531.     { AVIFOURCC_ISFT, "software" },
  532.     { AVIFOURCC_ISHP, "sharpness" },
  533.     { AVIFOURCC_ISRC, "source" },
  534.     { AVIFOURCC_ISRF, "source form" },
  535.     { AVIFOURCC_ITCH, "technician" },
  536.     { AVIFOURCC_ISMP, "time code" },
  537.     { AVIFOURCC_IDIT, "digitalization time" },
  538.     { AVIFOURCC_strn, "stream name" },
  539.     { 0,              "???" }
  540. };
  541. static int AVI_ChunkRead_strz( stream_t *s, avi_chunk_t *p_chk )
  542. {
  543.     int i_index;
  544.     avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
  545.     AVI_READCHUNK_ENTER;
  546.     for( i_index = 0;; i_index++)
  547.     {
  548.         if( !AVI_strz_type[i_index].i_fourcc ||
  549.             AVI_strz_type[i_index].i_fourcc == p_strz->i_chunk_fourcc )
  550.         {
  551.             break;
  552.         }
  553.     }
  554.     p_strz->p_type = strdup( AVI_strz_type[i_index].psz_type );
  555.     p_strz->p_str = malloc( i_read + 1);
  556.     if( p_strz->i_chunk_size )
  557.     {
  558.         memcpy( p_strz->p_str, p_read, i_read );
  559.     }
  560.     p_strz->p_str[i_read] = 0;
  561. #ifdef AVI_DEBUG
  562.     msg_Dbg( (vlc_object_t*)s, "%4.4s: %s : %s",
  563.              (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str);
  564. #endif
  565.     AVI_READCHUNK_EXIT( VLC_SUCCESS );
  566. }
  567. static void AVI_ChunkFree_strz( avi_chunk_t *p_chk )
  568. {
  569.     avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
  570.     FREENULL( p_strz->p_type );
  571.     FREENULL( p_strz->p_str );
  572. }
  573. static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk )
  574. {
  575.     return AVI_NextChunk( s, p_chk );
  576. }
  577. static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk )
  578. {
  579.     VLC_UNUSED( p_chk );
  580. }
  581. static const struct
  582. {
  583.     vlc_fourcc_t i_fourcc;
  584.     int   (*AVI_ChunkRead_function)( stream_t *s, avi_chunk_t *p_chk );
  585.     void  (*AVI_ChunkFree_function)( avi_chunk_t *p_chk );
  586. } AVI_Chunk_Function [] =
  587. {
  588.     { AVIFOURCC_RIFF, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
  589.     { AVIFOURCC_ON2,  AVI_ChunkRead_list, AVI_ChunkFree_nothing },
  590.     { AVIFOURCC_LIST, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
  591.     { AVIFOURCC_avih, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
  592.     { AVIFOURCC_ON2h, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
  593.     { AVIFOURCC_strh, AVI_ChunkRead_strh, AVI_ChunkFree_nothing },
  594.     { AVIFOURCC_strf, AVI_ChunkRead_strf, AVI_ChunkFree_strf },
  595.     { AVIFOURCC_strd, AVI_ChunkRead_strd, AVI_ChunkFree_strd },
  596.     { AVIFOURCC_idx1, AVI_ChunkRead_idx1, AVI_ChunkFree_idx1 },
  597.     { AVIFOURCC_indx, AVI_ChunkRead_indx, AVI_ChunkFree_indx },
  598.     { AVIFOURCC_JUNK, AVI_ChunkRead_nothing, AVI_ChunkFree_nothing },
  599.     { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  600.     { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  601.     { AVIFOURCC_IART, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  602.     { AVIFOURCC_ICMS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  603.     { AVIFOURCC_ICMT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  604.     { AVIFOURCC_ICOP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  605.     { AVIFOURCC_ICRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  606.     { AVIFOURCC_ICRP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  607.     { AVIFOURCC_IDIM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  608.     { AVIFOURCC_IDPI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  609.     { AVIFOURCC_IENG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  610.     { AVIFOURCC_IGNR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  611.     { AVIFOURCC_IKEY, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  612.     { AVIFOURCC_ILGT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  613.     { AVIFOURCC_IMED, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  614.     { AVIFOURCC_INAM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  615.     { AVIFOURCC_IPLT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  616.     { AVIFOURCC_IPRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  617.     { AVIFOURCC_ISBJ, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  618.     { AVIFOURCC_ISFT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  619.     { AVIFOURCC_ISHP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  620.     { AVIFOURCC_ISRC, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  621.     { AVIFOURCC_ISRF, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  622.     { AVIFOURCC_ITCH, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  623.     { AVIFOURCC_ISMP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  624.     { AVIFOURCC_IDIT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  625.     { AVIFOURCC_strn, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
  626.     { 0,           NULL,               NULL }
  627. };
  628. static int AVI_ChunkFunctionFind( vlc_fourcc_t i_fourcc )
  629. {
  630.     unsigned int i_index;
  631.     for( i_index = 0; ; i_index++ )
  632.     {
  633.         if( ( AVI_Chunk_Function[i_index].i_fourcc == i_fourcc )||
  634.             ( AVI_Chunk_Function[i_index].i_fourcc == 0 ) )
  635.         {
  636.             return i_index;
  637.         }
  638.     }
  639. }
  640. int  _AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father )
  641. {
  642.     int i_index;
  643.     if( !p_chk )
  644.     {
  645.         return VLC_EGENERIC;
  646.     }
  647.     if( AVI_ChunkReadCommon( s, p_chk ) )
  648.     {
  649.         msg_Warn( (vlc_object_t*)s, "cannot read one chunk" );
  650.         return VLC_EGENERIC;
  651.     }
  652.     if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) )
  653.     {
  654.         msg_Warn( (vlc_object_t*)s, "found null fourcc chunk (corrupted file?)" );
  655.         return VLC_EGENERIC;
  656.     }
  657.     p_chk->common.p_father = p_father;
  658.     i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
  659.     if( AVI_Chunk_Function[i_index].AVI_ChunkRead_function )
  660.     {
  661.         return AVI_Chunk_Function[i_index].AVI_ChunkRead_function( s, p_chk );
  662.     }
  663.     else if( ( ((char*)&p_chk->common.i_chunk_fourcc)[0] == 'i' &&
  664.                ((char*)&p_chk->common.i_chunk_fourcc)[1] == 'x' ) ||
  665.              ( ((char*)&p_chk->common.i_chunk_fourcc)[2] == 'i' &&
  666.                ((char*)&p_chk->common.i_chunk_fourcc)[3] == 'x' ) )
  667.     {
  668.         p_chk->common.i_chunk_fourcc = AVIFOURCC_indx;
  669.         return AVI_ChunkRead_indx( s, p_chk );
  670.     }
  671.     msg_Warn( (vlc_object_t*)s, "unknown chunk (not loaded)" );
  672.     return AVI_NextChunk( s, p_chk );
  673. }
  674. void _AVI_ChunkFree( stream_t *s,
  675.                      avi_chunk_t *p_chk )
  676. {
  677.     int i_index;
  678.     avi_chunk_t *p_child, *p_next;
  679.     if( !p_chk )
  680.     {
  681.         return;
  682.     }
  683.     /* Free all child chunk */
  684.     p_child = p_chk->common.p_first;
  685.     while( p_child )
  686.     {
  687.         p_next = p_child->common.p_next;
  688.         AVI_ChunkFree( s, p_child );
  689.         free( p_child );
  690.         p_child = p_next;
  691.     }
  692.     i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
  693.     if( AVI_Chunk_Function[i_index].AVI_ChunkFree_function )
  694.     {
  695. #ifdef AVI_DEBUG
  696.         msg_Dbg( (vlc_object_t*)s, "free chunk %4.4s",
  697.                  (char*)&p_chk->common.i_chunk_fourcc );
  698. #endif
  699.         AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_chk);
  700.     }
  701.     else
  702.     {
  703.         msg_Warn( (vlc_object_t*)s, "unknown chunk (not unloaded)" );
  704.     }
  705.     p_chk->common.p_first = NULL;
  706.     p_chk->common.p_last  = NULL;
  707.     return;
  708. }
  709. static void AVI_ChunkDumpDebug_level( vlc_object_t *p_obj,
  710.                                       avi_chunk_t  *p_chk, unsigned i_level )
  711. {
  712.     unsigned i;
  713.     avi_chunk_t *p_child;
  714.     char str[512];
  715.     if( i_level * 5 + 1 >= sizeof(str) )
  716.         return;
  717.     memset( str, ' ', sizeof( str ) );
  718.     for( i = 1; i < i_level; i++ )
  719.     {
  720.         str[i * 5] = '|';
  721.     }
  722.     if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF ||
  723.         p_chk->common.i_chunk_fourcc == AVIFOURCC_ON2  ||
  724.         p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST )
  725.     {
  726.         snprintf( &str[i_level * 5], sizeof(str) - 5*i_level,
  727.                  "%c %4.4s-%4.4s size:%"PRIu64" pos:%"PRIu64,
  728.                  i_level ? '+' : '*',
  729.                  (char*)&p_chk->common.i_chunk_fourcc,
  730.                  (char*)&p_chk->list.i_type,
  731.                  p_chk->common.i_chunk_size,
  732.                  p_chk->common.i_chunk_pos );
  733.     }
  734.     else
  735.     {
  736.         snprintf( &str[i_level * 5], sizeof(str) - 5*i_level,
  737.                  "+ %4.4s size:%"PRIu64" pos:%"PRIu64,
  738.                  (char*)&p_chk->common.i_chunk_fourcc,
  739.                  p_chk->common.i_chunk_size,
  740.                  p_chk->common.i_chunk_pos );
  741.     }
  742.     msg_Dbg( p_obj, "%s", str );
  743.     p_child = p_chk->common.p_first;
  744.     while( p_child )
  745.     {
  746.         AVI_ChunkDumpDebug_level( p_obj, p_child, i_level + 1 );
  747.         p_child = p_child->common.p_next;
  748.     }
  749. }
  750. int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root )
  751. {
  752.     avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root;
  753.     avi_chunk_t      *p_chk;
  754.     bool b_seekable;
  755.     stream_Control( s, STREAM_CAN_FASTSEEK, &b_seekable );
  756.     p_list->i_chunk_pos  = 0;
  757.     p_list->i_chunk_size = stream_Size( s );
  758.     p_list->i_chunk_fourcc = AVIFOURCC_LIST;
  759.     p_list->p_father = NULL;
  760.     p_list->p_next  = NULL;
  761.     p_list->p_first = NULL;
  762.     p_list->p_last  = NULL;
  763.     p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
  764.     for( ; ; )
  765.     {
  766.         p_chk = malloc( sizeof( avi_chunk_t ) );
  767.         memset( p_chk, 0, sizeof( avi_chunk_t ) );
  768.         if( !p_root->common.p_first )
  769.         {
  770.             p_root->common.p_first = p_chk;
  771.         }
  772.         else
  773.         {
  774.             p_root->common.p_last->common.p_next = p_chk;
  775.         }
  776.         p_root->common.p_last = p_chk;
  777.         if( AVI_ChunkRead( s, p_chk, p_root ) ||
  778.            ( stream_Tell( s ) >=
  779.               (off_t)p_chk->common.p_father->common.i_chunk_pos +
  780.                (off_t)__EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
  781.         {
  782.             break;
  783.         }
  784.         /* If we can't seek then stop when we 've found first RIFF-AVI */
  785.         if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF &&
  786.             p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable )
  787.         {
  788.             break;
  789.         }
  790.     }
  791.     AVI_ChunkDumpDebug_level( (vlc_object_t*)s, p_root, 0 );
  792.     return VLC_SUCCESS;
  793. }
  794. void AVI_ChunkFreeRoot( stream_t *s,
  795.                         avi_chunk_t  *p_chk )
  796. {
  797.     AVI_ChunkFree( s, p_chk );
  798. }
  799. int  _AVI_ChunkCount( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc )
  800. {
  801.     int i_count;
  802.     avi_chunk_t *p_child;
  803.     if( !p_chk )
  804.     {
  805.         return 0;
  806.     }
  807.     i_count = 0;
  808.     p_child = p_chk->common.p_first;
  809.     while( p_child )
  810.     {
  811.         if( p_child->common.i_chunk_fourcc == i_fourcc ||
  812.             ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST &&
  813.               p_child->list.i_type == i_fourcc ) )
  814.         {
  815.             i_count++;
  816.         }
  817.         p_child = p_child->common.p_next;
  818.     }
  819.     return i_count;
  820. }
  821. void *_AVI_ChunkFind( avi_chunk_t *p_chk,
  822.                       vlc_fourcc_t i_fourcc, int i_number )
  823. {
  824.     avi_chunk_t *p_child;
  825.     if( !p_chk )
  826.     {
  827.         return NULL;
  828.     }
  829.     p_child = p_chk->common.p_first;
  830.     while( p_child )
  831.     {
  832.         if( p_child->common.i_chunk_fourcc == i_fourcc ||
  833.             ( p_child->common.i_chunk_fourcc == AVIFOURCC_LIST &&
  834.               p_child->list.i_type == i_fourcc ) )
  835.         {
  836.             if( i_number == 0 )
  837.             {
  838.                 /* We found it */
  839.                 return p_child;
  840.             }
  841.             i_number--;
  842.         }
  843.         p_child = p_child->common.p_next;
  844.     }
  845.     return NULL;
  846. }