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

/*****************************************************************************
 * Preamble
 *****************************************************************************/

27
28
29
30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
33
#include <vlc_demux.h>
34

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
35
#include <vlc_dialog.h>
zorglub's avatar
zorglub committed
36

zorglub's avatar
zorglub committed
37
38
39
#include <vlc_meta.h>
#include <vlc_codecs.h>
#include <vlc_charset.h>
40

41
#include "libavi.h"
42
43
44
45

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
hartman's avatar
hartman committed
46
47

#define INTERLEAVE_TEXT N_("Force interleaved method" )
48
#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." )
hartman's avatar
hartman committed
49
50
51

#define INDEX_TEXT N_("Force index creation")
#define INDEX_LONGTEXT N_( \
zorglub's avatar
zorglub committed
52
    "Recreate a index for the AVI file. Use this if your AVI file is damaged "\
zorglub's avatar
zorglub committed
53
    "or incomplete (not seekable)." )
hartman's avatar
hartman committed
54

Laurent Aimar's avatar
Laurent Aimar committed
55
56
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
57

58
static const int pi_index[] = {0,1,2};
59

60
static const char *const ppsz_indexes[] = { N_("Ask"), N_("Always fix"),
61
62
                                N_("Never fix") };

63
64
65
66
67
68
vlc_module_begin ()
    set_shortname( "AVI" )
    set_description( N_("AVI demuxer") )
    set_capability( "demux", 212 )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
69

hartman's avatar
hartman committed
70
    add_bool( "avi-interleaved", 0, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
71
              INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, true )
72
    add_integer( "avi-index", 0, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
73
              INDEX_TEXT, INDEX_LONGTEXT, false )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
74
        change_integer_list( pi_index, ppsz_indexes, NULL )
hartman's avatar
hartman committed
75

76
77
    set_callbacks( Open, Close )
vlc_module_end ()
78

79
80
81
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
82
83
84
85
static int Control         ( demux_t *, int, va_list );
static int Seek            ( demux_t *, mtime_t, int );
static int Demux_Seekable  ( demux_t * );
static int Demux_UnSeekable( demux_t * );
86
87

#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
88

Laurent Aimar's avatar
Laurent Aimar committed
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
typedef struct
{
    vlc_fourcc_t i_fourcc;
    off_t        i_pos;
    uint32_t     i_size;
    vlc_fourcc_t i_type;     /* only for AVIFOURCC_LIST */

    uint8_t      i_peek[8];  /* first 8 bytes */

    unsigned int i_stream;
    unsigned int i_cat;
} avi_packet_t;


typedef struct
{
    vlc_fourcc_t i_id;
    uint32_t     i_flags;
    off_t        i_pos;
    uint32_t     i_length;
109
    int64_t      i_lengthtotal;
Laurent Aimar's avatar
Laurent Aimar committed
110
111
112
113
114

} avi_entry_t;

typedef struct
{
115
116
    bool            b_activated;
    bool            b_eof;
Laurent Aimar's avatar
Laurent Aimar committed
117
118
119
120
121
122

    unsigned int    i_cat; /* AUDIO_ES, VIDEO_ES */
    vlc_fourcc_t    i_codec;

    int             i_rate;
    int             i_scale;
123
    unsigned int    i_samplesize;
Laurent Aimar's avatar
Laurent Aimar committed
124
125
126

    es_out_id_t     *p_es;

hartman's avatar
hartman committed
127
    /* Avi Index */
Laurent Aimar's avatar
Laurent Aimar committed
128
    avi_entry_t     *p_index;
hartman's avatar
hartman committed
129
130
    unsigned int    i_idxnb;
    unsigned int    i_idxmax;
Laurent Aimar's avatar
Laurent Aimar committed
131

hartman's avatar
hartman committed
132
133
    unsigned int    i_idxposc;  /* numero of chunk */
    unsigned int    i_idxposb;  /* byte in the current chunk */
Laurent Aimar's avatar
Laurent Aimar committed
134

135
136
137
    /* extra information given to the decoder */
    void            *p_extra;

Laurent Aimar's avatar
Laurent Aimar committed
138
    /* For VBR audio only */
hartman's avatar
hartman committed
139
140
141
142
143
    unsigned int    i_blockno;
    unsigned int    i_blocksize;

    /* For muxed streams */
    stream_t        *p_out_muxed;
Laurent Aimar's avatar
Laurent Aimar committed
144
145
146
147
148
149
150
} avi_track_t;

