libavi.c 40.5 KB
Newer Older
1
/*****************************************************************************
hartman's avatar
hartman committed
2
 * libavi.c : LibAVI
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001 VLC authors and VideoLAN
5
 * $Id$
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
8
9
10
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
14
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
15
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
17
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
18
19
20
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
22
23
 *****************************************************************************/


24
25
26
27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <vlc_common.h>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
29
#include <vlc_demux.h>                                   /* stream_*, *_ES */
30
#include <vlc_codecs.h>                            /* VLC_BITMAPINFOHEADER */
31
32
33

#include "libavi.h"

34
35
#include <limits.h>

36
#ifndef NDEBUG
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
37
# define AVI_DEBUG 1
38
#endif
39

40
#define __EVEN( x ) (((x) + 1) & ~1)
41

42
static vlc_fourcc_t GetFOURCC( const uint8_t *p_buff )
43
{
44
    return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
45
}
46

47
48
49
50
51
52
53
54
55
56
static uint64_t AVI_ChunkSize( const avi_chunk_t *p_ck )
{
    return __EVEN(p_ck->common.i_chunk_size) + 8;
}

static uint64_t AVI_ChunkEnd( const avi_chunk_t *p_ck )
{
    return p_ck->common.i_chunk_pos + AVI_ChunkSize( p_ck );
}

57
58
59
60
61
/****************************************************************************
 *
 * Basics functions to manipulates chunks
 *
 ****************************************************************************/
62
63
static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk,
                                const avi_chunk_t *p_father )
64
{
65
    const uint8_t *p_peek;
66
67
68

    memset( p_chk, 0, sizeof( avi_chunk_t ) );

69
    const uint64_t i_pos = vlc_stream_Tell( s );
70
    if( vlc_stream_Peek( s, &p_peek, 8 ) < 8 )
71
72
73
74
75
    {
        if( stream_Size( s ) > 0 && (uint64_t) stream_Size( s ) > i_pos )
            msg_Warn( s, "can't peek at %"PRIu64, i_pos );
        else
            msg_Dbg( s, "no more data at %"PRIu64, i_pos );
76
        return VLC_EGENERIC;
77
    }
78

79
    p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );
80
    p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );
81
    p_chk->common.i_chunk_pos    = i_pos;
82

83
84
85
    if( p_chk->common.i_chunk_size >= UINT64_MAX - 8 ||
        p_chk->common.i_chunk_pos > UINT64_MAX - 8 ||
        UINT64_MAX - p_chk->common.i_chunk_pos - 8 < __EVEN(p_chk->common.i_chunk_size) )
86
87
        return VLC_EGENERIC;

88
89
90
91
    if( p_father && AVI_ChunkEnd( p_chk ) > AVI_ChunkEnd( p_father ) )
    {
        msg_Warn( s, "chunk %4.4s does not fit into parent %ld",
                     (char*)&p_chk->common.i_chunk_fourcc, AVI_ChunkEnd( p_father ) );
92
93
94
95
96
97

        /* How hard is to produce files with the correct declared size ? */
        if( p_father->common.i_chunk_fourcc != AVIFOURCC_RIFF ||
            p_father->common.p_father == NULL ||
            p_father->common.p_father->common.p_father != NULL ) /* Root > RIFF only */
            return VLC_EGENERIC;
98
    }
99

100
#ifdef AVI_DEBUG
101
    msg_Dbg( (vlc_object_t*)s,
102
             "found chunk, fourcc: %4.4s size:%"PRIu64" pos:%"PRIu64,
103
             (char*)&p_chk->common.i_chunk_fourcc,
104
105
106
             p_chk->common.i_chunk_size,
             p_chk->common.i_chunk_pos );
#endif
107
    return VLC_SUCCESS;
108
109
}

110
static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk )
111
112
{
    avi_chunk_t chk;
113

114
115
    if( !p_chk )
    {
116
        if( AVI_ChunkReadCommon( s, &chk, NULL ) )
117
        {
118
            return VLC_EGENERIC;
119
120
121
122
        }
        p_chk = &chk;
    }

123
    bool b_seekable = false;
124
    const uint64_t i_offset = AVI_ChunkEnd( p_chk );
125
    if ( !vlc_stream_Control(s, STREAM_CAN_SEEK, &b_seekable) && b_seekable )
126
    {
127
        return vlc_stream_Seek( s, i_offset );
128
129
130
    }
    else
    {
131
132
        ssize_t i_read = i_offset - vlc_stream_Tell( s );
        return (i_read >=0 && vlc_stream_Read( s, NULL, i_read ) == i_read) ?
133
134
                    VLC_SUCCESS : VLC_EGENERIC;
    }
135
136
137
138
}

