Coverage Report

Created: 2025-07-11 07:16

/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
2.44M
#define __EVEN( x ) (((x) + 1) & ~1)
40
41
static vlc_fourcc_t GetFOURCC( const uint8_t *p_buff )
42
911k
{
43
911k
    return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
44
911k
}
45
46
static uint64_t AVI_ChunkSize( const avi_chunk_t *p_ck )
47
1.52M
{
48
1.52M
    return __EVEN(p_ck->common.i_chunk_size) + 8;
49
1.52M
}
50
51
static uint64_t AVI_ChunkEnd( const avi_chunk_t *p_ck )
52
1.52M
{
53
1.52M
    return p_ck->common.i_chunk_pos + AVI_ChunkSize( p_ck );
54
1.52M
}
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
541k
{
64
541k
    const uint8_t *p_peek;
65
66
541k
    memset( p_chk, 0, sizeof( avi_chunk_t ) );
67
68
541k
    const uint64_t i_pos = vlc_stream_Tell( s );
69
541k
    if( vlc_stream_Peek( s, &p_peek, 8 ) < 8 )
70
32.7k
    {
71
32.7k
        if( stream_Size( s ) > 0 && (uint64_t) stream_Size( s ) > i_pos )
72
32.7k
            msg_Warn( s, "can't peek at %"PRIu64, i_pos );
73
31.6k
        else
74
32.7k
            msg_Dbg( s, "no more data at %"PRIu64, i_pos );
75
32.7k
        return VLC_EGENERIC;
76
32.7k
    }
77
78
509k
    p_chk->common.i_chunk_fourcc = GetFOURCC( p_peek );
79
509k
    p_chk->common.i_chunk_size   = GetDWLE( p_peek + 4 );
80
509k
    p_chk->common.i_chunk_pos    = i_pos;
81
82
509k
    if( p_chk->common.i_chunk_size >= UINT64_MAX - 8 ||
83
509k
        p_chk->common.i_chunk_pos > UINT64_MAX - 8 ||
84
509k
        UINT64_MAX - p_chk->common.i_chunk_pos - 8 < __EVEN(p_chk->common.i_chunk_size) )
85
0
        return VLC_EGENERIC;
86
87
509k
    if( p_father && AVI_ChunkEnd( p_chk ) > AVI_ChunkEnd( p_father ) )
88
70.9k
    {
89
70.9k
        msg_Warn( s, "chunk %4.4s does not fit into parent %"PRIu64,
90
70.9k
                  (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
70.9k
        if( p_father->common.i_chunk_fourcc != AVIFOURCC_RIFF ||
94
70.9k
            p_father->common.p_father == NULL ||
95
70.9k
            p_father->common.p_father->common.p_father != NULL ) /* Root > RIFF only */
96
53.3k
            return VLC_EGENERIC;
97
70.9k
    }
98
99
455k
#ifdef AVI_DEBUG
100
455k
    msg_Dbg( s,
101
455k
             "found chunk, fourcc: %4.4s size:%"PRIu64" pos:%"PRIu64,
102
455k
             (char*)&p_chk->common.i_chunk_fourcc,
103
455k
             p_chk->common.i_chunk_size,
104
455k
             p_chk->common.i_chunk_pos );
105
455k
#endif
106
455k
    return VLC_SUCCESS;
107
509k
}
108
109
static int AVI_GotoNextChunk( stream_t *s, const avi_chunk_t *p_chk )
110
101k
{
111
101k
    bool b_seekable = false;
112
101k
    const uint64_t i_offset = AVI_ChunkEnd( p_chk );
113
101k
    if ( !vlc_stream_Control(s, STREAM_CAN_SEEK, &b_seekable) && b_seekable )
114
101k
    {
115
101k
        return vlc_stream_Seek( s, i_offset );
116
101k
    }
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
94.1k
{
125
94.1k
    avi_chunk_t chk;
126
127
94.1k
    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
94.1k
    return AVI_GotoNextChunk( s, p_chk );
137
94.1k
}
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
176k
{
146
176k
    avi_chunk_t *p_chk;
147
176k
    const uint8_t *p_peek;
148
176k
    bool b_seekable;
149
176k
    int i_ret = VLC_SUCCESS;
150
151
176k
    if( p_container->common.i_chunk_size > 0 && p_container->common.i_chunk_size < 4 )
152
52
    {
153
        /* empty box */
154
52
        msg_Warn( s, "empty list chunk" );
155
52
        return VLC_EGENERIC;
156
52
    }
157
176k
    if( vlc_stream_Peek( s, &p_peek, 12 ) < 12 )
158
428
    {
159
428
        msg_Warn( s, "unexpected end of file while reading list chunk" );
160
428
        return VLC_EGENERIC;
161
428
    }
162
163
176k
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
164
165
176k
    p_container->list.i_type = GetFOURCC( p_peek + 8 );
166
167
    /* XXX fixed for on2 hack */
168
176k
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_ON2 && p_container->list.i_type == AVIFOURCC_ON2f )
169
779
    {
170
779
        p_container->common.i_chunk_fourcc = AVIFOURCC_RIFF;
171
779
        p_container->list.i_type = AVIFOURCC_AVI;
172
779
    }
173
174
176k
    if( p_container->common.i_chunk_fourcc == AVIFOURCC_LIST &&
175
176k
        p_container->list.i_type == AVIFOURCC_movi )
176
23.1k
    {
177
23.1k
        if( !b_seekable )
178
0
            return VLC_SUCCESS;
179
23.1k
        msg_Dbg( s, "skipping movi chunk" );
180
23.1k
        return AVI_NextChunk( s, p_container ); /* points at beginning of LIST-movi if not seekable */
181
23.1k
    }
182
183
153k
    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
153k
#ifdef AVI_DEBUG
190
153k
    msg_Dbg( s,
191
153k
             "found LIST chunk: \'%4.4s\'",
192
153k
             (char*)&p_container->list.i_type );
193
153k
#endif
194
153k
    msg_Dbg( s, "<list \'%4.4s\'>", (char*)&p_container->list.i_type );
195
196
153k
    avi_chunk_t **pp_append = &p_container->common.p_first;
197
153k
    for( ; ; )
198
487k
    {
199
487k
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
200
487k
        if( !p_chk )
201
0
            return VLC_EGENERIC;
202
203
487k
        i_ret = AVI_ChunkRead( s, p_chk, p_container );
204
487k
        if( i_ret )
205
113k
        {
206
113k
            AVI_ChunkClean( s, p_chk );
207
113k
            free( p_chk );
208
113k
            p_chk = NULL;
209
113k
            if( i_ret != AVI_ZEROSIZED_CHUNK )
210
112k
                break;
211
113k
        }
212
213
375k
        if( p_chk )
214
374k
        {
215
374k
            *pp_append = p_chk;
216
749k
            while( *pp_append )
217
374k
                pp_append = &((*pp_append)->common.p_next);
218
374k
        }
219
220
375k
        if( p_container->common.i_chunk_size > 0 &&
221
375k
            vlc_stream_Tell( s ) >= AVI_ChunkEnd( p_container ) )
222
40.7k
        {
223
40.7k
            break;
224
40.7k
        }
225
226
        /* If we can't seek then stop when we 've found LIST-movi */
227
334k
        if( p_chk &&
228
334k
            p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST &&
229
334k
            p_chk->list.i_type == AVIFOURCC_movi &&
230
334k
            ( !b_seekable || p_chk->common.i_chunk_size == 0 ) )
231
99
        {
232
99
            break;
233
99
        }
234
235
334k
    }
236
153k
    msg_Dbg( s, "</list \'%4.4s\'>%x", (char*)&p_container->list.i_type, i_ret );
237
238
153k
    if( i_ret == AVI_ZERO_FOURCC || i_ret == AVI_ZEROSIZED_CHUNK )
239
7.38k
        return AVI_GotoNextChunk( s, p_container );
240
241
145k
    return VLC_SUCCESS;
242
153k
}
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
200k
    int64_t i_read = __EVEN(p_chk->common.i_chunk_size ) + 8; \
304
200k
    if( i_read > 100000000 ) \
305
200k
    { \
306
2.58k
        msg_Err( s, "Big chunk ignored" ); \
307
2.58k
        return VLC_EGENERIC; \
308
2.58k
    } \
309
200k
    uint8_t  *p_read, *p_buff;    \
310
197k
    if( !( p_read = p_buff = malloc(i_read ) ) ) \
311
197k
    { \
312
0
        return VLC_EGENERIC; \
313
0
    } \
314
197k
    i_read = vlc_stream_Read( s, p_read, i_read ); \
315
197k
    if( i_read < (int64_t)__EVEN(p_chk->common.i_chunk_size ) + 8 ) \
316
197k
    { \
317
2.57k
        free( p_buff ); \
318
2.57k
        return VLC_EGENERIC; \
319
2.57k
    }\
320
197k
    p_read += 8; \
321
195k
    i_read -= 8
322
323
#define AVI_READ( res, func, size ) \
324
12.5M
    if( i_read < size ) { \
325
14.5k
        free( p_buff); \
326
14.5k
        return VLC_EGENERIC; \
327
14.5k
    } \
328
12.5M
    i_read -= size; \
329
12.5M
    res = func( p_read ); \
330
12.5M
    p_read += size \
331
332
#define AVI_READCHUNK_EXIT( code ) \
333
180k
    do { \
334
180k
        free( p_buff ); \
335
180k
        return code; \
336
180k
    } while(0)
337
338
static inline uint8_t GetB( uint8_t *ptr )
339
37.2k
{
340
37.2k
    return *ptr;
341
37.2k
}
342
343
#define AVI_READ1BYTE( i_byte ) \
344
37.5k
    AVI_READ( i_byte, GetB, 1 )
345
346
#define AVI_READ2BYTES( i_word ) \
347
155k
    AVI_READ( i_word, GetWLE, 2 )
348
349
#define AVI_READ4BYTES( i_dword ) \
350
8.73M
    AVI_READ( i_dword, GetDWLE, 4 )
351
352
#define AVI_READ8BYTES( i_qword ) \
353
3.43M
    AVI_READ( i_qword, GetQWLE, 8 )
354
355
#define AVI_READFOURCC( i_dword ) \
356
227k
    AVI_READ( i_dword, GetFOURCC, 4 )
357
358
static int AVI_ChunkRead_avih( stream_t *s, avi_chunk_t *p_chk )
359
35.3k
{
360
104k
    AVI_READCHUNK_ENTER;
361
362
104k
    p_chk->common.i_chunk_fourcc = AVIFOURCC_avih;
363
104k
    AVI_READ4BYTES( p_chk->avih.i_microsecperframe);
364
34.3k
    AVI_READ4BYTES( p_chk->avih.i_maxbytespersec );
365
34.1k
    AVI_READ4BYTES( p_chk->avih.i_reserved1 );
366
33.6k
    AVI_READ4BYTES( p_chk->avih.i_flags );
367
33.6k
    AVI_READ4BYTES( p_chk->avih.i_totalframes );
368
33.0k
    AVI_READ4BYTES( p_chk->avih.i_initialframes );
369
32.7k
    AVI_READ4BYTES( p_chk->avih.i_streams );
370
32.6k
    AVI_READ4BYTES( p_chk->avih.i_suggestedbuffersize );
371
32.3k
    AVI_READ4BYTES( p_chk->avih.i_width );
372
32.3k
    AVI_READ4BYTES( p_chk->avih.i_height );
373
32.2k
    AVI_READ4BYTES( p_chk->avih.i_scale );
374
31.9k
    AVI_READ4BYTES( p_chk->avih.i_rate );
375
31.7k
    AVI_READ4BYTES( p_chk->avih.i_start );
376
31.4k
    AVI_READ4BYTES( p_chk->avih.i_length );
377
31.1k
#ifdef AVI_DEBUG
378
31.1k
    msg_Dbg( s,
379
31.1k
             "avih: streams:%d flags:%s%s%s%s %dx%d",
380
31.1k
             p_chk->avih.i_streams,
381
31.1k
             p_chk->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
382
31.1k
             p_chk->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
383
31.1k
             p_chk->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
384
31.1k
             p_chk->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
385
31.1k
             p_chk->avih.i_width, p_chk->avih.i_height );
386
31.1k
#endif
387
31.1k
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
388
31.1k
}
389
390
static int AVI_ChunkRead_strh( stream_t *s, avi_chunk_t *p_chk )
391
53.3k
{
392
158k
    AVI_READCHUNK_ENTER;
393
394
158k
    AVI_READFOURCC( p_chk->strh.i_type );
395
52.5k
    AVI_READFOURCC( p_chk->strh.i_handler );
396
52.2k
    AVI_READ4BYTES( p_chk->strh.i_flags );
397
52.1k
    AVI_READ4BYTES( p_chk->strh.i_reserved1 );
398
51.8k
    AVI_READ4BYTES( p_chk->strh.i_initialframes );
399
51.3k
    AVI_READ4BYTES( p_chk->strh.i_scale );
400
51.1k
    AVI_READ4BYTES( p_chk->strh.i_rate );
401
50.9k
    AVI_READ4BYTES( p_chk->strh.i_start );
402
50.8k
    AVI_READ4BYTES( p_chk->strh.i_length );
403
50.7k
    AVI_READ4BYTES( p_chk->strh.i_suggestedbuffersize );
404
50.4k
    AVI_READ4BYTES( p_chk->strh.i_quality );
405
50.2k
    AVI_READ4BYTES( p_chk->strh.i_samplesize );
406
49.9k
#ifdef AVI_DEBUG
407
49.9k
    msg_Dbg( s,
408
49.9k
             "strh: type:%4.4s handler:0x%8.8x samplesize:%d %.2ffps",
409
49.9k
             (char*)&p_chk->strh.i_type,
410
49.9k
             p_chk->strh.i_handler,
411
49.9k
             p_chk->strh.i_samplesize,
412
49.9k
             ( p_chk->strh.i_scale ?
413
49.9k
                (float)p_chk->strh.i_rate / (float)p_chk->strh.i_scale : -1) );
414
49.9k
#endif
415
416
49.9k
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
417
49.9k
}
418
419
static int AVI_ChunkRead_strf( stream_t *s, avi_chunk_t *p_chk )
420
62.4k
{
421
62.4k
    avi_chunk_t *p_strh;
422
423
186k
    AVI_READCHUNK_ENTER;
424
186k
    if( p_chk->common.p_father == NULL )
425
1
    {
426
1
        msg_Err( s, "malformed avi file" );
427
1
        AVI_READCHUNK_EXIT( VLC_EGENERIC );
428
1
    }
429
61.8k
    if( !( p_strh = AVI_ChunkFind( p_chk->common.p_father, AVIFOURCC_strh, 0, false ) ) )
430
11.9k
    {
431
11.9k
        msg_Err( s, "malformed avi file" );
432
11.9k
        AVI_READCHUNK_EXIT( p_chk->common.i_chunk_size > 0  ? VLC_EGENERIC : AVI_ZEROSIZED_CHUNK );
433
11.9k
    }
434
435
49.8k
    switch( p_strh->strh.i_type )
436
49.8k
    {
437
23.0k
        case( AVIFOURCC_auds ):
438
23.0k
            p_chk->strf.auds.i_cat = AUDIO_ES;
439
23.0k
            p_chk->strf.auds.p_wf = malloc( __MAX( p_chk->common.i_chunk_size, sizeof( WAVEFORMATEX ) ) );
440
23.0k
            if ( !p_chk->strf.auds.p_wf )
441
0
            {
442
0
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
443
0
            }
444
45.8k
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wFormatTag );
445
45.8k
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nChannels );
446
22.5k
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nSamplesPerSec );
447
22.2k
            AVI_READ4BYTES( p_chk->strf.auds.p_wf->nAvgBytesPerSec );
448
21.9k
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->nBlockAlign );
449
21.9k
            AVI_READ2BYTES( p_chk->strf.auds.p_wf->wBitsPerSample );