struct demux_sys_t
{
    mtime_t i_time;
    mtime_t i_length;

151
152
    bool  b_seekable;
    bool  b_muxed;
Laurent Aimar's avatar
Laurent Aimar committed
153
154
    avi_chunk_t ck_root;

155
    bool  b_odml;
Laurent Aimar's avatar
Laurent Aimar committed
156
157
158
159
160
161
162
163
164
165
166
167

    off_t   i_movi_begin;
    off_t   i_movi_lastchunk_pos;   /* XXX position of last valid chunk */

    /* number of streams and information */
    unsigned int i_track;
    avi_track_t  **track;

    /* meta */
    vlc_meta_t  *meta;
};

168
169
static inline off_t __EVEN( off_t i )
{
170
    return (i & 1) ? i + 1 : i;
171
172
}

173
174
175
176
static mtime_t AVI_PTSToChunk( avi_track_t *, mtime_t i_pts );
static mtime_t AVI_PTSToByte ( avi_track_t *, mtime_t i_pts );
static mtime_t AVI_GetDPTS   ( avi_track_t *, int64_t i_count );
static mtime_t AVI_GetPTS    ( avi_track_t * );
177

178

Laurent Aimar's avatar
Laurent Aimar committed
179
180
static int AVI_StreamChunkFind( demux_t *, unsigned int i_stream );
static int AVI_StreamChunkSet ( demux_t *,
181
                                unsigned int i_stream, unsigned int i_ck );
Laurent Aimar's avatar
Laurent Aimar committed
182
static int AVI_StreamBytesSet ( demux_t *,
183
                                unsigned int i_stream, off_t   i_byte );
184

185
vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );
186
static int   AVI_GetKeyFlag    ( vlc_fourcc_t , uint8_t * );
187

Laurent Aimar's avatar
Laurent Aimar committed
188
189
190
191
static int AVI_PacketGetHeader( demux_t *, avi_packet_t *p_pk );
static int AVI_PacketNext     ( demux_t * );
static int AVI_PacketRead     ( demux_t *, avi_packet_t *, block_t **);
static int AVI_PacketSearch   ( demux_t * );
192

Laurent Aimar's avatar
Laurent Aimar committed
193
194
static void AVI_IndexLoad    ( demux_t * );
static void AVI_IndexCreate  ( demux_t * );
Laurent Aimar's avatar
Laurent Aimar committed
195
static void AVI_IndexAddEntry( demux_sys_t *, int, avi_entry_t * );
196

Laurent Aimar's avatar
Laurent Aimar committed
197
static mtime_t  AVI_MovieGetLength( demux_t * );
198

199
200
201
/*****************************************************************************
 * Stream management
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
202
203
static int        AVI_TrackSeek  ( demux_t *, int, mtime_t );
static int        AVI_TrackStopFinishedStreams( demux_t *);
204

Laurent Aimar's avatar
Laurent Aimar committed
205
206
207
208
209
210
211
212
213
/* Remarks:
 - For VBR mp3 stream:
    count blocks by rounded-up chunksizes instead of chunks
    we need full emulation of dshow avi demuxer bugs :(
    fixes silly nandub-style a-v delaying in avi with vbr mp3...
    (from mplayer 2002/08/02)
 - to complete....
 */

214
215
216
217
218
/*****************************************************************************
 * Open: check file and initializes AVI structures
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
Laurent Aimar's avatar
Laurent Aimar committed
219
    demux_t  *p_demux = (demux_t *)p_this;
220
221
    demux_sys_t     *p_sys;

222
    bool       b_index = false;
223
    int              i_do_index;
zorglub's avatar
zorglub committed
224

ivoire's avatar
ivoire committed
225
    avi_chunk_list_t    *p_riff;
226
227
    avi_chunk_list_t    *p_hdrl, *p_movi;
    avi_chunk_avih_t    *p_avih;
228
229

    unsigned int i_track;
230
    unsigned int i, i_peeker;
231

232
    const uint8_t *p_peek;
233

234
    /* Is it an avi file ? */
235
236
    if( stream_Peek( p_demux->s, &p_peek, 200 ) < 200 ) return VLC_EGENERIC;

237
238
    for( i_peeker = 0; i_peeker < 188; i_peeker++ )
    {
239
240
241
242
        if( !strncmp( (char *)&p_peek[0], "RIFF", 4 ) && !strncmp( (char *)&p_peek[8], "AVI ", 4 ) )
            break;
        if( !strncmp( (char *)&p_peek[0], "ON2 ", 4 ) && !strncmp( (char *)&p_peek[8], "ON2f", 4 ) )
            break;
243
244
245
        p_peek++;
    }
    if( i_peeker == 188 )
