avi.c 79.7 KB
Newer Older
1 2 3
/*****************************************************************************
 * avi.c : AVI file Stream input module for vlc
 *****************************************************************************
4
 * Copyright (C) 2001-2004 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
Antoine Cellerier's avatar
Antoine Cellerier 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/vlc.h>
Clément Stenac's avatar
Clément Stenac committed
32
#include <vlc_demux.h>
33

Clément Stenac's avatar
Clément Stenac committed
34
#include <vlc_interface.h>
Clément Stenac's avatar
Clément Stenac committed
35

Clément Stenac's avatar
Clément Stenac committed
36 37 38
#include <vlc_meta.h>
#include <vlc_codecs.h>
#include <vlc_charset.h>
39

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

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
45 46

#define INTERLEAVE_TEXT N_("Force interleaved method" )
47
#define INTERLEAVE_LONGTEXT N_( "Force interleaved method." )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
48 49 50

#define INDEX_TEXT N_("Force index creation")
#define INDEX_LONGTEXT N_( \
51
    "Recreate a index for the AVI file. Use this if your AVI file is damaged "\
Clément Stenac's avatar
Clément Stenac committed
52
    "or incomplete (not seekable)." )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
53

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

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

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

62
vlc_module_begin();
63
    set_shortname( "AVI" );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
64
    set_description( _("AVI demuxer") );
65
    set_capability( "demux", 212 );
Clément Stenac's avatar
Clément Stenac committed
66 67
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_DEMUX );
68

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
69
    add_bool( "avi-interleaved", 0, NULL,
70
              INTERLEAVE_TEXT, INTERLEAVE_LONGTEXT, true );
71
    add_integer( "avi-index", 0, NULL,
72
              INDEX_TEXT, INDEX_LONGTEXT, false );
73
        change_integer_list( pi_index, ppsz_indexes, 0 );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
74

75
    set_callbacks( Open, Close );
76 77
vlc_module_end();

78 79 80
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
81 82 83 84
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 * );
85 86

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

Laurent Aimar's avatar
Laurent Aimar committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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;
    uint32_t     i_lengthtotal;

} avi_entry_t;

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

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

    int             i_rate;
    int             i_scale;
    int             i_samplesize;

    es_out_id_t     *p_es;

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
125
    /* Avi Index */
Laurent Aimar's avatar
Laurent Aimar committed
126
    avi_entry_t     *p_index;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
127 128
    unsigned int    i_idxnb;
    unsigned int    i_idxmax;
Laurent Aimar's avatar
Laurent Aimar committed
129

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
130 131
    unsigned int    i_idxposc;  /* numero of chunk */
    unsigned int    i_idxposb;  /* byte in the current chunk */
Laurent Aimar's avatar
Laurent Aimar committed
132

133 134 135
    /* extra information given to the decoder */
    void            *p_extra;

Laurent Aimar's avatar
Laurent Aimar committed
136
    /* For VBR audio only */
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
137 138 139 140 141
    unsigned int    i_blockno;
    unsigned int    i_blocksize;

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

struct demux_sys_t
{
    mtime_t i_time;
    mtime_t i_length;

149 150
    bool  b_seekable;
    bool  b_muxed;
Laurent Aimar's avatar
Laurent Aimar committed
151 152
    avi_chunk_t ck_root;

153
    bool  b_odml;
Laurent Aimar's avatar
Laurent Aimar committed
154 155 156 157 158 159 160 161 162 163

    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;
164 165 166 167

    /* Progress box */
    mtime_t    last_update;
    int        i_dialog_id;
Laurent Aimar's avatar
Laurent Aimar committed
168 169
};

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

175 176 177 178
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 * );
179

180

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

187
vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );
188
static int   AVI_GetKeyFlag    ( vlc_fourcc_t , uint8_t * );
189

Laurent Aimar's avatar
Laurent Aimar committed
190 191 192 193
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 * );
194

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

