Statistics
| Branch: | Revision:

ffmpeg / libavformat / ffm.c @ 764ef400

History | View | Annotate | Download (19.2 KB)

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
/* disable pts hack for testing */
55
int ffm_nopts = 0;
56

    
57
#ifdef CONFIG_ENCODERS
58
static void flush_packet(AVFormatContext *s)
59
{
60
    FFMContext *ffm = s->priv_data;
61
    int fill_size, h;
62
    ByteIOContext *pb = &s->pb;
63

    
64
    fill_size = ffm->packet_end - ffm->packet_ptr;
65
    memset(ffm->packet_ptr, 0, fill_size);
66

    
67
    /* put header */
68
    put_be16(pb, PACKET_ID);
69
    put_be16(pb, fill_size);
70
    put_be64(pb, ffm->pts);
71
    h = ffm->frame_offset;
72
    if (ffm->first_packet)
73
        h |= 0x8000;
74
    put_be16(pb, h);
75
    put_buffer(pb, ffm->packet, ffm->packet_end - ffm->packet);
76

    
77
    /* prepare next packet */
78
    ffm->frame_offset = 0; /* no key frame */
79
    ffm->pts = 0; /* no pts */
80
    ffm->packet_ptr = ffm->packet;
81
    ffm->first_packet = 0;
82
}
83

    
84
/* 'first' is true if first data of a frame */
85
static void ffm_write_data(AVFormatContext *s,
86
                           const uint8_t *buf, int size,
87
                           int64_t pts, int first)
88
{
89
    FFMContext *ffm = s->priv_data;
90
    int len;
91

    
92
    if (first && ffm->frame_offset == 0)
93
        ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
94
    if (first && ffm->pts == 0)
95
        ffm->pts = pts;
96

    
97
    /* write as many packets as needed */
98
    while (size > 0) {
99
        len = ffm->packet_end - ffm->packet_ptr;
100
        if (len > size)
101
            len = size;
102
        memcpy(ffm->packet_ptr, buf, len);
103

    
104
        ffm->packet_ptr += len;
105
        buf += len;
106
        size -= len;
107
        if (ffm->packet_ptr >= ffm->packet_end) {
108
            /* special case : no pts in packet : we leave the current one */
109
            if (ffm->pts == 0)
110
                ffm->pts = pts;
111

    
112
            flush_packet(s);
113
        }
114
    }
115
}
116

    
117
static int ffm_write_header(AVFormatContext *s)
118
{
119
    FFMContext *ffm = s->priv_data;
120
    AVStream *st;
121
    FFMStream *fst;
122
    ByteIOContext *pb = &s->pb;
123
    AVCodecContext *codec;
124
    int bit_rate, i;
125

    
126
    ffm->packet_size = FFM_PACKET_SIZE;
127

    
128
    /* header */
129
    put_tag(pb, "FFM1");
130
    put_be32(pb, ffm->packet_size);
131
    /* XXX: store write position in other file ? */
132
    put_be64(pb, ffm->packet_size); /* current write position */
133

    
134
    put_be32(pb, s->nb_streams);
135
    bit_rate = 0;
136
    for(i=0;i<s->nb_streams;i++) {
137
        st = s->streams[i];
138
        bit_rate += st->codec.bit_rate;
139
    }
140
    put_be32(pb, bit_rate);
141

    
142
    /* list of streams */
143
    for(i=0;i<s->nb_streams;i++) {
144
        st = s->streams[i];
145
        fst = av_mallocz(sizeof(FFMStream));
146
        if (!fst)
147
            goto fail;
148
        st->priv_data = fst;
149

    
150
        codec = &st->codec;
151
        /* generic info */
152
        put_be32(pb, codec->codec_id);
153
        put_byte(pb, codec->codec_type);
154
        put_be32(pb, codec->bit_rate);
155
        put_be32(pb, st->quality);
156
        put_be32(pb, codec->flags);
157
        /* specific info */
158
        switch(codec->codec_type) {
159
        case CODEC_TYPE_VIDEO:
160
            put_be32(pb, codec->frame_rate_base);
161
            put_be32(pb, codec->frame_rate);
162
            put_be16(pb, codec->width);
163
            put_be16(pb, codec->height);
164
            put_be16(pb, codec->gop_size);
165
            put_byte(pb, codec->qmin);
166
            put_byte(pb, codec->qmax);
167
            put_byte(pb, codec->max_qdiff);
168
            put_be16(pb, (int) (codec->qcompress * 10000.0));
169
            put_be16(pb, (int) (codec->qblur * 10000.0));
170
            put_be32(pb, codec->bit_rate_tolerance);
171
            put_strz(pb, codec->rc_eq);
172
            put_be32(pb, codec->rc_max_rate);
173
            put_be32(pb, codec->rc_min_rate);
174
            put_be32(pb, codec->rc_buffer_size);
175
            put_be64_double(pb, codec->i_quant_factor);
176
            put_be64_double(pb, codec->b_quant_factor);
177
            put_be64_double(pb, codec->i_quant_offset);
178
            put_be64_double(pb, codec->b_quant_offset);
179
            put_be32(pb, codec->dct_algo);
180
            break;
181
        case CODEC_TYPE_AUDIO:
182
            put_be32(pb, codec->sample_rate);
183
            put_le16(pb, codec->channels);
184
            put_le16(pb, codec->frame_size);
185
            break;
186
        default:
187
            av_abort();
188
        }
189
        /* hack to have real time */
190
        if (ffm_nopts)
191
            fst->pts = 0;
192
        else
193
            fst->pts = av_gettime();
194
    }
195

    
196
    /* flush until end of block reached */
197
    while ((url_ftell(pb) % ffm->packet_size) != 0)
198
        put_byte(pb, 0);
199

    
200
    put_flush_packet(pb);
201

    
202
    /* init packet mux */
203
    ffm->packet_ptr = ffm->packet;
204
    ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
205
    ffm->frame_offset = 0;
206
    ffm->pts = 0;
207
    ffm->first_packet = 1;
208

    
209
    return 0;
210
 fail:
211
    for(i=0;i<s->nb_streams;i++) {
212
        st = s->streams[i];
213
        av_freep(&st->priv_data);
214
    }
215
    return -1;
216
}
217

    
218
static int ffm_write_packet(AVFormatContext *s, int stream_index,
219
                            const uint8_t *buf, int size, int64_t force_pts)