246
    {
247
        return VLC_EGENERIC;
248
    }
249

250
    /* Initialize input  structures. */
Laurent Aimar's avatar
Laurent Aimar committed
251
    p_sys = p_demux->p_sys = malloc( sizeof(demux_sys_t) );
252
253
254
255
    memset( p_sys, 0, sizeof( demux_sys_t ) );
    p_sys->i_time   = 0;
    p_sys->i_length = 0;
    p_sys->i_movi_lastchunk_pos = 0;
256
257
    p_sys->b_odml   = false;
    p_sys->b_muxed  = false;
258
259
    p_sys->i_track  = 0;
    p_sys->track    = NULL;
260
    p_sys->meta     = NULL;
261

Laurent Aimar's avatar
Laurent Aimar committed
262
    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_seekable );
263

Laurent Aimar's avatar
Laurent Aimar committed
264
265
    p_demux->pf_control = Control;
    p_demux->pf_demux = Demux_Seekable;
266

267
    /* For unseekable stream, automaticaly use Demux_UnSeekable */
Laurent Aimar's avatar
Laurent Aimar committed
268
    if( !p_sys->b_seekable || config_GetInt( p_demux, "avi-interleaved" ) )
269
    {
Laurent Aimar's avatar
Laurent Aimar committed
270
        p_demux->pf_demux = Demux_UnSeekable;
271
    }
272

273
274
    if( i_peeker > 0 )
    {
275
        stream_Read( p_demux->s, NULL, i_peeker );
276
277
    }

Laurent Aimar's avatar
Laurent Aimar committed
278
    if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) )
279
    {
Laurent Aimar's avatar
Laurent Aimar committed
280
        msg_Err( p_demux, "avi module discarded (invalid file)" );
281
        return VLC_EGENERIC;
282
    }
283

284
    if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 )
285
    {
286
        unsigned int i_count =
287
            AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF );
288

Laurent Aimar's avatar
Laurent Aimar committed
289
        msg_Warn( p_demux, "multiple riff -> OpenDML ?" );
290
291
        for( i = 1; i < i_count; i++ )
        {
292
            avi_chunk_list_t *p_sysx;
293

294
295
            p_sysx = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, i );
            if( p_sysx->i_type == AVIFOURCC_AVIX )
296
            {
Laurent Aimar's avatar
Laurent Aimar committed
297
                msg_Warn( p_demux, "detected OpenDML file" );
298
                p_sys->b_odml = true;
299
300
301
302
                break;
            }
        }
    }
303

304
    p_riff  = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
305
306
    p_hdrl  = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
    p_movi  = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
307

308
    if( !p_hdrl || !p_movi )
309
    {
Laurent Aimar's avatar
Laurent Aimar committed
310
        msg_Err( p_demux, "avi module discarded (invalid file)" );
311
        goto error;
312
    }
313

314
    if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) )
315
    {
Laurent Aimar's avatar
Laurent Aimar committed
316
        msg_Err( p_demux, "cannot find avih chunk" );
317
        goto error;
318
    }
319
320
    i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
    if( p_avih->i_streams != i_track )
321
    {
Laurent Aimar's avatar
Laurent Aimar committed
322
        msg_Warn( p_demux,
323
                  "found %d stream but %d are declared",
324
                  i_track, p_avih->i_streams );
325
    }
326
    if( i_track == 0 )
327
    {
Laurent Aimar's avatar
Laurent Aimar committed
328
        msg_Err( p_demux, "no stream defined!" );
329
        goto error;
330
    }
331

332
    /* print information on streams */
Laurent Aimar's avatar
Laurent Aimar committed
333
    msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ",
334
             i_track,
335
336
337
338
             p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
             p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
             p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
             p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
339
    if( ( p_sys->meta = vlc_meta_New() ) )
340
    {
341
        char buffer[200];
Laurent Aimar's avatar
Laurent Aimar committed
342
343
344
345
346
        snprintf( buffer, sizeof(buffer), "%s%s%s%s",
                  p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
                  p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
                  p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
                  p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
347
        vlc_meta_SetSetting( p_sys->meta, buffer );
348
    }
349

350
    /* now read info on each stream and create ES */
351
352
    for( i = 0 ; i < i_track; i++ )
    {
hartman's avatar
hartman committed
353
        avi_track_t           *tk     = malloc( sizeof( avi_track_t ) );
354
355
356
        if( !tk )
            goto error;

hartman's avatar
hartman committed
357
358
359
360
361
        avi_chunk_list_t      *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
        avi_chunk_strh_t      *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
        avi_chunk_STRING_t    *p_strn = AVI_ChunkFind( p_strl, AVIFOURCC_strn, 0 );
        avi_chunk_strf_auds_t *p_auds = NULL;
        avi_chunk_strf_vids_t *p_vids = NULL;
362
363
        es_format_t fmt;

364
365
366
        memset( tk, 0, sizeof(*tk) );
        tk->b_eof = false;
        tk->b_activated = true;
hartman's avatar
hartman committed
367

368
369
        p_vids = (avi_chunk_strf_vids_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
        p_auds = (avi_chunk_strf_auds_t*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
370
371

        if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )
372
        {
Laurent Aimar's avatar
Laurent Aimar committed
373
            msg_Warn( p_demux, "stream[%d] incomplete", i );
374
            free( tk );
375
            continue;
376
        }
377

378
379
380
        tk->i_rate  = p_strh->i_rate;
        tk->i_scale = p_strh->i_scale;
        tk->i_samplesize = p_strh->i_samplesize;
Laurent Aimar's avatar
Laurent Aimar committed
381
        msg_Dbg( p_demux, "stream[%d] rate:%d scale:%d samplesize:%d",
382
383
384
                 i, tk->i_rate, tk->i_scale, tk->i_samplesize );

        switch( p_strh->i_type )
385
        {
386
            case( AVIFOURCC_auds ):
387
388
389
                tk->i_cat   = AUDIO_ES;
                tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
                                                  p_auds->p_wf->wFormatTag );
390
391
392

                tk->i_blocksize = p_auds->p_wf->nBlockAlign;
                if( tk->i_blocksize == 0 )
Laurent Aimar's avatar
Laurent Aimar committed
393
394
395
396
397
398
                {
                    if( p_auds->p_wf->wFormatTag == 1 )
                        tk->i_blocksize = p_auds->p_wf->nChannels * (p_auds->p_wf->wBitsPerSample/8);
                    else
                        tk->i_blocksize = 1;
                }
399
400
401
402
403
404
405
406
                else if( tk->i_samplesize != 0 && tk->i_samplesize != tk->i_blocksize )
                {
                    msg_Warn( p_demux, "track[%d] samplesize=%d and blocksize=%d are not equal."
                                       "Using blocksize as a workaround.",
                                       i, tk->i_samplesize, tk->i_blocksize );
                    tk->i_samplesize = tk->i_blocksize;
                }

407
                if( tk->i_codec == VLC_CODEC_VORBIS )
408
409
410
411
                {
                    tk->i_blocksize = 0; /* fix vorbis VBR decoding */
                }

412
413
414
                es_format_Init( &fmt, AUDIO_ES, tk->i_codec );

                fmt.audio.i_channels        = p_auds->p_wf->nChannels;
gbazin's avatar
   
gbazin committed
415
                fmt.audio.i_rate            = p_auds->p_wf->nSamplesPerSec;
gbazin's avatar
   
gbazin committed
416
                fmt.i_bitrate               = p_auds->p_wf->nAvgBytesPerSec*8;
417
418
                fmt.audio.i_blockalign      = p_auds->p_wf->nBlockAlign;
                fmt.audio.i_bitspersample   = p_auds->p_wf->wBitsPerSample;
419
                fmt.b_packetized            = !tk->i_blocksize;
420
421
422
423
424
425
426

                msg_Dbg( p_demux,
                    "stream[%d] audio(0x%x) %d channels %dHz %dbits",
                    i, p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels,
                    p_auds->p_wf->nSamplesPerSec, 
                    p_auds->p_wf->wBitsPerSample );

gbazin's avatar
   
gbazin committed
427
428
                fmt.i_extra = __MIN( p_auds->p_wf->cbSize,
                    p_auds->i_chunk_size - sizeof(WAVEFORMATEX) );
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
                fmt.p_extra = tk->p_extra = malloc( fmt.i_extra );
                if( !fmt.p_extra ) goto error;
                memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra );

                /* Rewrite the vorbis headers from Xiph-like format
                 * to VLC internal format
                 *
                 * Xiph format:
                 *  - 1st byte == N, is the number of packets - 1
                 *  - Following bytes are the size of the N first packets:
                 *      while( *p == 0xFF ) { size += 0xFF; p++ } size += *p;
                 *      (the size of the last packet is the size of remaining
                 *      data in the buffer)
                 *  - Finally, all the packets concatenated
                 *
                 * VLC format:
                 *  - Size of the packet on 16 bits (big endian) FIXME: should be 32 bits to be safe
                 *  - The packet itself
                 *  - Size of the next packet, and so on ...
                 */

450
                if( tk->i_codec == VLC_CODEC_VORBIS )
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
                {
                    uint8_t *p_extra = fmt.p_extra; 
                    size_t i_extra = fmt.i_extra;

                    if( i_extra <= 1 ) break;
                    if( *p_extra++ != 2 ) break; /* 3 packets - 1 = 2 */
                    i_extra--;

                    size_t i_identifier_len = 0;
                    while( *p_extra == 0xFF )
                    {
                        i_identifier_len += 0xFF;
                        p_extra++;
                        if( --i_extra <= 1 ) break;
                    }
                    i_identifier_len += *p_extra++;
                    if( i_identifier_len > --i_extra ) break;

                    size_t i_comment_len = 0;
                    while( *p_extra == 0xFF )
                    {
                        i_comment_len += 0xFF;
                        p_extra++;
                        if( --i_extra <= 1 ) break;
                    }
                    i_comment_len += *p_extra++;
                    if( i_comment_len > --i_extra ) break;
                    size_t i_cookbook_len = i_extra;

                    size_t i_headers_size = 3  * 2 + i_identifier_len +
                                            i_comment_len + i_cookbook_len;
                    uint8_t *p_out = malloc( i_headers_size );
                    if( !p_out ) goto error;
                    free( fmt.p_extra );
                    fmt.p_extra = tk->p_extra = p_out;
                    fmt.i_extra = i_headers_size;
                    #define copy_packet( len ) \
                        *p_out++ = len >> 8; \
                        *p_out++ = len & 0xFF; \
                        memcpy( p_out, p_extra, len ); \
                        p_out += len; \
                        p_extra += len;
                    copy_packet( i_identifier_len );
                    copy_packet( i_comment_len );
                    copy_packet( i_cookbook_len );
                    #undef copy_packet
                    break;
                }
499
500
501
                break;

            case( AVIFOURCC_vids ):
502
503
504
                tk->i_cat   = VIDEO_ES;
                tk->i_codec = AVI_FourccGetCodec( VIDEO_ES,
                                                  p_vids->p_bih->biCompression );
hartman's avatar
hartman committed
505
506
507
508
509
510
511
                if( p_vids->p_bih->biCompression == VLC_FOURCC( 'D', 'X', 'S', 'B' ) )
                {
                   msg_Dbg( p_demux, "stream[%d] subtitles", i );
                   es_format_Init( &fmt, SPU_ES, p_vids->p_bih->biCompression );
                   break;
                }
                else if( p_vids->p_bih->biCompression == 0x00 )
512
513
514
515
                {
                    switch( p_vids->p_bih->biBitCount )
                    {
                        case 32:
516
                            tk->i_codec = VLC_CODEC_RGB32;
517
518
                            break;
                        case 24:
519
                            tk->i_codec = VLC_CODEC_RGB24;
520
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
521
                        case 16: /* Yes it is RV15 */
522
                        case 15:
523
                            tk->i_codec = VLC_CODEC_RGB15;
524
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
525
                        case 9: /* <- TODO check that */
526
                            tk->i_codec = VLC_CODEC_I410;
527
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
528
                        case 8: /* <- TODO check that */
529
                            tk->i_codec = VLC_CODEC_GREY;
530
                            break;
531
532
                    }
                    es_format_Init( &fmt, VIDEO_ES, tk->i_codec );
533

Laurent Aimar's avatar
Laurent Aimar committed
534
                    switch( tk->i_codec )
535
                    {
536
537
                    case VLC_CODEC_RGB24:
                    case VLC_CODEC_RGB32:
Laurent Aimar's avatar
Laurent Aimar committed
538
                        fmt.video.i_rmask = 0x00ff0000;
539
                        fmt.video.i_gmask = 0x0000ff00;
Laurent Aimar's avatar
Laurent Aimar committed
540
541
                        fmt.video.i_bmask = 0x000000ff;
                        break;
542
                    case VLC_CODEC_RGB15:
Laurent Aimar's avatar
Laurent Aimar committed
543
544
545
546
547
548
                        fmt.video.i_rmask = 0x7c00;
                        fmt.video.i_gmask = 0x03e0;
                        fmt.video.i_bmask = 0x001f;
                        break;
                    default:
                        break;
549
                    }
550
551
552
553
                }
                else
                {
                    es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );
554
                    if( tk->i_codec == VLC_CODEC_MP4V &&
555
                        !strncasecmp( (char*)&p_strh->i_handler, "XVID", 4 ) )
556
                    {
557
558
                        fmt.i_codec           =
                        fmt.i_original_fourcc = VLC_FOURCC( 'X', 'V', 'I', 'D' );
559
                    }
560
                }
561
562
563
                tk->i_samplesize = 0;
                fmt.video.i_width  = p_vids->p_bih->biWidth;
                fmt.video.i_height = p_vids->p_bih->biHeight;
sigmunau's avatar
sigmunau committed
564
                fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;
565
566
                fmt.video.i_frame_rate = tk->i_rate;
                fmt.video.i_frame_rate_base = tk->i_scale;
gbazin's avatar
   
gbazin committed
567
568
569
570
                fmt.i_extra =
                    __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
                           p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) );
                fmt.p_extra = &p_vids->p_bih[1];