/****************************************************************************
 *
139
 * Functions to read chunks
140
141
 *
 ****************************************************************************/
142
static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
143
144
{
    avi_chunk_t *p_chk;
145
    const uint8_t *p_peek;
146
    bool b_seekable;
147
    int i_ret = VLC_SUCCESS;
148

149
    if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 4 )
150
151
    {
        /* empty box */
152
        msg_Warn( (vlc_object_t*)s, "empty list chunk" );
153
        return VLC_EGENERIC;
154
    }
155
    if( vlc_stream_Peek( s, &p_peek, 12 ) < 12 )
156
    {
157
        msg_Warn( (vlc_object_t*)s, "cannot peek while reading list chunk" );
158
        return VLC_EGENERIC;
159
    }
160

161
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
162

163
    p_container->list.i_type = GetFOURCC( p_peek + 8 );
164

165
166
167
168
169
170
171
    /* XXX fixed for on2 hack */
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f )
    {
        p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF;
        p_container->list.i_type = AVIFOURCC_AVI;
    }

172
173
174
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
        p_container->list.i_type == AVIFOURCC_movi )
    {
175
176
        if( !b_seekable )
            return VLC_SUCCESS;
hartman's avatar
hartman committed
177
        msg_Dbg( (vlc_object_t*)s, "skipping movi chunk" );
178
        return AVI_NextChunk( s, p_container ); /* points at begining of LIST-movi if not seekable */
179
180
    }

181
    if( vlc_stream_Read( s, NULL, 12 ) != 12 )
182
    {
183
        msg_Warn( (vlc_object_t*)s, "cannot enter chunk" );
184
185
        return VLC_EGENERIC;
    }
186

187
#ifdef AVI_DEBUG
188
    msg_Dbg( (vlc_object_t*)s,
189
190
             "found LIST chunk: \'%4.4s\'",
             (char*)&p_container->list.i_type );
191
#endif
192
    msg_Dbg( (vlc_object_t*)s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );
193
194

    union  avi_chunk_u **pp_append = &p_container->common.p_first;
195
196
    for( ; ; )
    {
197
198
199
200
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
        if( !p_chk )
            return VLC_EGENERIC;

201
202
        i_ret = AVI_ChunkRead( s, p_chk, p_container );
        if( i_ret )
203
        {
204
205
            AVI_ChunkClean( s, p_chk );
            free( p_chk );
206
207
            break;
        }
208
209
210
211
212

        *pp_append = p_chk;
        while( *pp_append )
            pp_append = &((*pp_append)->common.p_next);

213
214
        if( p_container->common.i_chunk_size > 0 &&
            vlc_stream_Tell( s ) >= AVI_ChunkEnd( p_container ) )
215
216
217
        {
            break;
        }
218

219
220
        /* If we can't seek then stop when we 've found LIST-movi */
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
221
222
            p_chk->list.i_type == AVIFOURCC_movi &&
            ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
223
224
225
226
        {
            break;
        }

227
    }
228
    msg_Dbg( (vlc_object_t*)s, "</list \'%4.4s\'>", (char*)&p_container->list.i_type );
229

230
    if ( i_ret == AVI_ZERO_FOURCC ) return i_ret;
231
    return VLC_SUCCESS;
232
233
}

234
235
236
/* Allow to append indexes after starting playback */
int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff )
{
237
    avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0, true );
238
239
240
241
    if ( !p_movi )
        return VLC_EGENERIC;

    avi_chunk_t *p_chk;
242
    const uint64_t i_indexpos = AVI_ChunkEnd( p_movi );
243
244
245
    bool b_seekable = false;
    int i_ret = VLC_SUCCESS;

246
247
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
    if ( !b_seekable || vlc_stream_Seek( s, i_indexpos ) )
248
249
        return VLC_EGENERIC;

250
    union  avi_chunk_u **pp_append = &p_riff->common.p_first;
251
252
    for( ; ; )
    {
253
254
255
256
257
258
259
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
        if( !p_chk )
        {
            i_ret = VLC_EGENERIC;
            break;
        }

260
261
        i_ret = AVI_ChunkRead( s, p_chk, p_riff );
        if( i_ret )
262
263
264
        {
            AVI_ChunkClean( s, p_chk );
            free( p_chk );
265
            break;
266
267
268
269
270
        }

        *pp_append = p_chk;
        while( *pp_append )
            pp_append = &((*pp_append)->common.p_next);
271
272

        if( p_chk->common.p_father->common.i_chunk_size > 0 &&
273
           ( vlc_stream_Tell( s ) >
274
275
             p_chk->common.p_father->common.i_chunk_pos +
             __EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        {
            break;
        }

        /* If we can't seek then stop when we 've found any index */
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx ||
            p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 )
        {
            break;
        }

    }

    return i_ret;
}

292
#define AVI_READCHUNK_ENTER \
293
    int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \
294
295
296
297
298
    if( i_read > 100000000 ) \
    { \
        msg_Err( s, "Big chunk ignored" ); \
        return VLC_EGENERIC; \
    } \
299
    uint8_t  *p_read, *p_buff;    \
300
301
    if( !( p_read = p_buff = malloc(i_read ) ) ) \
    { \
302
        return VLC_EGENERIC; \
303
    } \
304
    i_read = vlc_stream_Read( s, p_read, i_read ); \
305
306
    if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) \
    { \
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
307
        free( p_buff ); \
308
309
        return VLC_EGENERIC; \
    }\
310
311
    p_read += 8; \
    i_read -= 8
312

313
314
315
316
317
318
319
320
321
#define AVI_READ( res, func, size ) \
    if( i_read < size ) { \
        free( p_buff); \
        return VLC_EGENERIC; \
    } \
    i_read -= size; \
    res = func( p_read ); \
    p_read += size \

322
#define AVI_READCHUNK_EXIT( code ) \
323
324
325
326
    do { \
        free( p_buff ); \
        return code; \
    } while(0)
327

328
329
330
331
332
static inline uint8_t GetB( uint8_t *ptr )
{
    return *ptr;
}

333
#define AVI_READ1BYTE( i_byte ) \
334
    AVI_READ( i_byte, GetB, 1 )
335

336
#define AVI_READ2BYTES( i_word ) \
337
    AVI_READ( i_word, GetWLE, 2 )
338
339

#define AVI_READ4BYTES( i_dword ) \
340
    AVI_READ( i_dword, GetDWLE, 4 )
341

342
343
#define AVI_READ8BYTES( i_qword ) \
    AVI_READ( i_qword, GetQWLE, 8 )
344

345
#define AVI_READFOURCC( i_dword ) \
346
    AVI_READ( i_dword, GetFOURCC, 4 )
347

348
static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk )
349
350
351
{
    AVI_READCHUNK_ENTER;

352
    p_chk->common.i_chunk_fourcc = AVIFOURCC_avih;
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
    AVI_READ4BYTES( p_chk->avih.i_microsecperframe);
    AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );
    AVI_READ4BYTES( p_chk->avih.i_reserved1 );
    AVI_READ4BYTES( p_chk->avih.i_flags );
    AVI_READ4BYTES( p_chk->avih.i_totalframes );
    AVI_READ4BYTES( p_chk->avih.i_initialframes );
    AVI_READ4BYTES( p_chk->avih.i_streams );
    AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );
    AVI_READ4BYTES( p_chk->avih.i_width );
    AVI_READ4BYTES( p_chk->avih.i_height );
    AVI_READ4BYTES( p_chk->avih.i_scale );
    AVI_READ4BYTES( p_chk->avih.i_rate );
    AVI_READ4BYTES( p_chk->avih.i_start );
    AVI_READ4BYTES( p_chk->avih.i_length );
#ifdef AVI_DEBUG
368
369
    msg_Dbg( (vlc_object_t*)s,
             "avih: streams:%d flags:%s%s%s%s %dx%d",
370
371
372
373
374
375
             p_chk->avih.i_streams,
             p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
             p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
             p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
             p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
             p_chk->avih.i_width, p_chk->avih.i_height );
376
#endif
377
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
378
379
}

380
static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk )
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
{
    AVI_READCHUNK_ENTER;

    AVI_READFOURCC( p_chk->strh.i_type );
    AVI_READFOURCC( p_chk->strh.i_handler );
    AVI_READ4BYTES( p_chk->strh.i_flags );
    AVI_READ4BYTES( p_chk->strh.i_reserved1 );
    AVI_READ4BYTES( p_chk->strh.i_initialframes );
    AVI_READ4BYTES( p_chk->strh.i_scale );
    AVI_READ4BYTES( p_chk->strh.i_rate );
    AVI_READ4BYTES( p_chk->strh.i_start );
    AVI_READ4BYTES( p_chk->strh.i_length );
    AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );
    AVI_READ4BYTES( p_chk->strh.i_quality );
    AVI_READ4BYTES( p_chk->strh.i_samplesize );
#ifdef AVI_DEBUG
397
    msg_Dbg( (vlc_object_t*)s,
398
399
             "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",
             (char*)&p_chk->strh.i_type,
400
401
             p_chk->strh.i_handler,
             p_chk->strh.i_samplesize,
402
             ( p_chk->strh.i_scale ?
403
404
                (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );
#endif
405

406
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
407
408
}

409
static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk )
410
411
412
413
414
415
{
    avi_chunk_t *p_strh;

    AVI_READCHUNK_ENTER;
    if( p_chk->common.p_father == NULL )
    {
416
        msg_Err( (vlc_object_t*)s, "malformed avi file" );
417
        AVI_READCHUNK_EXIT( VLC_EGENERIC );
418
    }
419
    if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0, false ) ) )
420
    {
421
        msg_Err( (vlc_object_t*)s, "malformed avi file" );
422
        AVI_READCHUNK_EXIT( p_chk->common.i_chunk_size > 0  ? VLC_EGENERIC : AVI_ZEROSIZED_CHUNK );
423
    }
424

425
426
427
    switch( p_strh->strh.i_type )
    {
        case( AVIFOURCC_auds ):
428
            p_chk->strf.auds.i_cat = AUDIO_ES;
429
            p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );
430
431
432
433
            if ( !p_chk->strf.auds.p_wf )
            {
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
            }
434
435
436
437
438
439
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );
440

441
442
            if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM
                 && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )
443
            {
444
                AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );
445

446
447
448
449
450
451
452
                /* prevent segfault */
                if( p_chk->strf.auds.p_wf->cbSize >
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )
                {
                    p_chk->strf.auds.p_wf->cbSize =
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );
                }
453

hartman's avatar
hartman committed
454
455
                if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
                {
456
                    msg_Dbg( s, "Extended header found" );
hartman's avatar
hartman committed
457
                }
458
459
460
461
462
463
464
            }
            else
            {
                p_chk->strf.auds.p_wf->cbSize = 0;
            }
            if( p_chk->strf.auds.p_wf->cbSize > 0 )
            {
465
                memcpy( &p_chk->strf.auds.p_wf[1] ,
Rémi Denis-Courmont's avatar
Typo    
Rémi Denis-Courmont committed
466
                        p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourcc+size */
467
                        p_chk->strf.auds.p_wf->cbSize );
468
469
            }
#ifdef AVI_DEBUG
470
            msg_Dbg( (vlc_object_t*)s,
471
                     "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkbps",
472
473
474
475
                     p_chk->strf.auds.p_wf->wFormatTag,
                     p_chk->strf.auds.p_wf->nChannels,
                     p_chk->strf.auds.p_wf->nSamplesPerSec,
                     p_chk->strf.auds.p_wf->wBitsPerSample,
476
                     p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1000 );
477
478
479
#endif
            break;
        case( AVIFOURCC_vids ):
hartman's avatar
hartman committed
480
            p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */
481
            p_chk->strf.vids.i_cat = VIDEO_ES;
482
            p_chk->strf.vids.p_bih = malloc( __MAX( p_chk->common.i_chunk_size,
483
                                         sizeof( *p_chk->strf.vids.p_bih ) ) );
484
485
486
487
            if ( !p_chk->strf.vids.p_bih )
            {
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
            }
gbazin's avatar
   
gbazin committed
488
489
490
491
492
493
494
495
496
497
498
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );
            AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );
499
            if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )
500
501
502
            {
                p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;
            }
503
            if ( p_chk->common.i_chunk_size > sizeof(VLC_BITMAPINFOHEADER) )
504
            {
505
506
                uint64_t i_extrasize = p_chk->common.i_chunk_size - sizeof(VLC_BITMAPINFOHEADER);

507
                /* There's a color palette appended, set up VLC_BITMAPINFO */
508
                memcpy( &p_chk->strf.vids.p_bih[1],
509
                        p_buff + 8 + sizeof(VLC_BITMAPINFOHEADER), /* 8=fourrc+size */
510
511
512
                        i_extrasize );

                if ( !p_chk->strf.vids.p_bih->biClrUsed )
513
514
515
516
517
518
                {
                    if( p_chk->strf.vids.p_bih->biBitCount < 32 )
                        p_chk->strf.vids.p_bih->biClrUsed = (1 << p_chk->strf.vids.p_bih->biBitCount);
                    else
                        p_chk->strf.vids.p_bih->biBitCount = UINT16_MAX;
                }
519

520
                if( i_extrasize / sizeof(uint32_t) > UINT32_MAX )
521
522
523
524
                    p_chk->strf.vids.p_bih->biClrUsed = UINT32_MAX;
                else
                {
                    p_chk->strf.vids.p_bih->biClrUsed =
525
                            __MIN( i_extrasize / sizeof(uint32_t),
526
527
                                   p_chk->strf.vids.p_bih->biClrUsed );
                }
528
529
530

                /* stay within VLC's limits */
                p_chk->strf.vids.p_bih->biClrUsed =
531
                    __MIN( VIDEO_PALETTE_COLORS_MAX, p_chk->strf.vids.p_bih->biClrUsed );
532
            }