220
{
221
    AVStream *st = s->streams[stream_index];
222
    FFMStream *fst = st->priv_data;
223
    int64_t pts;
224
    uint8_t header[FRAME_HEADER_SIZE];
225
    int duration;
226

    
227
    if (st->codec.codec_type == CODEC_TYPE_AUDIO) {
228
        duration = ((float)st->codec.frame_size / st->codec.sample_rate * 1000000.0);
229
    } else {
230
        duration = (1000000.0 * st->codec.frame_rate_base / (float)st->codec.frame_rate);
231
    }
232

    
233
    pts = fst->pts;
234
    /* packet size & key_frame */
235
    header[0] = stream_index;
236
    header[1] = 0;
237
    if (st->codec.coded_frame->key_frame) //if st->codec.coded_frame==NULL then there is a bug somewhere else
238
        header[1] |= FLAG_KEY_FRAME;
239
    header[2] = (size >> 16) & 0xff;
240
    header[3] = (size >> 8) & 0xff;
241
    header[4] = size & 0xff;
242
    header[5] = (duration >> 16) & 0xff;
243
    header[6] = (duration >> 8) & 0xff;
244
    header[7] = duration & 0xff;
245
    ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1);
246
    ffm_write_data(s, buf, size, pts, 0);
247

    
248
    fst->pts += duration;
249
    return 0;
250
}
251

    
252
static int ffm_write_trailer(AVFormatContext *s)
253
{
254
    ByteIOContext *pb = &s->pb;
255
    FFMContext *ffm = s->priv_data;
256
    int i;
257

    
258
    /* flush packets */
259
    if (ffm->packet_ptr > ffm->packet)
260
        flush_packet(s);
261

    
262
    put_flush_packet(pb);
263

    
264
    if (!url_is_streamed(pb)) {
265
        int64_t size;
266
        /* update the write offset */
267
        size = url_ftell(pb);
268
        url_fseek(pb, 8, SEEK_SET);
269
        put_be64(pb, size);
270
        put_flush_packet(pb);
271
    }
272

    
273
    for(i=0;i<s->nb_streams;i++)
274
        av_freep(&s->streams[i]->priv_data);
275
    return 0;
276
}
277
#endif //CONFIG_ENCODERS
278

    
279
/* ffm demux */
280

    
281
static int ffm_is_avail_data(AVFormatContext *s, int size)
282
{
283
    FFMContext *ffm = s->priv_data;
284
    offset_t pos, avail_size;
285
    int len;
286

    
287
    len = ffm->packet_end - ffm->packet_ptr;
288
    if (!ffm_nopts) {
289
        /* XXX: I don't understand this test, so I disabled it for testing */
290
        if (size <= len)
291
            return 1;
292
    }
293
    pos = url_ftell(&s->pb);
294
    if (pos == ffm->write_index) {
295
        /* exactly at the end of stream */
296
        return 0;
297
    } else if (pos < ffm->write_index) {
298
        avail_size = ffm->write_index - pos;
299
    } else {
300
        avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
301
    }
302
    avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
303
    if (size <= avail_size)
304
        return 1;
305
    else
306
        return 0;
307
}
308

    
309
/* first is true if we read the frame header */
310
static int ffm_read_data(AVFormatContext *s,
311
                         uint8_t *buf, int size, int first)