571
                msg_Dbg( p_demux, "stream[%d] video(%4.4s) %"PRIu32"x%"PRIu32" %dbpp %ffps",
572
                         i, (char*)&p_vids->p_bih->biCompression,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
573
574
                         (uint32_t)p_vids->p_bih->biWidth,
                         (uint32_t)p_vids->p_bih->biHeight,
575
576
                         p_vids->p_bih->biBitCount,
                         (float)tk->i_rate/(float)tk->i_scale );
577
578
579
580
581
582
583

                if( p_vids->p_bih->biCompression == 0x00 )
                {
                    /* RGB DIB are coded from bottom to top */
                    fmt.video.i_height =
                        (unsigned int)(-(int)p_vids->p_bih->biHeight);
                }
584
585
586
587

                /* Extract palette from extradata if bpp <= 8
                 * (assumes that extradata contains only palette but appears
                 *  to be true for all palettized codecs we support) */
Laurent Aimar's avatar
Laurent Aimar committed
588
                if( fmt.video.i_bits_per_pixel > 0 && fmt.video.i_bits_per_pixel <= 8 )
589
                {
Laurent Aimar's avatar
Laurent Aimar committed
590
591
592
593
594
                    /* The palette is not always included in biSize */
                    fmt.i_extra = p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER);
                    if( fmt.i_extra > 0 )
                    {
                        const uint8_t *p_pal = fmt.p_extra;
595

596
                        fmt.video.p_palette = calloc( 1, sizeof(video_palette_t) );
Laurent Aimar's avatar
Laurent Aimar committed
597
                        fmt.video.p_palette->i_entries = __MIN(fmt.i_extra/4, 256);
598

Laurent Aimar's avatar
Laurent Aimar committed
599
600
601
602
603
                        for( int i = 0; i < fmt.video.p_palette->i_entries; i++ )
                        {
                            for( int j = 0; j < 4; j++ )
                                fmt.video.p_palette->palette[i][j] = p_pal[4*i+j];
                        }
604
                    }
