avi.c 85.5 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
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
30
#include <assert.h>
31

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

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

zorglub's avatar
zorglub committed
39
40
41
#include <vlc_meta.h>
#include <vlc_codecs.h>
#include <vlc_charset.h>
42
#include <vlc_memory.h>
43

44
#include "libavi.h"
45
46
47
48

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
hartman's avatar
hartman committed
49
50

#define INTERLEAVE_TEXT N_("Force interleaved method" )
51
#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." )
hartman's avatar
hartman committed
52
53
54

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

Laurent Aimar's avatar
Laurent Aimar committed
58
59
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
60

61
static const int pi_index[] = {0,1,2};
62

63
64
65
static const char *const ppsz_indexes[] = { N_("Ask for action"),
                                            N_("Always fix"),
                                            N_("Never fix") };
66

67
68
69
70
71
72
vlc_module_begin ()
    set_shortname( "AVI" )
    set_description( N_("AVI demuxer") )
    set_capability( "demux", 212 )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
73

74
    add_bool( "avi-interleaved", false,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
75
              INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, true )
76
    add_integer( "avi-index", 0,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
77
              INDEX_TEXT, INDEX_LONGTEXT, false )
78
        change_integer_list( pi_index, ppsz_indexes )
hartman's avatar
hartman committed
79

80
81
    set_callbacks( Open, Close )
vlc_module_end ()
82

83
84
85
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
86
87
88
89
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 * );
90
91

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

93
94
95
96
97
static char *FromACP( const char *str )
{
    return FromCharset(vlc_pgettext("GetACP", "CP1252"), str, strlen(str));
}

Laurent Aimar's avatar
Laurent Aimar committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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;
118
    int64_t      i_lengthtotal;
Laurent Aimar's avatar
Laurent Aimar committed
119
120
121

} avi_entry_t;

122
123
124
125
126
127
128
129
130
131
132
typedef struct
{
    unsigned int    i_size;
    unsigned int    i_max;
    avi_entry_t     *p_entry;

} avi_index_t;
static void avi_index_Init( avi_index_t * );
static void avi_index_Clean( avi_index_t * );
static void avi_index_Append( avi_index_t *, off_t *, avi_entry_t * );

Laurent Aimar's avatar
Laurent Aimar committed
133
134
typedef struct
{
135
136
    bool            b_activated;
    bool            b_eof;
Laurent Aimar's avatar
Laurent Aimar committed
137
138
139
140
141
142

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

    int             i_rate;
    int             i_scale;
143
    unsigned int    i_samplesize;
Laurent Aimar's avatar
Laurent Aimar committed
144
145
146

    es_out_id_t     *p_es;

hartman's avatar
hartman committed
147
    /* Avi Index */
148
    avi_index_t     idx;
Laurent Aimar's avatar
Laurent Aimar committed
149

hartman's avatar
hartman committed
150
151
    unsigned int    i_idxposc;  /* numero of chunk */
    unsigned int    i_idxposb;  /* byte in the current chunk */
Laurent Aimar's avatar
Laurent Aimar committed
152
153

    /* For VBR audio only */
hartman's avatar
hartman committed
154
155
156
157
158
    unsigned int    i_blockno;
    unsigned int    i_blocksize;

    /* For muxed streams */
    stream_t        *p_out_muxed;
Laurent Aimar's avatar
Laurent Aimar committed
159
160
161
162
163
164
165
} avi_track_t;

struct demux_sys_t
{
    mtime_t i_time;
    mtime_t i_length;

166
167
    bool  b_seekable;
    bool  b_muxed;
Laurent Aimar's avatar
Laurent Aimar committed
168
169
    avi_chunk_t ck_root;

170
    bool  b_odml;
Laurent Aimar's avatar
Laurent Aimar committed
171
172
173
174
175
176
177
178
179
180

    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;
181
182
183

    unsigned int       i_attachment;
    input_attachment_t **attachment;
Laurent Aimar's avatar
Laurent Aimar committed
184
185
};

186
187
static inline off_t __EVEN( off_t i )
{
188
    return (i & 1) ? i + 1 : i;
189
190
}

191
192
193
194
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 * );
195

196

