ffmdec.c 16 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * FFM (avserver live feed) demuxer
3
 * Copyright (c) 2001 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * Libav is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
21

22
#include "libavutil/intreadwrite.h"
23
#include "libavutil/intfloat.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
24
#include "avformat.h"
25
#include "internal.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
26
#include "ffm.h"
27
#if CONFIG_AVSERVER
Fabrice Bellard's avatar
Fabrice Bellard committed
28
#include <unistd.h>
Fabrice Bellard's avatar
Fabrice Bellard committed
29

30
int64_t ffm_read_write_index(int fd)
31 32 33 34
{
    uint8_t buf[8];

    lseek(fd, 8, SEEK_SET);
35 36
    if (read(fd, buf, 8) != 8)
        return AVERROR(EIO);
37 38 39
    return AV_RB64(buf);
}

40
int ffm_write_write_index(int fd, int64_t pos)
41 42 43 44 45 46 47
{
    uint8_t buf[8];
    int i;

    for(i=0;i<8;i++)
        buf[i] = (pos >> (56 - i * 8)) & 0xff;
    lseek(fd, 8, SEEK_SET);
48 49 50
    if (write(fd, buf, 8) != 8)
        return AVERROR(EIO);
    return 8;
51 52
}

53
void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size)
54 55 56 57 58
{
    FFMContext *ffm = s->priv_data;
    ffm->write_index = pos;
    ffm->file_size = file_size;
}
59
#endif // CONFIG_AVSERVER
60

Fabrice Bellard's avatar
Fabrice Bellard committed
61 62 63
static int ffm_is_avail_data(AVFormatContext *s, int size)
{
    FFMContext *ffm = s->priv_data;
64
    int64_t pos, avail_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
65 66 67
    int len;

    len = ffm->packet_end - ffm->packet_ptr;
68 69
    if (size <= len)
        return 1;
70
    pos = avio_tell(s->pb);
71
    if (!ffm->write_index) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
72
        if (pos == ffm->file_size)
73 74 75
            return AVERROR_EOF;
        avail_size = ffm->file_size - pos;
    } else {
Fabrice Bellard's avatar
Fabrice Bellard committed
76 77
    if (pos == ffm->write_index) {
        /* exactly at the end of stream */
78
        return AVERROR(EAGAIN);
Fabrice Bellard's avatar
Fabrice Bellard committed
79 80 81 82 83
    } else if (pos < ffm->write_index) {
        avail_size = ffm->write_index - pos;
    } else {
        avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
    }
84
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
85 86 87 88
    avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
    if (size <= avail_size)
        return 1;
    else
89
        return AVERROR(EAGAIN);
Fabrice Bellard's avatar
Fabrice Bellard committed
90 91
}