Laurent Aimar's avatar
Laurent Aimar committed
199
static mtime_t  AVI_MovieGetLength( demux_t * );
200

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

Laurent Aimar's avatar
Laurent Aimar committed
207 208 209 210 211 212 213 214 215
/* 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....
 */

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

224
    bool       b_index = false;
225
    int              i_do_index;
Clément Stenac's avatar
Clément Stenac committed
226

227 228 229 230
    avi_chunk_t         ck_riff;
    avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
    avi_chunk_list_t    *p_hdrl, *p_movi;
    avi_chunk_avih_t    *p_avih;
231 232

    unsigned int i_track;
233
    unsigned int i, i_peeker;
234

235
    const uint8_t *p_peek;
236

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

240 241
    for( i_peeker = 0; i_peeker < 188; i_peeker++ )
    {
242 243 244 245
        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;
246 247 248
        p_peek++;
    }
    if( i_peeker == 188 )
249
    {
250
        return VLC_EGENERIC;
251
    }
252

253
    /* Initialize input  structures. */
Laurent Aimar's avatar
Laurent Aimar committed
254
    p_sys = p_demux->p_sys = malloc( sizeof(demux_sys_t) );
255 256 257 258
    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;
259 260
    p_sys->b_odml   = false;
    p_sys->b_muxed  = false;
261 262
    p_sys->i_track  = 0;
    p_sys->track    = NULL;
263
    p_sys->meta     = NULL;
264

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

Laurent Aimar's avatar
Laurent Aimar committed
267 268
    p_demux->pf_control = Control;
    p_demux->pf_demux = Demux_Seekable;
269

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

276 277
    if( i_peeker > 0 )
    {
278
        stream_Read( p_demux->s, NULL, i_peeker );
279 280
    }

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

287
    if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 )
288
    {
289
        unsigned int i_count =
290
            AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF );
291

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

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

307
    p_riff  = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
308 309
    p_hdrl  = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
    p_movi  = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
310

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

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

335
    /* print information on streams */
Laurent Aimar's avatar
Laurent Aimar committed
336
    msg_Dbg( p_demux, "AVIH: %d stream, flags %s%s%s%s ",
337
             i_track,
338 339 340 341
             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":"" );
342
    if( ( p_sys->meta = vlc_meta_New() ) )
343
    {
344 345 346 347 348 349
        char buffer[200];
        sprintf( 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":"" );
350
        vlc_meta_SetSetting( p_sys->meta, buffer );
351
    }
352

353
    /* now read info on each stream and create ES */
354 355
    for( i = 0 ; i < i_track; i++ )
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
356
        avi_track_t           *tk     = malloc( sizeof( avi_track_t ) );
357 358 359 360 361 362
        if( !tk )
        {
            msg_Err( p_demux, "Out of memory" );
            goto error;
        }

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
363 364 365 366 367
        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;
368 369
        es_format_t fmt;

370
        memset( tk, 0, sizeof( avi_track_t ) );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
371

372 373
        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 );
374 375

        if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )
376
        {
Laurent Aimar's avatar
Laurent Aimar committed
377
            msg_Warn( p_demux, "stream[%d] incomplete", i );
378
            continue;
379
        }
380

381 382 383
        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
384
        msg_Dbg( p_demux, "stream[%d] rate:%d scale:%d samplesize:%d",
385 386 387
                 i, tk->i_rate, tk->i_scale, tk->i_samplesize );

        switch( p_strh->i_type )
388
        {
389
            case( AVIFOURCC_auds ):
390 391 392
                tk->i_cat   = AUDIO_ES;
                tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
                                                  p_auds->p_wf->wFormatTag );
393 394 395
                if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
                    tk->i_blocksize = 0; /* fix vorbis VBR decoding */
                else if( ( tk->i_blocksize = p_auds->p_wf->nBlockAlign ) == 0 )
