avidec.c 36.4 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
            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);
382
            if(!(ast->scale && ast->rate)){
383
                av_log(s, AV_LOG_WARNING, "Scale/Rate is %u/%u which is invalid. (This file has been generated by broken software)\n", ast->scale, ast->rate);
Michael Niedermayer's avatar
Michael Niedermayer committed
384 385 386 387 388 389 390
                if(frame_period){
                    ast->rate = 1000000;
                    ast->scale = frame_period;
                }else{
                    ast->rate = 25;
                    ast->scale = 1;
                }
391
            }
392
            av_set_pts_info(st, 64, ast->scale, ast->rate);
393

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

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

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

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

456 457 458 459 460 461 462
                    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;
                    }

463 464 465 466 467
                    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);
                    }
468

469
                    if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
470
                        get_byte(pb);
471

472 473 474
                    /* 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 */
475 476
                    if (st->codec->extradata_size && (st->codec->bits_per_sample <= 8)) {
                        st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl));
477
#ifdef WORDS_BIGENDIAN
478 479
                        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]);
480
#else
481 482
                        memcpy(st->codec->palctrl->palette, st->codec->extradata,
                               FFMIN(st->codec->extradata_size, AVPALETTE_SIZE));
483
#endif
484
                        st->codec->palctrl->palette_changed = 1;
485 486
                    }

Fabrice Bellard's avatar
Fabrice Bellard committed
487 488 489
#ifdef DEBUG
                    print_tag("video", tag1, 0);
#endif
490 491 492
                    st->codec->codec_type = CODEC_TYPE_VIDEO;
                    st->codec->codec_tag = tag1;
                    st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1);
493
                    st->need_parsing = AVSTREAM_PARSE_HEADERS; // this is needed to get the pict type which is needed for generating correct pts
494
//                    url_fskip(pb, size - 5 * 4);
Fabrice Bellard's avatar
Fabrice Bellard committed
495
                    break;
496
                case CODEC_TYPE_AUDIO:
497
                    get_wav_header(pb, st->codec, size);
498
                    if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){
499
                        av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align);
500 501
                        ast->sample_size= st->codec->block_align;
                    }
502 503
                    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
504
                    /* Force parsing as several audio frames can be in
505 506
                     * one packet and timestamps refer to packet start*/
                    st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
