avidec.c 35.9 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * AVI demuxer
3
 * Copyright (c) 2001 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20 21 22
 */
#include "avformat.h"
#include "avi.h"
23
#include "dv.h"
24
#include "riff.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
25

26 27 28
#undef NDEBUG
#include <assert.h>

Fabrice Bellard's avatar
Fabrice Bellard committed
29
//#define DEBUG
Fabrice Bellard's avatar
Fabrice Bellard committed
30 31 32
//#define DEBUG_SEEK

typedef struct AVIStream {
33
    int64_t frame_offset; /* current frame (video) or byte (audio) counter
Fabrice Bellard's avatar
Fabrice Bellard committed
34
                         (used to compute the pts) */
35 36 37
    int remaining;
    int packet_size;

Fabrice Bellard's avatar
Fabrice Bellard committed
38
    int scale;
39
    int rate;
40
    int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */
41

42
    int64_t cum_len; /* temporary storage (used during seek) */
43

44 45
    int prefix;                       ///< normally 'd'<<8 + 'c' or 'w'<<8 + 'b'
    int prefix_count;
46 47
    uint32_t pal[256];
    int has_pal;
Fabrice Bellard's avatar
Fabrice Bellard committed
48
} AVIStream;
Fabrice Bellard's avatar
Fabrice Bellard committed
49 50

typedef struct {
51 52
    int64_t  riff_end;
    int64_t  movi_end;
53
    int64_t  fsize;
Fabrice Bellard's avatar
Fabrice Bellard committed
54
    offset_t movi_list;
Fabrice Bellard's avatar
Fabrice Bellard committed
55
    int index_loaded;
56
    int is_odml;
57 58
    int non_interleaved;
    int stream_index;
59
    DVDemuxContext* dv_demux;
Fabrice Bellard's avatar
Fabrice Bellard committed
60 61
} AVIContext;

62 63 64 65
static const char avi_headers[][8] = {
    { 'R', 'I', 'F', 'F',    'A', 'V', 'I', ' ' },
    { 'R', 'I', 'F', 'F',    'A', 'V', 'I', 'X' },
    { 'R', 'I', 'F', 'F',    'A', 'V', 'I', 0x19},
66
    { 'O', 'N', '2', ' ',    'O', 'N', '2', 'f' },
67
    { 'R', 'I', 'F', 'F',    'A', 'M', 'V', ' ' },
68 69 70
    { 0 }
};

71
static int avi_load_index(AVFormatContext *s);
72
static int guess_ni_flag(AVFormatContext *s);
73

Fabrice Bellard's avatar
Fabrice Bellard committed
74
#ifdef DEBUG
75
static void print_tag(const char *str, unsigned int tag, int size)
Fabrice Bellard's avatar
Fabrice Bellard committed
76 77 78 79 80 81 82 83 84 85
{
    printf("%s: tag=%c%c%c%c size=0x%x\n",
           str, tag & 0xff,
           (tag >> 8) & 0xff,
           (tag >> 16) & 0xff,
           (tag >> 24) & 0xff,
           size);
}
#endif

86 87
static int get_riff(AVIContext *avi, ByteIOContext *pb)
{
88 89
    char header[8];
    int i;
90

91 92
    /* check RIFF header */
    get_buffer(pb, header, 4);
93 94
    avi->riff_end = get_le32(pb);   /* RIFF chunk size */
    avi->riff_end += url_ftell(pb); /* RIFF chunk end */
95 96 97 98 99 100
    get_buffer(pb, header+4, 4);

    for(i=0; avi_headers[i][0]; i++)
        if(!memcmp(header, avi_headers[i], 8))
            break;
    if(!avi_headers[i][0])
101
        return -1;
102

103 104 105
    if(header[7] == 0x19)
        av_log(NULL, AV_LOG_INFO, "file has been generated with a totally broken muxer\n");

106 107 108
    return 0;
}

109
static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){
110
    AVIContext *avi = s->priv_data;
111
    ByteIOContext *pb = s->pb;
112 113 114 115 116 117 118 119 120 121
    int longs_pre_entry= get_le16(pb);
    int index_sub_type = get_byte(pb);
    int index_type     = get_byte(pb);
    int entries_in_use = get_le32(pb);
    int chunk_id       = get_le32(pb);
    int64_t base       = get_le64(pb);
    int stream_id= 10*((chunk_id&0xFF) - '0') + (((chunk_id>>8)&0xFF) - '0');
    AVStream *st;
    AVIStream *ast;
    int i;
122
    int64_t last_pos= -1;
123
    int64_t filesize= url_fsize(s->pb);
124

125
#ifdef DEBUG_SEEK
126
    av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n",
127 128
        longs_pre_entry,index_type, entries_in_use, chunk_id, base);
#endif
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

    if(stream_id > s->nb_streams || stream_id < 0)
        return -1;
    st= s->streams[stream_id];
    ast = st->priv_data;

    if(index_sub_type)
        return -1;

    get_le32(pb);

    if(index_type && longs_pre_entry != 2)
        return -1;
    if(index_type>1)
        return -1;

145 146 147 148 149 150 151 152
    if(filesize > 0 && base >= filesize){
        av_log(s, AV_LOG_ERROR, "ODML index invalid\n");
        if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF)
            base &= 0xFFFFFFFF;
        else
            return -1;
    }