Laurent Aimar's avatar
Laurent Aimar committed
396 397 398 399 400 401 402 403 404 405
                {
                    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;
                    }
                }
406 407 408
                es_format_Init( &fmt, AUDIO_ES, tk->i_codec );

                fmt.audio.i_channels        = p_auds->p_wf->nChannels;
Gildas Bazin's avatar
 
Gildas Bazin committed
409
                fmt.audio.i_rate            = p_auds->p_wf->nSamplesPerSec;
Gildas Bazin's avatar
 
Gildas Bazin committed
410
                fmt.i_bitrate               = p_auds->p_wf->nAvgBytesPerSec*8;
411 412
                fmt.audio.i_blockalign      = p_auds->p_wf->nBlockAlign;
                fmt.audio.i_bitspersample   = p_auds->p_wf->wBitsPerSample;
413
                fmt.b_packetized            = !tk->i_blocksize;
414 415 416 417 418 419 420

                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 );

Gildas Bazin's avatar
 
Gildas Bazin committed
421 422
                fmt.i_extra = __MIN( p_auds->p_wf->cbSize,
                    p_auds->i_chunk_size - sizeof(WAVEFORMATEX) );
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 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
                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 ...
                 */

                if( tk->i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
                {
                    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;
                }
493 494 495
                break;

            case( AVIFOURCC_vids ):
496 497 498
                tk->i_cat   = VIDEO_ES;
                tk->i_codec = AVI_FourccGetCodec( VIDEO_ES,
                                                  p_vids->p_bih->biCompression );
499 500 501 502 503 504 505 506 507 508 509
                if( p_vids->p_bih->biCompression == 0x00 )
                {
                    switch( p_vids->p_bih->biBitCount )
                    {
                        case 32:
                            tk->i_codec = VLC_FOURCC('R','V','3','2');
                            break;
                        case 24:
                            tk->i_codec = VLC_FOURCC('R','V','2','4');
                            break;
                        case 16:
510 511
                            /* tk->i_codec = VLC_FOURCC('R','V','1','6');*/
                            /* break;*/
512 513 514 515 516 517
                        case 15:
                            tk->i_codec = VLC_FOURCC('R','V','1','5');
                            break;
                        case 9:
                            tk->i_codec = VLC_FOURCC( 'Y', 'V', 'U', '9' ); /* <- TODO check that */
                            break;
518 519 520
                        case 8:
                            tk->i_codec = VLC_FOURCC('Y','8','0','0');
                            break;
521 522
                    }
                    es_format_Init( &fmt, VIDEO_ES, tk->i_codec );
523 524 525 526 527 528 529 530

                    if( p_vids->p_bih->biBitCount == 24 )
                    {
                        /* This is in BGR format */
                        fmt.video.i_bmask = 0x00ff0000;
                        fmt.video.i_gmask = 0x0000ff00;
                        fmt.video.i_rmask = 0x000000ff;
                    }
531 532 533 534
                }
                else
                {
                    es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );
535 536
                    if( tk->i_codec == FOURCC_mp4v &&
                        !strncasecmp( (char*)&p_strh->i_handler, "XVID", 4 ) )
537 538 539
                    {
                        fmt.i_codec = VLC_FOURCC( 'X', 'V', 'I', 'D' );
                    }
540
                }
541 542 543
                tk->i_samplesize = 0;
                fmt.video.i_width  = p_vids->p_bih->biWidth;
                fmt.video.i_height = p_vids->p_bih->biHeight;
544
                fmt.video.i_bits_per_pixel = p_vids->p_bih->biBitCount;
545 546
                fmt.video.i_frame_rate = tk->i_rate;
                fmt.video.i_frame_rate_base = tk->i_scale;
Gildas Bazin's avatar
 
Gildas Bazin committed
547 548 549 550
                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];
Laurent Aimar's avatar
Laurent Aimar committed
551
                msg_Dbg( p_demux, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
552
                         i, (char*)&p_vids->p_bih->biCompression,
553 554 555 556
                         p_vids->p_bih->biWidth,
                         p_vids->p_bih->biHeight,
                         p_vids->p_bih->biBitCount,
                         (float)tk->i_rate/(float)tk->i_scale );
557 558 559 560 561 562 563

                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);
                }
564 565 566 567 568 569 570 571 572 573 574 575

                /* Extract palette from extradata if bpp <= 8
                 * (assumes that extradata contains only palette but appears
                 *  to be true for all palettized codecs we support) */
                if( fmt.i_extra && fmt.video.i_bits_per_pixel <= 8 &&
                    fmt.video.i_bits_per_pixel > 0 )
                {
                    int i;

                    fmt.video.p_palette = calloc( sizeof(video_palette_t), 1 );
                    fmt.video.p_palette->i_entries = 1;

576 577 578
                    /* Apparently this is necessary. But why ? */
                    fmt.i_extra =
                        p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER);
579
                    for( i = 0; i < __MIN(fmt.i_extra/4, 256); i++ )
580
                    {
581 582
                        ((uint32_t *)&fmt.video.p_palette->palette[0][0])[i] =
                            GetDWLE((uint32_t*)fmt.p_extra + i);
583
                    }
584
                }
585
                break;
586 587 588 589 590 591 592

            case( AVIFOURCC_txts):
                tk->i_cat   = SPU_ES;
                tk->i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
                msg_Dbg( p_demux, "stream[%d] subtitles", i );
                es_format_Init( &fmt, SPU_ES, tk->i_codec );
                break;
593

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
594 595
            case( AVIFOURCC_iavs):
            case( AVIFOURCC_ivas):
596
                p_sys->b_muxed = true;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
597 598 599
                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 ||
600 601 602
                    p_strh->i_handler == FOURCC_dvsl ||
                    p_strh->i_handler == FOURCC_dv25 ||
                    p_strh->i_handler == FOURCC_dv50 )
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
603
                {
604
                    tk->p_out_muxed = stream_DemuxNew( p_demux, (char *)"rawdv", p_demux->out );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
605 606 607 608 609 610 611
                    if( !tk->p_out_muxed )
                        msg_Err( p_demux, "could not load the DV parser" );
                    else break;
                }
                free( tk );
                continue;

612 613
            case( AVIFOURCC_mids):
                msg_Dbg( p_demux, "stream[%d] midi is UNSUPPORTED", i );
614

615
            default:
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
616
                msg_Warn( p_demux, "stream[%d] unknown type %4.4s", i, (char *)&p_strh->i_type );
617 618
                free( tk );
                continue;
619
        }
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
620 621
        if( p_strn )
        {
622 623
            /* The charset of p_strn is undefined */
            EnsureUTF8( p_strn->p_str );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
624 625
            fmt.psz_description = strdup( p_strn->p_str );
        }
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
626 627
        if( tk->p_out_muxed == NULL )
            tk->p_es = es_out_Add( p_demux->out, &fmt );
628 629 630 631 632
        TAB_APPEND( p_sys->i_track, p_sys->track, tk );
    }

    if( p_sys->i_track <= 0 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
633
        msg_Err( p_demux, "no valid track" );
634
        goto error;
635 636
    }

637 638
    i_do_index =  config_GetInt( p_demux, "avi-index" );
    if( i_do_index == 1 ) /* Always fix */
639
    {
Clément Stenac's avatar
Clément Stenac committed
640
aviindex:
641
        if( p_sys->b_seekable )
642
        {
Laurent Aimar's avatar
Laurent Aimar committed
643
            AVI_IndexCreate( p_demux );
644
        }
645
        else
646
        {
Laurent Aimar's avatar
Laurent Aimar committed
647 648
            msg_Warn( p_demux, "cannot create index (unseekable stream)" );
            AVI_IndexLoad( p_demux );
649 650
        }
    }
