[FFmpeg-devel] Fwd: Interested in NEW Seeking API of GSoC09

Daniel Verkamp daniel
Sat Mar 21 03:53:44 CET 2009


On Fri, Mar 20, 2009 at 9:03 PM, zhentan feng <spyfeng at gmail.com> wrote:
> Hi
>
> This is a forward mail from ffmpeg-soc list without reply and forgive me
> repost it here.
> If the qualification task is necessary, I'll choose "Implement a Vivo
> demuxer for ffmpeg" as a qualification task.
>
> ---------- Forwarded message ----------
> From: zhentan feng <spyfeng at gmail.com>
> Date: 2009/3/20
> Subject: Interested in NEW Seeking API of GSoC09
> To: FFmpeg Google SoC list <ffmpeg-soc at mplayerhq.hu>
> Cc: Baptiste Coudurier <baptiste.coudurier at smartjog.com>
>
>
> hi,
>
> My name is zhentan feng, and I am a student from china.
> I have finished last year's soc project MXF muxer mentored by Baptiste.
>
> This summer, I plan to apply a soc project of ffmpeg again, and i am
> interested in the NEW Seeking API project.
> should I start from qualification task again or beginning to collect
> information for the new project?
>
> sincerely yours
> zhentan feng
> --
> Best wishes~

Hi,

I was playing around with writing a Vivo demuxer myself, but it
currently doesn't work; attached is the (horribly messy) work so far.

I'm not sure if it's actually working, but feeding the supposedly
H.263 video stream from any of the samples to ffmpeg's decoder results
in a bunch of nasty error messages about various invalid values; this
could be because my code is broken (likely :) or because the video is
not actually standard H.263 (also possible; anyone have more
information?).  The mplayer demuxer uses the binary Win32 codecs to
decode both the video and audio, so it's not too much help here.

FFmpeg also doesn't currently support either of the possible audio
codecs (G.723 and Siren), so I can't check if those work either.

I'm probably not going to work on it any more unless someone's got a
revelation about the H.263 problems, so feel free to do what you want
with it...

Thanks,
-- Daniel Verkamp
-------------- next part --------------
>From 3ecddffe0c0e7bd452c078ad3467e885164036c2 Mon Sep 17 00:00:00 2001
From: Daniel Verkamp <daniel at drv.nu>
Date: Fri, 20 Mar 2009 20:21:49 -0500
Subject: [PATCH] work in progress vivo demuxer

---
 libavformat/Makefile     |    1 +
 libavformat/allformats.c |    1 +
 libavformat/vivodec.c    |  304 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 306 insertions(+), 0 deletions(-)
 create mode 100644 libavformat/vivodec.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index f2285d7..5f64edd 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -214,6 +214,7 @@ OBJS-$(CONFIG_TXD_DEMUXER)               += txd.o
 OBJS-$(CONFIG_VC1_DEMUXER)               += raw.o
 OBJS-$(CONFIG_VC1T_DEMUXER)              += vc1test.o
 OBJS-$(CONFIG_VC1T_MUXER)                += vc1testenc.o
+OBJS-$(CONFIG_VIVO_DEMUXER)              += vivodec.o
 OBJS-$(CONFIG_VMD_DEMUXER)               += sierravmd.o
 OBJS-$(CONFIG_VOC_DEMUXER)               += vocdec.o voc.o
 OBJS-$(CONFIG_VOC_MUXER)                 += vocenc.o voc.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 39ac3b8..2e7593e 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -187,6 +187,7 @@ void av_register_all(void)
     REGISTER_DEMUXER  (TXD, txd);
     REGISTER_DEMUXER  (VC1, vc1);
     REGISTER_MUXDEMUX (VC1T, vc1t);
+    REGISTER_DEMUXER  (VIVO, vivo);
     REGISTER_DEMUXER  (VMD, vmd);
     REGISTER_MUXDEMUX (VOC, voc);
     REGISTER_DEMUXER  (VQF, vqf);