533
            else p_chk->strf.vids.p_bih->biClrUsed = 0;
534
#ifdef AVI_DEBUG
535
            msg_Dbg( (vlc_object_t*)s,
536
                     "strf: video:%4.4s %"PRIu32"x%"PRIu32" planes:%d %dbpp",
537
                     (char*)&p_chk->strf.vids.p_bih->biCompression,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
538
539
                     (uint32_t)p_chk->strf.vids.p_bih->biWidth,
                     (uint32_t)p_chk->strf.vids.p_bih->biHeight,
gbazin's avatar
   
gbazin committed
540
541
                     p_chk->strf.vids.p_bih->biPlanes,
                     p_chk->strf.vids.p_bih->biBitCount );
542
543
#endif
            break;
544
545
546
547
        case AVIFOURCC_iavs:
        case AVIFOURCC_ivas:
            p_chk->strf.common.i_cat = UNKNOWN_ES;
            break;
548
549
550
        case( AVIFOURCC_txts ):
            p_chk->strf.common.i_cat = SPU_ES;
            break;
551
        default:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
552
553
            msg_Warn( (vlc_object_t*)s, "unknown stream type: %4.4s",
                    (char*)&p_strh->strh.i_type );
554
            p_chk->strf.common.i_cat = UNKNOWN_ES;
555
556
            break;
    }
557
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
558
}
559
static void AVI_ChunkFree_strf( avi_chunk_t *p_chk )
560
{
561
    avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;
562
    if( p_strf->common.i_cat == AUDIO_ES )
563
    {
zorglub's avatar
zorglub committed
564
        FREENULL( p_strf->auds.p_wf );
565
566
567
    }
    else if( p_strf->common.i_cat == VIDEO_ES )
    {
zorglub's avatar
zorglub committed
568
        FREENULL( p_strf->vids.p_bih );
569
    }
570
571
}

572
static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk )
573
{
574
575
576
    if ( p_chk->common.i_chunk_size == 0 )
    {
        msg_Dbg( (vlc_object_t*)s, "Zero sized pre-JUNK section met" );
577
        return AVI_ZEROSIZED_CHUNK;
578
579
    }

580
    AVI_READCHUNK_ENTER;
581
582
583
584
    p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );
    if( p_chk->strd.p_data )
        memcpy( p_chk->strd.p_data, p_buff + 8, p_chk->common.i_chunk_size );
    AVI_READCHUNK_EXIT( p_chk->strd.p_data ? VLC_SUCCESS : VLC_EGENERIC );
585
586
}

587
588
static void AVI_ChunkFree_strd( avi_chunk_t *p_chk )
{
589
    free( p_chk->strd.p_data );
590
591
}

592
static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk )
593
{
594
    unsigned int i_count, i_index;
595
596
597

    AVI_READCHUNK_ENTER;

598
    i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;
599
600
601
602
603

    p_chk->idx1.i_entry_count = i_count;
    p_chk->idx1.i_entry_max   = i_count;
    if( i_count > 0 )
    {
604
605
606
        p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );
        if( !p_chk->idx1.entry )
            AVI_READCHUNK_EXIT( VLC_EGENERIC );
607
608
609

        for( i_index = 0; i_index < i_count ; i_index++ )
        {
610
            AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );
611
612
613
614
615
616
617
618
619
620
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );
        }
    }
    else
    {
        p_chk->idx1.entry = NULL;
    }
#ifdef AVI_DEBUG
621
    msg_Dbg( (vlc_object_t*)s, "idx1: index entry:%d", i_count );
622
#endif
623
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
624
625
}

626
static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk )
627
628
629
{
    p_chk->idx1.i_entry_count = 0;
    p_chk->idx1.i_entry_max   = 0;
630
    FREENULL( p_chk->idx1.entry );
631
632
}

633
634


635
static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk )
636
637
{
    unsigned int i_count, i;
638
    int          i_ret = VLC_SUCCESS;
639
    int32_t      i_dummy;
640
    VLC_UNUSED(i_dummy);
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;

    AVI_READCHUNK_ENTER;

    AVI_READ2BYTES( p_indx->i_longsperentry );
    AVI_READ1BYTE ( p_indx->i_indexsubtype );
    AVI_READ1BYTE ( p_indx->i_indextype );
    AVI_READ4BYTES( p_indx->i_entriesinuse );

    AVI_READ4BYTES( p_indx->i_id );
    p_indx->idx.std     = NULL;
    p_indx->idx.field   = NULL;
    p_indx->idx.super   = NULL;

    if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == 0 )
    {
        AVI_READ8BYTES( p_indx->i_baseoffset );
        AVI_READ4BYTES( i_dummy );

        i_count = __MIN( p_indx->i_entriesinuse, i_read / 8 );
        p_indx->i_entriesinuse = i_count;
662
663
        p_indx->idx.std = calloc( i_count, sizeof( indx_std_entry_t ) );
        if( i_count == 0 || p_indx->idx.std )
664
        {
665
666
667
668
669
            for( i = 0; i < i_count; i++ )
            {
                AVI_READ4BYTES( p_indx->idx.std[i].i_offset );
                AVI_READ4BYTES( p_indx->idx.std[i].i_size );
            }
670
        }
671
        else i_ret = VLC_EGENERIC;
672
673
674
675
676
677
678
679
    }
    else if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
    {
        AVI_READ8BYTES( p_indx->i_baseoffset );
        AVI_READ4BYTES( i_dummy );

        i_count = __MIN( p_indx->i_entriesinuse, i_read / 12 );
        p_indx->i_entriesinuse = i_count;
680
681
        p_indx->idx.field = calloc( i_count, sizeof( indx_field_entry_t ) );
        if( i_count == 0 || p_indx->idx.field )
682
        {
683
684
685
686
687
688
            for( i = 0; i < i_count; i++ )
            {
                AVI_READ4BYTES( p_indx->idx.field[i].i_offset );
                AVI_READ4BYTES( p_indx->idx.field[i].i_size );
                AVI_READ4BYTES( p_indx->idx.field[i].i_offsetfield2 );
            }
689
        }
690
        else i_ret = VLC_EGENERIC;
691
692
693
694
695
696
697
698
699
700
    }
    else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
    {
        p_indx->i_baseoffset = 0;
        AVI_READ4BYTES( i_dummy );
        AVI_READ4BYTES( i_dummy );
        AVI_READ4BYTES( i_dummy );

        i_count = __MIN( p_indx->i_entriesinuse, i_read / 16 );
        p_indx->i_entriesinuse = i_count;
701
702
        p_indx->idx.super = calloc( i_count, sizeof( indx_super_entry_t ) );
        if( i_count == 0 || p_indx->idx.super )
703
        {
704
705
706
707
708
709
            for( i = 0; i < i_count; i++ )
            {
                AVI_READ8BYTES( p_indx->idx.super[i].i_offset );
                AVI_READ4BYTES( p_indx->idx.super[i].i_size );
                AVI_READ4BYTES( p_indx->idx.super[i].i_duration );
            }
710
        }
711
        else i_ret = VLC_EGENERIC;
712
713
714
    }
    else
    {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
715
        msg_Warn( (vlc_object_t*)s, "unknown type/subtype index" );
716
717
718
    }

#ifdef AVI_DEBUG
719
720
    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 );
721
#endif
722
    AVI_READCHUNK_EXIT( i_ret );
723
}
724
static void AVI_ChunkFree_indx( avi_chunk_t *p_chk )
725
726
727
{
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;

zorglub's avatar
zorglub committed
728
729
730
    FREENULL( p_indx->idx.std );
    FREENULL( p_indx->idx.field );
    FREENULL( p_indx->idx.super );
731
732
}

733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
static int AVI_ChunkRead_vprp( stream_t *s, avi_chunk_t *p_chk )
{
    avi_chunk_vprp_t *p_vprp = (avi_chunk_vprp_t*)p_chk;

    AVI_READCHUNK_ENTER;

    AVI_READ4BYTES( p_vprp->i_video_format_token );
    AVI_READ4BYTES( p_vprp->i_video_standard );
    AVI_READ4BYTES( p_vprp->i_vertical_refresh );
    AVI_READ4BYTES( p_vprp->i_h_total_in_t );
    AVI_READ4BYTES( p_vprp->i_v_total_in_lines );
    AVI_READ4BYTES( p_vprp->i_frame_aspect_ratio );
    AVI_READ4BYTES( p_vprp->i_frame_width_in_pixels );
    AVI_READ4BYTES( p_vprp->i_frame_height_in_pixels );
    AVI_READ4BYTES( p_vprp->i_nb_fields_per_frame );
    for( unsigned i = 0; i < __MIN( p_vprp->i_nb_fields_per_frame, 2 ); i++ )
    {
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_height );
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_width );
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_height );
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_width );
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_x_offset );
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_y_offset );
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_x_offset_in_t );
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_y_valid_start_line );
    }
759

760
761
762
763
764
765
#ifdef AVI_DEBUG
    msg_Dbg( (vlc_object_t*)s, "vprp: format:%d standard:%d",
             p_vprp->i_video_format_token, p_vprp->i_video_standard );
