]> git.sesse.net Git - ffmpeg/blob - libavformat/ffm.c
Mpeg start codes patch by ("Dmitry Borisov" <jbors at mail dot ru>)
[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         goto end;
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  end:
428     url_fseek(pb, ptr, SEEK_SET);
429 }
430
431
432 static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
433 {
434     FFMContext *ffm = s->priv_data;
435     AVStream *st;
436     FFMStream *fst;
437     ByteIOContext *pb = &s->pb;
438     AVCodecContext *codec;
439     int i, nb_streams;
440     uint32_t tag;
441
442     /* header */
443     tag = get_le32(pb);
444     if (tag != MKTAG('F', 'F', 'M', '1'))
445         goto fail;
446     ffm->packet_size = get_be32(pb);
447     if (ffm->packet_size != FFM_PACKET_SIZE)
448         goto fail;
449     ffm->write_index = get_be64(pb);
450     /* get also filesize */
451     if (!url_is_streamed(pb)) {
452         ffm->file_size = url_filesize(url_fileno(pb));
453         adjust_write_index(s);
454     } else {
455         ffm->file_size = (uint64_t_C(1) << 63) - 1;
456     }
457
458     nb_streams = get_be32(pb);
459     get_be32(pb); /* total bitrate */
460     /* read each stream */
461     for(i=0;i<nb_streams;i++) {
462         char rc_eq_buf[128];
463
464         st = av_new_stream(s, 0);
465         if (!st)
466             goto fail;
467         fst = av_mallocz(sizeof(FFMStream));
468         if (!fst)
469             goto fail;
470         st->priv_data = fst;
471
472         codec = &st->codec;
473         /* generic info */
474         st->codec.codec_id = get_be32(pb);
475         st->codec.codec_type = get_byte(pb); /* codec_type */
476         codec->bit_rate = get_be32(pb);
477         st->quality = get_be32(pb);
478         codec->flags = get_be32(pb);
479         /* specific info */
480         switch(codec->codec_type) {
481         case CODEC_TYPE_VIDEO:
482             codec->frame_rate_base = get_be32(pb);
483             codec->frame_rate = get_be32(pb);
484             codec->width = get_be16(pb);
485             codec->height = get_be16(pb);
486             codec->gop_size = get_be16(pb);
487             codec->qmin = get_byte(pb);
488             codec->qmax = get_byte(pb);
489             codec->max_qdiff = get_byte(pb);
490             codec->qcompress = get_be16(pb) / 10000.0;
491             codec->qblur = get_be16(pb) / 10000.0;
492             codec->bit_rate_tolerance = get_be32(pb);
493             codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
494             codec->rc_max_rate = get_be32(pb);
495             codec->rc_min_rate = get_be32(pb);
496             codec->rc_buffer_size = get_be32(pb);
497             codec->i_quant_factor = get_be64_double(pb);
498             codec->b_quant_factor = get_be64_double(pb);
499             codec->i_quant_offset = get_be64_double(pb);
500             codec->b_quant_offset = get_be64_double(pb);
501             codec->dct_algo = get_be32(pb);
502             break;
503         case CODEC_TYPE_AUDIO:
504             codec->sample_rate = get_be32(pb);
505             codec->channels = get_le16(pb);
506             codec->frame_size = get_le16(pb);
507             break;
508         default:
509             goto fail;
510         }
511
512     }
513
514     /* get until end of block reached */
515     while ((url_ftell(pb) % ffm->packet_size) != 0)
516         get_byte(pb);
517
518     /* init packet demux */
519     ffm->packet_ptr = ffm->packet;
520     ffm->packet_end = ffm->packet;
521     ffm->frame_offset = 0;
522     ffm->pts = 0;
523     ffm->read_state = READ_HEADER;
524     ffm->first_packet = 1;
525     return 0;
526  fail:
527     for(i=0;i<s->nb_streams;i++) {
528         st = s->streams[i];
529         if (st) {
530             av_freep(&st->priv_data);
531             av_free(st);
532         }
533     }
534     return -1;
535 }
536
537 /* return < 0 if eof */
538 static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
539 {
540     int size;
541     FFMContext *ffm = s->priv_data;
542     int duration;
543
544     switch(ffm->read_state) {
545     case READ_HEADER:
546         if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) {
547             return -EAGAIN;
548         }
549 #if 0
550         printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n",
551                url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);
552 #endif
553         if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != 
554             FRAME_HEADER_SIZE)
555             return -EAGAIN;
556 #if 0
557         {
558             int i;
559             for(i=0;i<FRAME_HEADER_SIZE;i++)
560                 printf("%02x ", ffm->header[i]);
561             printf("\n");
562         }
563 #endif
564         ffm->read_state = READ_DATA;
565         /* fall thru */
566     case READ_DATA:
567         size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4];
568         if (!ffm_is_avail_data(s, size)) {
569             return -EAGAIN;
570         }
571
572         duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7];
573
574         av_new_packet(pkt, size);
575         pkt->stream_index = ffm->header[0];
576         if (ffm->header[1] & FLAG_KEY_FRAME)
577             pkt->flags |= PKT_FLAG_KEY;
578
579         ffm->read_state = READ_HEADER;
580         if (ffm_read_data(s, pkt->data, size, 0) != size) {
581             /* bad case: desynchronized packet. we cancel all the packet loading */
582             av_free_packet(pkt);
583             return -EAGAIN;
584         }
585         pkt->pts = ffm->pts;
586         pkt->duration = duration;
587         break;
588     }
589     return 0;
590 }
591
592 //#define DEBUG_SEEK
593
594 /* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated
595    by the write position inside this function */
596 static void ffm_seek1(AVFormatContext *s, offset_t pos1)
597 {
598     FFMContext *ffm = s->priv_data;
599     ByteIOContext *pb = &s->pb;
600     offset_t pos;
601
602     pos = pos1 + ffm->write_index;
603     if (pos >= ffm->file_size)
604         pos -= (ffm->file_size - FFM_PACKET_SIZE);
605 #ifdef DEBUG_SEEK
606     printf("seek to %Lx -> %Lx\n", pos1, pos);
607 #endif
608     url_fseek(pb, pos, SEEK_SET);
609 }
610
611 static int64_t get_pts(AVFormatContext *s, offset_t pos)
612 {
613     ByteIOContext *pb = &s->pb;
614     int64_t pts;
615
616     ffm_seek1(s, pos);
617     url_fskip(pb, 4);
618     pts = get_be64(pb);
619 #ifdef DEBUG_SEEK
620     printf("pts=%0.6f\n", pts / 1000000.0);
621 #endif
622     return pts;
623 }
624
625 /* seek to a given time in the file. The file read pointer is
626    positionned at or before pts. XXX: the following code is quite
627    approximative */
628 static int ffm_seek(AVFormatContext *s, int64_t wanted_pts)
629 {
630     FFMContext *ffm = s->priv_data;
631     offset_t pos_min, pos_max, pos;
632     int64_t pts_min, pts_max, pts;
633     double pos1;
634
635 #ifdef DEBUG_SEEK
636     printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
637 #endif
638     /* find the position using linear interpolation (better than
639        dichotomy in typical cases) */
640     pos_min = 0;
641     pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
642     while (pos_min <= pos_max) {
643         pts_min = get_pts(s, pos_min);
644         pts_max = get_pts(s, pos_max);
645         /* linear interpolation */
646         pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
647             (double)(pts_max - pts_min);
648         pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
649         if (pos <= pos_min)
650             pos = pos_min;
651         else if (pos >= pos_max)
652             pos = pos_max;
653         pts = get_pts(s, pos);
654         /* check if we are lucky */
655         if (pts == wanted_pts) {
656             goto found;
657         } else if (pts > wanted_pts) {
658             pos_max = pos - FFM_PACKET_SIZE;
659         } else {
660             pos_min = pos + FFM_PACKET_SIZE;
661         }
662     }
663     pos = pos_min;
664     if (pos > 0)
665         pos -= FFM_PACKET_SIZE;
666  found:
667     ffm_seek1(s, pos);
668     return 0;
669 }
670
671 offset_t ffm_read_write_index(int fd)
672 {
673     uint8_t buf[8];
674     offset_t pos;
675     int i;
676
677     lseek(fd, 8, SEEK_SET);
678     read(fd, buf, 8);
679     pos = 0;
680     for(i=0;i<8;i++)
681         pos |= (int64_t)buf[i] << (56 - i * 8);
682     return pos;
683 }
684
685 void ffm_write_write_index(int fd, offset_t pos)
686 {
687     uint8_t buf[8];
688     int i;
689
690     for(i=0;i<8;i++)
691         buf[i] = (pos >> (56 - i * 8)) & 0xff;
692     lseek(fd, 8, SEEK_SET);
693     write(fd, buf, 8);
694 }
695
696 void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size)
697 {
698     FFMContext *ffm = s->priv_data;
699     ffm->write_index = pos;
700     ffm->file_size = file_size;
701 }
702
703 static int ffm_read_close(AVFormatContext *s)
704 {
705     AVStream *st;
706     int i;
707
708     for(i=0;i<s->nb_streams;i++) {
709         st = s->streams[i];
710         av_freep(&st->priv_data);
711     }
712     return 0;
713 }
714
715 static int ffm_probe(AVProbeData *p)
716 {
717     if (p->buf_size >= 4 &&
718         p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && 
719         p->buf[3] == '1')
720         return AVPROBE_SCORE_MAX + 1;
721     return 0;
722 }
723
724 static AVInputFormat ffm_iformat = {
725     "ffm",
726     "ffm format",
727     sizeof(FFMContext),
728     ffm_probe,
729     ffm_read_header,
730     ffm_read_packet,
731     ffm_read_close,
732     ffm_seek,
733 };
734
735 #ifdef CONFIG_ENCODERS
736 static AVOutputFormat ffm_oformat = {
737     "ffm",
738     "ffm format",
739     "",
740     "ffm",
741     sizeof(FFMContext),
742     /* not really used */
743     CODEC_ID_MP2,
744     CODEC_ID_MPEG1VIDEO,
745     ffm_write_header,
746     ffm_write_packet,
747     ffm_write_trailer,
748 };
749 #endif //CONFIG_ENCODERS
750
751 int ffm_init(void)
752 {
753     av_register_input_format(&ffm_iformat);
754 #ifdef CONFIG_ENCODERS
755     av_register_output_format(&ffm_oformat);
756 #endif //CONFIG_ENCODERS
757     return 0;
758 }