]> git.sesse.net Git - ffmpeg/blob - libavformat/ffm.c
Add more resilience in reading ffm files. In particular, don't assume
[ffmpeg] / libavformat / ffm.c
1 /*
2  * FFM (ffserver live feed) encoder and 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 <unistd.h>
21
22 /* The FFM file is made of blocks of fixed size */
23 #define FFM_HEADER_SIZE 14
24 #define PACKET_ID       0x666d
25
26 /* each packet contains frames (which can span several packets */
27 #define FRAME_HEADER_SIZE    8
28 #define FLAG_KEY_FRAME       0x01
29
30 typedef struct FFMStream {
31     int64_t pts;
32 } FFMStream;
33
34 enum {
35     READ_HEADER,
36     READ_DATA,
37 };
38
39 typedef struct FFMContext {
40     /* only reading mode */
41     offset_t write_index, file_size;
42     int read_state;
43     uint8_t header[FRAME_HEADER_SIZE];
44
45     /* read and write */
46     int first_packet; /* true if first packet, needed to set the discontinuity tag */
47     int packet_size;
48     int frame_offset;
49     int64_t pts;
50     uint8_t *packet_ptr, *packet_end;
51     uint8_t packet[FFM_PACKET_SIZE];
52 } FFMContext;
53
54 static int64_t get_pts(AVFormatContext *s, offset_t pos);
55
56 /* disable pts hack for testing */
57 int ffm_nopts = 0;
58
59 #ifdef CONFIG_ENCODERS
60 static void flush_packet(AVFormatContext *s)
61 {
62     FFMContext *ffm = s->priv_data;
63     int fill_size, h;
64     ByteIOContext *pb = &s->pb;
65
66     fill_size = ffm->packet_end - ffm->packet_ptr;
67     memset(ffm->packet_ptr, 0, fill_size);
68
69     if (url_ftell(pb) % ffm->packet_size) 
70         av_abort();
71
72     /* put header */
73     put_be16(pb, PACKET_ID);
74     put_be16(pb, fill_size);
75     put_be64(pb, ffm->pts);
76     h = ffm->frame_offset;
77     if (ffm->first_packet)
78         h |= 0x8000;
79     put_be16(pb, h);
80     put_buffer(pb, ffm->packet, ffm->packet_end - ffm->packet);
81
82     /* prepare next packet */
83     ffm->frame_offset = 0; /* no key frame */
84     ffm->pts = 0; /* no pts */
85     ffm->packet_ptr = ffm->packet;
86     ffm->first_packet = 0;
87 }
88
89 /* 'first' is true if first data of a frame */
90 static void ffm_write_data(AVFormatContext *s,
91                            const uint8_t *buf, int size,
92                            int64_t pts, int first)
93 {
94     FFMContext *ffm = s->priv_data;
95     int len;
96
97     if (first && ffm->frame_offset == 0)
98         ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
99     if (first && ffm->pts == 0)
100         ffm->pts = pts;
101
102     /* write as many packets as needed */
103     while (size > 0) {
104         len = ffm->packet_end - ffm->packet_ptr;
105         if (len > size)
106             len = size;
107         memcpy(ffm->packet_ptr, buf, len);
108
109         ffm->packet_ptr += len;
110         buf += len;
111         size -= len;
112         if (ffm->packet_ptr >= ffm->packet_end) {
113             /* special case : no pts in packet : we leave the current one */
114             if (ffm->pts == 0)
115                 ffm->pts = pts;
116
117             flush_packet(s);
118         }
119     }
120 }
121
122 static int ffm_write_header(AVFormatContext *s)
123 {
124     FFMContext *ffm = s->priv_data;
125     AVStream *st;
126     FFMStream *fst;
127     ByteIOContext *pb = &s->pb;
128     AVCodecContext *codec;
129     int bit_rate, i;
130
131     ffm->packet_size = FFM_PACKET_SIZE;
132
133     /* header */
134     put_tag(pb, "FFM1");
135     put_be32(pb, ffm->packet_size);
136     /* XXX: store write position in other file ? */
137     put_be64(pb, ffm->packet_size); /* current write position */
138
139     put_be32(pb, s->nb_streams);
140     bit_rate = 0;
141     for(i=0;i<s->nb_streams;i++) {
142         st = s->streams[i];
143         bit_rate += st->codec.bit_rate;
144     }
145     put_be32(pb, bit_rate);
146
147     /* list of streams */
148     for(i=0;i<s->nb_streams;i++) {
149         st = s->streams[i];
150         fst = av_mallocz(sizeof(FFMStream));
151         if (!fst)
152             goto fail;
153         st->priv_data = fst;
154
155         codec = &st->codec;
156         /* generic info */
157         put_be32(pb, codec->codec_id);
158         put_byte(pb, codec->codec_type);
159         put_be32(pb, codec->bit_rate);
160         put_be32(pb, st->quality);
161         put_be32(pb, codec->flags);
162         /* specific info */
163         switch(codec->codec_type) {
164         case CODEC_TYPE_VIDEO:
165             put_be32(pb, codec->frame_rate_base);
166             put_be32(pb, codec->frame_rate);
167             put_be16(pb, codec->width);
168             put_be16(pb, codec->height);
169             put_be16(pb, codec->gop_size);
170             put_byte(pb, codec->qmin);
171             put_byte(pb, codec->qmax);
172             put_byte(pb, codec->max_qdiff);
173             put_be16(pb, (int) (codec->qcompress * 10000.0));
174             put_be16(pb, (int) (codec->qblur * 10000.0));
175             put_be32(pb, codec->bit_rate_tolerance);
176             put_strz(pb, codec->rc_eq);
177             put_be32(pb, codec->rc_max_rate);
178             put_be32(pb, codec->rc_min_rate);
179             put_be32(pb, codec->rc_buffer_size);
180             put_be64_double(pb, codec->i_quant_factor);
181             put_be64_double(pb, codec->b_quant_factor);
182             put_be64_double(pb, codec->i_quant_offset);
183             put_be64_double(pb, codec->b_quant_offset);
184             put_be32(pb, codec->dct_algo);
185             break;
186         case CODEC_TYPE_AUDIO:
187             put_be32(pb, codec->sample_rate);
188             put_le16(pb, codec->channels);
189             put_le16(pb, codec->frame_size);
190             break;
191         default:
192             av_abort();
193         }
194         /* hack to have real time */
195         if (ffm_nopts)
196             fst->pts = 0;
197         else
198             fst->pts = av_gettime();
199     }
200
201     /* flush until end of block reached */
202     while ((url_ftell(pb) % ffm->packet_size) != 0)
203         put_byte(pb, 0);
204
205     put_flush_packet(pb);
206
207     /* init packet mux */
208     ffm->packet_ptr = ffm->packet;
209     ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
210     if (ffm->packet_end < ffm->packet)
211         av_abort();
212     ffm->frame_offset = 0;
213     ffm->pts = 0;
214     ffm->first_packet = 1;
215
216     return 0;
217  fail:
218     for(i=0;i<s->nb_streams;i++) {
219         st = s->streams[i];
220         av_freep(&st->priv_data);
221     }
222     return -1;
223 }
224
225 static int ffm_write_packet(AVFormatContext *s, int stream_index,
226                             const uint8_t *buf, int size, int64_t force_pts)
227 {
228     AVStream *st = s->streams[stream_index];
229     FFMStream *fst = st->priv_data;
230     int64_t pts;
231     uint8_t header[FRAME_HEADER_SIZE];
232     int duration;
233
234     if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
235         duration = ((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0);
236     } else {
237         duration = (1000000.0 * st->codec.frame_rate_base / (float)st->codec.frame_rate);
238     }
239
240     pts = fst->pts;
241     /* packet size & key_frame */
242     header[0] = stream_index;
243     header[1] = 0;
244     if (st->codec.coded_frame->key_frame) //if st->codec.coded_frame==NULL then there is a bug somewhere else
245         header[1] |= FLAG_KEY_FRAME;
246     header[2] = (size >> 16) & 0xff;
247     header[3] = (size >> 8) & 0xff;
248     header[4] = size & 0xff;
249     header[5] = (duration >> 16) & 0xff;
250     header[6] = (duration >> 8) & 0xff;
251     header[7] = duration & 0xff;
252     ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1);
253     ffm_write_data(s, buf, size, pts, 0);
254
255     fst->pts += duration;
256     return 0;
257 }
258
259 static int ffm_write_trailer(AVFormatContext *s)
260 {
261     ByteIOContext *pb = &s->pb;
262     FFMContext *ffm = s->priv_data;
263     int i;
264
265     /* flush packets */
266     if (ffm->packet_ptr > ffm->packet)
267         flush_packet(s);
268
269     put_flush_packet(pb);
270
271     if (!url_is_streamed(pb)) {
272         int64_t size;
273         /* update the write offset */
274         size = url_ftell(pb);
275         url_fseek(pb, 8, SEEK_SET);
276         put_be64(pb, size);
277         put_flush_packet(pb);
278     }
279
280     for(i=0;i<s->nb_streams;i++)
281         av_freep(&s->streams[i]->priv_data);
282     return 0;
283 }
284 #endif //CONFIG_ENCODERS
285
286 /* ffm demux */
287
288 static int ffm_is_avail_data(AVFormatContext *s, int size)
289 {
290     FFMContext *ffm = s->priv_data;
291     offset_t pos, avail_size;
292     int len;
293
294     len = ffm->packet_end - ffm->packet_ptr;
295     if (!ffm_nopts) {
296         /* XXX: I don't understand this test, so I disabled it for testing */
297         if (size <= len)
298             return 1;
299     }
300     pos = url_ftell(&s->pb);
301     if (pos == ffm->write_index) {
302         /* exactly at the end of stream */
303         return 0;
304     } else if (pos < ffm->write_index) {
305         avail_size = ffm->write_index - pos;
306     } else {
307         avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
308     }
309     avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
310     if (size <= avail_size)
311         return 1;
312     else
313         return 0;
314 }
315
316 /* first is true if we read the frame header */
317 static int ffm_read_data(AVFormatContext *s,
318                          uint8_t *buf, int size, int first)
319 {
320     FFMContext *ffm = s->priv_data;
321     ByteIOContext *pb = &s->pb;
322     int len, fill_size, size1, frame_offset;
323
324     size1 = size;
325     while (size > 0) {
326     redo:
327         len = ffm->packet_end - ffm->packet_ptr;
328         if (len > size)
329             len = size;
330         if (len == 0) {
331             if (url_ftell(pb) == ffm->file_size)
332                 url_fseek(pb, ffm->packet_size, SEEK_SET);
333     retry_read:
334             get_be16(pb); /* PACKET_ID */
335             fill_size = get_be16(pb);
336             ffm->pts = get_be64(pb);
337             frame_offset = get_be16(pb);
338             get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
339             ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
340             if (ffm->packet_end < ffm->packet)
341                 av_abort();
342             /* if first packet or resynchronization packet, we must
343                handle it specifically */
344             if (ffm->first_packet || (frame_offset & 0x8000)) {
345                 if (!frame_offset) {
346                     /* This packet has no frame headers in it */
347                     if (url_ftell(pb) >= ffm->packet_size * 3) {
348                         url_fseek(pb, -ffm->packet_size * 2, SEEK_CUR);
349                         goto retry_read;
350                     }
351                     /* This is bad, we cannot find a valid frame header */
352                     return 0;
353                 }
354                 ffm->first_packet = 0;
355                 if ((frame_offset & 0x7ffff) < FFM_HEADER_SIZE)
356                     av_abort();
357                 ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
358                 if (!first)
359                     break;
360             } else {
361                 ffm->packet_ptr = ffm->packet;
362             }
363             goto redo;
364         }
365         memcpy(buf, ffm->packet_ptr, len);
366         buf += len;
367         ffm->packet_ptr += len;
368         size -= len;
369         first = 0;
370     }
371     return size1 - size;
372 }
373
374
375 static void adjust_write_index(AVFormatContext *s)
376 {
377     FFMContext *ffm = s->priv_data;
378     ByteIOContext *pb = &s->pb;
379     int64_t pts;
380     //offset_t orig_write_index = ffm->write_index;
381     offset_t pos_min, pos_max;
382     int64_t pts_start;
383     offset_t ptr = url_ftell(pb);
384
385
386     pos_min = 0;
387     pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
388
389     pts_start = get_pts(s, pos_min);
390
391     pts = get_pts(s, pos_max);
392
393     if (pts - 100000 > pts_start) 
394         return;
395
396     ffm->write_index = FFM_PACKET_SIZE;
397
398     pts_start = get_pts(s, pos_min);
399
400     pts = get_pts(s, pos_max);
401
402     if (pts - 100000 <= pts_start) {
403         while (1) {
404             offset_t newpos;
405             int64_t newpts;
406
407             newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
408
409             if (newpos == pos_min)
410                 break;
411
412             newpts = get_pts(s, newpos);
413
414             if (newpts - 100000 <= pts) {
415                 pos_max = newpos;
416                 pts = newpts;
417             } else {
418                 pos_min = newpos;
419             }
420         }
421         ffm->write_index += pos_max;
422     }
423
424     //printf("Adjusted write index from %lld to %lld: pts=%0.6f\n", orig_write_index, ffm->write_index, pts / 1000000.);
425     //printf("pts range %0.6f - %0.6f\n", get_pts(s, 0) / 1000000. , get_pts(s, ffm->file_size - 2 * FFM_PACKET_SIZE) / 1000000. );
426
427     url_fseek(pb, ptr, SEEK_SET);
428 }
429
430
431 static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
432 {
433     FFMContext *ffm = s->priv_data;
434     AVStream *st;
435     FFMStream *fst;
436     ByteIOContext *pb = &s->pb;
437     AVCodecContext *codec;
438     int i, nb_streams;
439     uint32_t tag;
440
441     /* header */
442     tag = get_le32(pb);
443     if (tag != MKTAG('F', 'F', 'M', '1'))
444         goto fail;
445     ffm->packet_size = get_be32(pb);
446     if (ffm->packet_size != FFM_PACKET_SIZE)
447         goto fail;
448     ffm->write_index = get_be64(pb);
449     /* get also filesize */
450     if (!url_is_streamed(pb)) {
451         ffm->file_size = url_filesize(url_fileno(pb));
452         adjust_write_index(s);
453     } else {
454         ffm->file_size = (uint64_t_C(1) << 63) - 1;
455     }
456
457     nb_streams = get_be32(pb);
458     get_be32(pb); /* total bitrate */
459     /* read each stream */
460     for(i=0;i<nb_streams;i++) {
461         char rc_eq_buf[128];
462
463         st = av_new_stream(s, 0);
464         if (!st)
465             goto fail;
466         fst = av_mallocz(sizeof(FFMStream));
467         if (!fst)
468             goto fail;
469         st->priv_data = fst;
470
471         codec = &st->codec;
472         /* generic info */
473         st->codec.codec_id = get_be32(pb);
474         st->codec.codec_type = get_byte(pb); /* codec_type */
475         codec->bit_rate = get_be32(pb);
476         st->quality = get_be32(pb);
477         codec->flags = get_be32(pb);
478         /* specific info */
479         switch(codec->codec_type) {
480         case CODEC_TYPE_VIDEO:
481             codec->frame_rate_base = get_be32(pb);
482             codec->frame_rate = get_be32(pb);
483             codec->width = get_be16(pb);
484             codec->height = get_be16(pb);
485             codec->gop_size = get_be16(pb);
486             codec->qmin = get_byte(pb);
487             codec->qmax = get_byte(pb);
488             codec->max_qdiff = get_byte(pb);
489             codec->qcompress = get_be16(pb) / 10000.0;
490             codec->qblur = get_be16(pb) / 10000.0;
491             codec->bit_rate_tolerance = get_be32(pb);
492             codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
493             codec->rc_max_rate = get_be32(pb);
494             codec->rc_min_rate = get_be32(pb);
495             codec->rc_buffer_size = get_be32(pb);
496             codec->i_quant_factor = get_be64_double(pb);
497             codec->b_quant_factor = get_be64_double(pb);
498             codec->i_quant_offset = get_be64_double(pb);
499             codec->b_quant_offset = get_be64_double(pb);
500             codec->dct_algo = get_be32(pb);
501             break;
502         case CODEC_TYPE_AUDIO:
503             codec->sample_rate = get_be32(pb);
504             codec->channels = get_le16(pb);
505             codec->frame_size = get_le16(pb);
506             break;
507         default:
508             goto fail;
509         }
510
511     }
512
513     /* get until end of block reached */
514     while ((url_ftell(pb) % ffm->packet_size) != 0)
515         get_byte(pb);
516
517     /* init packet demux */
518     ffm->packet_ptr = ffm->packet;
519     ffm->packet_end = ffm->packet;
520     ffm->frame_offset = 0;
521     ffm->pts = 0;
522     ffm->read_state = READ_HEADER;
523     ffm->first_packet = 1;
524     return 0;
525  fail:
526     for(i=0;i<s->nb_streams;i++) {
527         st = s->streams[i];
528         if (st) {
529             av_freep(&st->priv_data);
530             av_free(st);
531         }
532     }
533     return -1;
534 }
535
536 /* return < 0 if eof */
537 static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
538 {
539     int size;
540     FFMContext *ffm = s->priv_data;
541     int duration;
542
543     switch(ffm->read_state) {
544     case READ_HEADER:
545         if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) {
546             return -EAGAIN;
547         }
548 #if 0
549         printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n",
550                url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);
551 #endif
552         if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != 
553             FRAME_HEADER_SIZE)
554             return -EAGAIN;
555 #if 0
556         {
557             int i;
558             for(i=0;i<FRAME_HEADER_SIZE;i++)
559                 printf("%02x ", ffm->header[i]);
560             printf("\n");
561         }
562 #endif
563         ffm->read_state = READ_DATA;
564         /* fall thru */
565     case READ_DATA:
566         size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4];
567         if (!ffm_is_avail_data(s, size)) {
568             return -EAGAIN;
569         }
570
571         duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7];
572
573         av_new_packet(pkt, size);
574         pkt->stream_index = ffm->header[0];
575         if (ffm->header[1] & FLAG_KEY_FRAME)
576             pkt->flags |= PKT_FLAG_KEY;
577
578         ffm->read_state = READ_HEADER;
579         if (ffm_read_data(s, pkt->data, size, 0) != size) {
580             /* bad case: desynchronized packet. we cancel all the packet loading */
581             av_free_packet(pkt);
582             return -EAGAIN;
583         }
584         pkt->pts = ffm->pts;
585         pkt->duration = duration;
586         break;
587     }
588     return 0;
589 }
590
591 //#define DEBUG_SEEK
592
593 /* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated
594    by the write position inside this function */
595 static void ffm_seek1(AVFormatContext *s, offset_t pos1)
596 {
597     FFMContext *ffm = s->priv_data;
598     ByteIOContext *pb = &s->pb;
599     offset_t pos;
600
601     pos = pos1 + ffm->write_index;
602     if (pos >= ffm->file_size)
603         pos -= (ffm->file_size - FFM_PACKET_SIZE);
604 #ifdef DEBUG_SEEK
605     printf("seek to %Lx -> %Lx\n", pos1, pos);
606 #endif
607     url_fseek(pb, pos, SEEK_SET);
608 }
609
610 static int64_t get_pts(AVFormatContext *s, offset_t pos)
611 {
612     ByteIOContext *pb = &s->pb;
613     int64_t pts;
614
615     ffm_seek1(s, pos);
616     url_fskip(pb, 4);
617     pts = get_be64(pb);
618 #ifdef DEBUG_SEEK
619     printf("pts=%0.6f\n", pts / 1000000.0);
620 #endif
621     return pts;
622 }
623
624 /* seek to a given time in the file. The file read pointer is
625    positionned at or before pts. XXX: the following code is quite
626    approximative */
627 static int ffm_seek(AVFormatContext *s, int64_t wanted_pts)
628 {
629     FFMContext *ffm = s->priv_data;
630     offset_t pos_min, pos_max, pos;
631     int64_t pts_min, pts_max, pts;
632     double pos1;
633
634 #ifdef DEBUG_SEEK
635     printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
636 #endif
637     /* find the position using linear interpolation (better than
638        dichotomy in typical cases) */
639     pos_min = 0;
640     pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
641     while (pos_min <= pos_max) {
642         pts_min = get_pts(s, pos_min);
643         pts_max = get_pts(s, pos_max);
644         /* linear interpolation */
645         pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
646             (double)(pts_max - pts_min);
647         pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
648         if (pos <= pos_min)
649             pos = pos_min;
650         else if (pos >= pos_max)
651             pos = pos_max;
652         pts = get_pts(s, pos);
653         /* check if we are lucky */
654         if (pts == wanted_pts) {
655             goto found;
656         } else if (pts > wanted_pts) {
657             pos_max = pos - FFM_PACKET_SIZE;
658         } else {
659             pos_min = pos + FFM_PACKET_SIZE;
660         }
661     }
662     pos = pos_min;
663     if (pos > 0)
664         pos -= FFM_PACKET_SIZE;
665  found:
666     ffm_seek1(s, pos);
667     return 0;
668 }
669
670 offset_t ffm_read_write_index(int fd)
671 {
672     uint8_t buf[8];
673     offset_t pos;
674     int i;
675
676     lseek(fd, 8, SEEK_SET);
677     read(fd, buf, 8);
678     pos = 0;
679     for(i=0;i<8;i++)
680         pos |= (int64_t)buf[i] << (56 - i * 8);
681     return pos;
682 }
683
684 void ffm_write_write_index(int fd, offset_t pos)
685 {
686     uint8_t buf[8];
687     int i;
688
689     for(i=0;i<8;i++)
690         buf[i] = (pos >> (56 - i * 8)) & 0xff;
691     lseek(fd, 8, SEEK_SET);
692     write(fd, buf, 8);
693 }
694
695 void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size)
696 {
697     FFMContext *ffm = s->priv_data;
698     ffm->write_index = pos;
699     ffm->file_size = file_size;
700 }
701
702 static int ffm_read_close(AVFormatContext *s)
703 {
704     AVStream *st;
705     int i;
706
707     for(i=0;i<s->nb_streams;i++) {
708         st = s->streams[i];
709         av_freep(&st->priv_data);
710     }
711     return 0;
712 }
713
714 static int ffm_probe(AVProbeData *p)
715 {
716     if (p->buf_size >= 4 &&
717         p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && 
718         p->buf[3] == '1')
719         return AVPROBE_SCORE_MAX + 1;
720     return 0;
721 }
722
723 static AVInputFormat ffm_iformat = {
724     "ffm",
725     "ffm format",
726     sizeof(FFMContext),
727     ffm_probe,
728     ffm_read_header,
729     ffm_read_packet,
730     ffm_read_close,
731     ffm_seek,
732 };
733
734 #ifdef CONFIG_ENCODERS
735 static AVOutputFormat ffm_oformat = {
736     "ffm",
737     "ffm format",
738     "",
739     "ffm",
740     sizeof(FFMContext),
741     /* not really used */
742     CODEC_ID_MP2,
743     CODEC_ID_MPEG1VIDEO,
744     ffm_write_header,
745     ffm_write_packet,
746     ffm_write_trailer,
747 };
748 #endif //CONFIG_ENCODERS
749
750 int ffm_init(void)
751 {
752     av_register_input_format(&ffm_iformat);
753 #ifdef CONFIG_ENCODERS
754     av_register_output_format(&ffm_oformat);
755 #endif //CONFIG_ENCODERS
756     return 0;
757 }