#endif
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
}
766

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
static int AVI_ChunkRead_dmlh( stream_t *s, avi_chunk_t *p_chk )
{
    avi_chunk_dmlh_t *p_dmlh = (avi_chunk_dmlh_t*)p_chk;

    AVI_READCHUNK_ENTER;

    AVI_READ4BYTES( p_dmlh->dwTotalFrames );

#ifdef AVI_DEBUG
    msg_Dbg( (vlc_object_t*)s, "dmlh: dwTotalFrames %d",
             p_dmlh->dwTotalFrames );
#endif
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
}

782
static const struct
783
{
784
    vlc_fourcc_t i_fourcc;
zorglub's avatar
zorglub committed
785
    const char *psz_type;
786
787
} AVI_strz_type[] =
{
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
    { AVIFOURCC_IARL, "Archive location" },
    { AVIFOURCC_IART, "Artist" },
    { AVIFOURCC_ICMS, "Commisioned" },
    { AVIFOURCC_ICMT, "Comments" },
    { AVIFOURCC_ICOP, "Copyright" },
    { AVIFOURCC_ICRD, "Creation date" },
    { AVIFOURCC_ICRP, "Cropped" },
    { AVIFOURCC_IDIM, "Dimensions" },
    { AVIFOURCC_IDPI, "Dots per inch" },
    { AVIFOURCC_IENG, "Engineer" },
    { AVIFOURCC_IGNR, "Genre" },
    { AVIFOURCC_ISGN, "Secondary Genre" },
    { AVIFOURCC_IKEY, "Keywords" },
    { AVIFOURCC_ILGT, "Lightness" },
    { AVIFOURCC_IMED, "Medium" },
    { AVIFOURCC_INAM, "Name" },
    { AVIFOURCC_IPLT, "Palette setting" },
    { AVIFOURCC_IPRD, "Product" },
    { AVIFOURCC_ISBJ, "Subject" },
    { AVIFOURCC_ISFT, "Software" },
    { AVIFOURCC_ISHP, "Sharpness" },
    { AVIFOURCC_ISRC, "Source" },
    { AVIFOURCC_ISRF, "Source form" },
    { AVIFOURCC_ITCH, "Technician" },
    { AVIFOURCC_ISMP, "Time code" },
    { AVIFOURCC_IDIT, "Digitalization time" },
    { AVIFOURCC_IWRI, "Writer" },
    { AVIFOURCC_IPRO, "Producer" },
    { AVIFOURCC_ICNM, "Cinematographer" },
    { AVIFOURCC_IPDS, "Production designer" },
    { AVIFOURCC_IEDT, "Editor" },
    { AVIFOURCC_ICDS, "Costume designer" },
    { AVIFOURCC_IMUS, "Music" },
    { AVIFOURCC_ISTD, "Production studio" },
    { AVIFOURCC_IDST, "Distributor" },
    { AVIFOURCC_ICNT, "Country" },
    { AVIFOURCC_ISTR, "Starring" },
    { AVIFOURCC_IFRM, "Total number of parts" },
    { AVIFOURCC_strn, "Stream name" },
827
828
829
830
831
832
833
834
835
836
    { AVIFOURCC_IAS1, "First Language" },
    { AVIFOURCC_IAS2, "Second Language" },
    { AVIFOURCC_IAS3, "Third Language" },
    { AVIFOURCC_IAS4, "Fourth Language" },
    { AVIFOURCC_IAS5, "Fifth Language" },
    { AVIFOURCC_IAS6, "Sixth Language" },
    { AVIFOURCC_IAS7, "Seventh Language" },
    { AVIFOURCC_IAS8, "Eighth Language" },
    { AVIFOURCC_IAS9, "Ninth Language" },

837
838
    { 0,              "???" }
};
839

840
static int AVI_ChunkRead_strz( stream_t *s, avi_chunk_t *p_chk )
841
842
843
844
845
846
847
848
849
850
851
852
853
854
{
    int i_index;
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
    AVI_READCHUNK_ENTER;

    for( i_index = 0;; i_index++)
    {
        if( !AVI_strz_type[i_index].i_fourcc ||
            AVI_strz_type[i_index].i_fourcc == p_strz->i_chunk_fourcc )
        {
            break;
        }
    }
    p_strz->p_type = strdup( AVI_strz_type[i_index].psz_type );
855
856
    p_strz->p_str = malloc( p_strz->i_chunk_size + 1 );
    if( !p_strz->p_type || !p_strz->p_str )
857
    {
858
859
860
        free( p_strz->p_type );
        free( p_strz->p_str );
        AVI_READCHUNK_EXIT( VLC_EGENERIC );
861
    }
862
    memcpy( p_strz->p_str, p_read, p_strz->i_chunk_size );
863
    p_strz->p_str[p_strz->i_chunk_size] = 0;
864

865
#ifdef AVI_DEBUG
866
    msg_Dbg( (vlc_object_t*)s, "%4.4s: %s : %s",
867
             (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str);
868
#endif
869
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
870
}
871
static void AVI_ChunkFree_strz( avi_chunk_t *p_chk )
872
873
{
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
zorglub's avatar
zorglub committed
874
875
    FREENULL( p_strz->p_type );
    FREENULL( p_strz->p_str );
876
877
}

878
static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk )
879
{
880
    return AVI_NextChunk( s, p_chk );
881
}
882
static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk )
883
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
884
    VLC_UNUSED( p_chk );