507 508
                    /* 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)
509
                        st->need_parsing = AVSTREAM_PARSE_NONE;
510 511 512 513 514 515
                    /* 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;
                    }
516 517
                    if (amv_file_format)
                        st->codec->codec_id  = CODEC_ID_ADPCM_IMA_AMV;
Fabrice Bellard's avatar
Fabrice Bellard committed
518 519
                    break;
                default:
520 521 522
                    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
523 524 525 526 527
                    url_fskip(pb, size);
                    break;
                }
            }
            break;
528 529
        case MKTAG('i', 'n', 'd', 'x'):
            i= url_ftell(pb);
530
            if(!url_is_streamed(pb) && !(s->flags & AVFMT_FLAG_IGNIDX)){
531 532
                read_braindead_odml_indx(s, 0);
            }
533 534
            url_fseek(pb, i+size, SEEK_SET);
            break;
535 536 537 538 539 540 541 542 543 544 545 546
        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
547
                active_aspect.num= get_le16(pb);
548 549 550 551 552 553 554 555 556 557 558 559
                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;
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
        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
575 576 577
        case MKTAG('I', 'P', 'R', 'D'):
            avi_read_tag(pb, s->album, sizeof(s->album), size);
            break;
578 579 580 581
        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
582
        default:
583 584 585 586 587 588 589
            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
590 591 592 593 594 595 596 597 598 599 600
            /* 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++) {
601
            av_freep(&s->streams[i]->codec->extradata);
Michael Niedermayer's avatar
Michael Niedermayer committed
602
            av_freep(&s->streams[i]);
Fabrice Bellard's avatar
Fabrice Bellard committed
603 604 605
        }
        return -1;
    }
606

607
    if(!avi->index_loaded && !url_is_streamed(pb))
608
        avi_load_index(s);
609
    avi->index_loaded = 1;
610
    avi->non_interleaved |= guess_ni_flag(s);
611 612
    if(avi->non_interleaved) {
        av_log(s, AV_LOG_INFO, "Non interleaved AVI\n");
613
        clean_index(s);
614
    }
615

Fabrice Bellard's avatar
Fabrice Bellard committed
616 617 618
    return 0;
}

619
static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
620 621
{
    AVIContext *avi = s->priv_data;
622
    ByteIOContext *pb = s->pb;
623
    int n, d[8], size;
624
    offset_t i, sync;
625
    void* dstr;
626

627
    if (ENABLE_DV_DEMUXER && avi->dv_demux) {
628
        size = dv_get_packet(avi->dv_demux, pkt);
629 630
        if (size >= 0)
            return size;
631
    }
632

633
    if(avi->non_interleaved){
634
        int best_stream_index = 0;
635 636 637 638
        AVStream *best_st= NULL;
        AVIStream *best_ast;
        int64_t best_ts= INT64_MAX;
        int i;
639

640 641 642 643 644 645 646 647 648
        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);

649
//            av_log(NULL, AV_LOG_DEBUG, "%"PRId64" %d/%d %"PRId64"\n", ts, st->time_base.num, st->time_base.den, ast->frame_offset);
650
            if(ts < best_ts && st->nb_index_entries){
651 652 653 654 655
                best_ts= ts;
                best_st= st;
                best_stream_index= i;
            }
        }
656 657 658
        if(!best_st)
            return -1;

659 660 661 662 663 664 665 666 667 668
        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;
669
            pos += best_ast->packet_size - best_ast->remaining;
670
            url_fseek(s->pb, pos + 8, SEEK_SET);
671
//        av_log(NULL, AV_LOG_DEBUG, "pos=%"PRId64"\n", pos);
672

673 674
            assert(best_ast->remaining <= best_ast->packet_size);

675 676
            avi->stream_index= best_stream_index;
            if(!best_ast->remaining)
677
                best_ast->packet_size=
678
                best_ast->remaining= best_st->index_entries[i].size;
679 680
        }
    }
681

682
resync:
683 684 685 686
    if(avi->stream_index >= 0){
        AVStream *st= s->streams[ avi->stream_index ];
        AVIStream *ast= st->priv_data;
        int size;
687

688
        if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM
689
            size= INT_MAX;
690
        else if(ast->sample_size < 32)
691 692 693 694 695 696
            size= 64*ast->sample_size;
        else
            size= ast->sample_size;

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

699 700 701 702 703 704 705 706
        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);
        }

707
        if (ENABLE_DV_DEMUXER && avi->dv_demux) {
708 709 710 711 712 713 714 715 716 717 718
            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;
719
//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);
720 721
            pkt->stream_index = avi->stream_index;

722
            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
Michael Niedermayer's avatar
Michael Niedermayer committed
723 724
                AVIndexEntry *e;
                int index;
725
                assert(st->index_entries);
726

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

Michael Niedermayer's avatar
Michael Niedermayer committed
730 731 732 733
                if(index >= 0 && e->timestamp == ast->frame_offset){
                    if (e->flags & AVINDEX_KEYFRAME)
                        pkt->flags |= PKT_FLAG_KEY;
                }
734
            } else {
735
                pkt->flags |= PKT_FLAG_KEY;
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
            }
            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;
    }

751 752
    memset(d, -1, sizeof(int)*8);
    for(i=sync=url_ftell(pb); !url_feof(pb); i++) {
753
        int j;
754

755 756 757
        for(j=0; j<7; j++)
            d[j]= d[j+1];
        d[7]= get_byte(pb);
758

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

761
        if(    d[2] >= '0' && d[2] <= '9'
762 763 764 765
            && d[3] >= '0' && d[3] <= '9'){
            n= (d[2] - '0') * 10 + (d[3] - '0');
        }else{
            n= 100; //invalid stream id
766
        }
767
//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);
768
        if(i + size > avi->fsize || d[0]<0)
769
            continue;
770

771 772
        //parse ix##
        if(  (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams)
773
        //parse JUNK
774 775
           ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')
           ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){
776
            url_fskip(pb, size);
777
//av_log(NULL, AV_LOG_DEBUG, "SKIP\n");
778
            goto resync;
779
        }
780

781
        if(    d[0] >= '0' && d[0] <= '9'
782 783 784 785 786
            && d[1] >= '0' && d[1] <= '9'){
            n= (d[0] - '0') * 10 + (d[1] - '0');
        }else{
            n= 100; //invalid stream id
        }
787

788
        //parse ##dc/##wb
789
        if(n < s->nb_streams){
Michael Niedermayer's avatar
Michael Niedermayer committed
790 791 792 793
            AVStream *st;
            AVIStream *ast;
            st = s->streams[n];
            ast = st->priv_data;
794

795 796 797
            if(s->nb_streams>=2){
                AVStream *st1  = s->streams[1];
                AVIStream *ast1= st1->priv_data;
Michael Niedermayer's avatar
Michael Niedermayer committed
798 799 800 801 802 803 804 805 806 807 808 809 810
                //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");
                }
811
            }
812 813


Michael Niedermayer's avatar
Michael Niedermayer committed
814 815 816
            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){
817 818
                if(ast->sample_size) ast->frame_offset += pkt->size;
                else                 ast->frame_offset++;
819 820
                url_fskip(pb, size);
                goto resync;
Michael Niedermayer's avatar
Michael Niedermayer committed
821
            }
822

Michael Niedermayer's avatar
Michael Niedermayer committed
823
            if (d[2] == 'p' && d[3] == 'c' && size<=4*256+4) {
824 825 826 827 828 829 830 831 832
                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
833 834 835 836
            } 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')*/) {
837 838

//av_log(NULL, AV_LOG_DEBUG, "OK\n");
Michael Niedermayer's avatar
Michael Niedermayer committed
839 840 841 842 843 844
                if(d[2]*256+d[3] == ast->prefix)
                    ast->prefix_count++;
                else{
                    ast->prefix= d[2]*256+d[3];
                    ast->prefix_count= 0;
                }
845

Michael Niedermayer's avatar
Michael Niedermayer committed
846 847 848
                avi->stream_index= n;
                ast->packet_size= size + 8;
                ast->remaining= size;
849

Michael Niedermayer's avatar
Michael Niedermayer committed
850 851 852 853 854
                {
                    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);
                    }
