avidec.c 11.9 KB
Newer Older
F
Fabrice Bellard 已提交
1 2
/*
 * AVI decoder.
F
Fabrice Bellard 已提交
3
 * Copyright (c) 2001 Fabrice Bellard.
F
Fabrice Bellard 已提交
4
 *
F
Fabrice Bellard 已提交
5 6 7 8
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
F
Fabrice Bellard 已提交
9
 *
F
Fabrice Bellard 已提交
10
 * This library is distributed in the hope that it will be useful,
F
Fabrice Bellard 已提交
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
F
Fabrice Bellard 已提交
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
F
Fabrice Bellard 已提交
14
 *
F
Fabrice Bellard 已提交
15 16 17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
F
Fabrice Bellard 已提交
18 19 20 21 22 23
 */
#include "avformat.h"
#include "avi.h"

//#define DEBUG

24 25 26 27 28 29 30 31 32 33 34 35
static const struct AVI1Handler {
   enum CodecID vcid;
   enum CodecID acid;
   uint32_t tag;
} AVI1Handlers[] = {
  { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 's', 'd') },
  { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 'h', 'd') },
  { CODEC_ID_DVVIDEO, CODEC_ID_DVAUDIO, MKTAG('d', 'v', 's', 'l') },
  /* This is supposed to be the last one */
  { CODEC_ID_NONE, CODEC_ID_NONE, 0 },
};

F
Fabrice Bellard 已提交
36 37 38 39 40 41 42
typedef struct AVIIndex {
    unsigned char tag[4];
    unsigned int flags, pos, len;
    struct AVIIndex *next;
} AVIIndex;

typedef struct {
43
    int64_t riff_end;
44
    int64_t movi_end;
45 46 47 48
    int     type;
    uint8_t *buf;
    int      buf_size;
    int      stream_index;
F
Fabrice Bellard 已提交
49 50 51 52 53
    offset_t movi_list;
    AVIIndex *first, *last;
} AVIContext;