153 154
    for(i=0; i<entries_in_use; i++){
        if(index_type){
155
            int64_t pos= get_le32(pb) + base - 8;
156
            int len    = get_le32(pb);
157
            int key= len >= 0;
158 159
            len &= 0x7FFFFFFF;

160
#ifdef DEBUG_SEEK
161
            av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len);
162
#endif
163 164 165
            if(last_pos == pos || pos == base - 8)
                avi->non_interleaved= 1;
            else
166
                av_add_index_entry(st, pos, ast->cum_len / FFMAX(1, ast->sample_size), len, 0, key ? AVINDEX_KEYFRAME : 0);
167

168
            if(ast->sample_size)
169
                ast->cum_len += len;
170 171
            else
                ast->cum_len ++;
172
            last_pos= pos;
173
        }else{
Måns Rullgård's avatar
Måns Rullgård committed
174 175 176 177 178 179
            int64_t offset, pos;
            int duration;
            offset = get_le64(pb);
            get_le32(pb);       /* size */
            duration = get_le32(pb);
            pos = url_ftell(pb);
180 181 182 183 184 185 186 187

            url_fseek(pb, offset+8, SEEK_SET);
            read_braindead_odml_indx(s, frame_num);
            frame_num += duration;

            url_fseek(pb, pos, SEEK_SET);
        }
    }
188
    avi->index_loaded=1;
189 190 191
    return 0;
}

192
static void clean_index(AVFormatContext *s){
193 194
    int i;
    int64_t j;
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

    for(i=0; i<s->nb_streams; i++){
        AVStream *st = s->streams[i];
        AVIStream *ast = st->priv_data;
        int n= st->nb_index_entries;
        int max= ast->sample_size;
        int64_t pos, size, ts;

        if(n != 1 || ast->sample_size==0)
            continue;

        while(max < 1024) max+=max;

        pos= st->index_entries[0].pos;
        size= st->index_entries[0].size;
        ts= st->index_entries[0].timestamp;

        for(j=0; j<size; j+=max){
            av_add_index_entry(st, pos+j, ts + j/ast->sample_size, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME);
        }
    }
}

218 219 220 221 222 223 224 225 226
static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen,  unsigned int size)
{
    offset_t i = url_ftell(pb);
    size += (size & 1);
    get_strz(pb, buf, maxlen);
    url_fseek(pb, i+size, SEEK_SET);
    return 0;
}