885
886
}

887
static const struct
888
{
889
    vlc_fourcc_t i_fourcc;
890
891
    int   (*AVI_ChunkRead_function)( stream_t *s, avi_chunk_t *p_chk );
    void  (*AVI_ChunkFree_function)( avi_chunk_t *p_chk );
892
893
894
} AVI_Chunk_Function [] =
{
    { AVIFOURCC_RIFF, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
895
    { AVIFOURCC_ON2,  AVI_ChunkRead_list, AVI_ChunkFree_nothing },
896
897
    { AVIFOURCC_LIST, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
    { AVIFOURCC_avih, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
898
    { AVIFOURCC_ON2h, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
899
900
    { AVIFOURCC_strh, AVI_ChunkRead_strh, AVI_ChunkFree_nothing },
    { AVIFOURCC_strf, AVI_ChunkRead_strf, AVI_ChunkFree_strf },
901
    { AVIFOURCC_strd, AVI_ChunkRead_strd, AVI_ChunkFree_strd },
902
    { AVIFOURCC_idx1, AVI_ChunkRead_idx1, AVI_ChunkFree_idx1 },
903
    { AVIFOURCC_indx, AVI_ChunkRead_indx, AVI_ChunkFree_indx },
904
    { AVIFOURCC_vprp, AVI_ChunkRead_vprp, AVI_ChunkFree_nothing },
905
    { AVIFOURCC_JUNK, AVI_ChunkRead_nothing, AVI_ChunkFree_nothing },
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
906
    { AVIFOURCC_dmlh, AVI_ChunkRead_dmlh, AVI_ChunkFree_nothing },
907
908
909
910
911
912
913
914
915
916
917
918

    { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IART, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICMS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICMT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICOP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICRP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IDIM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IDPI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IENG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IGNR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
919
    { AVIFOURCC_ISGN, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
920
921
922
923
924
925
926
927
928
929
930
931
932
933
    { AVIFOURCC_IKEY, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ILGT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IMED, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_INAM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IPLT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IPRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISBJ, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISFT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISHP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISRC, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISRF, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ITCH, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISMP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IDIT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
934
935
936
937
    { AVIFOURCC_ILNG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IRTD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IWEB, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IPRT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
938
939
940
941
942
943
944
945
946
947
948
949
    { AVIFOURCC_IWRI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IPRO, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICNM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IPDS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IEDT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICDS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IMUS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISTD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IDST, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ICNT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_ISTR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IFRM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
950
951
952
953
954
955
956
957
958
    { AVIFOURCC_IAS1, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS2, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS3, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS4, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS5, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS6, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS7, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS8, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
    { AVIFOURCC_IAS9, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
959
960


961
    { AVIFOURCC_strn, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
962
963
964
    { 0,           NULL,               NULL }
};

965
static int AVI_ChunkFunctionFind( vlc_fourcc_t i_fourcc )
966
{
967
    unsigned int i_index;
968
969
970
971
972
    for( i_index = 0; ; i_index++ )
    {
        if( ( AVI_Chunk_Function[i_index].i_fourcc == i_fourcc )||
            ( AVI_Chunk_Function[i_index].i_fourcc == 0 ) )
        {
973
            return i_index;
974
975
976
977
        }
    }
}

978
int  AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father )
979
980
981
982
983
{
    int i_index;

    if( !p_chk )
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
984
        msg_Warn( (vlc_object_t*)s, "cannot read null chunk" );
985
        return VLC_EGENERIC;
986
987
    }

988
    if( AVI_ChunkReadCommon( s, p_chk, p_father ) )
989
        return VLC_EGENERIC;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
990

991
992
    if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) )
    {
993
        msg_Warn( (vlc_object_t*)s, "found null fourcc chunk (corrupted file?)" );
994
        return AVI_ZERO_FOURCC;
995
    }
996
997
998
999
1000
    p_chk->common.p_father = p_father;

    i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );