diff options
author | Clément Bœsch <ubitux@gmail.com> | 2012-12-27 22:36:47 +0100 |
---|---|---|
committer | Clément Bœsch <ubitux@gmail.com> | 2012-12-30 22:46:42 +0100 |
commit | 5c68aae90883497d59a2a49cf75816cf5906e14a (patch) | |
tree | 83ede8ebe1751d4d3af4946ff8b8a1bd27a41c54 | |
parent | 5f02844c8d4fc93972932a84f0a5cbb02fe12a00 (diff) | |
download | ffmpeg-5c68aae90883497d59a2a49cf75816cf5906e14a.tar.gz |
Add VPlayer subtitles demuxer and decoder.
Note that the linebreaks text codec option (but not the feature) has
been removed; its main goal was to allow demuxers to configure the text
decoder (and not meant to be used by users), but the AVOption are not a
viable solution. This is solved differently in this commit.
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | doc/general.texi | 1 | ||||
-rw-r--r-- | libavcodec/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 1 | ||||
-rw-r--r-- | libavcodec/codec_desc.c | 6 | ||||
-rw-r--r-- | libavcodec/textdec.c | 45 | ||||
-rw-r--r-- | libavcodec/version.h | 2 | ||||
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/allformats.c | 1 | ||||
-rw-r--r-- | libavformat/version.h | 2 | ||||
-rw-r--r-- | libavformat/vplayerdec.c | 128 | ||||
-rw-r--r-- | tests/fate/subtitles.mak | 3 | ||||
-rw-r--r-- | tests/ref/fate/sub-vplayer | 1 |
14 files changed, 183 insertions, 12 deletions
@@ -51,7 +51,7 @@ version <next>: - pp (postproc) filter ported from MPlayer - NIST Sphere demuxer - av_basename and av_dirname -- MPL2 subtitles demuxer and decoder +- MPL2 and VPlayer subtitles demuxers and decoders version 1.0: diff --git a/doc/general.texi b/doc/general.texi index 472ceac8ee..de8d080ebc 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -933,6 +933,7 @@ performance on systems without hardware floating point support). @item SubViewer @tab @tab X @tab @tab X @item TED Talks captions @tab @tab X @tab @tab X @item VobSub (IDX+SUB) @tab @tab X @tab @tab X +@item VPlayer @tab @tab X @tab @tab X @item WebVTT @tab @tab X @tab @tab X @item XSUB @tab @tab @tab X @tab X @end multitable diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 00e9f02d8f..949c66b706 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -465,6 +465,7 @@ OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56dsp.o \ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp56dsp.o \ vp6dsp.o vp56rac.o OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp8dsp.o vp56rac.o +OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 1194a744a4..314ef37764 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -456,6 +456,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (SUBRIP, subrip); REGISTER_DECODER(SUBVIEWER, subviewer); REGISTER_DECODER(TEXT, text); + REGISTER_DECODER(VPLAYER, vplayer); REGISTER_DECODER(WEBVTT, webvtt); REGISTER_ENCDEC (XSUB, xsub); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 69edcc9b48..8730ccbbba 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -467,6 +467,7 @@ enum AVCodecID { AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'), AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'), AV_CODEC_ID_MPL2 = MKBETAG('M','P','L','2'), + AV_CODEC_ID_VPLAYER = MKBETAG('V','P','l','r'), /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 8de4be107e..2ea5e99629 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2441,6 +2441,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle"), }, { + .id = AV_CODEC_ID_VPLAYER, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "vplayer", + .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), + }, + { .id = AV_CODEC_ID_WEBVTT, .type = AVMEDIA_TYPE_SUBTITLE, .name = "webvtt", diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c index 4b3a4ada3c..9e19b37dd9 100644 --- a/libavcodec/textdec.c +++ b/libavcodec/textdec.c @@ -30,25 +30,17 @@ typedef struct { AVClass *class; - char *linebreaks; + const char *linebreaks; int keep_ass_markup; } TextContext; #define OFFSET(x) offsetof(TextContext, x) #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - { "linebreaks", "Extra line breaks characters", OFFSET(linebreaks), AV_OPT_TYPE_STRING, {.str=NULL}, .flags=SD }, { "keep_ass_markup", "Set if ASS tags must be escaped", OFFSET(keep_ass_markup), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags=SD }, { NULL } }; -static const AVClass text_decoder_class = { - .class_name = "text decoder", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - static int text_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf, const char *p, const char *p_end) { @@ -113,6 +105,17 @@ static int text_decode_frame(AVCodecContext *avctx, void *data, return avpkt->size; } +#define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = { \ + .class_name = #decname " decoder", \ + .item_name = av_default_item_name, \ + .option = decname ## _options, \ + .version = LIBAVUTIL_VERSION_INT, \ +} + +#if CONFIG_TEXT_DECODER +#define text_options options +DECLARE_CLASS(text); + AVCodec ff_text_decoder = { .name = "text", .priv_data_size = sizeof(TextContext), @@ -123,3 +126,27 @@ AVCodec ff_text_decoder = { .init = ff_ass_subtitle_header_default, .priv_class = &text_decoder_class, }; +#endif + +#if CONFIG_VPLAYER_DECODER +#define vplayer_options options +DECLARE_CLASS(vplayer); + +static int vplayer_init(AVCodecContext *avctx) +{ + TextContext *text = avctx->priv_data; + text->linebreaks = "|"; + return ff_ass_subtitle_header_default(avctx); +} + +AVCodec ff_vplayer_decoder = { + .name = "vplayer", + .priv_data_size = sizeof(TextContext), + .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_VPLAYER, + .decode = text_decode_frame, + .init = vplayer_init, + .priv_class = &vplayer_decoder_class, +}; +#endif diff --git a/libavcodec/version.h b/libavcodec/version.h index 32d3650edf..bdd94b4e56 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 54 -#define LIBAVCODEC_VERSION_MINOR 82 +#define LIBAVCODEC_VERSION_MINOR 83 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavformat/Makefile b/libavformat/Makefile index bffa876aff..d0b47c06d0 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -366,6 +366,7 @@ OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o +OBJS-$(CONFIG_VPLAYER_DEMUXER) += vplayerdec.o OBJS-$(CONFIG_VQF_DEMUXER) += vqf.o OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o pcm.o OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index f37f608c2b..32458e4e83 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -276,6 +276,7 @@ void av_register_all(void) REGISTER_DEMUXER (VMD, vmd); REGISTER_DEMUXER (VOBSUB, vobsub); REGISTER_MUXDEMUX(VOC, voc); + REGISTER_DEMUXER (VPLAYER, vplayer); REGISTER_DEMUXER (VQF, vqf); REGISTER_DEMUXER (W64, w64); REGISTER_MUXDEMUX(WAV, wav); diff --git a/libavformat/version.h b/libavformat/version.h index 8a22dd44f6..31a25061d2 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 54 -#define LIBAVFORMAT_VERSION_MINOR 51 +#define LIBAVFORMAT_VERSION_MINOR 52 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/libavformat/vplayerdec.c b/libavformat/vplayerdec.c new file mode 100644 index 0000000000..73a48dbdc5 --- /dev/null +++ b/libavformat/vplayerdec.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012 Clément Bœsch + * + * 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 + * VPlayer subtitles format demuxer + */ + +#include "avformat.h" +#include "internal.h" +#include "subtitles.h" + +typedef struct { + FFDemuxSubtitlesQueue q; +} VPlayerContext; + +static int vplayer_probe(AVProbeData *p) +{ + char c; + const unsigned char *ptr = p->buf; + + if (sscanf(ptr, "%*d:%*d:%*d.%*d%c", &c) == 1 && strchr(": =", c)) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int64_t read_ts(char **line) +{ + char c; + int hh, mm, ss, ms, len; + + if (sscanf(*line, "%d:%d:%d.%d%c%n", + &hh, &mm, &ss, &ms, &c, &len) >= 5) { + *line += len; + return (hh*3600LL + mm*60LL + ss) * 100LL + ms; + } + return AV_NOPTS_VALUE; +} + +static int vplayer_read_header(AVFormatContext *s) +{ + VPlayerContext *vplayer = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 64, 1, 100); + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codec->codec_id = AV_CODEC_ID_VPLAYER; + + while (!url_feof(s->pb)) { + char line[4096]; + char *p = line; + const int64_t pos = avio_tell(s->pb); + int len = ff_get_line(s->pb, line, sizeof(line)); + int64_t pts_start; + + if (!len) + break; + + line[strcspn(line, "\r\n")] = 0; + + pts_start = read_ts(&p); + if (pts_start != AV_NOPTS_VALUE) { + AVPacket *sub; + + sub = ff_subtitles_queue_insert(&vplayer->q, p, strlen(p), 0); + if (!sub) + return AVERROR(ENOMEM); + sub->pos = pos; + sub->pts = pts_start; + sub->duration = -1; + } + } + + ff_subtitles_queue_finalize(&vplayer->q); + return 0; +} + +static int vplayer_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + VPlayerContext *vplayer = s->priv_data; + return ff_subtitles_queue_read_packet(&vplayer->q, pkt); +} + +static int vplayer_read_seek(AVFormatContext *s, int stream_index, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + VPlayerContext *vplayer = s->priv_data; + return ff_subtitles_queue_seek(&vplayer->q, s, stream_index, + min_ts, ts, max_ts, flags); +} + +static int vplayer_read_close(AVFormatContext *s) +{ + VPlayerContext *vplayer = s->priv_data; + ff_subtitles_queue_clean(&vplayer->q); + return 0; +} + +AVInputFormat ff_vplayer_demuxer = { + .name = "vplayer", + .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitles"), + .priv_data_size = sizeof(VPlayerContext), + .read_probe = vplayer_probe, + .read_header = vplayer_read_header, + .read_packet = vplayer_read_packet, + .read_seek2 = vplayer_read_seek, + .read_close = vplayer_read_close, + .extensions = "txt", +}; diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak index 9934ddf9e7..3f7e02d4e1 100644 --- a/tests/fate/subtitles.mak +++ b/tests/fate/subtitles.mak @@ -28,6 +28,9 @@ fate-sub-subripenc: CMD = md5 -i $(SAMPLES)/sub/MovText_capability_tester.mp4 -s FATE_SUBTITLES_ASS-$(call DEMDEC, SUBVIEWER, SUBVIEWER) += fate-sub-subviewer fate-sub-subviewer: CMD = md5 -i $(SAMPLES)/sub/SubViewer_capability_tester.sub -f ass +FATE_SUBTITLES_ASS-$(call DEMDEC, VPLAYER, VPLAYER) += fate-sub-vplayer +fate-sub-vplayer: CMD = md5 -i $(SAMPLES)/sub/VPlayer_capability_tester.txt -f ass + FATE_SUBTITLES_ASS-$(call DEMDEC, WEBVTT, WEBVTT) += fate-sub-webvtt fate-sub-webvtt: CMD = md5 -i $(SAMPLES)/sub/WebVTT_capability_tester.vtt -f ass diff --git a/tests/ref/fate/sub-vplayer b/tests/ref/fate/sub-vplayer new file mode 100644 index 0000000000..b8fc40e1e8 --- /dev/null +++ b/tests/ref/fate/sub-vplayer @@ -0,0 +1 @@ +c8201c542f43a9ea42a787ac74d28049 |