450
451
21.8k
            if( p_chk->strf.auds.p_wf->wFormatTag != WAVE_FORMAT_PCM
452
21.8k
                 && p_chk->common.i_chunk_size > sizeof( WAVEFORMATEX ) )
453
452
            {
454
452
                AVI_READ2BYTES( p_chk->strf.auds.p_wf->cbSize );
455
456
                /* prevent segfault */
457
452
                if( p_chk->strf.auds.p_wf->cbSize >
458
452
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX ) )
459
243
                {
460
243
                    p_chk->strf.auds.p_wf->cbSize =
461
243
                        p_chk->common.i_chunk_size - sizeof( WAVEFORMATEX );
462
243
                }
463
464
452
                if( p_chk->strf.auds.p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
465
70
                {
466
70
                    msg_Dbg( s, "Extended header found" );
467
70
                }
468
452
            }
469
21.4k
            else
470
21.4k
            {
471
21.4k
                p_chk->strf.auds.p_wf->cbSize = 0;
472
21.4k
            }
473
21.8k
            if( p_chk->strf.auds.p_wf->cbSize > 0 )
474
393
            {
475
393
                memcpy( &p_chk->strf.auds.p_wf[1] ,
476
393
                        p_buff + 8 + sizeof( WAVEFORMATEX ),    /*  8=fourcc+size */
477
393
                        p_chk->strf.auds.p_wf->cbSize );
478
393
            }