605
                }
606
                break;
607
608
609

            case( AVIFOURCC_txts):
                tk->i_cat   = SPU_ES;
610
                tk->i_codec = VLC_CODEC_SUBT;
611
612
613
                msg_Dbg( p_demux, "stream[%d] subtitles", i );
                es_format_Init( &fmt, SPU_ES, tk->i_codec );
                break;
614

hartman's avatar
hartman committed
615
616
            case( AVIFOURCC_iavs):
            case( AVIFOURCC_ivas):
617
                p_sys->b_muxed = true;
hartman's avatar
hartman committed
618
619
620
                msg_Dbg( p_demux, "stream[%d] iavs with handler %4.4s", i, (char *)&p_strh->i_handler );
                if( p_strh->i_handler == FOURCC_dvsd ||
                    p_strh->i_handler == FOURCC_dvhd ||
621
622
623
                    p_strh->i_handler == FOURCC_dvsl ||
                    p_strh->i_handler == FOURCC_dv25 ||
                    p_strh->i_handler == FOURCC_dv50 )
hartman's avatar
hartman committed
624
                {
625
                    tk->p_out_muxed = stream_DemuxNew( p_demux, (char *)"rawdv", p_demux->out );
hartman's avatar
hartman committed
626
627
628
629
630
631
632
                    if( !tk->p_out_muxed )
                        msg_Err( p_demux, "could not load the DV parser" );
                    else break;
                }
                free( tk );
                continue;

633
634
            case( AVIFOURCC_mids):
                msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i );
635

636
            default:
hartman's avatar
hartman committed
637
                msg_Warn( p_demux, "stream[%d] unknown type %4.4s", i, (char *)&p_strh->i_type );
638
639
                free( tk );
                continue;
640
        }
hartman's avatar
hartman committed
641
        if( p_strn )
642
            fmt.psz_description = FromLatin1( p_strn->p_str );