312
{
313
    FFMContext *ffm = s->priv_data;
314
    ByteIOContext *pb = &s->pb;
315
    int len, fill_size, size1, frame_offset;
316

    
317
    size1 = size;
318
    while (size > 0) {
319
    redo:
320
        len = ffm->packet_end - ffm->packet_ptr;
321
        if (len > size)
322
            len = size;
323
        if (len == 0) {
324
            if (url_ftell(pb) == ffm->file_size)
325
                url_fseek(pb, ffm->packet_size, SEEK_SET);
326
    retry_read:
327
            get_be16(pb); /* PACKET_ID */
328
            fill_size = get_be16(pb);
329
            ffm->pts = get_be64(pb);
330
            frame_offset = get_be16(pb);
331
            get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
332
            ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
333
            /* if first packet or resynchronization packet, we must
334
               handle it specifically */
335
            if (ffm->first_packet || (frame_offset & 0x8000)) {
336
                if (!frame_offset) {
337
                    /* This packet has no frame headers in it */
338
                    if (url_ftell(pb) >= ffm->packet_size * 3) {
339
                        url_fseek(pb, -ffm->packet_size * 2, SEEK_CUR);
340
                        goto retry_read;
341
                    }
342
                    /* This is bad, we cannot find a valid frame header */
343
                    return 0;
344
                }
345
                ffm->first_packet = 0;
346
                if ((frame_offset & 0x7ffff) < FFM_HEADER_SIZE)
347
                    av_abort();
348
                ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
349
                if (!first)
350
                    break;
351
            } else {
352
                ffm->packet_ptr = ffm->packet;
353
            }
354
            goto redo;
355
        }
356
        memcpy(buf, ffm->packet_ptr, len);
357
        buf += len;
358
        ffm->packet_ptr += len;
359
        size -= len;
360
        first = 0;
361
    }
362
    return size1 - size;
363
}
364

    
365

    
366
static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
367
{
368
    FFMContext *ffm = s->priv_data;
369
    AVStream *st;
370
    FFMStream *fst;
371
    ByteIOContext *pb = &s->pb;
372
    AVCodecContext *codec;
373
    int i, nb_streams;
374
    uint32_t tag;
375

    
376
    /* header */
377
    tag = get_le32(pb);
378
    if (tag != MKTAG('F', 'F', 'M', '1'))
379
        goto fail;
380
    ffm->packet_size = get_be32(pb);
381
    if (ffm->packet_size != FFM_PACKET_SIZE)
382
        goto fail;
383
    ffm->write_index = get_be64(pb);
384
    /* get also filesize */
385
    if (!url_is_streamed(pb)) {
386
        ffm->file_size = url_filesize(url_fileno(pb));
387
    } else {
388
        ffm->file_size = (uint64_t_C(1) << 63) - 1;
389
    }
390

    
391
    nb_streams = get_be32(pb);
392
    get_be32(pb); /* total bitrate */
393
    /* read each stream */
394
    for(i=0;i<nb_streams;i++) {
395
        char rc_eq_buf[128];
396

    
397
        st = av_new_stream(s, 0);
398
        if (!st)
399
            goto fail;
400
        fst = av_mallocz(sizeof(FFMStream));
401
        if (!fst)
402
            goto fail;
403
        st->priv_data = fst;
404

    
405
        codec = &st->codec;
406
        /* generic info */
407
        st->codec.codec_id = get_be32(pb);
408
        st->codec.codec_type = get_byte(pb); /* codec_type */
409
        codec->bit_rate = get_be32(pb);
410
        st->quality = get_be32(pb);
411
        codec->flags = get_be32(pb);
412
        /* specific info */
413
        switch(codec->codec_type) {
414
        case CODEC_TYPE_VIDEO:
415
            codec->frame_rate_base = get_be32(pb);
416
            codec->frame_rate = get_be32(pb);
417
            codec->width = get_be16(pb);
418
            codec->height = get_be16(pb);
419
            codec->gop_size = get_be16(pb);
420
            codec->qmin = get_byte(pb);
421
            codec->qmax = get_byte(pb);
422
            codec->max_qdiff = get_byte(pb);
423
            codec->qcompress = get_be16(pb) / 10000.0;
424
            codec->qblur = get_be16(pb) / 10000.0;
425
            codec->bit_rate_tolerance = get_be32(pb);
426
            codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
427
            codec->rc_max_rate = get_be32(pb);
428
            codec->rc_min_rate = get_be32(pb);
429
            codec->rc_buffer_size = get_be32(pb);
430
            codec->i_quant_factor = get_be64_double(pb);
431
            codec->b_quant_factor = get_be64_double(pb);
432
            codec->i_quant_offset = get_be64_double(pb);
433
            codec->b_quant_offset = get_be64_double(pb);
434
            codec->dct_algo = get_be32(pb);
435
            break;
436
        case CODEC_TYPE_AUDIO:
437
            codec->sample_rate = get_be32(pb);
438
            codec->channels = get_le16(pb);
439
            codec->frame_size = get_le16(pb);
440
            break;
441
        default:
442
            goto fail;
443
        }
444

    
445
    }
446

    
447
    /* get until end of block reached */
448
    while ((url_ftell(pb) % ffm->packet_size) != 0)
449
        get_byte(pb);
450

    
451
    /* init packet demux */
452
    ffm->packet_ptr = ffm->packet;
453
    ffm->packet_end = ffm->packet;
454
    ffm->frame_offset = 0;
455
    ffm->pts = 0;
456
    ffm->read_state = READ_HEADER;
457
    ffm->first_packet = 1;
458
    return 0;
459
 fail:
460
    for(i=0;i<s->nb_streams;i++) {
461
        st = s->streams[i];
462
        if (st) {
463
            av_freep(&st->priv_data);
464
            av_free(st);
465
        }
466
    }
467
    return -1;
468
}
469

    
470
/* return < 0 if eof */
471
static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
472
{
473
    int size;
474
    FFMContext *ffm = s->priv_data;
475
    int duration;
476

    
477
    switch(ffm->read_state) {
478
    case READ_HEADER:
479
        if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) {
480
            return -EAGAIN;
481
        }
482
#if 0
483
        printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n",
484
               url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size);