479
21.8k
#ifdef AVI_DEBUG
480
21.8k
            msg_Dbg( s,
481
21.8k
                     "strf: audio:0x%4.4x channels:%d %dHz %dbits/sample %dkbps",
482
21.8k
                     p_chk->strf.auds.p_wf->wFormatTag,
483
21.8k
                     p_chk->strf.auds.p_wf->nChannels,
484
21.8k
                     p_chk->strf.auds.p_wf->nSamplesPerSec,
485
21.8k
                     p_chk->strf.auds.p_wf->wBitsPerSample,
486
21.8k
                     p_chk->strf.auds.p_wf->nAvgBytesPerSec * 8 / 1000 );
487
21.8k
#endif
488
21.8k
            break;
489
23.4k
        case( AVIFOURCC_vids ):
490
23.4k
            p_strh->strh.i_samplesize = 0; /* XXX for ffmpeg avi file */
491
23.4k
            p_chk->strf.vids.i_cat = VIDEO_ES;
492
23.4k
            p_chk->strf.vids.p_bih = malloc( __MAX( p_chk->common.i_chunk_size,
493
23.4k
                                         sizeof( *p_chk->strf.vids.p_bih ) ) );
494
23.4k
            if ( !p_chk->strf.vids.p_bih )
495
0
            {
496
0
                AVI_READCHUNK_EXIT( VLC_ENOMEM );
497
0
            }
