00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024
00025 #include <vlc/vlc.h>
00026 #include <vlc/input.h>
00027 #include "codecs.h"
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
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
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
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;
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
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
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
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 ),
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;
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),
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
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
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
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