651
    else
652
    {
Laurent Aimar's avatar
Laurent Aimar committed
653
        AVI_IndexLoad( p_demux );
654
    }
655 656

    /* *** movie length in sec *** */
Laurent Aimar's avatar
Laurent Aimar committed
657
    p_sys->i_length = AVI_MovieGetLength( p_demux );
658
    if( p_sys->i_length < (mtime_t)p_avih->i_totalframes *
659 660
                          (mtime_t)p_avih->i_microsecperframe /
                          (mtime_t)1000000 )
661
    {
662 663
        msg_Warn( p_demux, "broken or missing index, 'seek' will be "
                           "axproximative or will have strange behaviour" );
664
        if( i_do_index == 0 && !b_index )
Clément Stenac's avatar
Clément Stenac committed
665 666
        {
            int i_create;
667 668 669
            i_create = intf_UserYesNo( p_demux, _("AVI Index") ,
                        _( "This AVI file is broken. Seeking will not "
                        "work correctly.\nDo you want to "
Felix Paul Kühne's avatar
Felix Paul Kühne committed
670
                        "try to repair it?\n\nThis might take a long time." ),
Clément Stenac's avatar
Clément Stenac committed
671
                        _( "Repair" ), _( "Don't repair" ), _( "Cancel") );
Clément Stenac's avatar
Clément Stenac committed
672 673
            if( i_create == DIALOG_OK_YES )
            {
674
                b_index = true;
Clément Stenac's avatar
Clément Stenac committed
675 676 677 678 679 680
                msg_Dbg( p_demux, "Fixing AVI index" );
                goto aviindex;
            }
            else if( i_create == DIALOG_CANCELLED )
            {
                /* Kill input */
681
                vlc_object_kill( p_demux->p_parent );
Clément Stenac's avatar
Clément Stenac committed
682 683 684
                goto error;
            }
        }
685
    }
Clément Stenac's avatar
Clément Stenac committed
686

687
    /* fix some BeOS MediaKit generated file */
688
    for( i = 0 ; i < p_sys->i_track; i++ )
689
    {
690 691 692 693
        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;
694

695
        if( tk->i_cat != AUDIO_ES )
696 697 698
        {
            continue;
        }
699 700 701
        if( tk->i_idxnb < 1 ||
            tk->i_scale != 1 ||
            tk->i_samplesize != 0 )
702 703 704
        {
            continue;
        }
705 706 707
        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 );
708

709 710
        if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM &&
            (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec )
711 712
        {
            int64_t i_track_length =
713 714
                tk->p_index[tk->i_idxnb-1].i_length +
                tk->p_index[tk->i_idxnb-1].i_lengthtotal;
715 716
            mtime_t i_length = (mtime_t)p_avih->i_totalframes *
                               (mtime_t)p_avih->i_microsecperframe;
717

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

729
    if( p_sys->b_seekable )
730 731
    {
        /* we have read all chunk so go back to movi */
Laurent Aimar's avatar
Laurent Aimar committed
732
        stream_Seek( p_demux->s, p_movi->i_chunk_pos );
733
    }
734
    /* Skip movi header */
Laurent Aimar's avatar
Laurent Aimar committed
735
    stream_Read( p_demux->s, NULL, 12 );
736

737
    p_sys->i_movi_begin = p_movi->i_chunk_pos;
738
    return VLC_SUCCESS;
739 740

error:
741 742 743 744
    if( p_sys->meta )
    {
        vlc_meta_Delete( p_sys->meta );
    }
Laurent Aimar's avatar
Laurent Aimar committed
745
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
746
    free( p_sys );
747
    return VLC_EGENERIC;
748 749
}