#ifdef DEBUG
Z
Zdenek Kabelac 已提交
54
static void print_tag(const char *str, unsigned int tag, int size)
F
Fabrice Bellard 已提交
55 56 57 58 59 60 61 62 63 64
{
    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

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
static int get_riff(AVIContext *avi, ByteIOContext *pb)
{
    uint32_t tag; 
    /* check RIFF header */
    tag = get_le32(pb);

    if (tag != MKTAG('R', 'I', 'F', 'F'))
        return -1;
    avi->riff_end = get_le32(pb);   /* RIFF chunk size */
    avi->riff_end += url_ftell(pb); /* RIFF chunk end */
    tag = get_le32(pb);
    if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X'))
        return -1;
    
    return 0;
}

Z
Zdenek Kabelac 已提交
82
static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
F
Fabrice Bellard 已提交
83
{
F
Fabrice Bellard 已提交
84
    AVIContext *avi = s->priv_data;
F
Fabrice Bellard 已提交
85
    ByteIOContext *pb = &s->pb;
86
    uint32_t tag, tag1, handler;
87
    int codec_type, stream_index, frame_period, bit_rate, scale, rate;
F
Fabrice Bellard 已提交
88
    unsigned int size;
89
    int i;
F
Fabrice Bellard 已提交
90 91
    AVStream *st;

92
    if (get_riff(avi, pb) < 0)
F
Fabrice Bellard 已提交
93
        return -1;
Z
Zdenek Kabelac 已提交
94

F
Fabrice Bellard 已提交
95 96 97 98
    /* first list tag */
    stream_index = -1;
    codec_type = -1;
    frame_period = 0;
99 100 101 102 103
    avi->type = 2;
    avi->buf = av_malloc(1);
    if (!avi->buf)
        return -1;
    avi->buf_size = 1;
F
Fabrice Bellard 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
    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')) {
                avi->movi_end = url_ftell(pb) + size - 4;
#ifdef DEBUG
                printf("movi end=%Lx\n", avi->movi_end);
#endif
                goto end_of_header;
            }
            break;
        case MKTAG('a', 'v', 'i', 'h'):
Z
Zdenek Kabelac 已提交
129 130
	    /* avi header */
            /* using frame_period is bad idea */
F
Fabrice Bellard 已提交
131 132
            frame_period = get_le32(pb);
            bit_rate = get_le32(pb) * 8;
Z
Zdenek Kabelac 已提交
133
	    url_fskip(pb, 4 * 4);
F
Fabrice Bellard 已提交
134 135
            s->nb_streams = get_le32(pb);
            for(i=0;i<s->nb_streams;i++) {
Z
Zdenek Kabelac 已提交
136
                AVStream *st = av_mallocz(sizeof(AVStream));
F
Fabrice Bellard 已提交
137 138
                if (!st)
                    goto fail;
M
cleanup  
Michael Niedermayer 已提交
139 140
                avcodec_get_context_defaults(&st->codec);

F
Fabrice Bellard 已提交
141
                s->streams[i] = st;
Z
Zdenek Kabelac 已提交
142
	    }
F
Fabrice Bellard 已提交
143 144 145 146 147 148 149
            url_fskip(pb, size - 7 * 4);
            break;
        case MKTAG('s', 't', 'r', 'h'):
            /* stream header */
            stream_index++;
            tag1 = get_le32(pb);
            switch(tag1) {
150 151 152 153 154 155 156
            case MKTAG('i', 'a', 'v', 's'):
	    case MKTAG('i', 'v', 'a', 's'):
	        if (s->nb_streams != 1)
		    goto fail;
		avi->type = 1;
		avi->stream_index = 0;
	    case MKTAG('v', 'i', 'd', 's'):
F
Fabrice Bellard 已提交
157
                codec_type = CODEC_TYPE_VIDEO;
158 159 160 161 162 163 164 165

                if (stream_index >= s->nb_streams) {
                    url_fskip(pb, size - 4);
                    break;
                } 

                st = s->streams[stream_index];

166
                handler = get_le32(pb); /* codec tag */
F
Fabrice Bellard 已提交
167 168 169 170
                get_le32(pb); /* flags */
                get_le16(pb); /* priority */
                get_le16(pb); /* language */
                get_le32(pb); /* XXX: initial frame ? */
171 172
                scale = get_le32(pb); /* scale */
                rate = get_le32(pb); /* rate */
173

174 175
                if(scale && rate){
                    st->codec.frame_rate = rate;
176
                    st->codec.frame_rate_base = scale;
177 178
                }else if(frame_period){
                    st->codec.frame_rate = 1000000;
179
                    st->codec.frame_rate_base = frame_period;
180 181 182 183
                }else{
                    st->codec.frame_rate = 25;
                    st->codec.frame_rate_base = 1;
                }
184
                
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
                if (avi->type == 1) {
                    AVStream *st = av_mallocz(sizeof(AVStream));
                    if (!st)
		        goto fail;
                    
		    avcodec_get_context_defaults(&st->codec);
		    s->streams[s->nb_streams++] = st;
		    stream_index++;
		    
		    for (i=0; AVI1Handlers[i].tag != 0; ++i)
		       if (AVI1Handlers[i].tag == handler)
		           break;

		    if (AVI1Handlers[i].tag != 0) {
		        s->streams[0]->codec.codec_type = CODEC_TYPE_VIDEO;
                        s->streams[0]->codec.codec_id   = AVI1Handlers[i].vcid;
		        s->streams[1]->codec.codec_type = CODEC_TYPE_AUDIO;
                        s->streams[1]->codec.codec_id   = AVI1Handlers[i].acid;
		    } else
		        goto fail;
		}
		
		url_fskip(pb, size - 7 * 4);
F
Fabrice Bellard 已提交
208 209 210 211
                break;
            case MKTAG('a', 'u', 'd', 's'):
                codec_type = CODEC_TYPE_AUDIO;
                /* nothing really useful */
212 213 214 215
                url_fskip(pb, size - 4);
                break;
            default:
                goto fail;
F
Fabrice Bellard 已提交
216 217 218 219
            }
            break;
        case MKTAG('s', 't', 'r', 'f'):
            /* stream header */
220
            if (stream_index >= s->nb_streams || avi->type == 1) {
F
Fabrice Bellard 已提交
221 222 223 224 225 226 227 228 229
                url_fskip(pb, size);
            } else {
                st = s->streams[stream_index];
                switch(codec_type) {
                case CODEC_TYPE_VIDEO:
                    get_le32(pb); /* size */
                    st->codec.width = get_le32(pb);
                    st->codec.height = get_le32(pb);
                    get_le16(pb); /* panes */
230
                    st->codec.bits_per_sample= get_le16(pb); /* depth */
F
Fabrice Bellard 已提交
231
                    tag1 = get_le32(pb);
232 233 234 235 236 237 238 239 240
                    get_le32(pb); /* ImageSize */
                    get_le32(pb); /* XPelsPerMeter */
                    get_le32(pb); /* YPelsPerMeter */
                    get_le32(pb); /* ClrUsed */
                    get_le32(pb); /* ClrImportant */

                    st->codec.extradata_size= size - 10*4;
                    st->codec.extradata= av_malloc(st->codec.extradata_size); //FIXME where should we free this?
                    get_buffer(pb, st->codec.extradata, st->codec.extradata_size);
M
Michael Niedermayer 已提交
241 242 243
                    
                    if(st->codec.extradata_size & 1) //FIXME check if the encoder really did this correctly
                        get_byte(pb);
244

F
Fabrice Bellard 已提交
245 246 247 248 249 250
#ifdef DEBUG
                    print_tag("video", tag1, 0);
#endif
                    st->codec.codec_type = CODEC_TYPE_VIDEO;
                    st->codec.codec_tag = tag1;
                    st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
251
//                    url_fskip(pb, size - 5 * 4);
F
Fabrice Bellard 已提交
252
                    break;
253
                case CODEC_TYPE_AUDIO:
254
                    get_wav_header(pb, &st->codec, size);
255 256
                    if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
                        url_fskip(pb, 1);
F
Fabrice Bellard 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
                    break;
                default:
                    url_fskip(pb, size);
                    break;
                }
            }
            break;
        default:
            /* 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++) {
M
Michael Niedermayer 已提交
276
            av_freep(&s->streams[i]->codec.extradata);
M
10l  
Michael Niedermayer 已提交
277
            av_freep(&s->streams[i]);
F
Fabrice Bellard 已提交
278 279 280
        }
        return -1;
    }
Z
Zdenek Kabelac 已提交
281

F
Fabrice Bellard 已提交
282 283 284
    return 0;
}

285 286 287 288 289 290
static void __destruct_pkt(struct AVPacket *pkt)
{
    pkt->data = NULL; pkt->size = 0;
    return;
}

Z
Zdenek Kabelac 已提交
291
static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
F
Fabrice Bellard 已提交
292 293 294
{
    AVIContext *avi = s->priv_data;
    ByteIOContext *pb = &s->pb;
295
    int n, d[8], size, i;
296

297
    memset(d, -1, sizeof(int)*8);
F
Fabrice Bellard 已提交
298

299 300 301
    if (avi->type == 1 && avi->stream_index)
        goto pkt_init;

302
    for(i=url_ftell(pb); !url_feof(pb); i++) {
303
        int j;
Z
Zdenek Kabelac 已提交
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
	if (i >= avi->movi_end) { /* Let's see if it's an OpenDML AVI */
	    uint32_t tag, size, tag2;
	    url_fskip(pb, avi->riff_end - url_ftell(pb));
	    if (get_riff(avi, pb) < 0)
	        return -1;
	    
	    tag = get_le32(pb);
	    size = get_le32(pb);
	    tag2 = get_le32(pb);
	    if (tag == MKTAG('L','I','S','T') && tag2 == MKTAG('m','o','v','i'))
	        avi->movi_end = url_ftell(pb) + size - 4; 
	    else
	        return -1;
	}

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
        for(j=0; j<7; j++)
            d[j]= d[j+1];
        d[7]= get_byte(pb);
        
        size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24);
        
        //parse ix##
        n= (d[2] - '0') * 10 + (d[3] - '0');
        if(    d[2] >= '0' && d[2] <= '9'
            && d[3] >= '0' && d[3] <= '9'
            && d[0] == 'i' && d[1] == 'x'
            && n < s->nb_streams
            && i + size <= avi->movi_end){
            
            url_fskip(pb, size);
        }
        
        //parse ##dc/##wb
        n= (d[0] - '0') * 10 + (d[1] - '0');
        if(    d[0] >= '0' && d[0] <= '9'
            && d[1] >= '0' && d[1] <= '9'
341 342 343 344
            && ((d[2] == 'd' && d[3] == 'c') || 
	        (d[2] == 'w' && d[3] == 'b') || 
		(d[2] == 'd' && d[3] == 'b') ||
		(d[2] == '_' && d[3] == '_'))
345
            && n < s->nb_streams
346
            && i + size <= avi->movi_end) {
347
        
348 349 350 351 352 353 354 355 356 357 358
	    uint8_t *tbuf = av_realloc(avi->buf, size + FF_INPUT_BUFFER_PADDING_SIZE);
	    if (!tbuf)
		return -1;
	    avi->buf = tbuf;
            avi->buf_size = size;
	    get_buffer(pb, avi->buf, size);
	    if (size & 1)
	        get_byte(pb);
	    if (avi->type != 1)
	        avi->stream_index = n;
	    goto pkt_init;
359 360 361 362
        }
    }
    
    return -1;