92 93 94 95
static int ffm_resync(AVFormatContext *s, int state)
{
    av_log(s, AV_LOG_ERROR, "resyncing\n");
    while (state != PACKET_ID) {
Anton Khirnov's avatar
Anton Khirnov committed
96
        if (s->pb->eof_reached) {
97 98 99
            av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n");
            return -1;
        }
100
        state = (state << 8) | avio_r8(s->pb);
101 102 103 104
    }
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
105
/* first is true if we read the frame header */
106
static int ffm_read_data(AVFormatContext *s,
107
                         uint8_t *buf, int size, int header)
Fabrice Bellard's avatar
Fabrice Bellard committed
108 109
{
    FFMContext *ffm = s->priv_data;
110
    AVIOContext *pb = s->pb;
111
    int len, fill_size, size1, frame_offset, id;
Fabrice Bellard's avatar
Fabrice Bellard committed
112 113 114 115 116

    size1 = size;
    while (size > 0) {
    redo:
        len = ffm->packet_end - ffm->packet_ptr;
117 118
        if (len < 0)
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
119 120 121
        if (len > size)
            len = size;
        if (len == 0) {
122
            if (avio_tell(pb) == ffm->file_size)
123
                avio_seek(pb, ffm->packet_size, SEEK_SET);
124
    retry_read:
125
            id = avio_rb16(pb); /* PACKET_ID */
126 127 128
            if (id != PACKET_ID)
                if (ffm_resync(s, id) < 0)
                    return -1;
129 130 131 132
            fill_size = avio_rb16(pb);
            ffm->dts = avio_rb64(pb);
            frame_offset = avio_rb16(pb);
            avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
Fabrice Bellard's avatar
Fabrice Bellard committed
133
            ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
134
            if (ffm->packet_end < ffm->packet || frame_offset < 0)
135
                return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
136 137 138
            /* if first packet or resynchronization packet, we must
               handle it specifically */
            if (ffm->first_packet || (frame_offset & 0x8000)) {
139 140
                if (!frame_offset) {
                    /* This packet has no frame headers in it */
141
                    if (avio_tell(pb) >= ffm->packet_size * 3) {
142
                        avio_seek(pb, -ffm->packet_size * 2, SEEK_CUR);
143 144 145 146 147
                        goto retry_read;
                    }
                    /* This is bad, we cannot find a valid frame header */
                    return 0;
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
148
                ffm->first_packet = 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
149
                if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE)
150
                    return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
151
                ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
152
                if (!header)
Fabrice Bellard's avatar
Fabrice Bellard committed
153 154 155 156 157 158 159 160 161 162
                    break;
            } else {
                ffm->packet_ptr = ffm->packet;
            }
            goto redo;
        }
        memcpy(buf, ffm->packet_ptr, len);
        buf += len;
        ffm->packet_ptr += len;
        size -= len;
163
        header = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
164 165 166 167
    }
    return size1 - size;
}

168 169
/* ensure that acutal seeking happens between FFM_PACKET_SIZE
   and file_size - FFM_PACKET_SIZE */
170
static void ffm_seek1(AVFormatContext *s, int64_t pos1)
171 172
{
    FFMContext *ffm = s->priv_data;
173
    AVIOContext *pb = s->pb;
174
    int64_t pos;
175

176 177
    pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE);
    pos = FFMAX(pos, FFM_PACKET_SIZE);
178
    av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos);
179
    avio_seek(pb, pos, SEEK_SET);
180 181
}

182
static int64_t get_dts(AVFormatContext *s, int64_t pos)
183
{
184
    AVIOContext *pb = s->pb;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
185
    int64_t dts;
186 187

    ffm_seek1(s, pos);
188
    avio_skip(pb, 4);
189
    dts = avio_rb64(pb);
190
    av_dlog(s, "dts=%0.6f\n", dts / 1000000.0);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
191
    return dts;
192
}
Fabrice Bellard's avatar
Fabrice Bellard committed
193

194 195 196
static void adjust_write_index(AVFormatContext *s)
{
    FFMContext *ffm = s->priv_data;
197
    AVIOContext *pb = s->pb;
198
    int64_t pts;
199 200
    //int64_t orig_write_index = ffm->write_index;
    int64_t pos_min, pos_max;
201
    int64_t pts_start;
202
    int64_t ptr = avio_tell(pb);
203 204 205 206 207


    pos_min = 0;
    pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
208
    pts_start = get_dts(s, pos_min);
209

Baptiste Coudurier's avatar
Baptiste Coudurier committed
210
    pts = get_dts(s, pos_max);
211

212
    if (pts - 100000 > pts_start)
213
        goto end;
214 215 216

    ffm->write_index = FFM_PACKET_SIZE;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
217
    pts_start = get_dts(s, pos_min);
218

Baptiste Coudurier's avatar
Baptiste Coudurier committed
219
    pts = get_dts(s, pos_max);
220 221 222

    if (pts - 100000 <= pts_start) {
        while (1) {
223
            int64_t newpos;
224 225 226 227 228 229 230
            int64_t newpts;

            newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;

            if (newpos == pos_min)
                break;

Baptiste Coudurier's avatar
Baptiste Coudurier committed
231
            newpts = get_dts(s, newpos);
232 233 234 235 236 237 238 239 240 241 242

            if (newpts - 100000 <= pts) {
                pos_max = newpos;
                pts = newpts;
            } else {
                pos_min = newpos;
            }
        }
        ffm->write_index += pos_max;
    }

243
    //printf("Adjusted write index from %"PRId64" to %"PRId64": pts=%0.6f\n", orig_write_index, ffm->write_index, pts / 1000000.);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
244
    //printf("pts range %0.6f - %0.6f\n", get_dts(s, 0) / 1000000. , get_dts(s, ffm->file_size - 2 * FFM_PACKET_SIZE) / 1000000. );
245

246
 end:
247
    avio_seek(pb, ptr, SEEK_SET);
248 249 250
}


