[FFmpeg-devel] [PATCH] add MicroDVD muxer and demuxer

Aurelien Jacobs aurel at gnuage.org
Tue Mar 29 00:42:28 CEST 2011


Signed-off-by: Aurelien Jacobs <aurel at gnuage.org>
---
 Changelog                 |    1 +
 MAINTAINERS               |    1 +
 doc/general.texi          |    1 +
 libavcodec/avcodec.h      |    1 +
 libavcodec/version.h      |    2 +-
 libavformat/Makefile      |    2 +
 libavformat/allformats.c  |    1 +
 libavformat/microdvddec.c |  129 +++++++++++++++++++++++++++++++++++++++++++++
 libavformat/microdvdenc.c |   51 ++++++++++++++++++
 libavformat/version.h     |    2 +-
 10 files changed, 189 insertions(+), 2 deletions(-)
 create mode 100644 libavformat/microdvddec.c
 create mode 100644 libavformat/microdvdenc.c

diff --git a/Changelog b/Changelog
index c91faab..451693a 100644
--- a/Changelog
+++ b/Changelog
@@ -81,6 +81,7 @@ version <next>:
 - Linux framebuffer input device added
 - Apple HTTP Live Streaming protocol handler
 - sndio support for playback and record
+- MicroDVD subtitle file muxer and demuxer
 
 
 version 0.6:
diff --git a/MAINTAINERS b/MAINTAINERS
index 772f956..db80e19 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -293,6 +293,7 @@ Muxers/Demuxers:
   matroskadec.c                         Aurelien Jacobs
   matroskaenc.c                         David Conrad
   metadata*                             Aurelien Jacobs
+  microdvd*                             Aurelien Jacobs
   mm.c                                  Peter Ross
   mov.c                                 Michael Niedermayer, Baptiste Coudurier
   movenc.c                              Michael Niedermayer, Baptiste Coudurier
diff --git a/doc/general.texi b/doc/general.texi
index 23ffb0d..cad1131 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -699,6 +699,7 @@ performance on systems without hardware floating point support).
 @item SSA/ASS      @tab X @tab X @tab X @tab X
 @item DVB          @tab X @tab X @tab X @tab X
 @item DVD          @tab X @tab X @tab X @tab X