Laurent Aimar's avatar
Laurent Aimar committed
197
198
static int AVI_StreamChunkFind( demux_t *, unsigned int i_stream );
static int AVI_StreamChunkSet ( demux_t *,
199
                                unsigned int i_stream, unsigned int i_ck );
Laurent Aimar's avatar
Laurent Aimar committed
200
static int AVI_StreamBytesSet ( demux_t *,
201
                                unsigned int i_stream, off_t   i_byte );
202

203
vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );
204
static int   AVI_GetKeyFlag    ( vlc_fourcc_t , uint8_t * );
205

Laurent Aimar's avatar
Laurent Aimar committed
206
207
208
209
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 * );
210

Laurent Aimar's avatar
Laurent Aimar committed
211
212
static void AVI_IndexLoad    ( demux_t * );
static void AVI_IndexCreate  ( demux_t * );
213

214
static void AVI_ExtractSubtitle( demux_t *, unsigned int i_stream, avi_chunk_list_t *, avi_chunk_STRING_t * );
215

Laurent Aimar's avatar
Laurent Aimar committed
216
static mtime_t  AVI_MovieGetLength( demux_t * );
217

218
219
static void AVI_MetaLoad( demux_t *, avi_chunk_list_t *p_riff, avi_chunk_avih_t *p_avih );

220
221
222
/*****************************************************************************
 * Stream management
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
223
224
static int        AVI_TrackSeek  ( demux_t *, int, mtime_t );
static int        AVI_TrackStopFinishedStreams( demux_t *);
225

Laurent Aimar's avatar
Laurent Aimar committed
226
227
228
229
230
231
232
233
234
/* 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....
 */

235
236
237
238
239
/*****************************************************************************
 * Open: check file and initializes AVI structures
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
Laurent Aimar's avatar
Laurent Aimar committed
240
    demux_t  *p_demux = (demux_t *)p_this;
241
242
    demux_sys_t     *p_sys;

243
    bool       b_index = false;
244
    int              i_do_index;
zorglub's avatar
zorglub committed
245

ivoire's avatar
ivoire committed
246
    avi_chunk_list_t    *p_riff;
247
248
    avi_chunk_list_t    *p_hdrl, *p_movi;
    avi_chunk_avih_t    *p_avih;
249
250

    unsigned int i_track;
251
    unsigned int i, i_peeker;
252

253
    const uint8_t *p_peek;
254

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

258
259
    for( i_peeker = 0; i_peeker < 188; i_peeker++ )
    {
260
261
262
263
        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;
264
265
266
        p_peek++;
    }
    if( i_peeker == 188 )
267
    {
268
        return VLC_EGENERIC;
269
    }
270

271
    /* Initialize input  structures. */
Laurent Aimar's avatar
Laurent Aimar committed
272
    p_sys = p_demux->p_sys = malloc( sizeof(demux_sys_t) );
273
274
275
276
    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;
277
278
    p_sys->b_odml   = false;
    p_sys->b_muxed  = false;
279
280
    p_sys->i_track  = 0;
    p_sys->track    = NULL;
281
    p_sys->meta     = NULL;
282
    TAB_INIT(p_sys->i_attachment, p_sys->attachment);
283

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

Laurent Aimar's avatar
Laurent Aimar committed
286
287
    p_demux->pf_control = Control;
    p_demux->pf_demux = Demux_Seekable;
288

ivoire's avatar
ivoire committed
289
    /* For unseekable stream, automatically use Demux_UnSeekable */
290
    if( !p_sys->b_seekable
291
     || var_InheritBool( p_demux, "avi-interleaved" ) )
292
    {
Laurent Aimar's avatar
Laurent Aimar committed
293
        p_demux->pf_demux = Demux_UnSeekable;
294
    }
295

296
297
    if( i_peeker > 0 )
    {
298
        stream_Read( p_demux->s, NULL, i_peeker );
299
300
    }

Laurent Aimar's avatar
Laurent Aimar committed
301
    if( AVI_ChunkReadRoot( p_demux->s, &p_sys->ck_root ) )
302
    {
Laurent Aimar's avatar
Laurent Aimar committed
303
        msg_Err( p_demux, "avi module discarded (invalid file)" );
Pierre's avatar
Pierre committed
304
        free(p_sys);
305
        return VLC_EGENERIC;
306
    }
307

308
    if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 )
309
    {
310
        unsigned int i_count =
311
            AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF );
312

Laurent Aimar's avatar
Laurent Aimar committed
313
        msg_Warn( p_demux, "multiple riff -> OpenDML ?" );
314
315
        for( i = 1; i < i_count; i++ )
        {
316
            avi_chunk_list_t *p_sysx;
317

318
319
            p_sysx = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, i );
            if( p_sysx->i_type == AVIFOURCC_AVIX )
320
            {
Laurent Aimar's avatar
Laurent Aimar committed
321
                msg_Warn( p_demux, "detected OpenDML file" );
322
                p_sys->b_odml = true;
323
324
325
326
                break;
            }
        }
    }
327

328
    p_riff  = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
329
330
    p_hdrl  = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
    p_movi  = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
331

332
    if( !p_hdrl || !p_movi )
333
    {
Laurent Aimar's avatar
Laurent Aimar committed
334
        msg_Err( p_demux, "avi module discarded (invalid file)" );
335
        goto error;
336
    }
337

338
    if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) )
339
    {
Laurent Aimar's avatar
Laurent Aimar committed
340
        msg_Err( p_demux, "cannot find avih chunk" );
341
        goto error;
342
    }
343
344
    i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
    if( p_avih->i_streams != i_track )
345
    {
Laurent Aimar's avatar
Laurent Aimar committed
346
        msg_Warn( p_demux,
347
                  "found %d stream but %d are declared",
348
                  i_track, p_avih->i_streams );
349
    }
350
    if( i_track == 0 )
351
    {
Laurent Aimar's avatar
Laurent Aimar committed
352
        msg_Err( p_demux, "no stream defined!" );
353
        goto error;
354
    }
355

356
    /* print information on streams */
Laurent Aimar's avatar
Laurent Aimar committed
357
    msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ",
358
             i_track,
359
360
361
362
             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":"" );
363
364

    AVI_MetaLoad( p_demux, p_riff, p_avih );
365

366
    /* now read info on each stream and create ES */
367
368
    for( i = 0 ; i < i_track; i++ )
    {
hartman's avatar
hartman committed
369
        avi_track_t           *tk     = malloc( sizeof( avi_track_t ) );
370
371
372
        if( !tk )
            goto error;

hartman's avatar
hartman committed
373
374
375
376
377
        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;
378
379
        es_format_t fmt;

380
381
382
        memset( tk, 0, sizeof(*tk) );
        tk->b_eof = false;
        tk->b_activated = true;
hartman's avatar
hartman committed
383

384
385
        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 );
386
387

        if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )
388
        {
Laurent Aimar's avatar
Laurent Aimar committed
389
            msg_Warn( p_demux, "stream[%d] incomplete", i );
390
            free( tk );
391
            continue;
392
        }
393

394
395
396
        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
397
        msg_Dbg( p_demux, "stream[%d] rate:%d scale:%d samplesize:%d",
398
399
400
                 i, tk->i_rate, tk->i_scale, tk->i_samplesize );

        switch( p_strh->i_type )
401
        {
402
            case( AVIFOURCC_auds ):
403
                tk->i_cat   = AUDIO_ES;
404
405
406
407
408
409
410
411
412
413
                if( p_auds->p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
                    p_auds->p_wf->cbSize >= sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) )
                {
                    WAVEFORMATEXTENSIBLE *p_wfe = (WAVEFORMATEXTENSIBLE *)p_auds->p_wf;
                    tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
                                                      p_wfe->SubFormat.Data1 );
                }
                else
                    tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
                                                      p_auds->p_wf->wFormatTag );
414
415
416

                tk->i_blocksize = p_auds->p_wf->nBlockAlign;
                if( tk->i_blocksize == 0 )
Laurent Aimar's avatar
Laurent Aimar committed
417
418
419
420
421
422
                {
                    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;
                }
423
424
425
426
427
428
429
430
                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;
                }

431
                if( tk->i_codec == VLC_CODEC_VORBIS )
432
433
434
435
                {
                    tk->i_blocksize = 0; /* fix vorbis VBR decoding */
                }

436
437
438
                es_format_Init( &fmt, AUDIO_ES, tk->i_codec );

                fmt.audio.i_channels        = p_auds->p_wf->nChannels;
gbazin's avatar
   
gbazin committed
439
                fmt.audio.i_rate            = p_auds->p_wf->nSamplesPerSec;
gbazin's avatar
   
gbazin committed
440
                fmt.i_bitrate               = p_auds->p_wf->nAvgBytesPerSec*8;
441
442
                fmt.audio.i_blockalign      = p_auds->p_wf->nBlockAlign;
                fmt.audio.i_bitspersample   = p_auds->p_wf->wBitsPerSample;
443
                fmt.b_packetized            = !tk->i_blocksize;
444
445

                msg_Dbg( p_demux,
446
447
448
                    "stream[%d] audio(0x%x - %s) %d channels %dHz %dbits",
                    i, p_auds->p_wf->wFormatTag,vlc_fourcc_GetDescription(AUDIO_ES,tk->i_codec),
                    p_auds->p_wf->nChannels,
449
                    p_auds->p_wf->nSamplesPerSec,
450
451
                    p_auds->p_wf->wBitsPerSample );

gbazin's avatar
   
gbazin committed
452
453
                fmt.i_extra = __MIN( p_auds->p_wf->cbSize,
                    p_auds->i_chunk_size - sizeof(WAVEFORMATEX) );
454
455
456
457
458
459
                if( fmt.i_extra > 0 )
                {
                    fmt.p_extra = malloc( fmt.i_extra );
                    if( !fmt.p_extra ) goto error;
                    memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra );
                }
460
461
462
                break;

            case( AVIFOURCC_vids ):
463
464
465
                tk->i_cat   = VIDEO_ES;
                tk->i_codec = AVI_FourccGetCodec( VIDEO_ES,
                                                  p_vids->p_bih->biCompression );
hartman's avatar
hartman committed
466
467
468
469
                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 );
470
                   tk->i_cat = SPU_ES;
hartman's avatar
hartman committed
471
472
473
                   break;
                }
                else if( p_vids->p_bih->biCompression == 0x00 )
474
475
476
477
                {
                    switch( p_vids->p_bih->biBitCount )
                    {
                        case 32:
478
                            tk->i_codec = VLC_CODEC_RGB32;
479
480
                            break;
                        case 24:
481
                            tk->i_codec = VLC_CODEC_RGB24;
482
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
483
                        case 16: /* Yes it is RV15 */
484
                        case 15:
485
                            tk->i_codec = VLC_CODEC_RGB15;
486
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
487
                        case 9: /* <- TODO check that */
488
                            tk->i_codec = VLC_CODEC_I410;
489
                            break;
Laurent Aimar's avatar
Laurent Aimar committed
490
                        case 8: /* <- TODO check that */
491
                            tk->i_codec = VLC_CODEC_GREY;
492
                            break;
493
494
                    }
                    es_format_Init( &fmt, VIDEO_ES, tk->i_codec );
495

Laurent Aimar's avatar
Laurent Aimar committed
496
                    switch( tk->i_codec )
497
                    {
498
499
                    case VLC_CODEC_RGB24:
                    case VLC_CODEC_RGB32:
Laurent Aimar's avatar
Laurent Aimar committed
500
                        fmt.video.i_rmask = 0x00ff0000;
501
                        fmt.video.i_gmask = 0x0000ff00;
Laurent Aimar's avatar
Laurent Aimar committed
502
503
                        fmt.video.i_bmask = 0x000000ff;
                        break;
504
                    case VLC_CODEC_RGB15:
Laurent Aimar's avatar
Laurent Aimar committed
505
506
507
508
509
510
                        fmt.video.i_rmask = 0x7c00;
                        fmt.video.i_gmask = 0x03e0;
                        fmt.video.i_bmask = 0x001f;
                        break;
                    default:
                        break;
511
                    }
512
513
514
515
                }
                else
                {
                    es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );
516
                    if( tk->i_codec == VLC_CODEC_MP4V &&
517
                        !strncasecmp( (char*)&p_strh->i_handler, "XVID", 4 ) )