251 252 253 254 255 256 257 258 259 260
static int ffm_close(AVFormatContext *s)
{
    int i;

    for (i = 0; i < s->nb_streams; i++)
        av_freep(&s->streams[i]->codec->rc_eq);

    return 0;
}

261

Fabrice Bellard's avatar
Fabrice Bellard committed
262 263
static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
264
    FFMContext *ffm = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
265
    AVStream *st;
266
    AVIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
267
    AVCodecContext *codec;
268
    int i, nb_streams;
269
    uint32_t tag;
Fabrice Bellard's avatar
Fabrice Bellard committed
270 271

    /* header */
272
    tag = avio_rl32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
273 274
    if (tag != MKTAG('F', 'F', 'M', '1'))
        goto fail;
275
    ffm->packet_size = avio_rb32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
276 277
    if (ffm->packet_size != FFM_PACKET_SIZE)
        goto fail;
278
    ffm->write_index = avio_rb64(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
279
    /* get also filesize */
280
    if (pb->seekable) {
281
        ffm->file_size = avio_size(pb);
282 283
        if (ffm->write_index)
            adjust_write_index(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
284
    } else {
285
        ffm->file_size = (UINT64_C(1) << 63) - 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
286 287
    }

288 289
    nb_streams = avio_rb32(pb);
    avio_rb32(pb); /* total bitrate */
Fabrice Bellard's avatar
Fabrice Bellard committed
290
    /* read each stream */
291
    for(i=0;i<nb_streams;i++) {
292 293
        char rc_eq_buf[128];

294
        st = avformat_new_stream(s, NULL);
Fabrice Bellard's avatar
Fabrice Bellard committed
295 296
        if (!st)
            goto fail;
297

298
        avpriv_set_pts_info(st, 64, 1, 1000000);
299

300
        codec = st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
301
        /* generic info */
302 303 304 305 306 307
        codec->codec_id = avio_rb32(pb);
        codec->codec_type = avio_r8(pb); /* codec_type */
        codec->bit_rate = avio_rb32(pb);
        codec->flags = avio_rb32(pb);
        codec->flags2 = avio_rb32(pb);
        codec->debug = avio_rb32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
308 309
        /* specific info */
        switch(codec->codec_type) {
310
        case AVMEDIA_TYPE_VIDEO:
311 312 313 314 315 316 317 318 319 320 321 322
            codec->time_base.num = avio_rb32(pb);
            codec->time_base.den = avio_rb32(pb);
            codec->width = avio_rb16(pb);
            codec->height = avio_rb16(pb);
            codec->gop_size = avio_rb16(pb);
            codec->pix_fmt = avio_rb32(pb);
            codec->qmin = avio_r8(pb);
            codec->qmax = avio_r8(pb);
            codec->max_qdiff = avio_r8(pb);
            codec->qcompress = avio_rb16(pb) / 10000.0;
            codec->qblur = avio_rb16(pb) / 10000.0;
            codec->bit_rate_tolerance = avio_rb32(pb);
323 324
            avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
            codec->rc_eq = av_strdup(rc_eq_buf);
325 326 327
            codec->rc_max_rate = avio_rb32(pb);
            codec->rc_min_rate = avio_rb32(pb);
            codec->rc_buffer_size = avio_rb32(pb);
328 329 330 331
            codec->i_quant_factor = av_int2double(avio_rb64(pb));
            codec->b_quant_factor = av_int2double(avio_rb64(pb));
            codec->i_quant_offset = av_int2double(avio_rb64(pb));
            codec->b_quant_offset = av_int2double(avio_rb64(pb));
332 333 334 335 336 337 338 339 340 341 342
            codec->dct_algo = avio_rb32(pb);
            codec->strict_std_compliance = avio_rb32(pb);
            codec->max_b_frames = avio_rb32(pb);
            codec->luma_elim_threshold = avio_rb32(pb);
            codec->chroma_elim_threshold = avio_rb32(pb);
            codec->mpeg_quant = avio_rb32(pb);
            codec->intra_dc_precision = avio_rb32(pb);
            codec->me_method = avio_rb32(pb);
            codec->mb_decision = avio_rb32(pb);
            codec->nsse_weight = avio_rb32(pb);
            codec->frame_skip_cmp = avio_rb32(pb);
343
            codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
344 345 346 347 348 349 350 351 352
            codec->codec_tag = avio_rb32(pb);
            codec->thread_count = avio_r8(pb);
            codec->coder_type = avio_rb32(pb);
            codec->me_cmp = avio_rb32(pb);
            codec->me_subpel_quality = avio_rb32(pb);
            codec->me_range = avio_rb32(pb);
            codec->keyint_min = avio_rb32(pb);
            codec->scenechange_threshold = avio_rb32(pb);
            codec->b_frame_strategy = avio_rb32(pb);
353 354
            codec->qcompress = av_int2double(avio_rb64(pb));
            codec->qblur = av_int2double(avio_rb64(pb));
355 356
            codec->max_qdiff = avio_rb32(pb);
            codec->refs = avio_rb32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
357
            break;
358
        case AVMEDIA_TYPE_AUDIO:
359 360 361 362
            codec->sample_rate = avio_rb32(pb);
            codec->channels = avio_rl16(pb);
            codec->frame_size = avio_rl16(pb);
            codec->sample_fmt = (int16_t) avio_rl16(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
363
            break;
364
        default:
365
            goto fail;
Fabrice Bellard's avatar
Fabrice Bellard committed
366
        }
367
        if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
368
            codec->extradata_size = avio_rb32(pb);
369 370 371
            codec->extradata = av_malloc(codec->extradata_size);
            if (!codec->extradata)
                return AVERROR(ENOMEM);
372
            avio_read(pb, codec->extradata, codec->extradata_size);
373
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
374 375 376
    }

    /* get until end of block reached */
377
    while ((avio_tell(pb) % ffm->packet_size) != 0)
378
        avio_r8(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
379 380 381 382 383

    /* init packet demux */
    ffm->packet_ptr = ffm->packet;
    ffm->packet_end = ffm->packet;
    ffm->frame_offset = 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
384
    ffm->dts = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
385 386 387 388
    ffm->read_state = READ_HEADER;
    ffm->first_packet = 1;
    return 0;
 fail:
389
    ffm_close(s);
Fabrice Bellard's avatar
Fabrice Bellard committed
390 391 392 393 394 395 396 397
    return -1;
}

/* return < 0 if eof */
static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    int size;
    FFMContext *ffm = s->priv_data;
398
    int duration, ret;
399

Fabrice Bellard's avatar
Fabrice Bellard committed
400 401
    switch(ffm->read_state) {
    case READ_HEADER:
402 403 404
        if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0)
            return ret;

405
        av_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n",
406
               avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size);
407
        if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
408
            FRAME_HEADER_SIZE)
409
            return -1;
410 411
        if (ffm->header[1] & FLAG_DTS)
            if (ffm_read_data(s, ffm->header+16, 4, 1) != 4)
412
                return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
413 414 415
        ffm->read_state = READ_DATA;
        /* fall thru */
    case READ_DATA:
416
        size = AV_RB24(ffm->header + 2);
417 418
        if ((ret = ffm_is_avail_data(s, size)) < 0)
            return ret;
Fabrice Bellard's avatar
Fabrice Bellard committed
419

420
        duration = AV_RB24(ffm->header + 5);
421

Fabrice Bellard's avatar
Fabrice Bellard committed
422 423
        av_new_packet(pkt, size);
        pkt->stream_index = ffm->header[0];
424 425 426 427
        if ((unsigned)pkt->stream_index >= s->nb_streams) {
            av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index);
            av_free_packet(pkt);
            ffm->read_state = READ_HEADER;
428
            return -1;
429
        }