498
46.6k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSize );
499
46.6k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biWidth );
500
23.1k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biHeight );
501
22.8k
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biPlanes );
502
22.8k
            AVI_READ2BYTES( p_chk->strf.vids.p_bih->biBitCount );
503
22.8k
            AVI_READFOURCC( p_chk->strf.vids.p_bih->biCompression );
504
21.5k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biSizeImage );
505
21.5k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biXPelsPerMeter );
506
21.5k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biYPelsPerMeter );
507
21.5k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrUsed );
508
21.5k
            AVI_READ4BYTES( p_chk->strf.vids.p_bih->biClrImportant );
509
21.4k
            if( p_chk->strf.vids.p_bih->biSize > p_chk->common.i_chunk_size )
510
10.0k
            {
511
10.0k
                p_chk->strf.vids.p_bih->biSize = p_chk->common.i_chunk_size;
512
10.0k
            }
513
21.4k
            if ( p_chk->common.i_chunk_size > sizeof(VLC_BITMAPINFOHEADER) )
514
8.03k
            {
515
8.03k
                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
8.03k
                memcpy( &p_chk->strf.vids.p_bih[1],
519
8.03k
                        p_buff + 8 + sizeof(VLC_BITMAPINFOHEADER), /* 8=fourrc+size */
520
8.03k
                        i_extrasize );
521
522
8.03k
                if ( !p_chk->strf.vids.p_bih->biClrUsed )
523
1.12k
                {
524
1.12k
                    if( p_chk->strf.vids.p_bih->biBitCount < 32 )
525
609
                        p_chk->strf.vids.p_bih->biClrUsed = (1 << p_chk->strf.vids.p_bih->biBitCount);
526
520
                    else
527
520
                        p_chk->strf.vids.p_bih->biBitCount = UINT16_MAX;
528
1.12k
                }
529
530
8.03k
                if( i_extrasize / sizeof(uint32_t) > UINT32_MAX )
531
0
                    p_chk->strf.vids.p_bih->biClrUsed = UINT32_MAX;
532
8.03k
                else
533
8.03k
                {
534
8.03k
                    p_chk->strf.vids.p_bih->biClrUsed =
535
8.03k
                            __MIN( i_extrasize / sizeof(uint32_t),
536
8.03k
                                   p_chk->strf.vids.p_bih->biClrUsed );
537
8.03k
                }
538
539
                /* stay within VLC's limits */
540
8.03k
                p_chk->strf.vids.p_bih->biClrUsed =
541
8.03k
                    __MIN( VIDEO_PALETTE_COLORS_MAX, p_chk->strf.vids.p_bih->biClrUsed );
542
8.03k
            }
543
13.4k
            else p_chk->strf.vids.p_bih->biClrUsed = 0;
544
21.4k
#ifdef AVI_DEBUG
545
21.4k
            msg_Dbg( s,
546
21.4k
                     "strf: video:%4.4s %"PRIu32"x%"PRIu32" planes:%d %dbpp",
547
21.4k
                     (char*)&p_chk->strf.vids.p_bih->biCompression,
548
21.4k
                     (uint32_t)p_chk->strf.vids.p_bih->biWidth,
549
21.4k
                     p_chk->strf.vids.p_bih->biHeight <= INT32_MAX ? p_chk->strf.vids.p_bih->biHeight
550
21.4k
                                                                   : -1 * p_chk->strf.vids.p_bih->biHeight,
551
21.4k
                     p_chk->strf.vids.p_bih->biPlanes,
552
21.4k
                     p_chk->strf.vids.p_bih->biBitCount );
553
21.4k
#endif
554
21.4k
            break;
555
313
        case AVIFOURCC_iavs:
556
1.83k
        case AVIFOURCC_ivas:
557
1.83k
            p_chk->strf.common.i_cat = UNKNOWN_ES;
558
1.83k
            break;
559
304
        case( AVIFOURCC_txts ):
560
304
            p_chk->strf.common.i_cat = SPU_ES;
561
304
            break;
562
1.22k
        default:
563
1.22k
            msg_Warn( s, "unknown stream type: %4.4s",
564
1.22k
                    (char*)&p_strh->strh.i_type );
565
1.22k
            p_chk->strf.common.i_cat = UNKNOWN_ES;
566
1.22k
            break;
567
49.8k
    }
