From 3c9bfb336867ccd32a6e8490930961bcc14b3fdc Mon Sep 17 00:00:00 2001 From: Aurelien Jacobs Date: Fri, 10 Sep 2010 23:10:53 +0200 Subject: [PATCH] add MicroDVD muxer and demuxer Signed-off-by: Aurelien Jacobs --- Changelog | 1 + MAINTAINERS | 1 + doc/general.texi | 1 + libavcodec/avcodec.h | 1 + libavformat/Makefile | 2 + libavformat/allformats.c | 1 + libavformat/microdvddec.c | 129 ++++++++++++++++++++++++++++++++++++++ libavformat/microdvdenc.c | 51 +++++++++++++++ libavformat/version.h | 2 +- 9 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 libavformat/microdvddec.c create mode 100644 libavformat/microdvdenc.c diff --git a/Changelog b/Changelog index 4833315bc2..e60c278abe 100644 --- a/Changelog +++ b/Changelog @@ -88,6 +88,7 @@ version : - Linux framebuffer input device added - Chronomaster DFA decoder - DPX image encoder +- MicroDVD subtitle file muxer and demuxer version 0.6: diff --git a/MAINTAINERS b/MAINTAINERS index 977df20b57..8588ba73ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -294,6 +294,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 696db5870e..3e4dbd270a 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -703,6 +703,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 +@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 6c7ec0e1c0..4659719a42 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -353,6 +353,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/libavformat/Makefile b/libavformat/Makefile index 719783c62d..5a2a5f491d 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -122,6 +122,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 3acaed99e3..7a8874ff3d 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -118,6 +118,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 0000000000..95c76afc8d --- /dev/null +++ b/libavformat/microdvddec.c @@ -0,0 +1,129 @@ +/* + * MicroDVD subtitle demuxer + * Copyright (c) 2010 Aurelien Jacobs + * + * 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; + double fps; + char c; + + if (!st) + return -1; + for (i=0; ilines); 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}{}%6lf", &frame, &fps) == 2 || + sscanf(microdvd->lines[i], "{%d}{%*d}%6lf", &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; ilines); 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 0000000000..b2abc547e6 --- /dev/null +++ b/libavformat/microdvdenc.c @@ -0,0 +1,51 @@ +/* + * MicroDVD subtitle muxer + * Copyright (c) 2010 Aurelien Jacobs + * + * 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 497779d358..84b6c112f0 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 104 +#define LIBAVFORMAT_VERSION_MINOR 105 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \