Coverage Report

Created: 2023-03-26 07:08

/src/vlc/modules/demux/avi/libavi.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * libavi.c : LibAVI
3
 *****************************************************************************
4
 * Copyright (C) 2001 VLC authors and VideoLAN
5
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU Lesser General Public License as published by
9
 * the Free Software Foundation; either version 2.1 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with this program; if not, write to the Free Software Foundation,
19
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20
 *****************************************************************************/
21
22
23
#ifdef HAVE_CONFIG_H
24
# include "config.h"
25
#endif
26
27
#include <vlc_common.h>
28
#include <vlc_demux.h>                                   /* stream_*, *_ES */
29
#include <vlc_codecs.h>                            /* VLC_BITMAPINFOHEADER */
30
31
#include "libavi.h"
32
33
#include <limits.h>
34
35
#ifndef NDEBUG
36
# define AVI_DEBUG 1
37
#endif
38
39
0
#define __EVEN( x ) (((x) + 1) & ~1)
40
41
static vlc_fourcc_t GetFOURCC( const uint8_t *p_buff )
42
0
{
43
0
    return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
44
0
}
45
46
static uint64_t AVI_ChunkSize( const avi_chunk_t *p_ck )
47
0
{
48
0
    return __EVEN(p_ck->common.i_chunk_size) + 8;
49
0
}
50
51
static uint64_t AVI_ChunkEnd( const avi_chunk_t *p_ck )
52
0
{
53
0
    return p_ck->common.i_chunk_pos + AVI_ChunkSize( p_ck );
54
0
}
55
56
/****************************************************************************
57
 *
58
 * Basics functions to manipulates chunks
59
 *
60
 ****************************************************************************/
61
static int AVI_ChunkReadCommon( stream_t *s, avi_chunk_t *p_chk,
62
                                const avi_chunk_t *p_father )
63
0
{
64
0
    const uint8_t *p_peek;
65
66
0
    memset( p_chk, 0, sizeof( avi_chunk_t ) );
67
68
0
    const uint64_t i_pos = vlc_stream_Tell( s );
69
0
    if( vlc_stream_Peek( s, &p_peek, 8 ) < 8 )
70
0
    {
71
0
        if( stream_Size( s ) > 0 && (uint64_t) stream_Size( s ) > i_pos )
72
0
            msg_Warn( s, "can't peek at %"PRIu64, i_pos );
73
0
        else
74
0
            msg_Dbg( s, "no more data at %"PRIu64, i_pos );
75
0
        return VLC_EGENERIC;
76
0
    }
77
78
0
    p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );
79
0
    p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );
80
0
    p_chk->common.i_chunk_pos    = i_pos;
81
82
0
    if( p_chk->common.i_chunk_size >= UINT64_MAX - 8 ||
83
0
        p_chk->common.i_chunk_pos > UINT64_MAX - 8 ||
84
0
        UINT64_MAX - p_chk->common.i_chunk_pos - 8 < __EVEN(p_chk->common.i_chunk_size) )
85
0
        return VLC_EGENERIC;
86
87
0
    if( p_father && AVI_ChunkEnd( p_chk ) > AVI_ChunkEnd( p_father ) )
88
0
    {
89
0
        msg_Warn( s, "chunk %4.4s does not fit into parent %"PRIu64,
90
0
                  (char*)&p_chk->common.i_chunk_fourcc, AVI_ChunkEnd( p_father ) );
91
92
        /* How hard is to produce files with the correct declared size ? */
93
0
        if( p_father->common.i_chunk_fourcc != AVIFOURCC_RIFF ||
94
0
            p_father->common.p_father == NULL ||
95
0
            p_father->common.p_father->common.p_father != NULL ) /* Root > RIFF only */
96
0
            return VLC_EGENERIC;
97
0
    }
98
99
0
#ifdef AVI_DEBUG
100
0
    msg_Dbg( s,
101
0
             "found chunk, fourcc: %4.4s size:%"PRIu64" pos:%"PRIu64,
102
0
             (char*)&p_chk->common.i_chunk_fourcc,
103
0
             p_chk->common.i_chunk_size,
104
0
             p_chk->common.i_chunk_pos );
105
0
#endif
106
0
    return VLC_SUCCESS;
107
0
}
108
109
static int AVI_GotoNextChunk( stream_t *s, const avi_chunk_t *p_chk )
110
0
{
111
0
    bool b_seekable = false;
112
0
    const uint64_t i_offset = AVI_ChunkEnd( p_chk );
113
0
    if ( !vlc_stream_Control(s, STREAM_CAN_SEEK, &b_seekable) && b_seekable )
114
0
    {
115
0
        return vlc_stream_Seek( s, i_offset );
116
0
    }
117
0
    ssize_t i_read = i_offset - vlc_stream_Tell( s );
118
0
    if (i_read < 0)
119
0
        return VLC_EGENERIC;
120
0
    return vlc_stream_Read( s, NULL, i_read ) != i_read ? VLC_EGENERIC : VLC_SUCCESS;
121
0
}
122
123
static int AVI_NextChunk( stream_t *s, avi_chunk_t *p_chk )
124
0
{
125
0
    avi_chunk_t chk;
126
127
0
    if( !p_chk )
128
0
    {
129
0
        if( AVI_ChunkReadCommon( s, &chk, NULL ) )
130
0
        {
131
0
            return VLC_EGENERIC;
132
0
        }
133
0
        p_chk = &chk;
134
0
    }
135
136
0
    return AVI_GotoNextChunk( s, p_chk );
137
0
}
138
139
/****************************************************************************
140
 *
141
 * Functions to read chunks
142
 *
143
 ****************************************************************************/
144
static int AVI_ChunkRead_list( stream_t *s, avi_chunk_t *p_container )
145
0
{
146
0
    avi_chunk_t *p_chk;
147
0
    const uint8_t *p_peek;
148
0
    bool b_seekable;
149
0
    int i_ret = VLC_SUCCESS;
150
151
0
    if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 4 )
152
0
    {
153
        /* empty box */
154
0
        msg_Warn( s, "empty list chunk" );
155
0
        return VLC_EGENERIC;
156
0
    }
157
0
    if( vlc_stream_Peek( s, &p_peek, 12 ) < 12 )
158
0
    {
159
0
        msg_Warn( s, "unexpected end of file while reading list chunk" );
160
0
        return VLC_EGENERIC;
161
0
    }
162
163
0
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
164
165
0
    p_container->list.i_type = GetFOURCC( p_peek + 8 );