518
                    {
519
520
                        fmt.i_codec           =
                        fmt.i_original_fourcc = VLC_FOURCC( 'X', 'V', 'I', 'D' );
521
                    }
522
                }
523
524
525
                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
526
                fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;
527
528
                fmt.video.i_frame_rate = tk->i_rate;
                fmt.video.i_frame_rate_base = tk->i_scale;
gbazin's avatar
   
gbazin committed
529
530
531
                fmt.i_extra =
                    __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
                           p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) );
532
533
534
535
536
537
                if( fmt.i_extra > 0 )
                {
                    fmt.p_extra = malloc( fmt.i_extra );
                    if( !fmt.p_extra ) goto error;
                    memcpy( fmt.p_extra, &p_vids->p_bih[1], fmt.i_extra );
                }
538

539
                msg_Dbg( p_demux, "stream[%d] video(%4.4s) %"PRIu32"x%"PRIu32" %dbpp %ffps",
540
                         i, (char*)&p_vids->p_bih->biCompression,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
541
542
                         (uint32_t)p_vids->p_bih->biWidth,
                         (uint32_t)p_vids->p_bih->biHeight,
543
544
                         p_vids->p_bih->biBitCount,
                         (float)tk->i_rate/(float)tk->i_scale );
545
546
547
548
549
550
551

                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);
                }
552
553
554
555

                /* 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
556
                if( fmt.video.i_bits_per_pixel > 0 && fmt.video.i_bits_per_pixel <= 8 )
557
                {
Laurent Aimar's avatar
Laurent Aimar committed
558
559
                    /* The palette is not always included in biSize */
                    fmt.i_extra = p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER);
560
                    if( fmt.i_extra > 0 && fmt.p_extra )
Laurent Aimar's avatar
Laurent Aimar committed
561
562
                    {
                        const uint8_t *p_pal = fmt.p_extra;
563

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

Laurent Aimar's avatar
Laurent Aimar committed
567
568
569
570
571
                        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];
                        }
572
                    }
573
                }
574
                break;
575
576

            case( AVIFOURCC_txts):
577
                msg_Dbg( p_demux, "stream[%d] subtitle attachment", i );
578
                AVI_ExtractSubtitle( p_demux, i, p_strl, p_strn );
579
580
                free( tk );
                continue;
581

hartman's avatar
hartman committed
582
583
            case( AVIFOURCC_iavs):
            case( AVIFOURCC_ivas):
584
                p_sys->b_muxed = true;
hartman's avatar
hartman committed
585
586
587
                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 ||
588
589
590
                    p_strh->i_handler == FOURCC_dvsl ||
                    p_strh->i_handler == FOURCC_dv25 ||
                    p_strh->i_handler == FOURCC_dv50 )
hartman's avatar
hartman committed
591
                {
592
                    tk->p_out_muxed = stream_DemuxNew( p_demux, (char *)"rawdv", p_demux->out );
hartman's avatar
hartman committed
593
594
595
596
597
598
599
                    if( !tk->p_out_muxed )
                        msg_Err( p_demux, "could not load the DV parser" );
                    else break;
                }
                free( tk );
                continue;

600
601
            case( AVIFOURCC_mids):
                msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i );
602

603
            default:
hartman's avatar
hartman committed
604
                msg_Warn( p_demux, "stream[%d] unknown type %4.4s", i, (char *)&p_strh->i_type );
605
606
                free( tk );
                continue;
607
        }
hartman's avatar
hartman committed
608
        if( p_strn )
609
            fmt.psz_description = FromACP( p_strn->p_str );
hartman's avatar
hartman committed
610
611
        if( tk->p_out_muxed == NULL )
            tk->p_es = es_out_Add( p_demux->out, &fmt );
612
        TAB_APPEND( p_sys->i_track, p_sys->track, tk );
613
614
615
616
        if(!p_sys->b_muxed )
        {
            es_format_Clean( &fmt );
        }
617
618
619
620
    }

    if( p_sys->i_track <= 0 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
621
        msg_Err( p_demux, "no valid track" );
622
        goto error;
623
624
    }

625
    i_do_index = var_InheritInteger( p_demux, "avi-index" );
