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.tags/n1.1
| @@ -51,7 +51,7 @@ version <next>: | |||||
| - pp (postproc) filter ported from MPlayer | - pp (postproc) filter ported from MPlayer | ||||
| - NIST Sphere demuxer | - NIST Sphere demuxer | ||||
| - av_basename and av_dirname | - av_basename and av_dirname | ||||
| - MPL2 subtitles demuxer and decoder | |||||
| - MPL2 and VPlayer subtitles demuxers and decoders | |||||
| version 1.0: | version 1.0: | ||||
| @@ -933,6 +933,7 @@ performance on systems without hardware floating point support). | |||||
| @item SubViewer @tab @tab X @tab @tab X | @item SubViewer @tab @tab X @tab @tab X | ||||
| @item TED Talks captions @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 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 WebVTT @tab @tab X @tab @tab X | ||||
| @item XSUB @tab @tab @tab X @tab X | @item XSUB @tab @tab @tab X @tab X | ||||
| @end multitable | @end multitable | ||||
| @@ -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 \ | OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp56dsp.o \ | ||||
| vp6dsp.o vp56rac.o | vp6dsp.o vp56rac.o | ||||
| OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp8dsp.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_VQA_DECODER) += vqavideo.o | ||||
| OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o | OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o | ||||
| OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o | OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o | ||||
| @@ -456,6 +456,7 @@ void avcodec_register_all(void) | |||||
| REGISTER_ENCDEC (SUBRIP, subrip); | REGISTER_ENCDEC (SUBRIP, subrip); | ||||
| REGISTER_DECODER(SUBVIEWER, subviewer); | REGISTER_DECODER(SUBVIEWER, subviewer); | ||||
| REGISTER_DECODER(TEXT, text); | REGISTER_DECODER(TEXT, text); | ||||
| REGISTER_DECODER(VPLAYER, vplayer); | |||||
| REGISTER_DECODER(WEBVTT, webvtt); | REGISTER_DECODER(WEBVTT, webvtt); | ||||
| REGISTER_ENCDEC (XSUB, xsub); | REGISTER_ENCDEC (XSUB, xsub); | ||||
| @@ -467,6 +467,7 @@ enum AVCodecID { | |||||
| AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'), | AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'), | ||||
| AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'), | AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'), | ||||
| AV_CODEC_ID_MPL2 = MKBETAG('M','P','L','2'), | 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) */ | /* 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. | AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. | ||||
| @@ -2440,6 +2440,12 @@ static const AVCodecDescriptor codec_descriptors[] = { | |||||
| .name = "subviewer", | .name = "subviewer", | ||||
| .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle"), | .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, | .id = AV_CODEC_ID_WEBVTT, | ||||
| .type = AVMEDIA_TYPE_SUBTITLE, | .type = AVMEDIA_TYPE_SUBTITLE, | ||||
| @@ -30,25 +30,17 @@ | |||||
| typedef struct { | typedef struct { | ||||
| AVClass *class; | AVClass *class; | ||||
| char *linebreaks; | |||||
| const char *linebreaks; | |||||
| int keep_ass_markup; | int keep_ass_markup; | ||||
| } TextContext; | } TextContext; | ||||
| #define OFFSET(x) offsetof(TextContext, x) | #define OFFSET(x) offsetof(TextContext, x) | ||||
| #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM | #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM | ||||
| static const AVOption options[] = { | 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 }, | { "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 } | { 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, | static int text_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf, | ||||
| const char *p, const char *p_end) | const char *p, const char *p_end) | ||||
| { | { | ||||
| @@ -113,6 +105,17 @@ static int text_decode_frame(AVCodecContext *avctx, void *data, | |||||
| return avpkt->size; | 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 = { | AVCodec ff_text_decoder = { | ||||
| .name = "text", | .name = "text", | ||||
| .priv_data_size = sizeof(TextContext), | .priv_data_size = sizeof(TextContext), | ||||
| @@ -123,3 +126,27 @@ AVCodec ff_text_decoder = { | |||||
| .init = ff_ass_subtitle_header_default, | .init = ff_ass_subtitle_header_default, | ||||
| .priv_class = &text_decoder_class, | .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 | |||||
| @@ -29,7 +29,7 @@ | |||||
| #include "libavutil/avutil.h" | #include "libavutil/avutil.h" | ||||
| #define LIBAVCODEC_VERSION_MAJOR 54 | #define LIBAVCODEC_VERSION_MAJOR 54 | ||||
| #define LIBAVCODEC_VERSION_MINOR 82 | |||||
| #define LIBAVCODEC_VERSION_MINOR 83 | |||||
| #define LIBAVCODEC_VERSION_MICRO 100 | #define LIBAVCODEC_VERSION_MICRO 100 | ||||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
| @@ -366,6 +366,7 @@ OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o | |||||
| OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o | OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o | ||||
| OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o | OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o | ||||
| OBJS-$(CONFIG_VOC_MUXER) += vocenc.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_VQF_DEMUXER) += vqf.o | ||||
| OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o pcm.o | OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o pcm.o | ||||
| OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o | OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o | ||||
| @@ -276,6 +276,7 @@ void av_register_all(void) | |||||
| REGISTER_DEMUXER (VMD, vmd); | REGISTER_DEMUXER (VMD, vmd); | ||||
| REGISTER_DEMUXER (VOBSUB, vobsub); | REGISTER_DEMUXER (VOBSUB, vobsub); | ||||
| REGISTER_MUXDEMUX(VOC, voc); | REGISTER_MUXDEMUX(VOC, voc); | ||||
| REGISTER_DEMUXER (VPLAYER, vplayer); | |||||
| REGISTER_DEMUXER (VQF, vqf); | REGISTER_DEMUXER (VQF, vqf); | ||||
| REGISTER_DEMUXER (W64, w64); | REGISTER_DEMUXER (W64, w64); | ||||
| REGISTER_MUXDEMUX(WAV, wav); | REGISTER_MUXDEMUX(WAV, wav); | ||||
| @@ -30,7 +30,7 @@ | |||||
| #include "libavutil/avutil.h" | #include "libavutil/avutil.h" | ||||
| #define LIBAVFORMAT_VERSION_MAJOR 54 | #define LIBAVFORMAT_VERSION_MAJOR 54 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 51 | |||||
| #define LIBAVFORMAT_VERSION_MINOR 52 | |||||
| #define LIBAVFORMAT_VERSION_MICRO 100 | #define LIBAVFORMAT_VERSION_MICRO 100 | ||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||
| @@ -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", | |||||
| }; | |||||
| @@ -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_SUBTITLES_ASS-$(call DEMDEC, SUBVIEWER, SUBVIEWER) += fate-sub-subviewer | ||||
| fate-sub-subviewer: CMD = md5 -i $(SAMPLES)/sub/SubViewer_capability_tester.sub -f ass | 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_SUBTITLES_ASS-$(call DEMDEC, WEBVTT, WEBVTT) += fate-sub-webvtt | ||||
| fate-sub-webvtt: CMD = md5 -i $(SAMPLES)/sub/WebVTT_capability_tester.vtt -f ass | fate-sub-webvtt: CMD = md5 -i $(SAMPLES)/sub/WebVTT_capability_tester.vtt -f ass | ||||
| @@ -0,0 +1 @@ | |||||
| c8201c542f43a9ea42a787ac74d28049 | |||||