diff options
Diffstat (limited to 'libavformat/ffmdec.c')
-rw-r--r-- | libavformat/ffmdec.c | 186 |
1 files changed, 172 insertions, 14 deletions
diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c index e6730eb2f5..02cf790f87 100644 --- a/libavformat/ffmdec.c +++ b/libavformat/ffmdec.c @@ -1,21 +1,21 @@ /* - * FFM (avserver live feed) demuxer + * FFM (ffserver live feed) demuxer * Copyright (c) 2001 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -24,6 +24,7 @@ #include "avformat.h" #include "internal.h" #include "ffm.h" +#include "avio_internal.h" static int ffm_is_avail_data(AVFormatContext *s, int size) { @@ -60,7 +61,7 @@ static int ffm_resync(AVFormatContext *s, int state) { av_log(s, AV_LOG_ERROR, "resyncing\n"); while (state != PACKET_ID) { - if (s->pb->eof_reached) { + if (url_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); return -1; } @@ -89,6 +90,11 @@ static int ffm_read_data(AVFormatContext *s, if (avio_tell(pb) == ffm->file_size) avio_seek(pb, ffm->packet_size, SEEK_SET); retry_read: + if (pb->buffer_size != ffm->packet_size) { + int64_t tell = avio_tell(pb); + ffio_set_buf_size(pb, ffm->packet_size); + avio_seek(pb, tell, SEEK_SET); + } id = avio_rb16(pb); /* PACKET_ID */ if (id != PACKET_ID) if (ffm_resync(s, id) < 0) @@ -105,8 +111,8 @@ static int ffm_read_data(AVFormatContext *s, if (ffm->first_packet || (frame_offset & 0x8000)) { if (!frame_offset) { /* This packet has no frame headers in it */ - if (avio_tell(pb) >= ffm->packet_size * 3) { - avio_seek(pb, -ffm->packet_size * 2, SEEK_CUR); + if (avio_tell(pb) >= ffm->packet_size * 3LL) { + avio_seek(pb, -ffm->packet_size * 2LL, SEEK_CUR); goto retry_read; } /* This is bad, we cannot find a valid frame header */ @@ -222,6 +228,140 @@ static int ffm_close(AVFormatContext *s) return 0; } +static int ffm2_read_header(AVFormatContext *s) +{ + FFMContext *ffm = s->priv_data; + AVStream *st; + AVIOContext *pb = s->pb; + AVCodecContext *codec; + + ffm->packet_size = avio_rb32(pb); + if (ffm->packet_size != FFM_PACKET_SIZE) + goto fail; + ffm->write_index = avio_rb64(pb); + /* get also filesize */ + if (pb->seekable) { + ffm->file_size = avio_size(pb); + if (ffm->write_index && 0) + adjust_write_index(s); + } else { + ffm->file_size = (UINT64_C(1) << 63) - 1; + } + + while(!url_feof(pb)) { + unsigned id = avio_rb32(pb); + unsigned size = avio_rb32(pb); + int64_t next = avio_tell(pb) + size; + char rc_eq_buf[128]; + + if(!id) + break; + + switch(id) { + case MKBETAG('M', 'A', 'I', 'N'): + avio_rb32(pb); /* nb_streams */ + avio_rb32(pb); /* total bitrate */ + break; + case MKBETAG('C', 'O', 'M', 'M'): + st = avformat_new_stream(s, NULL); + if (!st) + goto fail; + + avpriv_set_pts_info(st, 64, 1, 1000000); + + codec = st->codec; + /* generic info */ + codec->codec_id = avio_rb32(pb); + codec->codec_type = avio_r8(pb); + codec->bit_rate = avio_rb32(pb); + codec->flags = avio_rb32(pb); + codec->flags2 = avio_rb32(pb); + codec->debug = avio_rb32(pb); + if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { + codec->extradata_size = avio_rb32(pb); + codec->extradata = av_malloc(codec->extradata_size); + if (!codec->extradata) + return AVERROR(ENOMEM); + avio_read(pb, codec->extradata, codec->extradata_size); + } + avio_seek(pb, next, SEEK_SET); + id = avio_rb32(pb); + size = avio_rb32(pb); + next = avio_tell(pb) + size; + switch(id) { + case MKBETAG('S', 'T', 'V', 'I'): + 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); + avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); + codec->rc_eq = av_strdup(rc_eq_buf); + codec->rc_max_rate = avio_rb32(pb); + codec->rc_min_rate = avio_rb32(pb); + codec->rc_buffer_size = avio_rb32(pb); + 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)); + codec->dct_algo = avio_rb32(pb); + codec->strict_std_compliance = avio_rb32(pb); + codec->max_b_frames = 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); + codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb)); + 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); + codec->qcompress = av_int2double(avio_rb64(pb)); + codec->qblur = av_int2double(avio_rb64(pb)); + codec->max_qdiff = avio_rb32(pb); + codec->refs = avio_rb32(pb); + break; + case MKBETAG('S', 'T', 'A', 'U'): + codec->sample_rate = avio_rb32(pb); + codec->channels = avio_rl16(pb); + codec->frame_size = avio_rl16(pb); + break; + } + break; + } + avio_seek(pb, next, SEEK_SET); + } + + /* get until end of block reached */ + while ((avio_tell(pb) % ffm->packet_size) != 0) + avio_r8(pb); + + /* init packet demux */ + ffm->packet_ptr = ffm->packet; + ffm->packet_end = ffm->packet; + ffm->frame_offset = 0; + ffm->dts = 0; + ffm->read_state = READ_HEADER; + ffm->first_packet = 1; + return 0; + fail: + ffm_close(s); + return -1; +} static int ffm_read_header(AVFormatContext *s) { @@ -234,6 +374,8 @@ static int ffm_read_header(AVFormatContext *s) /* header */ tag = avio_rl32(pb); + if (tag == MKTAG('F', 'F', 'M', '2')) + return ffm2_read_header(s); if (tag != MKTAG('F', 'F', 'M', '1')) goto fail; ffm->packet_size = avio_rb32(pb); @@ -243,7 +385,7 @@ static int ffm_read_header(AVFormatContext *s) /* get also filesize */ if (pb->seekable) { ffm->file_size = avio_size(pb); - if (ffm->write_index) + if (ffm->write_index && 0) adjust_write_index(s); } else { ffm->file_size = (UINT64_C(1) << 63) - 1; @@ -380,7 +522,9 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) duration = AV_RB24(ffm->header + 5); - av_new_packet(pkt, size); + if (av_new_packet(pkt, size) < 0) { + return AVERROR(ENOMEM); + } pkt->stream_index = ffm->header[0]; if ((unsigned)pkt->stream_index >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index); @@ -422,11 +566,25 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); /* find the position using linear interpolation (better than dichotomy in typical cases) */ - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->file_size - FFM_PACKET_SIZE; + if (ffm->write_index && ffm->write_index < ffm->file_size) { + if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) { + pos_min = FFM_PACKET_SIZE; + pos_max = ffm->write_index - FFM_PACKET_SIZE; + } else { + pos_min = ffm->write_index; + pos_max = ffm->file_size - FFM_PACKET_SIZE; + } + } else { + pos_min = FFM_PACKET_SIZE; + pos_max = ffm->file_size - FFM_PACKET_SIZE; + } while (pos_min <= pos_max) { pts_min = get_dts(s, pos_min); pts_max = get_dts(s, pos_max); + if (pts_min > wanted_pts || pts_max <= wanted_pts) { + pos = pts_min > wanted_pts ? pos_min : pos_max; + goto found; + } /* linear interpolation */ pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / (double)(pts_max - pts_min); @@ -464,14 +622,14 @@ static int ffm_probe(AVProbeData *p) { if ( p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && - p->buf[3] == '1') + (p->buf[3] == '1' || p->buf[3] == '2')) return AVPROBE_SCORE_MAX + 1; return 0; } AVInputFormat ff_ffm_demuxer = { .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed)"), + .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"), .priv_data_size = sizeof(FFMContext), .read_probe = ffm_probe, .read_header = ffm_read_header, |