+ at item MicroDVD     @tab X @tab X @tab   @tab
 @item PGS          @tab   @tab   @tab   @tab X
 @item SubRip (SRT) @tab X @tab X @tab X @tab X
 @item XSUB         @tab   @tab   @tab X @tab X
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 7ab02e6..cab47f8 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -352,6 +352,7 @@ enum CodecID {
     CODEC_ID_HDMV_PGS_SUBTITLE,
     CODEC_ID_DVB_TELETEXT,
     CODEC_ID_SRT,
+    CODEC_ID_MICRODVD,
 
     /* other specific kind of codecs (generally used for attachments) */
     CODEC_ID_TTF= 0x18000,
diff --git a/libavcodec/version.h b/libavcodec/version.h
index a1c8365..5aa0b82 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -21,7 +21,7 @@
 #define AVCODEC_VERSION_H
 
 #define LIBAVCODEC_VERSION_MAJOR 52
-#define LIBAVCODEC_VERSION_MINOR 116
+#define LIBAVCODEC_VERSION_MINOR 117
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavformat/Makefile b/libavformat/Makefile
index c521cd3..0610073 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -121,6 +121,8 @@ OBJS-$(CONFIG_MATROSKA_MUXER)            += matroskaenc.o matroska.o \
                                             riff.o isom.o avc.o \
                                             flacenc_header.o avlanguage.o
 OBJS-$(CONFIG_MD5_MUXER)                 += md5enc.o
+OBJS-$(CONFIG_MICRODVD_DEMUXER)          += microdvddec.o
+OBJS-$(CONFIG_MICRODVD_MUXER)            += microdvdenc.o rawenc.o
 OBJS-$(CONFIG_MJPEG_DEMUXER)             += rawdec.o
 OBJS-$(CONFIG_MJPEG_MUXER)               += rawenc.o
 OBJS-$(CONFIG_MLP_DEMUXER)               += rawdec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index bca968a..1066cd1 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -117,6 +117,7 @@ void av_register_all(void)
     REGISTER_MUXER    (MD5, md5);
     REGISTER_MUXDEMUX (MATROSKA, matroska);
     REGISTER_MUXER    (MATROSKA_AUDIO, matroska_audio);
+    REGISTER_MUXDEMUX (MICRODVD, microdvd);
     REGISTER_MUXDEMUX (MJPEG, mjpeg);
     REGISTER_MUXDEMUX (MLP, mlp);
     REGISTER_DEMUXER  (MM, mm);
diff --git a/libavformat/microdvddec.c b/libavformat/microdvddec.c
new file mode 100644
index 0000000..c8fc2f3
--- /dev/null
+++ b/libavformat/microdvddec.c
@@ -0,0 +1,129 @@
+/*
+ * MicroDVD subtitle demuxer
+ * Copyright (c) 2010  Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * 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
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+#define MAX_LINESIZE 2048
+
+
+typedef struct {
+    uint8_t lines[3][MAX_LINESIZE];
+    int64_t pos[3];
+} MicroDVDContext;
+
+
+static int microdvd_probe(AVProbeData *p)
+{
+    unsigned char c, *ptr = p->buf;
+    int i;
+
+    if (AV_RB24(ptr) == 0xEFBBBF)
+        ptr += 3;  /* skip UTF-8 BOM */
+
+    for (i=0; i<3; i++) {
+        if (sscanf(ptr, "{%*d}{}%c",     &c) != 1 &&
+            sscanf(ptr, "{%*d}{%*d}%c",  &c) != 1 &&
+            sscanf(ptr, "{DEFAULT}{}%c", &c) != 1)
+            return 0;
+        ptr += strcspn(ptr, "\n") + 1;
+    }
+    return AVPROBE_SCORE_MAX;
+}
+
+static int microdvd_read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+    AVRational pts_info = (AVRational){ 2997, 125 };  /* default: 23.976 fps */
+    MicroDVDContext *microdvd = s->priv_data;
+    AVStream *st = av_new_stream(s, 0);
+    int i, frame;
+    float fps;
+    char c;
+
+    if (!st)
+        return -1;
+    for (i=0; i<FF_ARRAY_ELEMS(microdvd->lines); i++) {
+        microdvd->pos[i] = avio_tell(s->pb);
+        ff_get_line(s->pb, microdvd->lines[i], sizeof(microdvd->lines[i]));
+        if ((sscanf(microdvd->lines[i], "{%d}{}%5f",    &frame, &fps) == 2 ||
+             sscanf(microdvd->lines[i], "{%d}{%*d}%5f", &frame, &fps) == 2)
+            && frame <= 1 && fps > 3 && fps < 100)
+            pts_info = av_d2q(fps, 100000);
+        if (sscanf(microdvd->lines[i], "{DEFAULT}{}%c", &c) == 1) {
+            st->codec->extradata = av_strdup(microdvd->lines[i] + 11);
+            st->codec->extradata_size = strlen(st->codec->extradata);
+            i--;
+        }
+    }
+    av_set_pts_info(st, 64, pts_info.den, pts_info.num);
+    st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+    st->codec->codec_id   = CODEC_ID_MICRODVD;
+    return 0;
+}
+
+static int64_t get_pts(const char *buf)
+{
+    int frame;
+    char c;
+
+    if (sscanf(buf, "{%d}{%c", &frame, &c) == 2)
+        return frame;
+    return AV_NOPTS_VALUE;
+}
+
+static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    MicroDVDContext *microdvd = s->priv_data;
+    char buffer[MAX_LINESIZE];
+    int64_t pos = avio_tell(s->pb);
+    int i, len = 0, res = AVERROR_EOF;
+
+    for (i=0; i<FF_ARRAY_ELEMS(microdvd->lines); i++) {
+        if (microdvd->lines[i][0]) {
+            strcpy(buffer, microdvd->lines[i]);
+            pos = microdvd->pos[i];
+            len = strlen(buffer);
+            microdvd->lines[i][0] = 0;
+            break;
+        }
+    }
+    if (!len)
+        len = ff_get_line(s->pb, buffer, sizeof(buffer));
+
+    if (buffer[0] && !(res = av_new_packet(pkt, len))) {
+        memcpy(pkt->data, buffer, len);
+        pkt->flags |= AV_PKT_FLAG_KEY;
+        pkt->pos = pos;
+        pkt->pts = pkt->dts = get_pts(buffer);
+    }
+    return res;
+}
+
+AVInputFormat ff_microdvd_demuxer = {
+    .name           = "microdvd",
+    .long_name      = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
+    .priv_data_size = sizeof(MicroDVDContext),
+    .read_probe     = microdvd_probe,
+    .read_header    = microdvd_read_header,
+    .read_packet    = microdvd_read_packet,
+    .flags          = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/microdvdenc.c b/libavformat/microdvdenc.c
new file mode 100644
index 0000000..b2abc54
--- /dev/null
+++ b/libavformat/microdvdenc.c
@@ -0,0 +1,51 @@
+/*
+ * MicroDVD subtitle muxer
+ * Copyright (c) 2010  Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * 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
+ */
+
+#include "avformat.h"
+#include "rawenc.h"
+
+static int microdvd_write_header(struct AVFormatContext *s)
+{
+    AVCodecContext *avctx = s->streams[0]->codec;
+
+    if (s->nb_streams != 1 || avctx->codec_id != CODEC_ID_MICRODVD) {
+        av_log(s, AV_LOG_ERROR, "Exactly one MicroDVD stream is needed.\n");
+        return -1;
+    }
+
+    if (avctx->extradata && avctx->extradata_size > 0) {
+        avio_write(s->pb, "{DEFAULT}{}", 11);
+        avio_write(s->pb, avctx->extradata, avctx->extradata_size);
+        avio_flush(s->pb);
+    }
+    return 0;
+}
+
+AVOutputFormat ff_microdvd_muxer = {
+    .name           = "microdvd",
+    .long_name      = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
+    .mime_type      = "text/x-microdvd",
+    .extensions     = "sub",
+    .write_header   = microdvd_write_header,
+    .write_packet   = ff_raw_write_packet,
+    .flags          = AVFMT_NOTIMESTAMPS,
+    .subtitle_codec = CODEC_ID_MICRODVD,
+};
diff --git a/libavformat/version.h b/libavformat/version.h
index d03fe12..497779d 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -24,7 +24,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 52
-#define LIBAVFORMAT_VERSION_MINOR 103
+#define LIBAVFORMAT_VERSION_MINOR 104
 #define LIBAVFORMAT_VERSION_MICRO  0
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
-- 
1.7.4.1



More information about the ffmpeg-devel mailing list