227
static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
Fabrice Bellard's avatar
Fabrice Bellard committed
228
{
Fabrice Bellard's avatar
Fabrice Bellard committed
229
    AVIContext *avi = s->priv_data;
230
    ByteIOContext *pb = s->pb;
231
    uint32_t tag, tag1, handler;
232
    int codec_type, stream_index, frame_period, bit_rate;
233
    unsigned int size, nb_frames;
234
    int i;
Fabrice Bellard's avatar
Fabrice Bellard committed
235
    AVStream *st;
Måns Rullgård's avatar
Måns Rullgård committed
236
    AVIStream *ast = NULL;
237
    char str_track[4];
238 239
    int avih_width=0, avih_height=0;
    int amv_file_format=0;
Fabrice Bellard's avatar
Fabrice Bellard committed
240

241
    avi->stream_index= -1;
242

243
    if (get_riff(avi, pb) < 0)
Fabrice Bellard's avatar
Fabrice Bellard committed
244
        return -1;
245

246 247 248 249
    avi->fsize = url_fsize(pb);
    if(avi->fsize<=0)
        avi->fsize= avi->riff_end;

Fabrice Bellard's avatar
Fabrice Bellard committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    /* first list tag */
    stream_index = -1;
    codec_type = -1;
    frame_period = 0;
    for(;;) {
        if (url_feof(pb))
            goto fail;
        tag = get_le32(pb);
        size = get_le32(pb);
#ifdef DEBUG
        print_tag("tag", tag, size);
#endif

        switch(tag) {
        case MKTAG('L', 'I', 'S', 'T'):
            /* ignored, except when start of video packets */
            tag1 = get_le32(pb);
#ifdef DEBUG
            print_tag("list", tag1, 0);
#endif
            if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
Fabrice Bellard's avatar
Fabrice Bellard committed
271
                avi->movi_list = url_ftell(pb) - 4;
272
                if(size) avi->movi_end = avi->movi_list + size + (size & 1);
273
                else     avi->movi_end = url_fsize(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
274
#ifdef DEBUG
275
                printf("movi end=%"PRIx64"\n", avi->movi_end);
Fabrice Bellard's avatar
Fabrice Bellard committed
276 277 278 279
#endif
                goto end_of_header;
            }
            break;
280
        case MKTAG('d', 'm', 'l', 'h'):
281 282 283
            avi->is_odml = 1;
            url_fskip(pb, size + (size & 1));
            break;
284 285
        case MKTAG('a', 'm', 'v', 'h'):
            amv_file_format=1;
Fabrice Bellard's avatar
Fabrice Bellard committed
286
        case MKTAG('a', 'v', 'i', 'h'):
287
            /* avi header */
288
            /* using frame_period is bad idea */
Fabrice Bellard's avatar
Fabrice Bellard committed
289 290
            frame_period = get_le32(pb);
            bit_rate = get_le32(pb) * 8;
291 292 293 294
            get_le32(pb);
            avi->non_interleaved |= get_le32(pb) & AVIF_MUSTUSEINDEX;

            url_fskip(pb, 2 * 4);
295
            get_le32(pb);
296 297 298
            get_le32(pb);
            avih_width=get_le32(pb);
            avih_height=get_le32(pb);
299

300
            url_fskip(pb, size - 10 * 4);
301 302 303 304 305 306 307 308 309 310 311 312 313
            break;
        case MKTAG('s', 't', 'r', 'h'):
            /* stream header */

            tag1 = get_le32(pb);
            handler = get_le32(pb); /* codec tag */

            if(tag1 == MKTAG('p', 'a', 'd', 's')){
                url_fskip(pb, size - 8);
                break;
            }else{
                stream_index++;
                st = av_new_stream(s, stream_index);
Fabrice Bellard's avatar
Fabrice Bellard committed
314 315
                if (!st)
                    goto fail;
316

Fabrice Bellard's avatar
Fabrice Bellard committed
317 318 319 320
                ast = av_mallocz(sizeof(AVIStream));
                if (!ast)
                    goto fail;
                st->priv_data = ast;
321
            }
322 323
            if(amv_file_format)
                tag1 = stream_index ? MKTAG('a','u','d','s') : MKTAG('v','i','d','s');
324

325
#ifdef DEBUG
326
            print_tag("strh", tag1, -1);
327
#endif
328
            if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){
329 330
                int64_t dv_dur;

331
                /*
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
                 * After some consideration -- I don't think we
                 * have to support anything but DV in a type1 AVIs.
                 */
                if (s->nb_streams != 1)
                    goto fail;

                if (handler != MKTAG('d', 'v', 's', 'd') &&
                    handler != MKTAG('d', 'v', 'h', 'd') &&
                    handler != MKTAG('d', 'v', 's', 'l'))
                   goto fail;

                ast = s->streams[0]->priv_data;
                av_freep(&s->streams[0]->codec->extradata);
                av_freep(&s->streams[0]);
                s->nb_streams = 0;
347
                if (ENABLE_DV_DEMUXER) {
348 349 350
                    avi->dv_demux = dv_init_demux(s);
                    if (!avi->dv_demux)
                        goto fail;
351
                }
352 353 354 355
                s->streams[0]->priv_data = ast;
                url_fskip(pb, 3 * 4);
                ast->scale = get_le32(pb);
                ast->rate = get_le32(pb);
356 357 358 359 360 361 362 363 364 365 366 367
                url_fskip(pb, 4);  /* start time */

                dv_dur = get_le32(pb);
                if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) {
                    dv_dur *= AV_TIME_BASE;
                    s->duration = av_rescale(dv_dur, ast->scale, ast->rate);
                }
                /*
                 * else, leave duration alone; timing estimation in utils.c
                 *      will make a guess based on bit rate.
                 */

368
                stream_index = s->nb_streams - 1;
369
                url_fskip(pb, size - 9*4);
370 371
                break;
            }
372

373
            assert(stream_index < s->nb_streams);
374
            st->codec->stream_codec_tag= handler;
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
            get_le32(pb); /* flags */
            get_le16(pb); /* priority */
            get_le16(pb); /* language */
            get_le32(pb); /* initial frame */
            ast->scale = get_le32(pb);
            ast->rate = get_le32(pb);
            if(ast->scale && ast->rate){
            }else if(frame_period){
                ast->rate = 1000000;
                ast->scale = frame_period;
            }else{
                ast->rate = 25;
                ast->scale = 1;
            }
            av_set_pts_info(st, 64, ast->scale, ast->rate);
391

Michael Niedermayer's avatar
Michael Niedermayer committed
392
            ast->cum_len=get_le32(pb); /* start */
393
            nb_frames = get_le32(pb);
394

395
            st->start_time = 0;
396
            st->duration = nb_frames;
397 398 399
            get_le32(pb); /* buffer size */
            get_le32(pb); /* quality */
            ast->sample_size = get_le32(pb); /* sample ssize */
400
            ast->cum_len *= FFMAX(1, ast->sample_size);
401
//            av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->rate, ast->scale, ast->start, ast->sample_size);
402

403
            switch(tag1) {
404
            case MKTAG('v', 'i', 'd', 's'):
405
                codec_type = CODEC_TYPE_VIDEO;
406

407 408 409 410
                ast->sample_size = 0;
                break;
            case MKTAG('a', 'u', 'd', 's'):
                codec_type = CODEC_TYPE_AUDIO;
411
                break;
412
            case MKTAG('t', 'x', 't', 's'):
413
                //FIXME
414 415
                codec_type = CODEC_TYPE_DATA; //CODEC_TYPE_SUB ?  FIXME
                break;
416
            default:
Michael Niedermayer's avatar
Michael Niedermayer committed
417
                av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1);
418
                goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
419
            }
420
            ast->frame_offset= ast->cum_len;
421
            url_fskip(pb, size - 12 * 4);
Fabrice Bellard's avatar
Fabrice Bellard committed
422 423 424
            break;
        case MKTAG('s', 't', 'r', 'f'):
            /* stream header */