485
#endif
486
        if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != 
487
            FRAME_HEADER_SIZE)
488
            return -EAGAIN;
489
#if 0
490
        {
491
            int i;
492
            for(i=0;i<FRAME_HEADER_SIZE;i++)
493
                printf("%02x ", ffm->header[i]);
494
            printf("\n");
495
        }
496
#endif
497
        ffm->read_state = READ_DATA;
498
        /* fall thru */
499
    case READ_DATA:
500
        size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4];
501
        if (!ffm_is_avail_data(s, size)) {
502
            return -EAGAIN;
503
        }
504

    
505
        duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7];
506

    
507
        av_new_packet(pkt, size);
508
        pkt->stream_index = ffm->header[0];
509
        if (ffm->header[1] & FLAG_KEY_FRAME)
510
            pkt->flags |= PKT_FLAG_KEY;
511

    
512
        ffm->read_state = READ_HEADER;
513
        if (ffm_read_data(s, pkt->data, size, 0) != size) {
514
            /* bad case: desynchronized packet. we cancel all the packet loading */
515
            av_free_packet(pkt);
516
            return -EAGAIN;
517
        }
518
        pkt->pts = ffm->pts;
519
        pkt->duration = duration;
520
        break;
521
    }
522
    return 0;
523
}
524

    
525
//#define DEBUG_SEEK
526

    
527
/* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated
528
   by the write position inside this function */
529
static void ffm_seek1(AVFormatContext *s, offset_t pos1)
530
{
531
    FFMContext *ffm = s->priv_data;
532
    ByteIOContext *pb = &s->pb;
533
    offset_t pos;
534

    
535
    pos = pos1 + ffm->write_index;
536
    if (pos >= ffm->file_size)
537
        pos -= (ffm->file_size - FFM_PACKET_SIZE);
538
#ifdef DEBUG_SEEK
539
    printf("seek to %Lx -> %Lx\n", pos1, pos);
540
#endif
541
    url_fseek(pb, pos, SEEK_SET);
542
}
543

    
544
static int64_t get_pts(AVFormatContext *s, offset_t pos)
545
{
546
    ByteIOContext *pb = &s->pb;
547
    int64_t pts;
548

    
549
    ffm_seek1(s, pos);
550
    url_fskip(pb, 4);
551
    pts = get_be64(pb);
552
#ifdef DEBUG_SEEK
553
    printf("pts=%0.6f\n", pts / 1000000.0);
554
#endif
555
    return pts;
556
}
557

    
558
/* seek to a given time in the file. The file read pointer is
559
   positionned at or before pts. XXX: the following code is quite
560
   approximative */