750 751 752 753
/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close ( vlc_object_t * p_this )
754
{
Laurent Aimar's avatar
Laurent Aimar committed
755
    demux_t *    p_demux = (demux_t *)p_this;
756
    unsigned int i;
Laurent Aimar's avatar
Laurent Aimar committed
757
    demux_sys_t *p_sys = p_demux->p_sys  ;
758

759
    for( i = 0; i < p_sys->i_track; i++ )
760
    {
761
        if( p_sys->track[i] )
762
        {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
763 764
            if( p_sys->track[i]->p_out_muxed )
                stream_DemuxDelete( p_sys->track[i]->p_out_muxed );
765 766
            free( p_sys->track[i]->p_index );
            free( p_sys->track[i]->p_extra );
767
            free( p_sys->track[i] );
768 769
        }
    }
770
    free( p_sys->track );
Laurent Aimar's avatar
Laurent Aimar committed
771
    AVI_ChunkFreeRoot( p_demux->s, &p_sys->ck_root );
772
    vlc_meta_Delete( p_sys->meta );
773

774
    free( p_sys );
775 776
}

777 778 779 780 781 782 783
/*****************************************************************************
 * 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
 *****************************************************************************/
784
typedef struct
785
{
786
    bool b_ok;
787

788
    int i_toread;
789

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
790 791 792
    off_t i_posf; /* where we will read :
                   if i_idxposb == 0 : begining of chunk (+8 to acces data)
                   else : point on data directly */
793
} avi_track_toread_t;
794

Laurent Aimar's avatar
Laurent Aimar committed
795
static int Demux_Seekable( demux_t *p_demux )
796
{
Laurent Aimar's avatar
Laurent Aimar committed
797
    demux_sys_t *p_sys = p_demux->p_sys;
798 799 800

    unsigned int i_track_count = 0;
    unsigned int i_track;
801
    bool b_stream;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
802
    /* cannot be more than 100 stream (dcXX or wbXX) */
803
    avi_track_toread_t toread[100];
804 805


806
    /* detect new selected/unselected streams */
807
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
808
    {
809
        avi_track_t *tk = p_sys->track[i_track];
810
        bool  b;
811

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
812 813 814
        if( p_sys->b_muxed && tk->p_out_muxed )
        {
            i_track_count++;
815
            tk->b_activated = true;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
816 817 818
            continue;
        }

Laurent Aimar's avatar
Laurent Aimar committed
819
        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
820
        if( b && !tk->b_activated )
821
        {
822
            if( p_sys->b_seekable)
823
            {
Laurent Aimar's avatar
Laurent Aimar committed
824
                AVI_TrackSeek( p_demux, i_track, p_sys->i_time );
825
            }
826
            tk->b_activated = true;
827
        }
828
        else if( !b && tk->b_activated )
829
        {
830
            tk->b_activated = false;
831 832 833 834
        }
        if( b )
        {
            i_track_count++;
835 836 837
        }
    }

838
    if( i_track_count <= 0 )
839
    {
Laurent Aimar's avatar
 
Laurent Aimar committed
840 841 842 843 844 845 846 847 848
        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
849
        msg_Warn( p_demux, "no track selected, exiting..." );
Laurent Aimar's avatar
 
Laurent Aimar committed
850
        return 0;
851
    }
852

853
    /* wait for the good time */
854
    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time + 1 );
855
    p_sys->i_time += 25*1000;  /* read 25ms */
856 857

    /* init toread */
858
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
859
    {
860
        avi_track_t *tk = p_sys->track[i_track];
861
        mtime_t i_dpts;
862

863 864
        toread[i_track].b_ok = tk->b_activated;
        if( tk->i_idxposc < tk->i_idxnb )
865
        {
866 867
            toread[i_track].i_posf = tk->p_index[tk->i_idxposc].i_pos;
           if( tk->i_idxposb > 0 )
868
           {
869
                toread[i_track].i_posf += 8 + tk->i_idxposb;
870
           }
871
        }
872
        else
873
        {
874