hartman's avatar
hartman committed
643
644
        if( tk->p_out_muxed == NULL )
            tk->p_es = es_out_Add( p_demux->out, &fmt );
645
646
647
648
649
        TAB_APPEND( p_sys->i_track, p_sys->track, tk );
    }

    if( p_sys->i_track <= 0 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
650
        msg_Err( p_demux, "no valid track" );
651
        goto error;
652
653
    }

654
655
    i_do_index =  config_GetInt( p_demux, "avi-index" );
    if( i_do_index == 1 ) /* Always fix */
656
    {
zorglub's avatar
zorglub committed
657
aviindex:
658
        if( p_sys->b_seekable )
659
        {
Laurent Aimar's avatar
Laurent Aimar committed
660
            AVI_IndexCreate( p_demux );
661
        }
662
        else
663
        {
Laurent Aimar's avatar
Laurent Aimar committed
664
665
            msg_Warn( p_demux, "cannot create index (unseekable stream)" );
            AVI_IndexLoad( p_demux );
666
667
        }
    }
668
    else
669
    {
Laurent Aimar's avatar
Laurent Aimar committed
670
        AVI_IndexLoad( p_demux );
671
    }
672
673

    /* *** movie length in sec *** */
Laurent Aimar's avatar
Laurent Aimar committed
674
    p_sys->i_length = AVI_MovieGetLength( p_demux );
675
    if( p_sys->i_length < (mtime_t)p_avih->i_totalframes *
676
677
                          (mtime_t)p_avih->i_microsecperframe /
                          (mtime_t)1000000 )
678
    {
679
680
681
        if( !vlc_object_alive( p_demux) )
            goto error;

zorglub's avatar
zorglub committed
682
        msg_Warn( p_demux, "broken or missing index, 'seek' will be "
683
                           "approximative or will exhibit strange behavior" );
684
        if( i_do_index == 0 && !b_index )
zorglub's avatar
zorglub committed
685
        {
686
687
688
689
            if( !p_sys->b_seekable ) {
                b_index = true;
                goto aviindex;
            }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
690
691
692
693
694
            switch( dialog_Question( p_demux, _("AVI Index") ,
               _( "This AVI file is broken. Seeking will not work correctly.\n"
                  "Do you want to try to fix it?\n\n"
                  "This might take a long time." ),
                  _( "Repair" ), _( "Don't repair" ), _( "Cancel") ) )
zorglub's avatar
zorglub committed
695
            {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
696
697
698
699
700
701
702
703
                case 1:
                    b_index = true;
                    msg_Dbg( p_demux, "Fixing AVI index" );
                    goto aviindex;
                case 3:
                    /* Kill input */
                    vlc_object_kill( p_demux->p_parent );
                    goto error;
zorglub's avatar
zorglub committed
704
705
            }
        }
706
    }
zorglub's avatar
zorglub committed
707

708
    /* fix some BeOS MediaKit generated file */
709
    for( i = 0 ; i < p_sys->i_track; i++ )
710
    {
711
712
713
714
        avi_track_t         *tk = p_sys->track[i];
        avi_chunk_list_t    *p_strl;
        avi_chunk_strh_t    *p_strh;
        avi_chunk_strf_auds_t    *p_auds;
715

716
        if( tk->i_cat != AUDIO_ES )
717
718
719
        {
            continue;
        }
720
721
722
        if( tk->i_idxnb < 1 ||
            tk->i_scale != 1 ||
            tk->i_samplesize != 0 )
723
724
725
        {
            continue;
        }
726
727
728
        p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
        p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
        p_auds = AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
729

730
731
        if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM &&
            (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec )
732
733
        {
            int64_t i_track_length =
734
735
                tk->p_index[tk->i_idxnb-1].i_length +
                tk->p_index[tk->i_idxnb-1].i_lengthtotal;
736
737
            mtime_t i_length = (mtime_t)p_avih->i_totalframes *
                               (mtime_t)p_avih->i_microsecperframe;
738

739
740
            if( i_length == 0 )
            {
Laurent Aimar's avatar
Laurent Aimar committed
741
                msg_Warn( p_demux, "track[%d] cannot be fixed (BeOS MediaKit generated)", i );
742
743
                continue;
            }
744
745
            tk->i_samplesize = 1;
            tk->i_rate       = i_track_length  * (int64_t)1000000/ i_length;
Laurent Aimar's avatar
Laurent Aimar committed
746
            msg_Warn( p_demux, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, tk->i_rate, tk->i_scale );
747
748
        }
    }
749

750
    if( p_sys->b_seekable )