855
                }
Michael Niedermayer's avatar
Michael Niedermayer committed
856
                goto resync;
857
            }
858 859
        }
    }
860

861
    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
862 863
}

Fabrice Bellard's avatar
Fabrice Bellard committed
864 865 866 867
/* XXX: we make the implicit supposition that the position are sorted
   for each stream */
static int avi_read_idx1(AVFormatContext *s, int size)
{
868
    AVIContext *avi = s->priv_data;
869
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
870 871 872 873
    int nb_index_entries, i;
    AVStream *st;
    AVIStream *ast;
    unsigned int index, tag, flags, pos, len;
874
    unsigned last_pos= -1;
875

Fabrice Bellard's avatar
Fabrice Bellard committed
876 877 878 879 880 881 882 883 884 885
    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);
886
#if defined(DEBUG_SEEK)
887
        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
888 889
               i, tag, flags, pos, len);
#endif
890 891
        if(i==0 && pos > avi->movi_list)
            avi->movi_list= 0; //FIXME better check
892
        pos += avi->movi_list;
893

Fabrice Bellard's avatar
Fabrice Bellard committed
894 895 896 897 898 899
        index = ((tag & 0xff) - '0') * 10;
        index += ((tag >> 8) & 0xff) - '0';
        if (index >= s->nb_streams)
            continue;
        st = s->streams[index];
        ast = st->priv_data;
900

901
#if defined(DEBUG_SEEK)
902
        av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%"PRId64"\n", len, ast->cum_len);
903
#endif
904 905 906
        if(last_pos == pos)
            avi->non_interleaved= 1;
        else
907
            av_add_index_entry(st, pos, ast->cum_len / FFMAX(1, ast->sample_size), len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
908
        if(ast->sample_size)
909
            ast->cum_len += len;
910 911 912
        else
            ast->cum_len ++;
        last_pos= pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
913 914 915 916
    }
    return 0;
}