561
static int ffm_seek(AVFormatContext *s, int64_t wanted_pts)
562
{
563
    FFMContext *ffm = s->priv_data;
564
    offset_t pos_min, pos_max, pos;
565
    int64_t pts_min, pts_max, pts;
566
    double pos1;
567

    
568
#ifdef DEBUG_SEEK
569
    printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
570
#endif
571
    /* find the position using linear interpolation (better than
572
       dichotomy in typical cases) */
573
    pos_min = 0;
574
    pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
575
    while (pos_min <= pos_max) {
576
        pts_min = get_pts(s, pos_min);
577
        pts_max = get_pts(s, pos_max);
578
        /* linear interpolation */
579
        pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
580
            (double)(pts_max - pts_min);
581
        pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
582
        if (pos <= pos_min)
583
            pos = pos_min;
584
        else if (pos >= pos_max)
585
            pos = pos_max;
586
        pts = get_pts(s, pos);
587
        /* check if we are lucky */
588
        if (pts == wanted_pts) {
589
            goto found;
590
        } else if (pts > wanted_pts) {
591
            pos_max = pos - FFM_PACKET_SIZE;
592
        } else {
593
            pos_min = pos + FFM_PACKET_SIZE;
594
        }
595
    }
596
    pos = pos_min;
597
    if (pos > 0)
598
        pos -= FFM_PACKET_SIZE;
599
 found:
600
    ffm_seek1(s, pos);
601
    return 0;
602
}
603

    
604
offset_t ffm_read_write_index(int fd)
605
{
606
    uint8_t buf[8];
607
    offset_t pos;
608
    int i;
609

    
610
    lseek(fd, 8, SEEK_SET);
611
    read(fd, buf, 8);
612
    pos = 0;
613
    for(i=0;i<8;i++)
614
        pos |= (int64_t)buf[i] << (56 - i * 8);
615
    return pos;
616
}
617

    
618
void ffm_write_write_index(int fd, offset_t pos)
619
{
620
    uint8_t buf[8];
621
    int i;
622

    
623
    for(i=0;i<8;i++)
624
        buf[i] = (pos >> (56 - i * 8)) & 0xff;
625
    lseek(fd, 8, SEEK_SET);
626
    write(fd, buf, 8);
627
}
628

    
629
void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size)
630
{
631
    FFMContext *ffm = s->priv_data;
632
    ffm->write_index = pos;
633
    ffm->file_size = file_size;
634
}
635

    
636
static int ffm_read_close(AVFormatContext *s)
637
{
638
    AVStream *st;
639
    int i;
640

    
641
    for(i=0;i<s->nb_streams;i++) {
642
        st = s->streams[i];
643
        av_freep(&st->priv_data);
644
    }
645
    return 0;
646
}
647

    
648
static int ffm_probe(AVProbeData *p)
649
{
650
    if (p->buf_size >= 4 &&
651
        p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && 
652
        p->buf[3] == '1')
653
        return AVPROBE_SCORE_MAX + 1;
654
    return 0;
655
}
656

    
657
static AVInputFormat ffm_iformat = {
658
    "ffm",
659
    "ffm format",
660
    sizeof(FFMContext),
661
    ffm_probe,
662
    ffm_read_header,
663
    ffm_read_packet,
664
    ffm_read_close,
665
    ffm_seek,
666
};
667

    
668
#ifdef CONFIG_ENCODERS
669
static AVOutputFormat ffm_oformat = {
670
    "ffm",
671
    "ffm format",
672
    "",
673
    "ffm",
674
    sizeof(FFMContext),
675
    /* not really used */
676
    CODEC_ID_MP2,
677
    CODEC_ID_MPEG1VIDEO,
678
    ffm_write_header,
679
    ffm_write_packet,
680
    ffm_write_trailer,
681
};
682
#endif //CONFIG_ENCODERS
683

    
684
int ffm_init(void)
685
{
686
    av_register_input_format(&ffm_iformat);
687
#ifdef CONFIG_ENCODERS
688
    av_register_output_format(&ffm_oformat);
689
#endif //CONFIG_ENCODERS
690
    return 0;
691
}