425
            if (stream_index >= (unsigned)s->nb_streams || avi->dv_demux) {
Fabrice Bellard's avatar
Fabrice Bellard committed
426 427 428 429 430
                url_fskip(pb, size);
            } else {
                st = s->streams[stream_index];
                switch(codec_type) {
                case CODEC_TYPE_VIDEO:
431 432 433 434 435 436 437 438
                    if(amv_file_format){
                        st->codec->width=avih_width;
                        st->codec->height=avih_height;
                        st->codec->codec_type = CODEC_TYPE_VIDEO;
                        st->codec->codec_id = CODEC_ID_AMV;
                        url_fskip(pb, size);
                        break;
                    }
Fabrice Bellard's avatar
Fabrice Bellard committed
439
                    get_le32(pb); /* size */
440 441
                    st->codec->width = get_le32(pb);
                    st->codec->height = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
442
                    get_le16(pb); /* panes */
443
                    st->codec->bits_per_sample= get_le16(pb); /* depth */
Fabrice Bellard's avatar
Fabrice Bellard committed
444
                    tag1 = get_le32(pb);
445 446 447 448 449 450
                    get_le32(pb); /* ImageSize */
                    get_le32(pb); /* XPelsPerMeter */
                    get_le32(pb); /* YPelsPerMeter */
                    get_le32(pb); /* ClrUsed */
                    get_le32(pb); /* ClrImportant */

451 452 453 454 455 456 457
                    if (tag1 == MKTAG('D', 'X', 'S', 'B')) {
                        st->codec->codec_type = CODEC_TYPE_SUBTITLE;
                        st->codec->codec_tag = tag1;
                        st->codec->codec_id = CODEC_ID_XSUB;
                        break;
                    }

458 459 460 461 462
                    if(size > 10*4 && size<(1<<30)){
                        st->codec->extradata_size= size - 10*4;
                        st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
                        get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
                    }
463

464
                    if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
465
                        get_byte(pb);
466

467 468 469
                    /* Extract palette from extradata if bpp <= 8 */
                    /* This code assumes that extradata contains only palette */
                    /* This is true for all paletted codecs implemented in ffmpeg */
470 471
                    if (st->codec->extradata_size && (st->codec->bits_per_sample <= 8)) {
                        st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl));
472
#ifdef WORDS_BIGENDIAN
473 474
                        for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)/4; i++)
                            st->codec->palctrl->palette[i] = bswap_32(((uint32_t*)st->codec->extradata)[i]);
475
#else
476 477
                        memcpy(st->codec->palctrl->palette, st->codec->extradata,
                               FFMIN(st->codec->extradata_size, AVPALETTE_SIZE));
478
#endif
479
                        st->codec->palctrl->palette_changed = 1;
480 481
                    }

Fabrice Bellard's avatar
Fabrice Bellard committed
482 483 484
#ifdef DEBUG
                    print_tag("video", tag1, 0);
#endif
485 486 487
                    st->codec->codec_type = CODEC_TYPE_VIDEO;
                    st->codec->codec_tag = tag1;
                    st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1);
488
                    st->need_parsing = AVSTREAM_PARSE_HEADERS; // this is needed to get the pict type which is needed for generating correct pts
489
//                    url_fskip(pb, size - 5 * 4);
Fabrice Bellard's avatar
Fabrice Bellard committed
490
                    break;
491
                case CODEC_TYPE_AUDIO:
492
                    get_wav_header(pb, st->codec, size);
493
                    if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){
494
                        av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align);
495 496
                        ast->sample_size= st->codec->block_align;
                    }
497 498
                    if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
                        url_fskip(pb, 1);
Diego Biurrun's avatar
Diego Biurrun committed
499
                    /* Force parsing as several audio frames can be in
500 501
                     * one packet and timestamps refer to packet start*/
                    st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
502 503
                    /* ADTS header is in extradata, AAC without header must be stored as exact frames, parser not needed and it will fail */
                    if (st->codec->codec_id == CODEC_ID_AAC && st->codec->extradata_size)
504
                        st->need_parsing = AVSTREAM_PARSE_NONE;
505 506 507 508 509 510
                    /* AVI files with Xan DPCM audio (wrongly) declare PCM
                     * audio in the header but have Axan as stream_code_tag. */
                    if (st->codec->stream_codec_tag == ff_get_fourcc("Axan")){
                        st->codec->codec_id  = CODEC_ID_XAN_DPCM;
                        st->codec->codec_tag = 0;
                    }
511 512
                    if (amv_file_format)
                        st->codec->codec_id  = CODEC_ID_ADPCM_IMA_AMV;
Fabrice Bellard's avatar
Fabrice Bellard committed
513 514
                    break;
                default:
515 516 517
                    st->codec->codec_type = CODEC_TYPE_DATA;
                    st->codec->codec_id= CODEC_ID_NONE;
                    st->codec->codec_tag= 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
518 519 520 521 522
                    url_fskip(pb, size);
                    break;
                }
            }
            break;
523 524
        case MKTAG('i', 'n', 'd', 'x'):
            i= url_ftell(pb);
525
            if(!url_is_streamed(pb) && !(s->flags & AVFMT_FLAG_IGNIDX)){
526 527
                read_braindead_odml_indx(s, 0);
            }
528 529
            url_fseek(pb, i+size, SEEK_SET);
            break;
530 531 532 533 534 535 536 537 538 539 540 541
        case MKTAG('v', 'p', 'r', 'p'):
            if(stream_index < (unsigned)s->nb_streams && size > 9*4){
                AVRational active, active_aspect;

                st = s->streams[stream_index];
                get_le32(pb);
                get_le32(pb);
                get_le32(pb);
                get_le32(pb);
                get_le32(pb);

                active_aspect.den= get_le16(pb);
Michael Niedermayer's avatar
Michael Niedermayer committed
542
                active_aspect.num= get_le16(pb);
543 544 545 546 547 548 549 550 551 552 553 554
                active.num       = get_le32(pb);
                active.den       = get_le32(pb);
                get_le32(pb); //nbFieldsPerFrame

                if(active_aspect.num && active_aspect.den && active.num && active.den){
                    st->codec->sample_aspect_ratio= av_div_q(active_aspect, active);
//av_log(s, AV_LOG_ERROR, "vprp %d/%d %d/%d\n", active_aspect.num, active_aspect.den, active.num, active.den);
                }
                size -= 9*4;
            }
            url_fseek(pb, size, SEEK_CUR);
            break;
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
        case MKTAG('I', 'N', 'A', 'M'):
            avi_read_tag(pb, s->title, sizeof(s->title), size);
            break;
        case MKTAG('I', 'A', 'R', 'T'):
            avi_read_tag(pb, s->author, sizeof(s->author), size);
            break;
        case MKTAG('I', 'C', 'O', 'P'):
            avi_read_tag(pb, s->copyright, sizeof(s->copyright), size);
            break;
        case MKTAG('I', 'C', 'M', 'T'):
            avi_read_tag(pb, s->comment, sizeof(s->comment), size);
            break;
        case MKTAG('I', 'G', 'N', 'R'):
            avi_read_tag(pb, s->genre, sizeof(s->genre), size);
            break;
Panagiotis Issaris's avatar
Panagiotis Issaris committed
570 571 572
        case MKTAG('I', 'P', 'R', 'D'):
            avi_read_tag(pb, s->album, sizeof(s->album), size);
            break;
573 574 575 576
        case MKTAG('I', 'P', 'R', 'T'):
            avi_read_tag(pb, str_track, sizeof(str_track), size);
            sscanf(str_track, "%d", &s->track);
            break;
Fabrice Bellard's avatar
Fabrice Bellard committed
577
        default:
578 579 580 581 582 583 584
            if(size > 1000000){
                av_log(s, AV_LOG_ERROR, "well something went wrong during header parsing, "
                                        "ill ignore it and try to continue anyway\n");
                avi->movi_list = url_ftell(pb) - 4;
                avi->movi_end  = url_fsize(pb);
                goto end_of_header;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
585 586 587 588 589 590 591 592 593 594 595
            /* skip tag */
            size += (size & 1);
            url_fskip(pb, size);
            break;
        }
    }
 end_of_header:
    /* check stream number */
    if (stream_index != s->nb_streams - 1) {
    fail:
        for(i=0;i<s->nb_streams;i++) {
596
            av_freep(&s->streams[i]->codec->extradata);
Michael Niedermayer's avatar
Michael Niedermayer committed
597
            av_freep(&s->streams[i]);
Fabrice Bellard's avatar
Fabrice Bellard committed
598 599 600
        }
        return -1;
    }
601

602
    if(!avi->index_loaded && !url_is_streamed(pb))
603
        avi_load_index(s);
604
    avi->index_loaded = 1;
605
    avi->non_interleaved |= guess_ni_flag(s);
606 607
    if(avi->non_interleaved)
        clean_index(s);
608

Fabrice Bellard's avatar
Fabrice Bellard committed
609 610 611
    return 0;
}

612
static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
613 614
{
    AVIContext *avi = s->priv_data;
615
    ByteIOContext *pb = s->pb;
616
    int n, d[8], size;
617
    offset_t i, sync;
618
    void* dstr;
619

620
    if (ENABLE_DV_DEMUXER && avi->dv_demux) {
621
        size = dv_get_packet(avi->dv_demux, pkt);
622 623
        if (size >= 0)
            return size;
624
    }
625

626
    if(avi->non_interleaved){
627
        int best_stream_index = 0;
628 629 630 631
        AVStream *best_st= NULL;
        AVIStream *best_ast;
        int64_t best_ts= INT64_MAX;
        int i;
632

633 634 635 636 637 638 639 640 641
        for(i=0; i<s->nb_streams; i++){
            AVStream *st = s->streams[i];
            AVIStream *ast = st->priv_data;
            int64_t ts= ast->frame_offset;

            if(ast->sample_size)
                ts /= ast->sample_size;
            ts= av_rescale(ts, AV_TIME_BASE * (int64_t)st->time_base.num, st->time_base.den);

642
//            av_log(NULL, AV_LOG_DEBUG, "%"PRId64" %d/%d %"PRId64"\n", ts, st->time_base.num, st->time_base.den, ast->frame_offset);
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
            if(ts < best_ts){
                best_ts= ts;
                best_st= st;
                best_stream_index= i;
            }
        }
        best_ast = best_st->priv_data;
        best_ts= av_rescale(best_ts, best_st->time_base.den, AV_TIME_BASE * (int64_t)best_st->time_base.num); //FIXME a little ugly
        if(best_ast->remaining)
            i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
        else
            i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY);

//        av_log(NULL, AV_LOG_DEBUG, "%d\n", i);
        if(i>=0){
            int64_t pos= best_st->index_entries[i].pos;
659
            pos += best_ast->packet_size - best_ast->remaining;
660
            url_fseek(s->pb, pos + 8, SEEK_SET);
661
//        av_log(NULL, AV_LOG_DEBUG, "pos=%"PRId64"\n", pos);
662

663 664
            assert(best_ast->remaining <= best_ast->packet_size);

665 666
            avi->stream_index= best_stream_index;
            if(!best_ast->remaining)
667
                best_ast->packet_size=
668
                best_ast->remaining= best_st->index_entries[i].size;
669 670
        }
    }
671