917 918 919 920
static int guess_ni_flag(AVFormatContext *s){
    int i;
    int64_t last_start=0;
    int64_t first_end= INT64_MAX;
921

922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
    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
937 938 939
static int avi_load_index(AVFormatContext *s)
{
    AVIContext *avi = s->priv_data;
940
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
941
    uint32_t tag, size;
942
    offset_t pos= url_ftell(pb);
943

Fabrice Bellard's avatar
Fabrice Bellard committed
944 945
    url_fseek(pb, avi->movi_end, SEEK_SET);
#ifdef DEBUG_SEEK
946
    printf("movi_end=0x%"PRIx64"\n", avi->movi_end);
Fabrice Bellard's avatar
Fabrice Bellard committed
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
#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:
976
    url_fseek(pb, pos, SEEK_SET);
Fabrice Bellard's avatar
Fabrice Bellard committed
977 978 979
    return 0;
}

980
static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Fabrice Bellard's avatar
Fabrice Bellard committed
981 982 983
{
    AVIContext *avi = s->priv_data;
    AVStream *st;
984
    int i, index;
Fabrice Bellard's avatar
Fabrice Bellard committed
985 986 987 988 989 990 991
    int64_t pos;

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

    st = s->streams[stream_index];
995 996
    index= av_index_search_timestamp(st, timestamp, flags);
    if(index<0)
Fabrice Bellard's avatar
Fabrice Bellard committed
997
        return -1;
998

Fabrice Bellard's avatar
Fabrice Bellard committed
999
    /* find the position */
1000 1001 1002
    pos = st->index_entries[index].pos;
    timestamp = st->index_entries[index].timestamp;

1003
//    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
1004

1005 1006
    if (ENABLE_DV_DEMUXER && avi->dv_demux) {
        /* One and only one real stream for DV in AVI, and it has video  */
1007
        /* offsets. Calling with other stream indexes should have failed */
1008 1009 1010 1011 1012 1013 1014
        /* 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);

1015
        url_fseek(s->pb, pos, SEEK_SET);
1016 1017 1018 1019
        avi->stream_index= -1;
        return 0;
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
1020
    for(i = 0; i < s->nb_streams; i++) {
1021 1022
        AVStream *st2 = s->streams[i];
        AVIStream *ast2 = st2->priv_data;
1023 1024 1025 1026

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

1027 1028
        if (st2->nb_index_entries <= 0)
            continue;
1029

1030
//        assert(st2->codec->block_align);
1031 1032 1033
        assert(st2->time_base.den == ast2->rate);
        assert(st2->time_base.num == ast2->scale);
        index = av_index_search_timestamp(
1034
                st2,
1035 1036 1037 1038
                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;
1039

1040 1041 1042 1043 1044 1045 1046
        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++;
        }

1047
//        av_log(NULL, AV_LOG_DEBUG, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp);
1048 1049 1050 1051
        /* 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
1052
    }
1053

Fabrice Bellard's avatar
Fabrice Bellard committed
1054
    /* do the seek */
1055
    url_fseek(s->pb, pos, SEEK_SET);
1056
    avi->stream_index= -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
1057 1058 1059
    return 0;
}

1060
static int avi_read_close(AVFormatContext *s)
Fabrice Bellard's avatar
Fabrice Bellard committed
1061
{
Michael Niedermayer's avatar
Michael Niedermayer committed
1062 1063 1064 1065 1066
    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
1067
        AVIStream *ast = st->priv_data;
1068
        av_free(ast);
1069
        av_free(st->codec->palctrl);
Michael Niedermayer's avatar
Michael Niedermayer committed
1070 1071
    }

1072 1073 1074
    if (avi->dv_demux)
        av_free(avi->dv_demux);

Fabrice Bellard's avatar
Fabrice Bellard committed
1075 1076 1077 1078 1079
    return 0;
}

static int avi_probe(AVProbeData *p)
{
1080 1081
    int i;

Fabrice Bellard's avatar
Fabrice Bellard committed
1082
    /* check file header */
1083 1084 1085 1086 1087 1088
    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
1089 1090
}

1091
AVInputFormat avi_demuxer = {
Fabrice Bellard's avatar
Fabrice Bellard committed
1092
    "avi",
1093
    NULL_IF_CONFIG_SMALL("AVI format"),
Fabrice Bellard's avatar
Fabrice Bellard committed
1094 1095 1096 1097 1098
    sizeof(AVIContext),
    avi_probe,
    avi_read_header,
    avi_read_packet,
    avi_read_close,
Fabrice Bellard's avatar
Fabrice Bellard committed
1099
    avi_read_seek,
Fabrice Bellard's avatar
Fabrice Bellard committed
1100
};