568
46.7k
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
569
46.7k
}
570
static void AVI_ChunkFree_strf( avi_chunk_t *p_chk )
571
63.7k
{
572
63.7k
    avi_chunk_strf_t *p_strf = (avi_chunk_strf_t*)p_chk;
573
63.7k
    if( p_strf->common.i_cat == AUDIO_ES )
574
23.0k
    {
575
23.0k
        FREENULL( p_strf->auds.p_wf );
576
23.0k
    }
577
40.6k
    else if( p_strf->common.i_cat == VIDEO_ES )
578
23.4k
    {
579
23.4k
        FREENULL( p_strf->vids.p_bih );
580
23.4k
    }
581
63.7k
}
582
583
static int AVI_ChunkRead_strd( stream_t *s, avi_chunk_t *p_chk )
584
903
{
585
1.86k
    AVI_READCHUNK_ENTER;
586
1.86k
    if ( p_chk->common.i_chunk_size == 0 )
587
328
    {
588
328
        msg_Dbg( s, "Zero sized pre-JUNK section met" );
589
328
        AVI_READCHUNK_EXIT(AVI_ZEROSIZED_CHUNK);
590
328
    }
591
592
193
    p_chk->strd.p_data = malloc( p_chk->common.i_chunk_size );
593
193
    if( p_chk->strd.p_data )
594
193
        memcpy( p_chk->strd.p_data, p_buff + 8, p_chk->common.i_chunk_size );
595
193
    AVI_READCHUNK_EXIT( p_chk->strd.p_data ? VLC_SUCCESS : VLC_EGENERIC );
596
193
}
597
598
static void AVI_ChunkFree_strd( avi_chunk_t *p_chk )
599
1.05k
{
600
1.05k
    free( p_chk->strd.p_data );
601
1.05k
}
602
603
static int AVI_ChunkRead_idx1( stream_t *s, avi_chunk_t *p_chk )
604
2.38k
{
605
2.38k
    unsigned int i_count, i_index;
606
607
6.00k
    AVI_READCHUNK_ENTER;
608
609
6.00k
    i_count = __MIN( (int64_t)p_chk->common.i_chunk_size, i_read ) / 16;
610
611
6.00k
    p_chk->idx1.i_entry_count = i_count;
612
6.00k
    p_chk->idx1.i_entry_max   = i_count;
613
6.00k
    if( i_count > 0 )
614
1.41k
    {
615
1.41k
        p_chk->idx1.entry = calloc( i_count, sizeof( idx1_entry_t ) );
616
1.41k
        if( !p_chk->idx1.entry )
617
0
            AVI_READCHUNK_EXIT( VLC_EGENERIC );
618
619
101k
        for( i_index = 0; i_index < i_count ; i_index++ )
620
99.8k
        {
621
99.8k
            AVI_READFOURCC( p_chk->idx1.entry[i_index].i_fourcc );
622
99.8k
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_flags );
623
99.8k
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_pos );
624
99.8k
            AVI_READ4BYTES( p_chk->idx1.entry[i_index].i_length );
625
99.8k
        }
626
1.41k
    }
627
367
    else
628
367
    {
629
367
        p_chk->idx1.entry = NULL;
630
367
    }
631
1.78k
#ifdef AVI_DEBUG
632
1.78k
    msg_Dbg( s, "idx1: index entry:%d", i_count );
633
1.78k
#endif
634
1.78k
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
635
1.78k
}
636
637
static void AVI_ChunkFree_idx1( avi_chunk_t *p_chk )
638
2.74k
{
639
2.74k
    p_chk->idx1.i_entry_count = 0;
640
2.74k
    p_chk->idx1.i_entry_max   = 0;
641
2.74k
    FREENULL( p_chk->idx1.entry );
642
2.74k
}
643
644
645
646
static int AVI_ChunkRead_indx( stream_t *s, avi_chunk_t *p_chk )
647
19.9k
{
648
19.9k
    unsigned int i_count, i;
649
19.9k
    int          i_ret = VLC_SUCCESS;
650
19.9k
    int32_t      i_dummy;
651
19.9k
    VLC_UNUSED(i_dummy);
652
19.9k
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
653
654
58.5k
    AVI_READCHUNK_ENTER;
655
656
58.5k
    AVI_READ2BYTES( p_indx->i_longsperentry );
657
18.9k
    AVI_READ1BYTE ( p_indx->i_indexsubtype );
658
18.6k
    AVI_READ1BYTE ( p_indx->i_indextype );
659
18.6k
    AVI_READ4BYTES( p_indx->i_entriesinuse );
660
661
18.5k
    AVI_READ4BYTES( p_indx->i_id );
662
18.3k
    p_indx->idx.std     = NULL;
663
18.3k
    p_indx->idx.field   = NULL;
664
18.3k
    p_indx->idx.super   = NULL;
665
666
18.3k
    if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == 0 )
667
1.30k
    {
668
1.30k
        AVI_READ8BYTES( p_indx->i_baseoffset );
669
991
        AVI_READ4BYTES( i_dummy );
670
671
972
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 8 );
672
972
        p_indx->i_entriesinuse = i_count;
673
972
        p_indx->idx.std = calloc( i_count, sizeof( indx_std_entry_t ) );
674
972
        if( i_count == 0 || p_indx->idx.std )
675
972
        {
676
100k
            for( i = 0; i < i_count; i++ )
677
99.5k
            {
678
99.5k
                AVI_READ4BYTES( p_indx->idx.std[i].i_offset );
679
99.5k
                AVI_READ4BYTES( p_indx->idx.std[i].i_size );
680
99.5k
            }
681
972
        }
682
0
        else i_ret = VLC_EGENERIC;
683
972
    }
684
17.0k
    else if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS && p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
685
904
    {
686
904
        AVI_READ8BYTES( p_indx->i_baseoffset );
687
538
        AVI_READ4BYTES( i_dummy );
688
689
497
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 12 );
690
497
        p_indx->i_entriesinuse = i_count;
691
497
        p_indx->idx.field = calloc( i_count, sizeof( indx_field_entry_t ) );
692
497
        if( i_count == 0 || p_indx->idx.field )
693
497
        {
694
20.9k
            for( i = 0; i < i_count; i++ )
695
20.4k
            {
696
20.4k
                AVI_READ4BYTES( p_indx->idx.field[i].i_offset );
697
20.4k
                AVI_READ4BYTES( p_indx->idx.field[i].i_size );
698
20.4k
                AVI_READ4BYTES( p_indx->idx.field[i].i_offsetfield2 );
699
20.4k
            }
700
497
        }
701
0
        else i_ret = VLC_EGENERIC;
702
497
    }
703
16.1k
    else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