diff --git a/libavformat/vivodec.c b/libavformat/vivodec.c
new file mode 100644
index 0000000..8f4ff21
--- /dev/null
+++ b/libavformat/vivodec.c
@@ -0,0 +1,304 @@
+/*
+ * Vivo stream demuxer
+ * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * 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.
+ *
+ * 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file libavformat/vivodec.c
+ * @brief Vivo stream demuxer
+ * @author Daniel Verkamp <daniel at drv.nu>
+ * @sa http://wiki.multimedia.cx/index.php?title=Vivo
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+
+typedef struct VivoPacket {
+    unsigned type;
+    unsigned sequence;
+    unsigned len;
+} VivoPacket;
+
+typedef struct VivoContext {
+    VivoPacket pkt;
+    AVRational timebase;
+    int video_pts; // FIXME - parse out of h.263?
+} VivoContext;
+
+
+static int vivo_probe(AVProbeData *p)
+{
+    const unsigned char *buf = p->buf;
+    unsigned c, len = 0, i;
+
+    c = *buf++;
+
+    // stream must start with packet of type 0 and sequence number 0
+    if (c != 0)
+        return 0;
+
+    // read at most 2 bytes of coded length
+    for (i = 0; i < 2; i++) {
+        c = *buf++;
+        len = (len << 7) | (c & 0x7F);
+        if (~c & 0x80)
+            break;
+    }
+
+    if (i == 2 || len > 1024 || len < 21)
+        return 0;
+
+    if (memcmp(buf, "\r\nVersion:Vivo/", 15))
+        return 0;
+    buf += 15;
+
+    if (*buf != '0' && *buf != '1' && *buf != '2')
+        return 0;
+
+    return AVPROBE_SCORE_MAX;
+}
+
+
+static int vivo_get_packet_header(AVFormatContext *s, VivoPacket *vpkt)
+{
+    ByteIOContext *pb = s->pb;
+    unsigned c, get_len = 0;
+
+    // TODO: check for eof
+
+    c = get_byte(pb);
+
+    if (c == 0x82) {
+        get_len = 1;
+        c = get_byte(pb);
+    }
+
+    vpkt->type     = c >> 4;
+    vpkt->sequence = c & 0xF;
+
+    switch (vpkt->type) {
+    case 0:   get_len =   1; break;
+    case 1: vpkt->len = 128; break;
+    case 2:   get_len =   1; break;
+    case 3: vpkt->len =  40; break;
+    case 4: vpkt->len =  24; break;
+    default:
+        av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vpkt->type);
+        return -1;
+    }
+
+    if (get_len) {
+        vpkt->len = 0;
+        do {
+            c = get_byte(pb);
+            vpkt->len = (vpkt->len << 7) | (c & 0x7F);
+            // FIXME - check for EOF? what does get_byte return for EOF?
+        } while (c & 0x80);
+    }
+
+    return 0;
+}
+
+
+static int vivo_read_text_header(AVFormatContext *s, VivoPacket *vpkt,
+                                 AVStream *vst, AVStream *ast)
+{
+    VivoContext *vivo = s->priv_data;
+    ByteIOContext *pb = s->pb;
+    unsigned char text[vpkt->len + 1];
+    unsigned char *line, *line_end, *key, *value;
+    int value_int;
+
+    get_buffer(pb, text, vpkt->len);
+    text[vpkt->len] = '\0';
+
+    line = text;
+    while (*line) {
+        line_end = strstr(line, "\r\n");
+        if (!line_end)
+            break;
+
+        *line_end = '\0';
+        key = line;
+        line = line_end + 2; // skip \r\n
+
+        if (line_end == key) // skip blank lines
+            continue;
+
+        value = strchr(key, ':');
+        if (!value) {
+            av_log(s, AV_LOG_ERROR, "missing colon in key:value pair\n");
+            return -1;
+        }
+
+        *value++ = '\0';
+        value_int = atoi(value);
+
+        if (!strcmp(key, "Width")) {
+            vst->codec->width = value_int;
+        } else if (!strcmp(key, "Height")) {
+            vst->codec->height = value_int;
+        } else if (!strcmp(key, "TimeUnitNumerator")) {
+            vivo->timebase.num = value_int;
+        } else if (!strcmp(key, "TimeUnitDenominator")) {
+            vivo->timebase.den = value_int;
+        } else if (!strcmp(key, "SamplingFrequency")) {
+            ast->codec->sample_rate = value_int;
+            if (value_int == 16000) {
+                //ast->codec->codec_id = CODEC_ID_SIREN;
+            } else if (value_int == 8000) {
+                //ast->codec->codec_id = CODEC_ID_G723;
+            }
+        } else {
+            av_metadata_set(&s->metadata, key, value); // TODO - FIXME?
+            #undef fprintf
+            //fprintf(stderr, "key = '%s', value = '%s'\n", key, value);
+        }
+    }
+
+    return 0;
+}
+
+
+static int vivo_read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+    VivoContext *vivo = s->priv_data;
+    ByteIOContext *pb = s->pb;
+    AVStream *vst;
+    AVStream *ast;
+    int ret;
+
+    vst = av_new_stream(s, 0);
+    if (!vst)
+        return AVERROR(ENOMEM);
+    vst->codec->codec_type = CODEC_TYPE_VIDEO;
+    vst->codec->codec_id   = CODEC_ID_H263;
+
+    ast = av_new_stream(s, 0);
+    if (!ast)
+        return AVERROR(ENOMEM); // FIXME - memleak etc.
+    ast->codec->codec_type = CODEC_TYPE_AUDIO;
+    ast->codec->channels = 1;
+    ast->codec->bits_per_coded_sample = 8;
+    ast->codec->sample_fmt = SAMPLE_FMT_U8;
+
+    while (1) {
+        ret = vivo_get_packet_header(s, &vivo->pkt);
+        if (ret < 0)
+            return -1; // FIXME - memleak etc.
+
+        // done reading all text header packets?
+        if (vivo->pkt.sequence || vivo->pkt.type)
+            break;
+
+        ret = vivo_read_text_header(s, &vivo->pkt, vst, ast);
+        if (ret < 0)
+            return -1; // FIXME - memleak etc.
+    }
+
+    av_set_pts_info(vst, 64, vivo->timebase.num, vivo->timebase.den);
+
+    return 0;
+}
+
+
+static int vivo_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    VivoContext *vivo = s->priv_data;
+    ByteIOContext *pb = s->pb;
+    int ret, stream_index;
+    unsigned old_sequence = vivo->pkt.sequence, old_type = vivo->pkt.type;
+    unsigned len = 0;
+    uint8_t *buf = NULL, *buf_new;
+
+    if (url_feof(pb))
+            return AVERROR(EIO); // FIXME - return eof error
+
+    for (;;) {
+        // TODO
+        switch (vivo->pkt.type) {
+        case 0: // text header; skip?
+            fprintf(stderr, "skipping embedded text header...\n");
+            url_fseek(pb, vivo->pkt.len, SEEK_CUR);
+            goto read_next_packet;
+            break;
+        case 1: case 2: // video
+            stream_index = 0;
+            break;
+        case 3: case 4: // audio
+            stream_index = 1;
+            break;
+        default:
+            av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->pkt.type);
+            return -1;
+        }
+
+        // read data into buffer
+        buf_new = av_realloc(buf, len + vivo->pkt.len);
+        if (!buf_new) {
+            av_free(buf);
+            return AVERROR(ENOMEM);
+        }
+        buf = buf_new;
+        get_buffer(pb, buf + len, vivo->pkt.len);
+        len += vivo->pkt.len;
+
+read_next_packet:
+        if (url_feof(pb))
+            return AVERROR(EIO); // FIXME - return eof error
+
+        // get next packet header
+        ret = vivo_get_packet_header(s, &vivo->pkt);
+        if (ret < 0) {
+            av_free(buf);
+            return AVERROR(EIO);
+        }
+
+        // done reading this packet?
+        if (vivo->pkt.sequence != old_sequence || vivo->pkt.type != old_type)
+            break;
+    }
+
+    //av_hex_dump_log(s, AV_LOG_INFO, buf, len);
+
+    // copy data into packet
+    if(av_new_packet(pkt, len) < 0) {
+        av_log(s, AV_LOG_ERROR, "couldn't create packet\n");
+        av_free(buf);
+        return AVERROR(ENOMEM);
+    }
+
+    pkt->stream_index = stream_index;
+    pkt->pts = AV_NOPTS_VALUE; //vivo->video_pts++; // FIXME - mega hax
+    fprintf(stderr, "final packet size = %d, stream = %d\n", len, pkt->stream_index);
+
+    memcpy(pkt->data, buf, len);
+    av_free(buf);
+
+    return 0; // FIXME?
+}
+
+AVInputFormat vivo_demuxer = {
+    "vivo",
+    NULL_IF_CONFIG_SMALL("Vivo stream"),
+    sizeof(VivoContext),
+    vivo_probe,
+    vivo_read_header,
+    vivo_read_packet,
+};
-- 
1.6.2



More information about the ffmpeg-devel mailing list