exporting keyframe flags, fixes keyframe stuff with streamcopy
[ffmpeg.git] / libavformat / avidec.c
1 /*
2  * AVI decoder.
3  * Copyright (c) 2001 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "avformat.h"
20 #include "avi.h"
21 #include "dv.h"
22
23 //#define DEBUG
24 //#define DEBUG_SEEK
25
26 typedef struct AVIIndexEntry {
27     unsigned int flags;
28     unsigned int pos;
29     unsigned int cum_len; /* sum of all lengths before this packet */
30 } AVIIndexEntry;
31
32 typedef struct AVIStream {
33     AVIIndexEntry *index_entries;
34     int nb_index_entries;
35     int index_entries_allocated_size;
36     int frame_offset; /* current frame (video) or byte (audio) counter
37                          (used to compute the pts) */
38     int scale;
39     int rate;    
40     int sample_size; /* audio only data */
41     int start;
42     
43     int new_frame_offset; /* temporary storage (used during seek) */
44     int cum_len; /* temporary storage (used during seek) */
45 } AVIStream;
46
47 typedef struct {
48     int64_t  riff_end;
49     int64_t  movi_end;
50     offset_t movi_list;
51     int index_loaded;
52     DVDemuxContext* dv_demux;
53 } AVIContext;
54
55 static int avi_load_index(AVFormatContext *s);
56
57 #ifdef DEBUG
58 static void print_tag(const char *str, unsigned int tag, int size)
59 {
60     printf("%s: tag=%c%c%c%c size=0x%x\n",
61            str, tag & 0xff,
62            (tag >> 8) & 0xff,
63            (tag >> 16) & 0xff,
64            (tag >> 24) & 0xff,
65            size);
66 }
67 #endif
68
69 static int get_riff(AVIContext *avi, ByteIOContext *pb)
70 {
71     uint32_t tag; 
72     /* check RIFF header */
73     tag = get_le32(pb);
74
75     if (tag != MKTAG('R', 'I', 'F', 'F'))
76         return -1;
77     avi->riff_end = get_le32(pb);   /* RIFF chunk size */
78     avi->riff_end += url_ftell(pb); /* RIFF chunk end */
79     tag = get_le32(pb);
80     if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X'))
81         return -1;
82     
83     return 0;
84 }
85
86 static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
87 {
88     AVIContext *avi = s->priv_data;
89     ByteIOContext *pb = &s->pb;
90     uint32_t tag, tag1, handler;
91     int codec_type, stream_index, frame_period, bit_rate, scale, rate;
92     unsigned int size, nb_frames;
93     int i, n;
94     AVStream *st;
95     AVIStream *ast;
96     int xan_video = 0;  /* hack to support Xan A/V */
97
98     if (get_riff(avi, pb) < 0)
99         return -1;
100
101     /* first list tag */
102     stream_index = -1;
103     codec_type = -1;
104     frame_period = 0;
105     for(;;) {
106         if (url_feof(pb))
107             goto fail;
108         tag = get_le32(pb);
109         size = get_le32(pb);
110 #ifdef DEBUG
111         print_tag("tag", tag, size);
112 #endif
113
114         switch(tag) {
115         case MKTAG('L', 'I', 'S', 'T'):
116             /* ignored, except when start of video packets */
117             tag1 = get_le32(pb);
118 #ifdef DEBUG
119             print_tag("list", tag1, 0);
120 #endif
121             if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
122                 avi->movi_list = url_ftell(pb) - 4;
123                 avi->movi_end = avi->movi_list + size;
124 #ifdef DEBUG
125                 printf("movi end=%Lx\n", avi->movi_end);
126 #endif
127                 goto end_of_header;
128             }
129             break;
130         case MKTAG('a', 'v', 'i', 'h'):
131             /* avi header */
132             /* using frame_period is bad idea */
133             frame_period = get_le32(pb);
134             bit_rate = get_le32(pb) * 8;
135             url_fskip(pb, 4 * 4);
136             n = get_le32(pb);
137             for(i=0;i<n;i++) {
138                 AVIStream *ast;
139                 st = av_new_stream(s, i);
140                 if (!st)
141                     goto fail;
142
143                 ast = av_mallocz(sizeof(AVIStream));
144                 if (!ast)
145                     goto fail;
146                 st->priv_data = ast;
147             }
148             url_fskip(pb, size - 7 * 4);
149             break;
150         case MKTAG('s', 't', 'r', 'h'):
151             /* stream header */
152             stream_index++;
153             tag1 = get_le32(pb);
154             handler = get_le32(pb); /* codec tag */
155             switch(tag1) {
156             case MKTAG('i', 'a', 'v', 's'):
157             case MKTAG('i', 'v', 'a', 's'):
158                 /* 
159                  * After some consideration -- I don't think we 
160                  * have to support anything but DV in a type1 AVIs.
161                  */
162                 if (s->nb_streams != 1)
163                     goto fail;
164                 
165                 if (handler != MKTAG('d', 'v', 's', 'd') &&
166                     handler != MKTAG('d', 'v', 'h', 'd') &&
167                     handler != MKTAG('d', 'v', 's', 'l'))
168                    goto fail;
169                 
170                 av_freep(&s->streams[0]->codec.extradata);
171                 av_freep(&s->streams[0]);
172                 s->nb_streams = 0;
173                 avi->dv_demux = dv_init_demux(s);
174                 if (!avi->dv_demux)
175                     goto fail;
176                 stream_index = s->nb_streams - 1;
177                 url_fskip(pb, size - 8);
178                 break;
179             case MKTAG('v', 'i', 'd', 's'):
180                 codec_type = CODEC_TYPE_VIDEO;
181
182                 if (stream_index >= s->nb_streams) {
183                     url_fskip(pb, size - 8);
184                     break;
185                 } 
186
187                 st = s->streams[stream_index];
188                 ast = st->priv_data;
189                 st->codec.stream_codec_tag= handler;
190                 
191                 get_le32(pb); /* flags */
192                 get_le16(pb); /* priority */
193                 get_le16(pb); /* language */
194                 get_le32(pb); /* XXX: initial frame ? */
195                 scale = get_le32(pb); /* scale */
196                 rate = get_le32(pb); /* rate */
197
198                 if(scale && rate){
199                 }else if(frame_period){
200                     rate = 1000000;
201                     scale = frame_period;
202                 }else{
203                     rate = 25;
204                     scale = 1;
205                 }
206                 ast->rate = rate;
207                 ast->scale = scale;
208                 av_set_pts_info(st, 64, scale, rate);
209                 st->codec.frame_rate = rate;
210                 st->codec.frame_rate_base = scale;
211                 get_le32(pb); /* start */
212                 nb_frames = get_le32(pb);
213                 st->start_time = 0;
214                 st->duration = av_rescale(nb_frames,
215                     st->codec.frame_rate_base * AV_TIME_BASE,
216                     st->codec.frame_rate);
217                 url_fskip(pb, size - 9 * 4);
218                 break;
219             case MKTAG('a', 'u', 'd', 's'):
220                 {
221                     unsigned int length;
222
223                     codec_type = CODEC_TYPE_AUDIO;
224
225                     if (stream_index >= s->nb_streams) {
226                         url_fskip(pb, size - 8);
227                         break;
228                     } 
229                     st = s->streams[stream_index];
230                     ast = st->priv_data;
231                     
232                     get_le32(pb); /* flags */
233                     get_le16(pb); /* priority */
234                     get_le16(pb); /* language */
235                     get_le32(pb); /* initial frame */
236                     ast->scale = get_le32(pb); /* scale */
237                     ast->rate = get_le32(pb);
238                     av_set_pts_info(st, 64, ast->scale, ast->rate);
239                     ast->start= get_le32(pb); /* start */
240                     length = get_le32(pb); /* length, in samples or bytes */
241                     get_le32(pb); /* buffer size */
242                     get_le32(pb); /* quality */
243                     ast->sample_size = get_le32(pb); /* sample ssize */
244 //av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->scale, ast->rate, ast->sample_size, ast->start);
245                     st->start_time = 0;
246                     if (ast->rate != 0)
247                         st->duration = (int64_t)length * AV_TIME_BASE / ast->rate;
248                     url_fskip(pb, size - 12 * 4);
249                 }
250                 break;
251             default:
252                 goto fail;
253             }
254             break;
255         case MKTAG('s', 't', 'r', 'f'):
256             /* stream header */
257             if (stream_index >= s->nb_streams || avi->dv_demux) {
258                 url_fskip(pb, size);
259             } else {
260                 st = s->streams[stream_index];
261                 switch(codec_type) {
262                 case CODEC_TYPE_VIDEO:
263                     get_le32(pb); /* size */
264                     st->codec.width = get_le32(pb);
265                     st->codec.height = get_le32(pb);
266                     get_le16(pb); /* panes */
267                     st->codec.bits_per_sample= get_le16(pb); /* depth */
268                     tag1 = get_le32(pb);
269                     get_le32(pb); /* ImageSize */
270                     get_le32(pb); /* XPelsPerMeter */
271                     get_le32(pb); /* YPelsPerMeter */
272                     get_le32(pb); /* ClrUsed */
273                     get_le32(pb); /* ClrImportant */
274
275                     st->codec.extradata_size= size - 10*4;
276                     st->codec.extradata= av_malloc(st->codec.extradata_size);
277                     get_buffer(pb, st->codec.extradata, st->codec.extradata_size);
278                     
279                     if(st->codec.extradata_size & 1) //FIXME check if the encoder really did this correctly
280                         get_byte(pb);
281
282                     /* Extract palette from extradata if bpp <= 8 */
283                     /* This code assumes that extradata contains only palette */
284                     /* This is true for all paletted codecs implemented in ffmpeg */
285                     if (st->codec.extradata_size && (st->codec.bits_per_sample <= 8)) {
286                         st->codec.palctrl = av_mallocz(sizeof(AVPaletteControl));
287 #ifdef WORDS_BIGENDIAN
288                         for (i = 0; i < FFMIN(st->codec.extradata_size, AVPALETTE_SIZE)/4; i++)
289                             st->codec.palctrl->palette[i] = bswap_32(((uint32_t*)st->codec.extradata)[i]);
290 #else
291                         memcpy(st->codec.palctrl->palette, st->codec.extradata,
292                                FFMIN(st->codec.extradata_size, AVPALETTE_SIZE));
293 #endif
294                         st->codec.palctrl->palette_changed = 1;
295                     }
296
297 #ifdef DEBUG
298                     print_tag("video", tag1, 0);
299 #endif
300                     st->codec.codec_type = CODEC_TYPE_VIDEO;
301                     st->codec.codec_tag = tag1;
302                     st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
303                     if (st->codec.codec_id == CODEC_ID_XAN_WC4)
304                         xan_video = 1;
305 //                    url_fskip(pb, size - 5 * 4);
306                     break;
307                 case CODEC_TYPE_AUDIO:
308                     get_wav_header(pb, &st->codec, size);
309                     if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
310                         url_fskip(pb, 1);
311                     /* special case time: To support Xan DPCM, hardcode
312                      * the format if Xxan is the video codec */
313                     st->need_parsing = 1;
314                     /* force parsing as several audio frames can be in
315                        one packet */
316                     if (xan_video)
317                         st->codec.codec_id = CODEC_ID_XAN_DPCM;
318                     break;
319                 default:
320                     url_fskip(pb, size);
321                     break;
322                 }
323             }
324             break;
325         default:
326             /* skip tag */
327             size += (size & 1);
328             url_fskip(pb, size);
329             break;
330         }
331     }
332  end_of_header:
333     /* check stream number */
334     if (stream_index != s->nb_streams - 1) {
335     fail:
336         for(i=0;i<s->nb_streams;i++) {
337             av_freep(&s->streams[i]->codec.extradata);
338             av_freep(&s->streams[i]);
339         }
340         return -1;
341     }
342
343     assert(!avi->index_loaded);
344     avi_load_index(s);
345     avi->index_loaded = 1;
346  
347     return 0;
348 }
349
350 static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
351 {
352     AVIContext *avi = s->priv_data;
353     ByteIOContext *pb = &s->pb;
354     int n, d[8], size, i;
355     void* dstr;
356
357     memset(d, -1, sizeof(int)*8);
358    
359     if (avi->dv_demux) {
360         size = dv_get_packet(avi->dv_demux, pkt);
361         if (size >= 0)
362             return size;
363     }
364         
365     for(i=url_ftell(pb); !url_feof(pb); i++) {
366         int j;
367
368         if (i >= avi->movi_end) { /* Let's see if it's an OpenDML AVI */
369             uint32_t tag, size, tag2;
370             url_fskip(pb, avi->riff_end - url_ftell(pb));
371             if (get_riff(avi, pb) < 0)
372                 return -1;
373             
374             tag = get_le32(pb);
375             size = get_le32(pb);
376             tag2 = get_le32(pb);
377             if (tag == MKTAG('L','I','S','T') && tag2 == MKTAG('m','o','v','i'))
378                 avi->movi_end = url_ftell(pb) + size - 4; 
379             else
380                 return -1;
381         }
382
383         for(j=0; j<7; j++)
384             d[j]= d[j+1];
385         d[7]= get_byte(pb);
386         
387         size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24);
388         
389         //parse ix##
390         n= (d[2] - '0') * 10 + (d[3] - '0');
391         if(    d[2] >= '0' && d[2] <= '9'
392             && d[3] >= '0' && d[3] <= '9'
393             && d[0] == 'i' && d[1] == 'x'
394             && n < s->nb_streams
395             && i + size <= avi->movi_end){
396             
397             url_fskip(pb, size);
398         }
399         
400         //parse ##dc/##wb
401         n= (d[0] - '0') * 10 + (d[1] - '0');
402         if(    d[0] >= '0' && d[0] <= '9'
403             && d[1] >= '0' && d[1] <= '9'
404             && ((d[2] == 'd' && d[3] == 'c') || 
405                 (d[2] == 'w' && d[3] == 'b') || 
406                 (d[2] == 'd' && d[3] == 'b') ||
407                 (d[2] == '_' && d[3] == '_'))
408             && n < s->nb_streams
409             && i + size <= avi->movi_end) {
410         
411             av_new_packet(pkt, size);
412             get_buffer(pb, pkt->data, size);
413             if (size & 1) {
414                 get_byte(pb);
415                 size++;
416             }
417         
418             if (avi->dv_demux) {
419                 dstr = pkt->destruct;
420                 size = dv_produce_packet(avi->dv_demux, pkt,
421                                          pkt->data, pkt->size);
422                 pkt->destruct = dstr;
423                 pkt->flags |= PKT_FLAG_KEY;
424             } else {
425                 AVStream *st;
426                 AVIStream *ast;
427                 st = s->streams[n];
428                 ast = st->priv_data;
429
430                 /* XXX: how to handle B frames in avi ? */
431                 pkt->dts = ast->frame_offset;
432 //                pkt->dts += ast->start;
433                 if(ast->sample_size)
434                     pkt->dts /= ast->sample_size;
435 //printf("%Ld %d %d %d %d\n", pkt->pts, ast->frame_offset, ast->scale,  AV_TIME_BASE,  ast->rate);
436                 pkt->stream_index = n;
437                 /* FIXME: We really should read index for that */
438                 if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
439                     if (ast->frame_offset < ast->nb_index_entries) {
440                         if (ast->index_entries[ast->frame_offset].flags & AVIIF_INDEX)
441                             pkt->flags |= PKT_FLAG_KEY; 
442                     } else {
443                         /* if no index, better to say that all frames
444                            are key frames */
445                         pkt->flags |= PKT_FLAG_KEY;
446                     }
447                 } else {
448                     pkt->flags |= PKT_FLAG_KEY; 
449                 }
450                 if(ast->sample_size)
451                     ast->frame_offset += pkt->size;
452                 else
453                     ast->frame_offset++;
454             }
455             return size;
456         }
457     }
458     return -1;
459 }
460
461 /* XXX: we make the implicit supposition that the position are sorted
462    for each stream */
463 static int avi_read_idx1(AVFormatContext *s, int size)
464 {
465     ByteIOContext *pb = &s->pb;
466     int nb_index_entries, i;
467     AVStream *st;
468     AVIStream *ast;
469     AVIIndexEntry *ie, *entries;
470     unsigned int index, tag, flags, pos, len;
471     
472     nb_index_entries = size / 16;
473     if (nb_index_entries <= 0)
474         return -1;
475
476     /* read the entries and sort them in each stream component */
477     for(i = 0; i < nb_index_entries; i++) {
478         tag = get_le32(pb);
479         flags = get_le32(pb);
480         pos = get_le32(pb);
481         len = get_le32(pb);
482 #if defined(DEBUG_SEEK) && 0
483         printf("%d: tag=0x%x flags=0x%x pos=0x%x len=%d\n", 
484                i, tag, flags, pos, len);
485 #endif
486         index = ((tag & 0xff) - '0') * 10;
487         index += ((tag >> 8) & 0xff) - '0';
488         if (index >= s->nb_streams)
489             continue;
490         st = s->streams[index];
491         ast = st->priv_data;
492         
493         entries = av_fast_realloc(ast->index_entries,
494                                   &ast->index_entries_allocated_size,
495                                   (ast->nb_index_entries + 1) * 
496                                   sizeof(AVIIndexEntry));
497         if (entries) {
498             ast->index_entries = entries;
499             ie = &entries[ast->nb_index_entries++];
500             ie->flags = flags;
501             ie->pos = pos;
502             ie->cum_len = ast->cum_len;
503             ast->cum_len += len;
504         }
505     }
506     return 0;
507 }
508
509 static int avi_load_index(AVFormatContext *s)
510 {
511     AVIContext *avi = s->priv_data;
512     ByteIOContext *pb = &s->pb;
513     uint32_t tag, size;
514     offset_t pos= url_ftell(pb);
515     
516     url_fseek(pb, avi->movi_end, SEEK_SET);
517 #ifdef DEBUG_SEEK
518     printf("movi_end=0x%llx\n", avi->movi_end);
519 #endif
520     for(;;) {
521         if (url_feof(pb))
522             break;
523         tag = get_le32(pb);
524         size = get_le32(pb);
525 #ifdef DEBUG_SEEK
526         printf("tag=%c%c%c%c size=0x%x\n",
527                tag & 0xff,
528                (tag >> 8) & 0xff,
529                (tag >> 16) & 0xff,
530                (tag >> 24) & 0xff,
531                size);
532 #endif
533         switch(tag) {
534         case MKTAG('i', 'd', 'x', '1'):
535             if (avi_read_idx1(s, size) < 0)
536                 goto skip;
537             else
538                 goto the_end;
539             break;
540         default:
541         skip:
542             size += (size & 1);
543             url_fskip(pb, size);
544             break;
545         }
546     }
547  the_end:
548     url_fseek(pb, pos, SEEK_SET);
549     return 0;
550 }
551
552 /* return the index entry whose position is immediately >= 'wanted_pos' */
553 static int locate_frame_in_index(AVIIndexEntry *entries, 
554                                  int nb_entries, int wanted_pos)
555 {
556     int a, b, m, pos;
557     
558     a = 0;
559     b = nb_entries - 1;
560     while (a <= b) {
561         m = (a + b) >> 1;
562         pos = entries[m].pos;
563         if (pos == wanted_pos)
564             goto found;
565         else if (pos > wanted_pos) {
566             b = m - 1;
567         } else {
568             a = m + 1;
569         }
570     }
571     m = a;
572     if (m > 0)
573         m--;
574  found:
575     return m;
576 }
577
578 static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp)
579 {
580     AVIContext *avi = s->priv_data;
581     AVStream *st;
582     AVIStream *ast;
583     int frame_number, i;
584     int64_t pos;
585
586     if (!avi->index_loaded) {
587         /* we only load the index on demand */
588         avi_load_index(s);
589         avi->index_loaded = 1;
590     }
591     if (stream_index < 0) {
592         for(i = 0; i < s->nb_streams; i++) {
593             st = s->streams[i];
594             if (st->codec.codec_type == CODEC_TYPE_VIDEO)
595                 goto found;
596         }
597         return -1;
598     found:
599         stream_index = i;
600     }
601
602     st = s->streams[stream_index];
603     if (st->codec.codec_type != CODEC_TYPE_VIDEO)
604         return -1;
605     ast = st->priv_data;
606     /* compute the frame number */
607     frame_number = timestamp;
608 #ifdef DEBUG_SEEK
609     printf("timestamp=%0.3f nb_indexes=%d frame_number=%d\n", 
610            (double)timestamp / AV_TIME_BASE,
611            ast->nb_index_entries, frame_number);
612 #endif
613     /* find a closest key frame before */
614     if (frame_number >= ast->nb_index_entries)
615         return -1;
616     while (frame_number >= 0 &&
617            !(ast->index_entries[frame_number].flags & AVIIF_INDEX))
618         frame_number--;
619     if (frame_number < 0)
620         return -1;
621     ast->new_frame_offset = frame_number;
622
623     /* find the position */
624     pos = ast->index_entries[frame_number].pos;
625
626 #ifdef DEBUG_SEEK
627     printf("key_frame_number=%d pos=0x%llx\n", 
628            frame_number, pos);
629 #endif
630     
631     /* update the frame counters for all the other stream by looking
632        at the positions just after the one found */
633     for(i = 0; i < s->nb_streams; i++) {
634         int j;
635         if (i != stream_index) {
636             st = s->streams[i];
637             ast = st->priv_data;
638             if (ast->nb_index_entries <= 0)
639                 return -1;
640             j = locate_frame_in_index(ast->index_entries,
641                                       ast->nb_index_entries,
642                                       pos);
643             /* get next frame */
644             if ((j  + 1) < ast->nb_index_entries)
645                 j++;
646             /* extract the current frame number */
647             if (ast->sample_size==0)
648                 ast->new_frame_offset = j;
649             else
650                 ast->new_frame_offset = ast->index_entries[j].cum_len;
651         }
652     }
653     
654     /* everything is OK now. We can update the frame offsets */
655     for(i = 0; i < s->nb_streams; i++) {
656         st = s->streams[i];
657         ast = st->priv_data;
658         ast->frame_offset = ast->new_frame_offset;
659 #ifdef DEBUG_SEEK
660         printf("%d: frame_offset=%d\n", i, 
661                ast->frame_offset);
662 #endif
663     }
664     /* do the seek */
665     pos += avi->movi_list;
666     url_fseek(&s->pb, pos, SEEK_SET);
667     return 0;
668 }
669
670 static int avi_read_close(AVFormatContext *s)
671 {
672     int i;
673     AVIContext *avi = s->priv_data;
674
675     for(i=0;i<s->nb_streams;i++) {
676         AVStream *st = s->streams[i];
677         AVIStream *ast = st->priv_data;
678         if(ast){
679             av_free(ast->index_entries);
680             av_free(ast);
681         }
682         av_free(st->codec.extradata);
683         av_free(st->codec.palctrl);
684     }
685
686     if (avi->dv_demux)
687         av_free(avi->dv_demux);
688
689     return 0;
690 }
691
692 static int avi_probe(AVProbeData *p)
693 {
694     /* check file header */
695     if (p->buf_size <= 32)
696         return 0;
697     if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
698         p->buf[2] == 'F' && p->buf[3] == 'F' &&
699         p->buf[8] == 'A' && p->buf[9] == 'V' &&
700         p->buf[10] == 'I' && p->buf[11] == ' ')
701         return AVPROBE_SCORE_MAX;
702     else
703         return 0;
704 }
705
706 static AVInputFormat avi_iformat = {
707     "avi",
708     "avi format",
709     sizeof(AVIContext),
710     avi_probe,
711     avi_read_header,
712     avi_read_packet,
713     avi_read_close,
714     avi_read_seek,
715 };
716
717 int avidec_init(void)
718 {
719     av_register_input_format(&avi_iformat);
720     return 0;
721 }