626
    if( i_do_index == 1 ) /* Always fix */
627
    {
zorglub's avatar
zorglub committed
628
aviindex:
629
        if( p_sys->b_seekable )
630
        {
Laurent Aimar's avatar
Laurent Aimar committed
631
            AVI_IndexCreate( p_demux );
632
        }
633
        else
634
        {
Laurent Aimar's avatar
Laurent Aimar committed
635
636
            msg_Warn( p_demux, "cannot create index (unseekable stream)" );
            AVI_IndexLoad( p_demux );
637
638
        }
    }
639
    else
640
    {
Laurent Aimar's avatar
Laurent Aimar committed
641
        AVI_IndexLoad( p_demux );
642
    }
643
644

    /* *** movie length in sec *** */
Laurent Aimar's avatar
Laurent Aimar committed
645
    p_sys->i_length = AVI_MovieGetLength( p_demux );
646
647
648
649
650
651

    /* Check the index completeness */
    unsigned int i_idx_totalframes = 0;
    for( unsigned int i = 0; i < p_sys->i_track; i++ )
    {
        const avi_track_t *tk = p_sys->track[i];
652
653
        if( tk->i_cat == VIDEO_ES && tk->idx.p_entry )
            i_idx_totalframes = __MAX(i_idx_totalframes, tk->idx.i_size);
654
655
656
657
            continue;
    }
    if( i_idx_totalframes != p_avih->i_totalframes &&
        p_sys->i_length < (mtime_t)p_avih->i_totalframes *
658
659
                          (mtime_t)p_avih->i_microsecperframe /
                          (mtime_t)1000000 )
660
    {
661
662
663
        if( !vlc_object_alive( p_demux) )
            goto error;

zorglub's avatar
zorglub committed
664
        msg_Warn( p_demux, "broken or missing index, 'seek' will be "
665
                           "approximative or will exhibit strange behavior" );
666
        if( i_do_index == 0 && !b_index )
zorglub's avatar
zorglub committed
667
        {
668
669
670
671
            if( !p_sys->b_seekable ) {
                b_index = true;
                goto aviindex;
            }
672
673
674
675
676
677
            switch( dialog_Question( p_demux, _("Broken or missing AVI Index") ,
               _( "Because this AVI file index is broken or missing, "
                  "seeking will not work correctly.\n"
                  "VLC won't repair your file but can temporary fix this "
                  "problem by building an index in memory.\n"
                  "This step might take a long time on a large file.\n"
678
                  "What do you want to do ?" ),
679
                  _( "Build index then play" ), _( "Play as is" ), _( "Do not play") ) )
zorglub's avatar
zorglub committed
680
            {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
681
682
683
684
685
686
687
688
                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
689
690
            }
        }
691
    }
zorglub's avatar
zorglub committed
692

693
    /* fix some BeOS MediaKit generated file */
694
    for( i = 0 ; i < p_sys->i_track; i++ )
695
    {
696
697
698
699
        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;
700

701
        if( tk->i_cat != AUDIO_ES )
702
703
704
        {
            continue;
        }
705
        if( tk->idx.i_size < 1 ||
706
707
            tk->i_scale != 1 ||
            tk->i_samplesize != 0 )
708
709
710
        {
            continue;
        }
711
712
713
        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 );
714

715
716
        if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM &&
            (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec )
717
718
        {
            int64_t i_track_length =
719
720
                tk->idx.p_entry[tk->idx.i_size-1].i_length +
                tk->idx.p_entry[tk->idx.i_size-1].i_lengthtotal;
721
722
            mtime_t i_length = (mtime_t)p_avih->i_totalframes *
                               (mtime_t)p_avih->i_microsecperframe;
723

724
725
            if( i_length == 0 )
            {
Laurent Aimar's avatar
Laurent Aimar committed
726
                msg_Warn( p_demux, "track[%d] cannot be fixed (BeOS MediaKit generated)", i );
727
728
                continue;
            }
729
730
            tk->i_samplesize = 1;
            tk->i_rate       = i_track_length  * (int64_t)1000000/ i_length;
Laurent Aimar's avatar
Laurent Aimar committed
731
            msg_Warn( p_demux, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, tk->i_rate, tk->i_scale );
732
733
        }
    }
734

735
    if( p_sys->b_seekable )
736
737
    {
        /* we have read all chunk so go back to movi */
Laurent Aimar's avatar
Laurent Aimar committed
738
        stream_Seek( p_demux->s, p_movi->i_chunk_pos );
739
    }
740
    /* Skip movi header */
Laurent Aimar's avatar
Laurent Aimar committed
741
    stream_Read( p_demux->s, NULL, 12 );
742

743
    p_sys->i_movi_begin = p_movi->i_chunk_pos;
744
    return VLC_SUCCESS;
745
746

error:
747
748
749
750
    for( unsigned i = 0; i < p_sys->i_attachment; i++)
        vlc_input_attachment_Delete(p_sys->attachment[i]);
    free(p_sys->attachment);

751
752
    if( p_sys->meta )
        vlc_meta_Delete( p_sys->meta );
753

Laurent Aimar's avatar
Laurent Aimar committed
754
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
755
    free( p_sys );
756
    return vlc_object_alive( p_demux ) ? VLC_EGENERIC : VLC_ETIMEOUT;
757
758
}

759
760
761
762
/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close ( vlc_object_t * p_this )
763
{
Laurent Aimar's avatar
Laurent Aimar committed
764
    demux_t *    p_demux = (demux_t *)p_this;
765
    unsigned int i;
Laurent Aimar's avatar
Laurent Aimar committed
766
    demux_sys_t *p_sys = p_demux->p_sys  ;
767

768
    for( i = 0; i < p_sys->i_track; i++ )
769
    {
770
        if( p_sys->track[i] )
771
        {
hartman's avatar
hartman committed
772
            if( p_sys->track[i]->p_out_muxed )
773
                stream_Delete( p_sys->track[i]->p_out_muxed );
774
            avi_index_Clean( &p_sys->track[i]->idx );
775
            free( p_sys->track[i] );
776
777
        }
    }
778
    free( p_sys->track );
Laurent Aimar's avatar
Laurent Aimar committed
779
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
780
    vlc_meta_Delete( p_sys->meta );
781
782
783
    for( unsigned i = 0; i < p_sys->i_attachment; i++)
        vlc_input_attachment_Delete(p_sys->attachment[i]);
    free(p_sys->attachment);
784

785
    free( p_sys );
786
787
}

788
789
790
791
792
793
794
/*****************************************************************************
 * 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
 *****************************************************************************/
795
typedef struct
796
{
797
    bool b_ok;
798

799
    int i_toread;
800

hartman's avatar
hartman committed
801
802
803
    off_t i_posf; /* where we will read :
                   if i_idxposb == 0 : begining of chunk (+8 to acces data)
                   else : point on data directly */
804
} avi_track_toread_t;
805

Laurent Aimar's avatar
Laurent Aimar committed
806
static int Demux_Seekable( demux_t *p_demux )
807
{
Laurent Aimar's avatar
Laurent Aimar committed
808
    demux_sys_t *p_sys = p_demux->p_sys;
809
810
811

    unsigned int i_track_count = 0;
    unsigned int i_track;
hartman's avatar
hartman committed
812
    /* cannot be more than 100 stream (dcXX or wbXX) */
813
    avi_track_toread_t toread[100];
814
815


816
    /* detect new selected/unselected streams */
817
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
818
    {
819
        avi_track_t *tk = p_sys->track[i_track];
820
        bool  b;
821

hartman's avatar
hartman committed
822
823
824
        if( p_sys->b_muxed && tk->p_out_muxed )
        {
            i_track_count++;
825
            tk->b_activated = true;
hartman's avatar
hartman committed
826
827
828
            continue;
        }

Laurent Aimar's avatar
Laurent Aimar committed
829
        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
830
        if( b && !tk->b_activated )
831
        {
832
            if( p_sys->b_seekable)
833
            {
Laurent Aimar's avatar
Laurent Aimar committed
834
                AVI_TrackSeek( p_demux, i_track, p_sys->i_time );
835
            }
836
            tk->b_activated = true;
837
        }
838
        else if( !b && tk->b_activated )
Laurent Aimar's avatar