672
resync:
673 674 675 676
    if(avi->stream_index >= 0){
        AVStream *st= s->streams[ avi->stream_index ];
        AVIStream *ast= st->priv_data;
        int size;
677

678
        if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM
679
            size= INT_MAX;
680
        else if(ast->sample_size < 32)
681 682 683 684 685 686
            size= 64*ast->sample_size;
        else
            size= ast->sample_size;

        if(size > ast->remaining)
            size= ast->remaining;
Michael Niedermayer's avatar
Michael Niedermayer committed
687
        av_get_packet(pb, pkt, size);
688

689 690 691 692 693 694 695 696
        if(ast->has_pal && pkt->data && pkt->size<(unsigned)INT_MAX/2){
            ast->has_pal=0;
            pkt->size += 4*256;
            pkt->data = av_realloc(pkt->data, pkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
            if(pkt->data)
                memcpy(pkt->data + pkt->size - 4*256, ast->pal, 4*256);
        }

697
        if (ENABLE_DV_DEMUXER && avi->dv_demux) {
698 699 700 701 702 703 704 705 706 707 708
            dstr = pkt->destruct;
            size = dv_produce_packet(avi->dv_demux, pkt,
                                    pkt->data, pkt->size);
            pkt->destruct = dstr;
            pkt->flags |= PKT_FLAG_KEY;
        } else {
            /* XXX: how to handle B frames in avi ? */
            pkt->dts = ast->frame_offset;
//                pkt->dts += ast->start;
            if(ast->sample_size)
                pkt->dts /= ast->sample_size;
709
//av_log(NULL, AV_LOG_DEBUG, "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, avi->stream_index, size);
710 711
            pkt->stream_index = avi->stream_index;

712
            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
Michael Niedermayer's avatar
Michael Niedermayer committed
713 714
                AVIndexEntry *e;
                int index;
715
                assert(st->index_entries);
716

Michael Niedermayer's avatar
Michael Niedermayer committed
717 718
                index= av_index_search_timestamp(st, pkt->dts, 0);
                e= &st->index_entries[index];
719

Michael Niedermayer's avatar
Michael Niedermayer committed
720 721 722 723
                if(index >= 0 && e->timestamp == ast->frame_offset){
                    if (e->flags & AVINDEX_KEYFRAME)
                        pkt->flags |= PKT_FLAG_KEY;
                }
724
            } else {
725
                pkt->flags |= PKT_FLAG_KEY;
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
            }
            if(ast->sample_size)
                ast->frame_offset += pkt->size;
            else
                ast->frame_offset++;
        }
        ast->remaining -= size;
        if(!ast->remaining){
            avi->stream_index= -1;
            ast->packet_size= 0;
        }

        return size;
    }

741 742
    memset(d, -1, sizeof(int)*8);
    for(i=sync=url_ftell(pb); !url_feof(pb); i++) {
743
        int j;
744

745 746 747
        for(j=0; j<7; j++)
            d[j]= d[j+1];
        d[7]= get_byte(pb);
748

749
        size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24);
750

751
        if(    d[2] >= '0' && d[2] <= '9'
752 753 754 755
            && d[3] >= '0' && d[3] <= '9'){
            n= (d[2] - '0') * 10 + (d[3] - '0');
        }else{
            n= 100; //invalid stream id
756
        }
757
//av_log(NULL, AV_LOG_DEBUG, "%X %X %X %X %X %X %X %X %"PRId64" %d %d\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n);
758
        if(i + size > avi->fsize || d[0]<0)
759
            continue;
760

761 762
        //parse ix##
        if(  (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams)
763
        //parse JUNK
764 765
           ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')
           ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){
766
            url_fskip(pb, size);
767
//av_log(NULL, AV_LOG_DEBUG, "SKIP\n");
768
            goto resync;
769
        }
770

771
        if(    d[0] >= '0' && d[0] <= '9'
772 773 774 775 776
            && d[1] >= '0' && d[1] <= '9'){
            n= (d[0] - '0') * 10 + (d[1] - '0');
        }else{
            n= 100; //invalid stream id
        }
777

778
        //parse ##dc/##wb
779
        if(n < s->nb_streams){
Michael Niedermayer's avatar
Michael Niedermayer committed
780 781 782 783
            AVStream *st;
            AVIStream *ast;
            st = s->streams[n];
            ast = st->priv_data;
784

785 786 787
            if(s->nb_streams>=2){
                AVStream *st1  = s->streams[1];
                AVIStream *ast1= st1->priv_data;
Michael Niedermayer's avatar
Michael Niedermayer committed
788 789 790 791 792 793 794 795 796 797 798 799 800
                //workaround for broken small-file-bug402.avi
                if(   d[2] == 'w' && d[3] == 'b'
                   && n==0
                   && st ->codec->codec_type == CODEC_TYPE_VIDEO
                   && st1->codec->codec_type == CODEC_TYPE_AUDIO
                   && ast->prefix == 'd'*256+'c'
                   && (d[2]*256+d[3] == ast1->prefix || !ast1->prefix_count)
                  ){
                    n=1;
                    st = st1;
                    ast = ast1;
                    av_log(s, AV_LOG_WARNING, "Invalid stream+prefix combination, assuming audio\n");
                }
801
            }
802 803


Michael Niedermayer's avatar
Michael Niedermayer committed
804 805 806
            if(   (st->discard >= AVDISCARD_DEFAULT && size==0)
               /*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & PKT_FLAG_KEY))*/ //FIXME needs a little reordering
               || st->discard >= AVDISCARD_ALL){
807 808
                if(ast->sample_size) ast->frame_offset += pkt->size;
                else                 ast->frame_offset++;
809 810
                url_fskip(pb, size);
                goto resync;
Michael Niedermayer's avatar
Michael Niedermayer committed
811
            }
812

Michael Niedermayer's avatar
Michael Niedermayer committed
813
            if (d[2] == 'p' && d[3] == 'c' && size<=4*256+4) {
814 815 816 817 818 819 820 821 822
                int k = get_byte(pb);
                int last = (k + get_byte(pb) - 1) & 0xFF;

                get_le16(pb); //flags

                for (; k <= last; k++)
                    ast->pal[k] = get_be32(pb)>>8;// b + (g << 8) + (r << 16);
                ast->has_pal= 1;
                goto resync;
Michael Niedermayer's avatar
Michael Niedermayer committed
823 824 825 826
            } else if(   ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) ||
                         d[2]*256+d[3] == ast->prefix /*||
                         (d[2] == 'd' && d[3] == 'c') ||
                         (d[2] == 'w' && d[3] == 'b')*/) {
827 828

//av_log(NULL, AV_LOG_DEBUG, "OK\n");
Michael Niedermayer's avatar
Michael Niedermayer committed
829 830 831 832 833 834
                if(d[2]*256+d[3] == ast->prefix)
                    ast->prefix_count++;
                else{
                    ast->prefix= d[2]*256+d[3];
                    ast->prefix_count= 0;
                }
835

Michael Niedermayer's avatar
Michael Niedermayer committed
836 837 838
                avi->stream_index= n;
                ast->packet_size= size + 8;
                ast->remaining= size;
839

Michael Niedermayer's avatar
Michael Niedermayer committed
840 841 842 843 844
                {
                    uint64_t pos= url_ftell(pb) - 8;
                    if(!st->index_entries || !st->nb_index_entries || st->index_entries[st->nb_index_entries - 1].pos < pos){
                        av_add_index_entry(st, pos, ast->frame_offset / FFMAX(1, ast->sample_size), size, 0, AVINDEX_KEYFRAME);
                    }
845
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
846
                goto resync;
847
            }
848 849
        }
    }