704
15.2k
    {
705
15.2k
        p_indx->i_baseoffset = 0;
706
15.2k
        AVI_READ4BYTES( i_dummy );
707
15.1k
        AVI_READ4BYTES( i_dummy );
708
14.9k
        AVI_READ4BYTES( i_dummy );
709
710
14.8k
        i_count = __MIN( p_indx->i_entriesinuse, i_read / 16 );
711
14.8k
        p_indx->i_entriesinuse = i_count;
712
14.8k
        p_indx->idx.super = calloc( i_count, sizeof( indx_super_entry_t ) );
713
14.8k
        if( i_count == 0 || p_indx->idx.super )
714
14.8k
        {
715
3.44M
            for( i = 0; i < i_count; i++ )
716
3.42M
            {
717
3.42M
                AVI_READ8BYTES( p_indx->idx.super[i].i_offset );
718
3.42M
                AVI_READ4BYTES( p_indx->idx.super[i].i_size );
719
3.42M
                AVI_READ4BYTES( p_indx->idx.super[i].i_duration );
720
3.42M
            }
721
14.8k
        }
722
0
        else i_ret = VLC_EGENERIC;
723
14.8k
    }
724
852
    else
725
852
    {
726
852
        msg_Warn( s, "unknown type/subtype index" );
727
852
    }
728
729
17.1k
#ifdef AVI_DEBUG
730
17.1k
    msg_Dbg( s, "indx: type=%d subtype=%d entry=%d",
731
17.1k
             p_indx->i_indextype, p_indx->i_indexsubtype, p_indx->i_entriesinuse );
732
17.1k
#endif
733
17.1k
    AVI_READCHUNK_EXIT( i_ret );
734
17.1k
}
735
static void AVI_ChunkFree_indx( avi_chunk_t *p_chk )
736
19.9k
{
737
19.9k
    avi_chunk_indx_t *p_indx = (avi_chunk_indx_t*)p_chk;
738
739
19.9k
    FREENULL( p_indx->idx.std );
740
19.9k
    FREENULL( p_indx->idx.field );
741
19.9k
    FREENULL( p_indx->idx.super );
742
19.9k
}
743
744
static int AVI_ChunkRead_vprp( stream_t *s, avi_chunk_t *p_chk )
745
3.64k
{
746
3.64k
    avi_chunk_vprp_t *p_vprp = (avi_chunk_vprp_t*)p_chk;
747
748
10.0k
    AVI_READCHUNK_ENTER;
749
750
10.0k
    AVI_READ4BYTES( p_vprp->i_video_format_token );
751
3.07k
    AVI_READ4BYTES( p_vprp->i_video_standard );
752
3.02k
    AVI_READ4BYTES( p_vprp->i_vertical_refresh );
753
2.95k
    AVI_READ4BYTES( p_vprp->i_h_total_in_t );
754
2.61k
    AVI_READ4BYTES( p_vprp->i_v_total_in_lines );
755
2.39k
    AVI_READ4BYTES( p_vprp->i_frame_aspect_ratio );
756
2.29k
    AVI_READ4BYTES( p_vprp->i_frame_width_in_pixels );
757
2.04k
    AVI_READ4BYTES( p_vprp->i_frame_height_in_pixels );
758
1.96k
    AVI_READ4BYTES( p_vprp->i_nb_fields_per_frame );
759
2.22k
    for( unsigned i = 0; i < __MIN( p_vprp->i_nb_fields_per_frame, 2 ); i++ )
760
1.73k
    {
761
1.73k
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_height );
762
1.52k
        AVI_READ4BYTES( p_vprp->field_info[i].i_compressed_bm_width );
763
1.47k
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_height );
764
1.24k
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_width );
765
1.11k
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_x_offset );
766
867
        AVI_READ4BYTES( p_vprp->field_info[i].i_valid_bm_y_offset );
767
601
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_x_offset_in_t );
768
535
        AVI_READ4BYTES( p_vprp->field_info[i].i_video_y_valid_start_line );
769
482
    }
770
771
485
#ifdef AVI_DEBUG
772
485
    msg_Dbg( s, "vprp: format:%d standard:%d",
773
485
             p_vprp->i_video_format_token, p_vprp->i_video_standard );
774
485
#endif
775
485
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
776
485
}
777
778
static int AVI_ChunkRead_dmlh( stream_t *s, avi_chunk_t *p_chk )
779
1.54k
{
780
1.54k
    avi_chunk_dmlh_t *p_dmlh = (avi_chunk_dmlh_t*)p_chk;
781
782
3.34k
    AVI_READCHUNK_ENTER;
783
784
3.34k
    AVI_READ4BYTES( p_dmlh->dwTotalFrames );
785
786
611
#ifdef AVI_DEBUG
787
611
    msg_Dbg( s, "dmlh: dwTotalFrames %d",
788
611
             p_dmlh->dwTotalFrames );
789
611
#endif
790
611
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
791
611
}
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
20.8k
{
853
20.8k
    int i_index;
854
20.8k
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
855
61.4k
    AVI_READCHUNK_ENTER;
856
857
399k
    for( i_index = 0;; i_index++)
858
419k
    {
859
419k
        if( !AVI_strz_type[i_index].i_fourcc ||
860
419k
            AVI_strz_type[i_index].i_fourcc == p_strz->i_chunk_fourcc )
861
20.3k
        {
862
20.3k
            break;
863
20.3k
        }
864
419k
    }
865
61.4k
    p_strz->p_type = strdup( AVI_strz_type[i_index].psz_type );
866
61.4k
    p_strz->p_str = malloc( p_strz->i_chunk_size + 1 );
867
61.4k
    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
20.3k
    memcpy( p_strz->p_str, p_read, p_strz->i_chunk_size );
874
20.3k
    p_strz->p_str[p_strz->i_chunk_size] = 0;
875
876
20.3k
#ifdef AVI_DEBUG
877
20.3k
    msg_Dbg( s, "%4.4s: %s : %s",
878
20.3k
             (char*)&p_strz->i_chunk_fourcc, p_strz->p_type, p_strz->p_str);
879
20.3k
#endif
880
20.3k
    AVI_READCHUNK_EXIT( VLC_SUCCESS );
881
20.3k
}
882
static void AVI_ChunkFree_strz( avi_chunk_t *p_chk )
883
29.0k
{
884
29.0k
    avi_chunk_STRING_t *p_strz = (avi_chunk_STRING_t*)p_chk;
885
29.0k
    FREENULL( p_strz->p_type );
886
29.0k
    FREENULL( p_strz->p_str );
887
29.0k
}
888
889
static int AVI_ChunkRead_nothing( stream_t *s, avi_chunk_t *p_chk )
890
15.6k
{
891
15.6k
    return AVI_NextChunk( s, p_chk );
892
15.6k
}
893
static void AVI_ChunkFree_nothing( avi_chunk_t *p_chk )
894
334k
{
895
334k
    VLC_UNUSED( p_chk );
896
334k
}
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
1.00M
{
978
1.00M
    unsigned int i_index;
979
15.8M
    for( i_index = 0; ; i_index++ )
980
16.8M
    {
981
16.8M
        if( ( AVI_Chunk_Function[i_index].i_fourcc == i_fourcc )||
982
16.8M
            ( AVI_Chunk_Function[i_index].i_fourcc == 0 ) )
983
1.00M
        {
984
1.00M
            return i_index;
985
1.00M
        }
986
16.8M
    }
987
1.00M
}
988
989
int  AVI_ChunkRead( stream_t *s, avi_chunk_t *p_chk, avi_chunk_t *p_father )
990
541k
{
991
541k
    int i_index;
992
993
541k
    if( !p_chk )
994
0
    {
995
0
        msg_Warn( s, "cannot read null chunk" );
996
0
        return VLC_EGENERIC;
997
0
    }
998
999
541k
    if( AVI_ChunkReadCommon( s, p_chk, p_father ) )
1000
86.1k
        return VLC_EGENERIC;
1001
1002
455k
    if( p_chk->common.i_chunk_fourcc == VLC_FOURCC( 0, 0, 0, 0 ) )
1003
7.50k
    {
1004
7.50k
        msg_Warn( s, "found null fourcc chunk (corrupted file?)" );
1005
7.50k
        return AVI_ZERO_FOURCC;
1006
7.50k
    }
1007
448k
    p_chk->common.p_father = p_father;
1008
1009
448k
    i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
1010
448k
    if( AVI_Chunk_Function[i_index].AVI_ChunkRead_function )
1011
374k
    {
1012
374k
        return AVI_Chunk_Function[i_index].AVI_ChunkRead_function( s, p_chk );
1013
374k
    }
1014
73.7k
    else if( ( ((char*)&p_chk->common.i_chunk_fourcc)[0] == 'i' &&
1015
73.7k
               ((char*)&p_chk->common.i_chunk_fourcc)[1] == 'x' ) ||
1016
73.7k
             ( ((char*)&p_chk->common.i_chunk_fourcc)[2] == 'i' &&
1017
57.5k
               ((char*)&p_chk->common.i_chunk_fourcc)[3] == 'x' ) )
1018
18.4k
    {
1019
18.4k
        p_chk->common.i_chunk_fourcc = AVIFOURCC_indx;
1020
18.4k
        return AVI_ChunkRead_indx( s, p_chk );
1021
18.4k
    }
1022
1023
55.3k
    msg_Warn( s, "unknown chunk: %4.4s (not loaded)",
1024
55.3k
            (char*)&p_chk->common.i_chunk_fourcc );
1025
55.3k
    return AVI_NextChunk( s, p_chk );
1026
448k
}
1027
1028
void AVI_ChunkClean( stream_t *s,
1029
                     avi_chunk_t *p_chk )
1030
553k
{
1031
553k
    int i_index;
1032
553k
    avi_chunk_t *p_child, *p_next;
1033
1034
553k
    if( !p_chk )
1035
0
    {
1036
0
        return;
1037
0
    }
1038
1039
    /* Free all child chunk */
1040
553k
    p_child = p_chk->common.p_first;
1041
947k
    while( p_child )
1042
394k
    {
1043
394k
        p_next = p_child->common.p_next;
1044
394k
        AVI_ChunkClean( s, p_child );
1045
394k
        free( p_child );
1046
394k
        p_child = p_next;
1047
394k
    }
1048
1049
553k
    i_index = AVI_ChunkFunctionFind( p_chk->common.i_chunk_fourcc );
1050
553k
    if( AVI_Chunk_Function[i_index].AVI_ChunkFree_function )
1051
451k
    {
1052
451k
#ifdef AVI_DEBUG
1053
451k
        msg_Dbg( s, "free chunk %4.4s",
1054
451k
                 (char*)&p_chk->common.i_chunk_fourcc );
1055
451k
#endif
1056
451k
        AVI_Chunk_Function[i_index].AVI_ChunkFree_function( p_chk);
1057
451k
    }
1058
102k
    else if( p_chk->common.i_chunk_fourcc != 0 )
1059
61.7k
    {
1060
61.7k
        msg_Warn( s, "unknown chunk: %4.4s (not unloaded)",
1061
61.7k
                (char*)&p_chk->common.i_chunk_fourcc );
1062
61.7k
    }
1063
553k
    p_chk->common.p_first = NULL;
1064
1065
553k
    return;
1066
553k
}
1067
1068
static void AVI_ChunkDumpDebug_level( vlc_object_t *p_obj,
1069
                                      avi_chunk_t  *p_chk, unsigned i_level )
1070
164k
{
1071
164k
    avi_chunk_t *p_child;
1072
1073
164k
    char str[512];
1074
164k
    if( i_level >= (sizeof(str) - 1)/4 )
1075
0
        return;
1076
1077
164k
    memset( str, ' ', sizeof( str ) );
1078
447k
    for( unsigned i = 1; i < i_level; i++ )
1079
282k
    {
1080
282k
        str[i * 4] = '|';
1081
282k
    }
1082
164k
    if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF ||
1083
164k
        p_chk->common.i_chunk_fourcc == AVIFOURCC_ON2  ||
1084
164k
        p_chk->common.i_chunk_fourcc == AVIFOURCC_LIST )