166
167
    /* XXX fixed for on2 hack */
168
0
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f )
169
0
    {
170
0
        p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF;
171
0
        p_container->list.i_type = AVIFOURCC_AVI;
172
0
    }
173
174
0
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
175
0
        p_container->list.i_type == AVIFOURCC_movi )
176
0
    {
177
0
        if( !b_seekable )
178
0
            return VLC_SUCCESS;
179
0
        msg_Dbg( s, "skipping movi chunk" );
180
0
        return AVI_NextChunk( s, p_container ); /* points at beginning of LIST-movi if not seekable */
181
0
    }
182
183
0
    if( vlc_stream_Read( s, NULL, 12 ) != 12 )
184
0
    {
185
0
        msg_Warn( s, "cannot enter chunk" );
186
0
        return VLC_EGENERIC;
187
0
    }
188
189
0
#ifdef AVI_DEBUG
190
0
    msg_Dbg( s,
191
0
             "found LIST chunk: \'%4.4s\'",
192
0
             (char*)&p_container->list.i_type );
193
0
#endif
194
0
    msg_Dbg( s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );
195
196
0
    avi_chunk_t **pp_append = &p_container->common.p_first;
197
0
    for( ; ; )
198
0
    {
199
0
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
200
0
        if( !p_chk )
201
0
            return VLC_EGENERIC;
202
203
0
        i_ret = AVI_ChunkRead( s, p_chk, p_container );
204
0
        if( i_ret )
205
0
        {
206
0
            AVI_ChunkClean( s, p_chk );
207
0
            free( p_chk );
208
0
            p_chk = NULL;
209
0
            if( i_ret != AVI_ZEROSIZED_CHUNK )
210
0
                break;
211
0
        }
212
213
0
        if( p_chk )
214
0
        {
215
0
            *pp_append = p_chk;
216
0
            while( *pp_append )
217
0
                pp_append = &((*pp_append)->common.p_next);
218
0
        }
219
220
0
        if( p_container->common.i_chunk_size > 0 &&
221
0
            vlc_stream_Tell( s ) >= AVI_ChunkEnd( p_container ) )
222
0
        {
223
0
            break;
224
0
        }
225
226
        /* If we can't seek then stop when we 've found LIST-movi */
227
0
        if( p_chk &&
228
0
            p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
229
0
            p_chk->list.i_type == AVIFOURCC_movi &&
230
0
            ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
231
0
        {
232
0
            break;
233
0
        }
234
235
0
    }
236
0
    msg_Dbg( s, "</list \'%4.4s\'>%x", (char*)&p_container->list.i_type, i_ret );
237
238
0
    if( i_ret == AVI_ZERO_FOURCC || i_ret == AVI_ZEROSIZED_CHUNK )
239
0
        return AVI_GotoNextChunk( s, p_container );
240
241
0
    return VLC_SUCCESS;
242
0
}
243
244
/* Allow to append indexes after starting playback */
245
int AVI_ChunkFetchIndexes( stream_t *s, avi_chunk_t *p_riff )
246
0
{
247
0
    avi_chunk_t *p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0, true );
248
0
    if ( !p_movi )
249
0
        return VLC_EGENERIC;
250
251
0
    avi_chunk_t *p_chk;
252
0
    const uint64_t i_indexpos = AVI_ChunkEnd( p_movi );
253
0
    bool b_seekable = false;
254
0
    int i_ret = VLC_SUCCESS;
255
256
0
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
257
0
    if ( !b_seekable || vlc_stream_Seek( s, i_indexpos ) )
258
0
        return VLC_EGENERIC;
259
260
0
    avi_chunk_t **pp_append = &p_riff->common.p_first;
261
0
    for( ; ; )
262
0
    {
263
0
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
264
0
        if( !p_chk )
265
0
        {
266
0
            i_ret = VLC_EGENERIC;
267
0
            break;
268
0
        }
269
270
0
        i_ret = AVI_ChunkRead( s, p_chk, p_riff );
271
0
        if( i_ret )
272
0
        {
273
0
            AVI_ChunkClean( s, p_chk );
274
0
            free( p_chk );
275
0
            break;
276
0
        }
277
278
0
        *pp_append = p_chk;
279
0
        while( *pp_append )
280
0
            pp_append = &((*pp_append)->common.p_next);
281
282
0
        if( p_chk->common.p_father->common.i_chunk_size > 0 &&
283
0
           ( vlc_stream_Tell( s ) >
284
0
             p_chk->common.p_father->common.i_chunk_pos +
285
0
             __EVEN( p_chk->common.p_father->common.i_chunk_size ) ) )
286
0
        {
287
0
            break;
288
0
        }
289
290
        /* If we can't seek then stop when we 've found any index */
291
0
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_indx ||
292
0
            p_chk->common.i_chunk_fourcc == AVIFOURCC_idx1 )
293
0
        {
294
0
            break;
295
0
        }
296
297
0
    }
298
299
0
    return i_ret;
300
0
}
301
302
#define AVI_READCHUNK_ENTER \
303
0
    int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \
304
0
    if( i_read > 100000000 ) \
305
0
    { \
306
0
        msg_Err( s, "Big chunk ignored" ); \
307
0
        return VLC_EGENERIC; \
308
0
    } \
309
0
    uint8_t  *p_read, *p_buff;    \
310
0
    if( !( p_read = p_buff = malloc(i_read ) ) ) \
311
0
    { \
312
0
        return VLC_EGENERIC; \
313
0
    } \
314
0
    i_read = vlc_stream_Read( s, p_read, i_read ); \
315
0
    if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) \
316
0
    { \
317
0
        free( p_buff ); \
318
0
        return VLC_EGENERIC; \
319
0
    }\
320
0
    p_read += 8; \
321
0
    i_read -= 8
322
323
#define AVI_READ( res, func, size ) \
324
0
    if( i_read < size ) { \
325
0
        free( p_buff); \
326
0
        return VLC_EGENERIC; \
327
0
    } \
328
0
    i_read -= size; \
329
0
    res = func( p_read ); \
330
0
    p_read += size \
331
332
#define AVI_READCHUNK_EXIT( code ) \
333
0
    do { \
334
0
        free( p_buff ); \
335
0
        return code; \
336
0
    } while(0)
337
338
static inline uint8_t GetB( uint8_t *ptr )
339
0
{
340
0
    return *ptr;
341
0
}
342
343
#define AVI_READ1BYTE( i_byte ) \
344
0
    AVI_READ( i_byte, GetB, 1 )
345
346
#define AVI_READ2BYTES( i_word ) \
347
0
    AVI_READ( i_word, GetWLE, 2 )
348
349
#define AVI_READ4BYTES( i_dword ) \
350
0
    AVI_READ( i_dword, GetDWLE, 4 )
351
352
#define AVI_READ8BYTES( i_qword ) \
353
0
    AVI_READ( i_qword, GetQWLE, 8 )
354
355
#define AVI_READFOURCC( i_dword ) \
356
0
    AVI_READ( i_dword, GetFOURCC, 4 )
357
358
static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk )
359
0
{
360
0
    AVI_READCHUNK_ENTER;
361
362
0
    p_chk->common.i_chunk_fourcc = AVIFOURCC_avih;
363
0
    AVI_READ4BYTES( p_chk->avih.i_microsecperframe);
364
0
    AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );
365
0
    AVI_READ4BYTES( p_chk->avih.i_reserved1 );
366
0
    AVI_READ4BYTES( p_chk->avih.i_flags );
367
0
    AVI_READ4BYTES( p_chk->avih.i_totalframes );
368
0
    AVI_READ4BYTES( p_chk->avih.i_initialframes );
369
0
    AVI_READ4BYTES( p_chk->avih.i_streams );
370
0
    AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );
371
0
    AVI_READ4BYTES( p_chk->avih.i_width );
372
0
    AVI_READ4BYTES( p_chk->avih.i_height );
373
0
    AVI_READ4BYTES( p_chk->avih.i_scale );
374
0
    AVI_READ4BYTES( p_chk->avih.i_rate );
375
0
    AVI_READ4BYTES( p_chk->avih.i_start );
376
0
    AVI_READ4BYTES( p_chk->avih.i_length );
377
0
#ifdef AVI_DEBUG
378
0
    msg_Dbg( s,
379
0
             "avih: streams:%d flags:%s%s%s%s %dx%d",
380
0
             p_chk->avih.i_streams,
381
0
             p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
382
0
             p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
383
0
             p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
384
0
             p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
385
0
             p_chk->avih.i_width, p_chk->avih.i_height );
386
0
#endif
387
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
388
0
}
389
390
static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk )
391
0
{
392
0
    AVI_READCHUNK_ENTER;
393
394
0
    AVI_READFOURCC( p_chk->strh.i_type );
395
0
    AVI_READFOURCC( p_chk->strh.i_handler );
396
0
    AVI_READ4BYTES( p_chk->strh.i_flags );
397
0
    AVI_READ4BYTES( p_chk->strh.i_reserved1 );
398
0
    AVI_READ4BYTES( p_chk->strh.i_initialframes );
399
0
    AVI_READ4BYTES( p_chk->strh.i_scale );
400
0
    AVI_READ4BYTES( p_chk->strh.i_rate );
401
0
    AVI_READ4BYTES( p_chk->strh.i_start );
402
0
    AVI_READ4BYTES( p_chk->strh.i_length );
403
0
    AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );
404
0
    AVI_READ4BYTES( p_chk->strh.i_quality );
405
0
    AVI_READ4BYTES( p_chk->strh.i_samplesize );
406
0
#ifdef AVI_DEBUG
407
0
    msg_Dbg( s,
408
0
             "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",
409
0
             (char*)&p_chk->strh.i_type,
410
0
             p_chk->strh.i_handler,
411
0
             p_chk->strh.i_samplesize,
412
0
             ( p_chk->strh.i_scale ?
413
0
                (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );
414
0
#endif
415
416
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
417
0
}
418
419
static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk )
420
0
{
421
0
    avi_chunk_t *p_strh;
422
423
0
    AVI_READCHUNK_ENTER;
424
0
    if( p_chk->common.p_father == NULL )
425
0
    {
426
0
        msg_Err( s, "malformed avi file" );
427
0
        AVI_READCHUNK_EXIT( VLC_EGENERIC );
428
0
    }
429
0
    if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0, false ) ) )
430
0
    {
431
0
        msg_Err( s, "malformed avi file" );
432
0
        AVI_READCHUNK_EXIT( p_chk->common.i_chunk_size > 0  ? VLC_EGENERIC : AVI_ZEROSIZED_CHUNK );
433
0
    }
434
435
0
    switch( p_strh->strh.i_type )
436
0
    {
437
0
        case( AVIFOURCC_auds ):
438
0
            p_chk->strf.auds.i_cat = AUDIO_ES;
439
0
            p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );
440
0
            if ( !p_chk->strf.auds.p_wf )
441
0
            {
442
0
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
443
0
            }
444
0
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );
445
0
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );
446
0
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );
447
0
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );
448
0
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );
449
0
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );
450
451
0
            if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM
452
0
                 && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )
453
0
            {
454
0
                AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );
455
456
                /* prevent segfault */
457
0
                if( p_chk->strf.auds.p_wf->cbSize >
458
0
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )
459
0
                {
460
0
                    p_chk->strf.auds.p_wf->cbSize =
461
0
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );
462
0
                }
463
464
0
                if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
465
0
                {
466
0
                    msg_Dbg( s, "Extended header found" );
467
0
                }
468
0
            }
469
0
            else
470
0
            {
471
0
                p_chk->strf.auds.p_wf->cbSize = 0;
472
0
            }
473
0
            if( p_chk->strf.auds.p_wf->cbSize > 0 )
474
0
            {
475
0
                memcpy( &p_chk->strf.auds.p_wf[1] ,
476
0
                        p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourcc+size */
477
0
                        p_chk->strf.auds.p_wf->cbSize );
478
0
            }
479
0
#ifdef AVI_DEBUG
480
0
            msg_Dbg( s,
481
0
                     "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkbps",
482
0
                     p_chk->strf.auds.p_wf->wFormatTag,
483
0
                     p_chk->strf.auds.p_wf->nChannels,
484
0
                     p_chk->strf.auds.p_wf->nSamplesPerSec,
485
0
                     p_chk->strf.auds.p_wf->wBitsPerSample,
486
0
                     p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1000 );
487
0
#endif
488
0
            break;
489
0
        case( AVIFOURCC_vids ):
490
0
            p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */
491
0
            p_chk->strf.vids.i_cat = VIDEO_ES;
492
0
            p_chk->strf.vids.p_bih = malloc( __MAX( p_chk->common.i_chunk_size,
493
0
                                         sizeof( *p_chk->strf.vids.p_bih ) ) );
494
0
            if ( !p_chk->strf.vids.p_bih )
495
0
            {
496
0
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
497
0
            }
498
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );
499
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );
500
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );
501
0
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );
502
0
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );
503
0
            AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );
504
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );
505
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );
506
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );
507
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );
508
0
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );
509
0
            if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )
510
0
            {
511
0
                p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;
512
0
            }
513
0
            if ( p_chk->common.i_chunk_size > sizeof(VLC_BITMAPINFOHEADER) )
514
0
            {
515
0
                uint64_t i_extrasize = p_chk->common.i_chunk_size - sizeof(VLC_BITMAPINFOHEADER);
516
517
                /* There's a color palette appended, set up VLC_BITMAPINFO */
518
0
                memcpy( &p_chk->strf.vids.p_bih[1],
519
0
                        p_buff + 8 + sizeof(VLC_BITMAPINFOHEADER), /* 8=fourrc+size */
520
0
                        i_extrasize );
521
522
0
                if ( !p_chk->strf.vids.p_bih->biClrUsed )
523
0
                {
524
0
                    if( p_chk->strf.vids.p_bih->biBitCount < 32 )
525
0
                        p_chk->strf.vids.p_bih->biClrUsed = (1 << p_chk->strf.vids.p_bih->biBitCount);
526
0
                    else
527
0
                        p_chk->strf.vids.p_bih->biBitCount = UINT16_MAX;
528
0
                }
529
530
0
                if( i_extrasize / sizeof(uint32_t) > UINT32_MAX )
531
0
                    p_chk->strf.vids.p_bih->biClrUsed = UINT32_MAX;
532
0
                else
533
0
                {
534
0
                    p_chk->strf.vids.p_bih->biClrUsed =
535
0
                            __MIN( i_extrasize / sizeof(uint32_t),
536
0
                                   p_chk->strf.vids.p_bih->biClrUsed );
537
0
                }
538
539
                /* stay within VLC's limits */
540
0
                p_chk->strf.vids.p_bih->biClrUsed =
541
0
                    __MIN( VIDEO_PALETTE_COLORS_MAX, p_chk->strf.vids.p_bih->biClrUsed );
542
0
            }
543
0
            else p_chk->strf.vids.p_bih->biClrUsed = 0;
544
0
#ifdef AVI_DEBUG
545
0
            msg_Dbg( s,
546
0
                     "strf: video:%4.4s %"PRIu32"x%"PRIu32" planes:%d %dbpp",
547
0
                     (char*)&p_chk->strf.vids.p_bih->biCompression,
548
0
                     (uint32_t)p_chk->strf.vids.p_bih->biWidth,
549
0
                     p_chk->strf.vids.p_bih->biHeight <= INT32_MAX ? p_chk->strf.vids.p_bih->biHeight
550
0
                                                                   : -1 * p_chk->strf.vids.p_bih->biHeight,
551
0
                     p_chk->strf.vids.p_bih->biPlanes,
552
0
                     p_chk->strf.vids.p_bih->biBitCount );
553
0
#endif
554
0
            break;
555
0
        case AVIFOURCC_iavs:
556
0
        case AVIFOURCC_ivas:
557
0
            p_chk->strf.common.i_cat = UNKNOWN_ES;
558
0
            break;
559
0
        case( AVIFOURCC_txts ):
560
0
            p_chk->strf.common.i_cat = SPU_ES;
561
0
            break;
562
0
        default:
563
0
            msg_Warn( s, "unknown stream type: %4.4s",
564
0
                    (char*)&p_strh->strh.i_type );
565
0
            p_chk->strf.common.i_cat = UNKNOWN_ES;
566
0
            break;
567
0
    }
568
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
569
0
}
570
static void AVI_ChunkFree_strf( avi_chunk_t *p_chk )
571
0
{
572
0
    avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;
573
0
    if( p_strf->common.i_cat == AUDIO_ES )
574
0
    {
575
0
        FREENULL( p_strf->auds.p_wf );
576
0
    }
577
0
    else if( p_strf->common.i_cat == VIDEO_ES )
578
0
    {
579
0
        FREENULL( p_strf->vids.p_bih );
580
0
    }
581
0
}
582
583
static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk )
584
0
{
585
0
    if ( p_chk->common.i_chunk_size == 0 )
586
0
    {
587
0
        msg_Dbg( s, "Zero sized pre-JUNK section met" );
588
0
        return AVI_ZEROSIZED_CHUNK;
589
0
    }
590
591
0
    AVI_READCHUNK_ENTER;
592
0
    p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );
593
0
    if( p_chk->strd.p_data )
594
0
        memcpy( p_chk->strd.p_data, p_buff + 8, p_chk->common.i_chunk_size );
595
0
    AVI_READCHUNK_EXIT( p_chk->strd.p_data ? VLC_SUCCESS : VLC_EGENERIC );
596
0
}
597
598
static void AVI_ChunkFree_strd( avi_chunk_t *p_chk )
599
0
{
600
0
    free( p_chk->strd.p_data );
601
0
}
602
603
static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk )
604
0
{
605
0
    unsigned int i_count, i_index;
606
607
0
    AVI_READCHUNK_ENTER;
608
609
0
    i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;
610
611
0
    p_chk->idx1.i_entry_count = i_count;
612
0
    p_chk->idx1.i_entry_max   = i_count;
613
0
    if( i_count > 0 )
614
0
    {
615
0
        p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );
616
0
        if( !p_chk->idx1.entry )
617
0
            AVI_READCHUNK_EXIT( VLC_EGENERIC );
618
619
0
        for( i_index = 0; i_index < i_count ; i_index++ )
620
0
        {
621
0
            AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );
622
0
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );
623
0
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );
624
0
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );
625
0
        }
626
0
    }
627
0
    else
628
0
    {
629
0
        p_chk->idx1.entry = NULL;
630
0
    }
631
0
#ifdef AVI_DEBUG
632
0
    msg_Dbg( s, "idx1: index entry:%d", i_count );
633
0
#endif
634
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
635
0
}
636
637
static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk )
638
0
{
639
0
    p_chk->idx1.i_entry_count = 0;
640
0
    p_chk->idx1.i_entry_max   = 0;
641
0
    FREENULL( p_chk->idx1.entry );
642
0
}
643
644
645
646
static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk )
647
0
{
648
0
    unsigned int i_count, i;
649
0
    int          i_ret = VLC_SUCCESS;
650
0
    int32_t      i_dummy;
651
0
    VLC_UNUSED(i_dummy);
652
0
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
653
654
0
    AVI_READCHUNK_ENTER;
655
656
0
    AVI_READ2BYTES( p_indx->i_longsperentry );
657
0
    AVI_READ1BYTE ( p_indx->i_indexsubtype );
658
0
    AVI_READ1BYTE ( p_indx->i_indextype );
659
0
    AVI_READ4BYTES( p_indx->i_entriesinuse );
660
661
0
    AVI_READ4BYTES( p_indx->i_id );
662
0
    p_indx->idx.std     = NULL;
663
0
    p_indx->idx.field   = NULL;
664
0
    p_indx->idx.super   = NULL;
665
666
0
    if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == 0 )
667
0
    {
668
0
        AVI_READ8BYTES( p_indx->i_baseoffset );
669
0
        AVI_READ4BYTES( i_dummy );
670
671
0
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 8 );
672
0
        p_indx->i_entriesinuse = i_count;
673
0
        p_indx->idx.std = calloc( i_count, sizeof( indx_std_entry_t ) );
674
0
        if( i_count == 0 || p_indx->idx.std )
675
0
        {
676
0
            for( i = 0; i < i_count; i++ )
677
0
            {
678
0
                AVI_READ4BYTES( p_indx->idx.std[i].i_offset );
679
0
                AVI_READ4BYTES( p_indx->idx.std[i].i_size );
680
0
            }
681
0
        }
682
0
        else i_ret = VLC_EGENERIC;
683
0
    }
684
0
    else if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
685
0
    {
686
0
        AVI_READ8BYTES( p_indx->i_baseoffset );
687
0
        AVI_READ4BYTES( i_dummy );
688
689
0
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 12 );
690
0
        p_indx->i_entriesinuse = i_count;
691
0
        p_indx->idx.field = calloc( i_count, sizeof( indx_field_entry_t ) );
692
0
        if( i_count == 0 || p_indx->idx.field )
693
0
        {
694
0
            for( i = 0; i < i_count; i++ )
695
0
            {
696
0
                AVI_READ4BYTES( p_indx->idx.field[i].i_offset );
697
0
                AVI_READ4BYTES( p_indx->idx.field[i].i_size );
698
0
                AVI_READ4BYTES( p_indx->idx.field[i].i_offsetfield2 );
699
0
            }
700
0
        }
701
0
        else i_ret = VLC_EGENERIC;
702
0
    }
703
0
    else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
704
0
    {
705
0
        p_indx->i_baseoffset = 0;
706
0
        AVI_READ4BYTES( i_dummy );
707
0
        AVI_READ4BYTES( i_dummy );
708
0
        AVI_READ4BYTES( i_dummy );
709
710
0
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 16 );
711
0
        p_indx->i_entriesinuse = i_count;
712
0
        p_indx->idx.super = calloc( i_count, sizeof( indx_super_entry_t ) );
713
0
        if( i_count == 0 || p_indx->idx.super )
714
0
        {
715
0
            for( i = 0; i < i_count; i++ )
716
0
            {
717
0
                AVI_READ8BYTES( p_indx->idx.super[i].i_offset );
718
0
                AVI_READ4BYTES( p_indx->idx.super[i].i_size );
719
0
                AVI_READ4BYTES( p_indx->idx.super[i].i_duration );
720
0
            }
721
0
        }
722
0
        else i_ret = VLC_EGENERIC;
723
0
    }
724
0
    else
725
0
    {
726
0
        msg_Warn( s, "unknown type/subtype index" );
727
0
    }
728
729
0
#ifdef AVI_DEBUG
730
0
    msg_Dbg( s, "indx: type=%d subtype=%d entry=%d",
731
0
             p_indx->i_indextype, p_indx->i_indexsubtype, p_indx->i_entriesinuse );
732
0
#endif
733
0
    AVI_READCHUNK_EXIT( i_ret );
734
0
}
735
static void AVI_ChunkFree_indx( avi_chunk_t *p_chk )
736
0
{
737
0
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
738
739
0
    FREENULL( p_indx->idx.std );
740
0
    FREENULL( p_indx->idx.field );
741
0
    FREENULL( p_indx->idx.super );
742
0
}
743
744
static int AVI_ChunkRead_vprp( stream_t *s, avi_chunk_t *p_chk )
745
0
{
746
0
    avi_chunk_vprp_t *p_vprp = (avi_chunk_vprp_t*)p_chk;
747
748
0
    AVI_READCHUNK_ENTER;
749
750
0
    AVI_READ4BYTES( p_vprp->i_video_format_token );
751
0
    AVI_READ4BYTES( p_vprp->i_video_standard );
752
0
    AVI_READ4BYTES( p_vprp->i_vertical_refresh );
753
0
    AVI_READ4BYTES( p_vprp->i_h_total_in_t );
754
0
    AVI_READ4BYTES( p_vprp->i_v_total_in_lines );
755
0
    AVI_READ4BYTES( p_vprp->i_frame_aspect_ratio );
756
0
    AVI_READ4BYTES( p_vprp->i_frame_width_in_pixels );
757
0
    AVI_READ4BYTES( p_vprp->i_frame_height_in_pixels );
758
0
    AVI_READ4BYTES( p_vprp->i_nb_fields_per_frame );
759
0
    for( unsigned i = 0; i < __MIN( p_vprp->i_nb_fields_per_frame, 2 ); i++ )
760
0
    {
761
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_height );
762
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_width );
763
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_height );
764
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_width );
765
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_x_offset );
766
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_y_offset );
767
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_x_offset_in_t );
768
0
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_y_valid_start_line );
769
0
    }
770
771
0
#ifdef AVI_DEBUG
772
0
    msg_Dbg( s, "vprp: format:%d standard:%d",
773
0
             p_vprp->i_video_format_token, p_vprp->i_video_standard );