430
        pkt->pos = avio_tell(s->pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
431
        if (ffm->header[1] & FLAG_KEY_FRAME)
432
            pkt->flags |= AV_PKT_FLAG_KEY;
433

Fabrice Bellard's avatar
Fabrice Bellard committed
434 435 436 437
        ffm->read_state = READ_HEADER;
        if (ffm_read_data(s, pkt->data, size, 0) != size) {
            /* bad case: desynchronized packet. we cancel all the packet loading */
            av_free_packet(pkt);
438
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
439
        }
440 441 442 443 444
        pkt->pts = AV_RB64(ffm->header+8);
        if (ffm->header[1] & FLAG_DTS)
            pkt->dts = pkt->pts - AV_RB32(ffm->header+16);
        else
            pkt->dts = pkt->pts;
445
        pkt->duration = duration;
Fabrice Bellard's avatar
Fabrice Bellard committed
446 447 448 449 450 451
        break;
    }
    return 0;
}

/* seek to a given time in the file. The file read pointer is
Diego Biurrun's avatar
Diego Biurrun committed
452
   positioned at or before pts. XXX: the following code is quite
Fabrice Bellard's avatar
Fabrice Bellard committed
453
   approximative */
454
static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
Fabrice Bellard's avatar
Fabrice Bellard committed
455 456
{
    FFMContext *ffm = s->priv_data;
457
    int64_t pos_min, pos_max, pos;
458
    int64_t pts_min, pts_max, pts;
Fabrice Bellard's avatar
Fabrice Bellard committed
459 460
    double pos1;

461
    av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
Fabrice Bellard's avatar
Fabrice Bellard committed
462 463
    /* find the position using linear interpolation (better than
       dichotomy in typical cases) */
464 465
    pos_min = FFM_PACKET_SIZE;
    pos_max = ffm->file_size - FFM_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
466
    while (pos_min <= pos_max) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
467 468
        pts_min = get_dts(s, pos_min);
        pts_max = get_dts(s, pos_max);
Fabrice Bellard's avatar
Fabrice Bellard committed
469
        /* linear interpolation */
470
        pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
Fabrice Bellard's avatar
Fabrice Bellard committed
471
            (double)(pts_max - pts_min);
472
        pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
473 474 475 476
        if (pos <= pos_min)
            pos = pos_min;
        else if (pos >= pos_max)
            pos = pos_max;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
477
        pts = get_dts(s, pos);
Fabrice Bellard's avatar
Fabrice Bellard committed
478 479 480 481 482 483 484 485 486
        /* check if we are lucky */
        if (pts == wanted_pts) {
            goto found;
        } else if (pts > wanted_pts) {
            pos_max = pos - FFM_PACKET_SIZE;
        } else {
            pos_min = pos + FFM_PACKET_SIZE;
        }
    }
487
    pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
488

Fabrice Bellard's avatar
Fabrice Bellard committed
489 490
 found:
    ffm_seek1(s, pos);
491 492 493 494 495 496 497

    /* reset read state */
    ffm->read_state = READ_HEADER;
    ffm->packet_ptr = ffm->packet;
    ffm->packet_end = ffm->packet;
    ffm->first_packet = 1;

Fabrice Bellard's avatar
Fabrice Bellard committed
498 499 500
    return 0;
}

501 502
static int ffm_probe(AVProbeData *p)
{
503
    if (
504
        p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
505
        p->buf[3] == '1')
506 507 508 509
        return AVPROBE_SCORE_MAX + 1;
    return 0;
}

510
AVInputFormat ff_ffm_demuxer = {
511
    .name           = "ffm",
512
    .long_name      = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed) format"),
513 514 515 516 517 518
    .priv_data_size = sizeof(FFMContext),
    .read_probe     = ffm_probe,
    .read_header    = ffm_read_header,
    .read_packet    = ffm_read_packet,
    .read_close     = ffm_close,
    .read_seek      = ffm_seek,
Fabrice Bellard's avatar
Fabrice Bellard committed
519
};