Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavformat / ffmdec.c
index acc1dc4..679d926 100644 (file)
@@ -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
  */
 
@@ -26,6 +26,7 @@
 #include "avformat.h"
 #include "internal.h"
 #include "ffm.h"
+#include "avio_internal.h"
 
 static int ffm_is_avail_data(AVFormatContext *s, int size)
 {
@@ -62,7 +63,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;
         }
@@ -91,6 +92,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)
@@ -107,8 +113,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 */
@@ -224,6 +230,138 @@ 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) {
+                if (ff_alloc_extradata(codec, avio_rb32(pb)))
+                    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)
 {
@@ -236,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);
@@ -245,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;
@@ -328,9 +468,7 @@ static int ffm_read_header(AVFormatContext *s)
             goto fail;
         }
         if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
-            codec->extradata_size = avio_rb32(pb);
-            codec->extradata = av_malloc(codec->extradata_size);
-            if (!codec->extradata)
+            if (ff_alloc_extradata(codec, avio_rb32(pb)))
                 return AVERROR(ENOMEM);
             avio_read(pb, codec->extradata, codec->extradata_size);
         }
@@ -382,7 +520,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);
@@ -424,11 +564,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);
@@ -466,14 +620,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,