Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2012 Clément Bœsch | |
3 | * | |
4 | * This file is part of FFmpeg. | |
5 | * | |
6 | * FFmpeg is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
10 | * | |
11 | * FFmpeg is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with FFmpeg; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | /** | |
22 | * @file | |
23 | * Raw subtitles decoder | |
24 | */ | |
25 | ||
26 | #include "avcodec.h" | |
27 | #include "ass.h" | |
28 | #include "libavutil/bprint.h" | |
29 | #include "libavutil/opt.h" | |
30 | ||
31 | typedef struct { | |
32 | AVClass *class; | |
33 | const char *linebreaks; | |
34 | int keep_ass_markup; | |
35 | } TextContext; | |
36 | ||
37 | #define OFFSET(x) offsetof(TextContext, x) | |
38 | #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM | |
39 | static const AVOption options[] = { | |
40 | { "keep_ass_markup", "Set if ASS tags must be escaped", OFFSET(keep_ass_markup), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags=SD }, | |
41 | { NULL } | |
42 | }; | |
43 | ||
44 | static int text_decode_frame(AVCodecContext *avctx, void *data, | |
45 | int *got_sub_ptr, AVPacket *avpkt) | |
46 | { | |
47 | AVBPrint buf; | |
48 | AVSubtitle *sub = data; | |
49 | const char *ptr = avpkt->data; | |
50 | const TextContext *text = avctx->priv_data; | |
51 | const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); | |
52 | const int ts_duration = avpkt->duration != -1 ? | |
53 | av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1; | |
54 | ||
55 | av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); | |
56 | if (ptr && avpkt->size > 0 && *ptr) { | |
57 | ff_ass_bprint_text_event(&buf, ptr, avpkt->size, text->linebreaks, text->keep_ass_markup); | |
58 | if (!av_bprint_is_complete(&buf)) { | |
59 | av_bprint_finalize(&buf, NULL); | |
60 | return AVERROR(ENOMEM); | |
61 | } | |
62 | ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0); | |
63 | } | |
64 | *got_sub_ptr = sub->num_rects > 0; | |
65 | av_bprint_finalize(&buf, NULL); | |
66 | return avpkt->size; | |
67 | } | |
68 | ||
69 | #define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = { \ | |
70 | .class_name = #decname " decoder", \ | |
71 | .item_name = av_default_item_name, \ | |
72 | .option = decname ## _options, \ | |
73 | .version = LIBAVUTIL_VERSION_INT, \ | |
74 | } | |
75 | ||
76 | #if CONFIG_TEXT_DECODER | |
77 | #define text_options options | |
78 | DECLARE_CLASS(text); | |
79 | ||
80 | AVCodec ff_text_decoder = { | |
81 | .name = "text", | |
82 | .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"), | |
83 | .priv_data_size = sizeof(TextContext), | |
84 | .type = AVMEDIA_TYPE_SUBTITLE, | |
85 | .id = AV_CODEC_ID_TEXT, | |
86 | .decode = text_decode_frame, | |
87 | .init = ff_ass_subtitle_header_default, | |
88 | .priv_class = &text_decoder_class, | |
89 | }; | |
90 | #endif | |
91 | ||
92 | #if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER | |
93 | ||
94 | static int linebreak_init(AVCodecContext *avctx) | |
95 | { | |
96 | TextContext *text = avctx->priv_data; | |
97 | text->linebreaks = "|"; | |
98 | return ff_ass_subtitle_header_default(avctx); | |
99 | } | |
100 | ||
101 | #if CONFIG_VPLAYER_DECODER | |
102 | #define vplayer_options options | |
103 | DECLARE_CLASS(vplayer); | |
104 | ||
105 | AVCodec ff_vplayer_decoder = { | |
106 | .name = "vplayer", | |
107 | .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), | |
108 | .priv_data_size = sizeof(TextContext), | |
109 | .type = AVMEDIA_TYPE_SUBTITLE, | |
110 | .id = AV_CODEC_ID_VPLAYER, | |
111 | .decode = text_decode_frame, | |
112 | .init = linebreak_init, | |
113 | .priv_class = &vplayer_decoder_class, | |
114 | }; | |
115 | #endif | |
116 | ||
117 | #if CONFIG_PJS_DECODER | |
118 | #define pjs_options options | |
119 | DECLARE_CLASS(pjs); | |
120 | ||
121 | AVCodec ff_pjs_decoder = { | |
122 | .name = "pjs", | |
123 | .long_name = NULL_IF_CONFIG_SMALL("PJS subtitle"), | |
124 | .priv_data_size = sizeof(TextContext), | |
125 | .type = AVMEDIA_TYPE_SUBTITLE, | |
126 | .id = AV_CODEC_ID_PJS, | |
127 | .decode = text_decode_frame, | |
128 | .init = linebreak_init, | |
129 | .priv_class = &pjs_decoder_class, | |
130 | }; | |
131 | #endif | |
132 | ||
133 | #if CONFIG_SUBVIEWER1_DECODER | |
134 | #define subviewer1_options options | |
135 | DECLARE_CLASS(subviewer1); | |
136 | ||
137 | AVCodec ff_subviewer1_decoder = { | |
138 | .name = "subviewer1", | |
139 | .long_name = NULL_IF_CONFIG_SMALL("SubViewer1 subtitle"), | |
140 | .priv_data_size = sizeof(TextContext), | |
141 | .type = AVMEDIA_TYPE_SUBTITLE, | |
142 | .id = AV_CODEC_ID_SUBVIEWER1, | |
143 | .decode = text_decode_frame, | |
144 | .init = linebreak_init, | |
145 | .priv_class = &subviewer1_decoder_class, | |
146 | }; | |
147 | #endif | |
148 | ||
149 | #endif /* text subtitles with '|' line break */ |