363 364 365 366 367 368 369 370 371

pkt_init:
    av_init_packet(pkt);
    pkt->data = avi->buf;
    pkt->size = avi->buf_size;
    pkt->destruct = __destruct_pkt;
    pkt->stream_index = avi->stream_index;
    avi->stream_index = !avi->stream_index;
    return 0;
F
Fabrice Bellard 已提交
372 373
}

Z
Zdenek Kabelac 已提交
374
static int avi_read_close(AVFormatContext *s)
F
Fabrice Bellard 已提交
375
{
F
Fabrice Bellard 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    return 0;
}

static int avi_probe(AVProbeData *p)
{
    /* check file header */
    if (p->buf_size <= 32)
        return 0;
    if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
        p->buf[2] == 'F' && p->buf[3] == 'F' &&
        p->buf[8] == 'A' && p->buf[9] == 'V' &&
        p->buf[10] == 'I' && p->buf[11] == ' ')
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

static AVInputFormat avi_iformat = {
    "avi",
    "avi format",
    sizeof(AVIContext),
    avi_probe,
    avi_read_header,
    avi_read_packet,
    avi_read_close,
};

int avidec_init(void)
{
    av_register_input_format(&avi_iformat);
F
Fabrice Bellard 已提交
406 407
    return 0;
}