751
752
    {
        /* we have read all chunk so go back to movi */
Laurent Aimar's avatar
Laurent Aimar committed
753
        stream_Seek( p_demux->s, p_movi->i_chunk_pos );
754
    }
755
    /* Skip movi header */
Laurent Aimar's avatar
Laurent Aimar committed
756
    stream_Read( p_demux->s, NULL, 12 );
757

758
    p_sys->i_movi_begin = p_movi->i_chunk_pos;
759
    return VLC_SUCCESS;
760
761

error:
762
763
764
765
    if( p_sys->meta )
    {
        vlc_meta_Delete( p_sys->meta );
    }
Laurent Aimar's avatar
Laurent Aimar committed
766
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
767
    free( p_sys );
768
    return vlc_object_alive( p_demux ) ? VLC_EGENERIC : VLC_ETIMEOUT;
769
770
}

771
772
773
774
/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close ( vlc_object_t * p_this )
775
{
Laurent Aimar's avatar
Laurent Aimar committed
776
    demux_t *    p_demux = (demux_t *)p_this;
777
    unsigned int i;
Laurent Aimar's avatar
Laurent Aimar committed
778
    demux_sys_t *p_sys = p_demux->p_sys  ;
779

780
    for( i = 0; i < p_sys->i_track; i++ )
781
    {
782
        if( p_sys->track[i] )
783
        {
hartman's avatar
hartman committed
784
            if( p_sys->track[i]->p_out_muxed )
785
                stream_Delete( p_sys->track[i]->p_out_muxed );
786
787
            free( p_sys->track[i]->p_index );
            free( p_sys->track[i]->p_extra );
788
            free( p_sys->track[i] );
789
790
        }
    }
791
    free( p_sys->track );
Laurent Aimar's avatar
Laurent Aimar committed
792
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
793
    vlc_meta_Delete( p_sys->meta );
794

795
    free( p_sys );
796
797
}

798
799
800
801
802
803
804
/*****************************************************************************
 * Demux_Seekable: reads and demuxes data packets for stream seekable
 *****************************************************************************
 * AVIDemux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
805
typedef struct
806
{
807
    bool b_ok;
808

809
    int i_toread;
810

hartman's avatar
hartman committed
811
812
813
    off_t i_posf; /* where we will read :
                   if i_idxposb == 0 : begining of chunk (+8 to acces data)
                   else : point on data directly */
814
} avi_track_toread_t;
815

Laurent Aimar's avatar
Laurent Aimar committed
816
static int Demux_Seekable( demux_t *p_demux )
817
{
Laurent Aimar's avatar
Laurent Aimar committed
818
    demux_sys_t *p_sys = p_demux->p_sys;
819
820
821

    unsigned int i_track_count = 0;
    unsigned int i_track;
hartman's avatar
hartman committed
822
    /* cannot be more than 100 stream (dcXX or wbXX) */
823
    avi_track_toread_t toread[100];
824
825


826
    /* detect new selected/unselected streams */
827
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
828
    {
829
        avi_track_t *tk = p_sys->track[i_track];
830
        bool  b;
831

hartman's avatar
hartman committed
832
833
834
        if( p_sys->b_muxed && tk->p_out_muxed )
        {
            i_track_count++;
835
            tk->b_activated = true;
hartman's avatar
hartman committed
836
837
838
            continue;
        }

Laurent Aimar's avatar
Laurent Aimar committed
839
        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
840
        if( b && !tk->b_activated )
841
        {
842
            if( p_sys->b_seekable)
843
            {
Laurent Aimar's avatar
Laurent Aimar committed
844
                AVI_TrackSeek( p_demux, i_track, p_sys->i_time );
845
            }
846
            tk->b_activated = true;
847
        }
848
        else if( !b && tk->b_activated )
849
        {
850
            tk->b_activated = false;
851
852
853
854
        }
        if( b )
        {
            i_track_count++;
855
856
857
        }
    }

858
    if( i_track_count <= 0 )
859
    {
Laurent Aimar's avatar
   
Laurent Aimar committed
860
861
862
863
864
865
866
867
868
        int64_t i_length = p_sys->i_length * (mtime_t)1000000;

        p_sys->i_time += 25*1000;  /* read 25ms */
        if( i_length > 0 )
        {
            if( p_sys->i_time >= i_length )
                return 0;
            return 1;
        }
Laurent Aimar's avatar
Laurent Aimar committed
869
        msg_Warn( p_demux, "no track selected, exiting..." );
Laurent Aimar's avatar
   
Laurent Aimar committed
870
        return 0;
871
    }
872