774
0
#endif
775
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
776
0
}
777
778
static int AVI_ChunkRead_dmlh( stream_t *s, avi_chunk_t *p_chk )
779
0
{
780
0
    avi_chunk_dmlh_t *p_dmlh = (avi_chunk_dmlh_t*)p_chk;
781
782
0
    AVI_READCHUNK_ENTER;
783
784
0
    AVI_READ4BYTES( p_dmlh->dwTotalFrames );
785
786
0
#ifdef AVI_DEBUG
787
0
    msg_Dbg( s, "dmlh: dwTotalFrames %d",
788
0
             p_dmlh->dwTotalFrames );
789
0
#endif
790
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
791
0
}
792
793
static const struct
794
{
795
    vlc_fourcc_t i_fourcc;
796
    const char *psz_type;
797
} AVI_strz_type[] =
798
{
799
    { AVIFOURCC_IARL, "Archive location" },
800
    { AVIFOURCC_IART, "Artist" },
801
    { AVIFOURCC_ICMS, "Commisioned" },
802
    { AVIFOURCC_ICMT, "Comments" },
803
    { AVIFOURCC_ICOP, "Copyright" },
804
    { AVIFOURCC_ICRD, "Creation date" },
805
    { AVIFOURCC_ICRP, "Cropped" },
806
    { AVIFOURCC_IDIM, "Dimensions" },
807
    { AVIFOURCC_IDPI, "Dots per inch" },
808
    { AVIFOURCC_IENG, "Engineer" },
809
    { AVIFOURCC_IGNR, "Genre" },
810
    { AVIFOURCC_ISGN, "Secondary Genre" },
811
    { AVIFOURCC_IKEY, "Keywords" },
812
    { AVIFOURCC_ILGT, "Lightness" },
813
    { AVIFOURCC_IMED, "Medium" },
814
    { AVIFOURCC_INAM, "Name" },
815
    { AVIFOURCC_IPLT, "Palette setting" },
816
    { AVIFOURCC_IPRD, "Product" },
817
    { AVIFOURCC_ISBJ, "Subject" },
818
    { AVIFOURCC_ISFT, "Software" },
819
    { AVIFOURCC_ISHP, "Sharpness" },
820
    { AVIFOURCC_ISRC, "Source" },
821
    { AVIFOURCC_ISRF, "Source form" },
822
    { AVIFOURCC_ITCH, "Technician" },
823
    { AVIFOURCC_ISMP, "Time code" },
824
    { AVIFOURCC_IDIT, "Digitalization time" },
825
    { AVIFOURCC_IWRI, "Writer" },
826
    { AVIFOURCC_IPRO, "Producer" },
827
    { AVIFOURCC_ICNM, "Cinematographer" },
828
    { AVIFOURCC_IPDS, "Production designer" },
829
    { AVIFOURCC_IEDT, "Editor" },
830
    { AVIFOURCC_ICDS, "Costume designer" },
831
    { AVIFOURCC_IMUS, "Music" },
832
    { AVIFOURCC_ISTD, "Production studio" },
833
    { AVIFOURCC_IDST, "Distributor" },
834
    { AVIFOURCC_ICNT, "Country" },
835
    { AVIFOURCC_ISTR, "Starring" },
836
    { AVIFOURCC_IFRM, "Total number of parts" },
837
    { AVIFOURCC_strn, "Stream name" },
838
    { AVIFOURCC_IAS1, "First Language" },
839
    { AVIFOURCC_IAS2, "Second Language" },
840
    { AVIFOURCC_IAS3, "Third Language" },
841
    { AVIFOURCC_IAS4, "Fourth Language" },
842
    { AVIFOURCC_IAS5, "Fifth Language" },
843
    { AVIFOURCC_IAS6, "Sixth Language" },
844
    { AVIFOURCC_IAS7, "Seventh Language" },
845
    { AVIFOURCC_IAS8, "Eighth Language" },
846
    { AVIFOURCC_IAS9, "Ninth Language" },
847
848
    { 0,              "???" }
849
};
850
851
static int AVI_ChunkRead_strz( stream_t *s, avi_chunk_t *p_chk )
852
0
{
853
0
    int i_index;
854
0
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
855
0
    AVI_READCHUNK_ENTER;
856
857
0
    for( i_index = 0;; i_index++)
858
0
    {
859
0
        if( !AVI_strz_type[i_index].i_fourcc ||
860
0
            AVI_strz_type[i_index].i_fourcc == p_strz->i_chunk_fourcc )
861
0
        {
862
0
            break;
863
0
        }
864
0
    }
865
0
    p_strz->p_type = strdup( AVI_strz_type[i_index].psz_type );
866
0
    p_strz->p_str = malloc( p_strz->i_chunk_size + 1 );
867
0
    if( !p_strz->p_type || !p_strz->p_str )
868
0
    {
869
0
        free( p_strz->p_type );
870
0
        free( p_strz->p_str );
871
0
        AVI_READCHUNK_EXIT( VLC_EGENERIC );
872
0
    }
873
0
    memcpy( p_strz->p_str, p_read, p_strz->i_chunk_size );
874
0
    p_strz->p_str[p_strz->i_chunk_size] = 0;
875
876
0
#ifdef AVI_DEBUG
877
0
    msg_Dbg( s, "%4.4s: %s : %s",
878
0
             (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str);
879
0
#endif
880
0
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
881
0
}
882
static void AVI_ChunkFree_strz( avi_chunk_t *p_chk )
883
0
{
884
0
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
885
0
    FREENULL( p_strz->p_type );
886
0
    FREENULL( p_strz->p_str );
887
0
}
888
889
static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk )
890
0
{
891
0
    return AVI_NextChunk( s, p_chk );
892
0
}
893
static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk )
894
0
{
895
0
    VLC_UNUSED( p_chk );
896
0
}
897
898
static const struct
899
{
900
    vlc_fourcc_t i_fourcc;
901
    int   (*AVI_ChunkRead_function)( stream_t *s, avi_chunk_t *p_chk );
902
    void  (*AVI_ChunkFree_function)( avi_chunk_t *p_chk );
903
} AVI_Chunk_Function [] =
904
{
905
    { AVIFOURCC_RIFF, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
906
    { AVIFOURCC_ON2,  AVI_ChunkRead_list, AVI_ChunkFree_nothing },
907
    { AVIFOURCC_LIST, AVI_ChunkRead_list, AVI_ChunkFree_nothing },
908
    { AVIFOURCC_avih, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
909
    { AVIFOURCC_ON2h, AVI_ChunkRead_avih, AVI_ChunkFree_nothing },
910
    { AVIFOURCC_strh, AVI_ChunkRead_strh, AVI_ChunkFree_nothing },
911
    { AVIFOURCC_strf, AVI_ChunkRead_strf, AVI_ChunkFree_strf },
912
    { AVIFOURCC_strd, AVI_ChunkRead_strd, AVI_ChunkFree_strd },
913
    { AVIFOURCC_idx1, AVI_ChunkRead_idx1, AVI_ChunkFree_idx1 },
914
    { AVIFOURCC_indx, AVI_ChunkRead_indx, AVI_ChunkFree_indx },
915
    { AVIFOURCC_vprp, AVI_ChunkRead_vprp, AVI_ChunkFree_nothing },
916
    { AVIFOURCC_JUNK, AVI_ChunkRead_nothing, AVI_ChunkFree_nothing },
917
    { AVIFOURCC_dmlh, AVI_ChunkRead_dmlh, AVI_ChunkFree_nothing },
918
919
    { AVIFOURCC_IARL, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
920
    { AVIFOURCC_IART, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
921
    { AVIFOURCC_ICMS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
922
    { AVIFOURCC_ICMT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
923
    { AVIFOURCC_ICOP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
924
    { AVIFOURCC_ICRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
925
    { AVIFOURCC_ICRP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
926
    { AVIFOURCC_IDIM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
927
    { AVIFOURCC_IDPI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
928
    { AVIFOURCC_IENG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
929
    { AVIFOURCC_IGNR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
930
    { AVIFOURCC_ISGN, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
931
    { AVIFOURCC_IKEY, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
932
    { AVIFOURCC_ILGT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
933
    { AVIFOURCC_IMED, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
934
    { AVIFOURCC_INAM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
935
    { AVIFOURCC_IPLT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
936
    { AVIFOURCC_IPRD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
937
    { AVIFOURCC_ISBJ, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
938
    { AVIFOURCC_ISFT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
939
    { AVIFOURCC_ISHP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
940
    { AVIFOURCC_ISRC, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
941
    { AVIFOURCC_ISRF, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
942
    { AVIFOURCC_ITCH, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
943
    { AVIFOURCC_ISMP, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
944
    { AVIFOURCC_IDIT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
945
    { AVIFOURCC_ILNG, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
946
    { AVIFOURCC_IRTD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
947
    { AVIFOURCC_IWEB, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
948
    { AVIFOURCC_IPRT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
949
    { AVIFOURCC_IWRI, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
950
    { AVIFOURCC_IPRO, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
951
    { AVIFOURCC_ICNM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
952
    { AVIFOURCC_IPDS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
953
    { AVIFOURCC_IEDT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
954
    { AVIFOURCC_ICDS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
955
    { AVIFOURCC_IMUS, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
956
    { AVIFOURCC_ISTD, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
957
    { AVIFOURCC_IDST, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
958
    { AVIFOURCC_ICNT, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
959
    { AVIFOURCC_ISTR, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
960
    { AVIFOURCC_IFRM, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
961
    { AVIFOURCC_IAS1, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
962
    { AVIFOURCC_IAS2, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
963
    { AVIFOURCC_IAS3, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
964
    { AVIFOURCC_IAS4, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
965
    { AVIFOURCC_IAS5, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
966
    { AVIFOURCC_IAS6, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
967
    { AVIFOURCC_IAS7, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
968
    { AVIFOURCC_IAS8, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
969
    { AVIFOURCC_IAS9, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
970
971
972
    { AVIFOURCC_strn, AVI_ChunkRead_strz, AVI_ChunkFree_strz },
973
    { 0,           NULL,               NULL }
974
};
975
976
static int AVI_ChunkFunctionFind( vlc_fourcc_t i_fourcc )
977
0
{
978
0
    unsigned int i_index;
979
0
    for( i_index = 0; ; i_index++ )
980
0
    {
981
0
        if( ( AVI_Chunk_Function[i_index].i_fourcc == i_fourcc )||
982
0
            ( AVI_Chunk_Function[i_index].i_fourcc == 0 ) )
983
0
        {
984
0
            return i_index;
985
0
        }
986
0
    }
987
0
}
988
989
int  AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father )
990
0
{
991
0
    int i_index;
992
993
0
    if( !p_chk )
994
0
    {
995
0
        msg_Warn( s, "cannot read null chunk" );
996
0
        return VLC_EGENERIC;
997
0
    }
998
999
0
    if( AVI_ChunkReadCommon( s, p_chk, p_father ) )
1000
0
        return VLC_EGENERIC;
1001
1002
0
    if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) )
1003
0
    {
1004
0
        msg_Warn( s, "found null fourcc chunk (corrupted file?)" );
1005
0
        return AVI_ZERO_FOURCC;
1006
0
    }
1007
0
    p_chk->common.p_father = p_father;
1008
1009
0
    i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
1010
0
    if( AVI_Chunk_Function[i_index].AVI_ChunkRead_function )
1011
0
    {
1012
0
        return AVI_Chunk_Function[i_index].AVI_ChunkRead_function( s, p_chk );
1013
0
    }
1014
0
    else if( ( ((char*)&p_chk->common.i_chunk_fourcc)[0] == 'i' &&
1015
0
               ((char*)&p_chk->common.i_chunk_fourcc)[1] == 'x' ) ||
1016
0
             ( ((char*)&p_chk->common.i_chunk_fourcc)[2] == 'i' &&
1017
0
               ((char*)&p_chk->common.i_chunk_fourcc)[3] == 'x' ) )
1018
0
    {
1019
0
        p_chk->common.i_chunk_fourcc = AVIFOURCC_indx;
1020
0
        return AVI_ChunkRead_indx( s, p_chk );
1021
0
    }
1022
1023
0
    msg_Warn( s, "unknown chunk: %4.4s (not loaded)",
1024
0
            (char*)&p_chk->common.i_chunk_fourcc );
1025
0
    return AVI_NextChunk( s, p_chk );
1026
0
}
1027
1028
void AVI_ChunkClean( stream_t *s,
1029
                     avi_chunk_t *p_chk )
1030
0
{
1031
0
    int i_index;
1032
0
    avi_chunk_t *p_child, *p_next;
1033
1034
0
    if( !p_chk )
1035
0
    {
1036
0
        return;
1037
0
    }
1038
1039
    /* Free all child chunk */
1040
0
    p_child = p_chk->common.p_first;
1041
0
    while( p_child )
1042
0
    {
1043
0
        p_next = p_child->common.p_next;
1044
0
        AVI_ChunkClean( s, p_child );
1045
0
        free( p_child );
1046
0
        p_child = p_next;
1047
0
    }
1048
1049
0
    i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
1050
0
    if( AVI_Chunk_Function[i_index].AVI_ChunkFree_function )
1051
0
    {
1052
0
#ifdef AVI_DEBUG
1053
0
        msg_Dbg( s, "free chunk %4.4s",
1054
0
                 (char*)&p_chk->common.i_chunk_fourcc );
1055
0
#endif
1056
0
        AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_chk);
1057
0
    }
1058
0
    else if( p_chk->common.i_chunk_fourcc != 0 )
1059
0
    {
1060
0
        msg_Warn( s, "unknown chunk: %4.4s (not unloaded)",
1061
0
                (char*)&p_chk->common.i_chunk_fourcc );
1062
0
    }
1063
0
    p_chk->common.p_first = NULL;
1064
1065
0
    return;
1066
0
}
1067
1068
static void AVI_ChunkDumpDebug_level( vlc_object_t *p_obj,
1069
                                      avi_chunk_t  *p_chk, unsigned i_level )
1070
0
{
1071
0
    avi_chunk_t *p_child;
1072
1073
0
    char str[512];
1074
0
    if( i_level >= (sizeof(str) - 1)/4 )
1075
0
        return;
1076
1077
0
    memset( str, ' ', sizeof( str ) );
1078
0
    for( unsigned i = 1; i < i_level; i++ )
1079
0
    {
1080
0
        str[i * 4] = '|';
1081
0
    }
1082
0
    if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF ||
1083
0
        p_chk->common.i_chunk_fourcc == AVIFOURCC_ON2  ||
1084
0
        p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST )
1085
0
    {
1086
0
        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
1087
0
                 "%c %4.4s-%4.4s size:%"PRIu64" pos:%"PRIu64,
1088
0
                 i_level ? '+' : '*',
1089
0
                 (char*)&p_chk->common.i_chunk_fourcc,
1090
0
                 (char*)&p_chk->list.i_type,
1091
0
                 p_chk->common.i_chunk_size,
1092
0
                 p_chk->common.i_chunk_pos );
1093
0
    }
1094
0
    else
1095
0
    {
1096
0
        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
1097
0
                 "+ %4.4s size:%"PRIu64" pos:%"PRIu64,
1098
0
                 (char*)&p_chk->common.i_chunk_fourcc,
1099
0
                 p_chk->common.i_chunk_size,
1100
0
                 p_chk->common.i_chunk_pos );
1101
0
    }
1102
0
    msg_Dbg( p_obj, "%s", str );
1103
1104
0
    p_child = p_chk->common.p_first;
1105
0
    while( p_child )
1106
0
    {
1107
0
        AVI_ChunkDumpDebug_level( p_obj, p_child, i_level + 1 );
1108
0
        p_child = p_child->common.p_next;
1109
0
    }
1110
0
}
1111
1112
int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root )
1113
0
{
1114
0
    avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root;
1115
0
    avi_chunk_t      *p_chk;
1116
0
    bool b_seekable;
1117
1118
0
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
1119
1120
0
    p_list->i_chunk_pos  = 0;
1121
0
    p_list->i_chunk_size = ((UINT64_MAX - 12) >> 1) << 1;
1122
0
    p_list->i_chunk_fourcc = AVIFOURCC_LIST;
1123
0
    p_list->p_father = NULL;
1124
0
    p_list->p_next  = NULL;
1125
0
    p_list->p_first = NULL;
1126
1127
0
    p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
1128
1129
0
    avi_chunk_t **pp_append = &p_root->common.p_first;
1130
0
    for( ; ; )
1131
0
    {
1132
0
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
1133
0
        if( !p_chk )
1134
0
            return VLC_EGENERIC;
1135
1136
0
        if( AVI_ChunkRead( s, p_chk, p_root ) != VLC_SUCCESS )
1137
0
        {
1138
0
            AVI_ChunkClean( s, p_chk );
1139
0
            free( p_chk );
1140
0
            break;
1141
0
        }
1142
1143
0
        *pp_append = p_chk;
1144
0
        while( *pp_append )
1145
0
            pp_append = &((*pp_append)->common.p_next);
1146
1147
0
        if( vlc_stream_Tell( s ) >=
1148
0
                 p_chk->common.p_father->common.i_chunk_pos +
1149
0
                 __EVEN( p_chk->common.p_father->common.i_chunk_size ) )
1150
0
        {
1151
0
            break;
1152
0
        }
1153
1154
        /* If we can't seek then stop when we 've found first RIFF-AVI */
1155
0
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF &&
1156
0
            p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable )
1157
0
        {
1158
0
            break;
1159
0
        }
1160
0
    }
1161
1162
0
    p_list->i_chunk_size = stream_Size( s );
1163
1164
0
    AVI_ChunkDumpDebug_level( VLC_OBJECT(s), p_root, 0 );
1165
0
    return VLC_SUCCESS;
1166
0
}
1167
1168
void AVI_ChunkFreeRoot( stream_t *s,
1169
                        avi_chunk_t  *p_chk )
1170
0
{
1171
0
    AVI_ChunkClean( s, p_chk );
1172
0
}
1173
1174
1175
int  AVI_ChunkCount_( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc, bool b_list )
1176
0
{
1177
0
    if( !p_chk )
1178
0
        return 0;
1179
1180
0
    int i_count = 0;
1181
0
    for( avi_chunk_t *p_child = p_chk->common.p_first;
1182
0
                      p_child; p_child = p_child->common.p_next )
1183
0
    {
1184
0
        if( b_list && p_child->list.i_type == 0 )
1185
0
            continue;
1186
1187
0
        if( p_child->common.i_chunk_fourcc != i_fourcc &&
1188
0
            (!b_list || p_child->list.i_type != i_fourcc) )
1189
0
            continue;
1190
1191
0
        i_count++;
1192
0
    }
1193
1194
0
    return i_count;
1195
0
}
1196
1197
void *AVI_ChunkFind_( avi_chunk_t *p_chk,
1198
                      vlc_fourcc_t i_fourcc, int i_number, bool b_list )
1199
0
{
1200
0
    if( !p_chk )
1201
0
        return NULL;
1202
1203
0
    for( avi_chunk_t *p_child = p_chk->common.p_first;
1204
0
                      p_child; p_child = p_child->common.p_next )
1205
0
    {
1206
0
        if( b_list && p_child->list.i_type == 0 )
1207
0
            continue;
1208
1209
0
        if( p_child->common.i_chunk_fourcc != i_fourcc &&
1210
0
            (!b_list || p_child->list.i_type != i_fourcc) )
1211
0
            continue;
1212
1213
0
        if( i_number-- == 0 )
1214
0
            return p_child; /* We found it */
1215
0
    }
1216
1217
0
    return NULL;
1218
0
}
1219