850

851
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
852 853
}

Fabrice Bellard's avatar
Fabrice Bellard committed
854 855 856 857
/* XXX: we make the implicit supposition that the position are sorted
   for each stream */
static int avi_read_idx1(AVFormatContext *s, int size)
{
858
    AVIContext *avi = s->priv_data;
859
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
860 861 862 863
    int nb_index_entries, i;
    AVStream *st;
    AVIStream *ast;
    unsigned int index, tag, flags, pos, len;
864
    unsigned last_pos= -1;
865

Fabrice Bellard's avatar
Fabrice Bellard committed
866 867 868 869 870 871 872 873 874 875
    nb_index_entries = size / 16;
    if (nb_index_entries <= 0)
        return -1;

    /* read the entries and sort them in each stream component */
    for(i = 0; i < nb_index_entries; i++) {
        tag = get_le32(pb);
        flags = get_le32(pb);
        pos = get_le32(pb);
        len = get_le32(pb);
876
#if defined(DEBUG_SEEK)
877
        av_log(NULL, AV_LOG_DEBUG, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/",
Fabrice Bellard's avatar
Fabrice Bellard committed
878 879
               i, tag, flags, pos, len);
#endif
880 881
        if(i==0 && pos > avi->movi_list)
            avi->movi_list= 0; //FIXME better check
882
        pos += avi->movi_list;
883

Fabrice Bellard's avatar
Fabrice Bellard committed
884 885 886 887 888 889
        index = ((tag & 0xff) - '0') * 10;
        index += ((tag >> 8) & 0xff) - '0';
        if (index >= s->nb_streams)
            continue;
        st = s->streams[index];
        ast = st->priv_data;
890

891
#if defined(DEBUG_SEEK)
892
        av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%"PRId64"\n", len, ast->cum_len);
893
#endif
894 895 896
        if(last_pos == pos)
            avi->non_interleaved= 1;
        else
897
            av_add_index_entry(st, pos, ast->cum_len / FFMAX(1, ast->sample_size), len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
898
        if(ast->sample_size)
899
            ast->cum_len += len;
900 901 902
        else
            ast->cum_len ++;
        last_pos= pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
903 904 905 906
    }
    return 0;
}

907 908 909 910
static int guess_ni_flag(AVFormatContext *s){
    int i;
    int64_t last_start=0;
    int64_t first_end= INT64_MAX;
911

912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
    for(i=0; i<s->nb_streams; i++){
        AVStream *st = s->streams[i];
        int n= st->nb_index_entries;

        if(n <= 0)
            continue;

        if(st->index_entries[0].pos > last_start)
            last_start= st->index_entries[0].pos;
        if(st->index_entries[n-1].pos < first_end)
            first_end= st->index_entries[n-1].pos;
    }
    return last_start > first_end;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
927 928 929
static int avi_load_index(AVFormatContext *s)
{
    AVIContext *avi = s->priv_data;
930
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
931
    uint32_t tag, size;
932
    offset_t pos= url_ftell(pb);
933

Fabrice Bellard's avatar
Fabrice Bellard committed
934 935
    url_fseek(pb, avi->movi_end, SEEK_SET);
#ifdef DEBUG_SEEK
936
    printf("movi_end=0x%"PRIx64"\n", avi->movi_end);
Fabrice Bellard's avatar
Fabrice Bellard committed
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
#endif
    for(;;) {
        if (url_feof(pb))
            break;
        tag = get_le32(pb);
        size = get_le32(pb);
#ifdef DEBUG_SEEK
        printf("tag=%c%c%c%c size=0x%x\n",
               tag & 0xff,
               (tag >> 8) & 0xff,
               (tag >> 16) & 0xff,
               (tag >> 24) & 0xff,
               size);
#endif
        switch(tag) {
        case MKTAG('i', 'd', 'x', '1'):
            if (avi_read_idx1(s, size) < 0)
                goto skip;
            else
                goto the_end;
            break;
        default:
        skip:
            size += (size & 1);
            url_fskip(pb, size);
            break;
        }
    }
 the_end:
966
    url_fseek(pb, pos, SEEK_SET);
Fabrice Bellard's avatar
Fabrice Bellard committed
967 968 969
    return 0;
}

970
static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Fabrice Bellard's avatar
Fabrice Bellard committed
971 972 973
{
    AVIContext *avi = s->priv_data;
    AVStream *st;
974
    int i, index;
Fabrice Bellard's avatar
Fabrice Bellard committed
975 976 977 978 979 980 981
    int64_t pos;

    if (!avi->index_loaded) {
        /* we only load the index on demand */
        avi_load_index(s);
        avi->index_loaded = 1;
    }
982
    assert(stream_index>= 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
983 984

    st = s->streams[stream_index];
985 986
    index= av_index_search_timestamp(st, timestamp, flags);
    if(index<0)
Fabrice Bellard's avatar
Fabrice Bellard committed
987
        return -1;
988

Fabrice Bellard's avatar
Fabrice Bellard committed
989
    /* find the position */
990 991 992
    pos = st->index_entries[index].pos;
    timestamp = st->index_entries[index].timestamp;

993
//    av_log(NULL, AV_LOG_DEBUG, "XX %"PRId64" %d %"PRId64"\n", timestamp, index, st->index_entries[index].timestamp);
Fabrice Bellard's avatar
Fabrice Bellard committed
994

995 996 997 998 999 1000 1001 1002 1003 1004
    if (ENABLE_DV_DEMUXER && avi->dv_demux) {
        /* One and only one real stream for DV in AVI, and it has video  */
        /* offsets. Calling with other stream indices should have failed */
        /* the av_index_search_timestamp call above.                     */
        assert(stream_index == 0);

        /* Feed the DV video stream version of the timestamp to the */
        /* DV demux so it can synth correct timestamps              */
        dv_offset_reset(avi->dv_demux, timestamp);

1005
        url_fseek(s->pb, pos, SEEK_SET);
1006 1007 1008 1009
        avi->stream_index= -1;
        return 0;
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
1010
    for(i = 0; i < s->nb_streams; i++) {
1011 1012
        AVStream *st2 = s->streams[i];
        AVIStream *ast2 = st2->priv_data;
1013 1014 1015 1016

        ast2->packet_size=
        ast2->remaining= 0;

1017 1018
        if (st2->nb_index_entries <= 0)
            continue;
1019

1020
//        assert(st2->codec->block_align);
1021 1022 1023
        assert(st2->time_base.den == ast2->rate);
        assert(st2->time_base.num == ast2->scale);
        index = av_index_search_timestamp(
1024
                st2,
1025 1026 1027 1028
                av_rescale(timestamp, st2->time_base.den*(int64_t)st->time_base.num, st->time_base.den * (int64_t)st2->time_base.num),
                flags | AVSEEK_FLAG_BACKWARD);
        if(index<0)
            index=0;
1029

1030 1031 1032 1033 1034 1035 1036
        if(!avi->non_interleaved){
            while(index>0 && st2->index_entries[index].pos > pos)
                index--;
            while(index+1 < st2->nb_index_entries && st2->index_entries[index].pos < pos)
                index++;
        }

1037
//        av_log(NULL, AV_LOG_DEBUG, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp);
1038 1039 1040 1041
        /* extract the current frame number */
        ast2->frame_offset = st2->index_entries[index].timestamp;
        if(ast2->sample_size)
            ast2->frame_offset *=ast2->sample_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
1042
    }
1043

Fabrice Bellard's avatar
Fabrice Bellard committed
1044
    /* do the seek */
1045
    url_fseek(s->pb, pos, SEEK_SET);
1046
    avi->stream_index= -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1047 1048 1049
    return 0;
}

1050
static int avi_read_close(AVFormatContext *s)
Fabrice Bellard's avatar
Fabrice Bellard committed
1051
{
Michael Niedermayer's avatar
Michael Niedermayer committed
1052 1053 1054 1055 1056
    int i;
    AVIContext *avi = s->priv_data;

    for(i=0;i<s->nb_streams;i++) {
        AVStream *st = s->streams[i];
Fabrice Bellard's avatar
Fabrice Bellard committed
1057
        AVIStream *ast = st->priv_data;
1058
        av_free(ast);
1059
        av_free(st->codec->palctrl);
Michael Niedermayer's avatar
Michael Niedermayer committed
1060 1061
    }

1062 1063 1064
    if (avi->dv_demux)
        av_free(avi->dv_demux);

Fabrice Bellard's avatar
Fabrice Bellard committed
1065 1066 1067 1068 1069
    return 0;
}

static int avi_probe(AVProbeData *p)
{
1070 1071
    int i;

Fabrice Bellard's avatar
Fabrice Bellard committed
1072
    /* check file header */
1073 1074 1075 1076 1077 1078
    for(i=0; avi_headers[i][0]; i++)
        if(!memcmp(p->buf  , avi_headers[i]  , 4) &&
           !memcmp(p->buf+8, avi_headers[i]+4, 4))
            return AVPROBE_SCORE_MAX;

    return 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
1079 1080
}

1081
AVInputFormat avi_demuxer = {
Fabrice Bellard's avatar
Fabrice Bellard committed
1082 1083 1084 1085 1086 1087 1088
    "avi",
    "avi format",
    sizeof(AVIContext),
    avi_probe,
    avi_read_header,
    avi_read_packet,
    avi_read_close,
Fabrice Bellard's avatar
Fabrice Bellard committed
1089
    avi_read_seek,
Fabrice Bellard's avatar
Fabrice Bellard committed
1090
};