1085
79.8k
    {
1086
79.8k
        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
1087
79.8k
                 "%c %4.4s-%4.4s size:%"PRIu64" pos:%"PRIu64,
1088
79.8k
                 i_level ? '+' : '*',
1089
79.8k
                 (char*)&p_chk->common.i_chunk_fourcc,
1090
79.8k
                 (char*)&p_chk->list.i_type,
1091
79.8k
                 p_chk->common.i_chunk_size,
1092
79.8k
                 p_chk->common.i_chunk_pos );
1093
79.8k
    }
1094
84.4k
    else
1095
84.4k
    {
1096
84.4k
        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
1097
84.4k
                 "+ %4.4s size:%"PRIu64" pos:%"PRIu64,
1098
84.4k
                 (char*)&p_chk->common.i_chunk_fourcc,
1099
84.4k
                 p_chk->common.i_chunk_size,
1100
84.4k
                 p_chk->common.i_chunk_pos );
1101
84.4k
    }
1102
164k
    msg_Dbg( p_obj, "%s", str );
1103
1104
164k
    p_child = p_chk->common.p_first;
1105
316k
    while( p_child )
1106
152k
    {
1107
152k
        AVI_ChunkDumpDebug_level( p_obj, p_child, i_level + 1 );
1108
152k
        p_child = p_child->common.p_next;
1109
152k
    }
1110
164k
}
1111
1112
int AVI_ChunkReadRoot( stream_t *s, avi_chunk_t *p_root )
1113
12.3k
{
1114
12.3k
    avi_chunk_list_t *p_list = (avi_chunk_list_t*)p_root;
1115
12.3k
    avi_chunk_t      *p_chk;
1116
12.3k
    bool b_seekable;
1117
1118
12.3k
    vlc_stream_Control( s, STREAM_CAN_SEEK, &b_seekable );
1119
1120
12.3k
    p_list->i_chunk_pos  = 0;
1121
12.3k
    p_list->i_chunk_size = ((UINT64_MAX - 12) >> 1) << 1;
1122
12.3k
    p_list->i_chunk_fourcc = AVIFOURCC_LIST;
1123
12.3k
    p_list->p_father = NULL;
1124
12.3k
    p_list->p_next  = NULL;
1125
12.3k
    p_list->p_first = NULL;
1126
1127
12.3k
    p_list->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
1128
1129
12.3k
    avi_chunk_t **pp_append = &p_root->common.p_first;
1130
12.3k
    for( ; ; )
1131
31.8k
    {
1132
31.8k
        p_chk = calloc( 1, sizeof( avi_chunk_t ) );
1133
31.8k
        if( !p_chk )
1134
0
            return VLC_EGENERIC;
1135
1136
31.8k
        if( AVI_ChunkRead( s, p_chk, p_root ) != VLC_SUCCESS )
1137
12.3k
        {
1138
12.3k
            AVI_ChunkClean( s, p_chk );
1139
12.3k
            free( p_chk );
1140
12.3k
            break;
1141
12.3k
        }
1142
1143
19.5k
        *pp_append = p_chk;
1144
39.0k
        while( *pp_append )
1145
19.5k
            pp_append = &((*pp_append)->common.p_next);
1146
1147
19.5k
        if( vlc_stream_Tell( s ) >=
1148
19.5k
                 p_chk->common.p_father->common.i_chunk_pos +
1149
19.5k
                 __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
19.5k
        if( p_chk->common.i_chunk_fourcc == AVIFOURCC_RIFF &&
1156
19.5k
            p_chk->list.i_type == AVIFOURCC_AVI && !b_seekable )
1157
0
        {
1158
0
            break;
1159
0
        }
1160
19.5k
    }
1161
1162
12.3k
    p_list->i_chunk_size = stream_Size( s );
1163
1164
12.3k
    AVI_ChunkDumpDebug_level( VLC_OBJECT(s), p_root, 0 );
1165
12.3k
    return VLC_SUCCESS;
1166
12.3k
}
1167
1168
void AVI_ChunkFreeRoot( stream_t *s,
1169
                        avi_chunk_t  *p_chk )
1170
12.3k
{
1171
12.3k
    AVI_ChunkClean( s, p_chk );
1172
12.3k
}
1173
1174
1175
int  AVI_ChunkCount_( avi_chunk_t *p_chk, vlc_fourcc_t i_fourcc, bool b_list )
1176
22.9k
{
1177
22.9k
    if( !p_chk )
1178
0
        return 0;
1179
1180
22.9k
    int i_count = 0;
1181
22.9k
    for( avi_chunk_t *p_child = p_chk->common.p_first;
1182
90.6k
                      p_child; p_child = p_child->common.p_next )
1183
67.6k
    {
1184
67.6k
        if( b_list && p_child->list.i_type == 0 )
1185
15.5k
            continue;
1186
1187
52.0k
        if( p_child->common.i_chunk_fourcc != i_fourcc &&
1188
52.0k
            (!b_list || p_child->list.i_type != i_fourcc) )
1189
16.0k
            continue;
1190
1191
36.0k
        i_count++;
1192
36.0k
    }
1193
1194
22.9k
    return i_count;
1195
22.9k
}
1196
1197
void *AVI_ChunkFind_( avi_chunk_t *p_chk,
1198
                      vlc_fourcc_t i_fourcc, int i_number, bool b_list )
1199
337k
{
1200
337k
    if( !p_chk )
1201
4
        return NULL;
1202
1203
337k
    for( avi_chunk_t *p_child = p_chk->common.p_first;
1204
1.60M
                      p_child; p_child = p_child->common.p_next )
1205
1.47M
    {
1206
1.47M
        if( b_list && p_child->list.i_type == 0 )
1207
380k
            continue;
1208
1209
1.08M
        if( p_child->common.i_chunk_fourcc != i_fourcc &&
1210
1.08M
            (!b_list || p_child->list.i_type != i_fourcc) )
1211
481k
            continue;
1212
1213
607k
        if( i_number-- == 0 )
1214
203k
            return p_child; /* We found it */
1215
607k
    }
1216
1217
134k
    return NULL;
1218
337k
}
1219