~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to modules/demux/avi/libavi.c

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

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