libavi.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:30k
源码类别:

多媒体

开发平台:

MultiPlatform

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