/src/ffmpeg/libavcodec/ass.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * SSA/ASS common functions |
3 | | * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org> |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "avcodec.h" |
23 | | #include "ass.h" |
24 | | #include "libavutil/avstring.h" |
25 | | #include "libavutil/bprint.h" |
26 | | #include "libavutil/mem.h" |
27 | | #include "version.h" |
28 | | |
29 | | int ff_ass_subtitle_header_full(AVCodecContext *avctx, |
30 | | int play_res_x, int play_res_y, |
31 | | const char *font, int font_size, |
32 | | int primary_color, int secondary_color, |
33 | | int outline_color, int back_color, |
34 | | int bold, int italic, int underline, |
35 | | int border_style, int alignment) |
36 | 14.0k | { |
37 | 14.0k | avctx->subtitle_header = av_asprintf( |
38 | 14.0k | "[Script Info]\n" |
39 | 14.0k | "; Script generated by FFmpeg/Lavc%s\n" |
40 | 14.0k | "ScriptType: v4.00+\n" |
41 | 14.0k | "PlayResX: %d\n" |
42 | 14.0k | "PlayResY: %d\n" |
43 | 14.0k | "ScaledBorderAndShadow: yes\n" |
44 | 14.0k | "YCbCr Matrix: None\n" |
45 | 14.0k | "\n" |
46 | 14.0k | "[V4+ Styles]\n" |
47 | | |
48 | | /* ASS (v4+) header */ |
49 | 14.0k | "Format: Name, " |
50 | 14.0k | "Fontname, Fontsize, " |
51 | 14.0k | "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " |
52 | 14.0k | "Bold, Italic, Underline, StrikeOut, " |
53 | 14.0k | "ScaleX, ScaleY, " |
54 | 14.0k | "Spacing, Angle, " |
55 | 14.0k | "BorderStyle, Outline, Shadow, " |
56 | 14.0k | "Alignment, MarginL, MarginR, MarginV, " |
57 | 14.0k | "Encoding\n" |
58 | | |
59 | 14.0k | "Style: " |
60 | 14.0k | "Default," /* Name */ |
61 | 14.0k | "%s,%d," /* Font{name,size} */ |
62 | 14.0k | "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */ |
63 | 14.0k | "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */ |
64 | 14.0k | "100,100," /* Scale{X,Y} */ |
65 | 14.0k | "0,0," /* Spacing, Angle */ |
66 | 14.0k | "%d,1,0," /* BorderStyle, Outline, Shadow */ |
67 | 14.0k | "%d,10,10,10," /* Alignment, Margin[LRV] */ |
68 | 14.0k | "1\n" /* Encoding */ |
69 | | |
70 | 14.0k | "\n" |
71 | 14.0k | "[Events]\n" |
72 | 14.0k | "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n", |
73 | 14.0k | !(avctx->flags & AV_CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "", |
74 | 14.0k | play_res_x, play_res_y, font, font_size, |
75 | 14.0k | primary_color, secondary_color, outline_color, back_color, |
76 | 14.0k | -bold, -italic, -underline, border_style, alignment); |
77 | | |
78 | 14.0k | if (!avctx->subtitle_header) |
79 | 0 | return AVERROR(ENOMEM); |
80 | 14.0k | avctx->subtitle_header_size = strlen(avctx->subtitle_header); |
81 | 14.0k | return 0; |
82 | 14.0k | } |
83 | | |
84 | | int ff_ass_subtitle_header(AVCodecContext *avctx, |
85 | | const char *font, int font_size, |
86 | | int color, int back_color, |
87 | | int bold, int italic, int underline, |
88 | | int border_style, int alignment) |
89 | 14.0k | { |
90 | 14.0k | return ff_ass_subtitle_header_full(avctx, |
91 | 14.0k | ASS_DEFAULT_PLAYRESX, ASS_DEFAULT_PLAYRESY, |
92 | 14.0k | font, font_size, color, color, |
93 | 14.0k | back_color, back_color, |
94 | 14.0k | bold, italic, underline, |
95 | 14.0k | border_style, alignment); |
96 | 14.0k | } |
97 | | |
98 | | int ff_ass_subtitle_header_default(AVCodecContext *avctx) |
99 | 10.9k | { |
100 | 10.9k | return ff_ass_subtitle_header(avctx, ASS_DEFAULT_FONT, |
101 | 10.9k | ASS_DEFAULT_FONT_SIZE, |
102 | 10.9k | ASS_DEFAULT_COLOR, |
103 | 10.9k | ASS_DEFAULT_BACK_COLOR, |
104 | 10.9k | ASS_DEFAULT_BOLD, |
105 | 10.9k | ASS_DEFAULT_ITALIC, |
106 | 10.9k | ASS_DEFAULT_UNDERLINE, |
107 | 10.9k | ASS_DEFAULT_BORDERSTYLE, |
108 | 10.9k | ASS_DEFAULT_ALIGNMENT); |
109 | 10.9k | } |
110 | | |
111 | | char *ff_ass_get_dialog(int readorder, int layer, const char *style, |
112 | | const char *speaker, const char *text) |
113 | 4.42M | { |
114 | 4.42M | return av_asprintf("%d,%d,%s,%s,0,0,0,,%s", |
115 | 4.42M | readorder, layer, style ? style : "Default", |
116 | 4.42M | speaker ? speaker : "", text); |
117 | 4.42M | } |
118 | | |
119 | | int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog, |
120 | | int readorder, int layer, const char *style, |
121 | | const char *speaker, unsigned *nb_rect_allocated) |
122 | 4.42M | { |
123 | 4.42M | AVSubtitleRect **rects = sub->rects, *rect; |
124 | 4.42M | char *ass_str; |
125 | 4.42M | uint64_t new_nb = 0; |
126 | | |
127 | 4.42M | if (sub->num_rects >= UINT_MAX) |
128 | 0 | return AVERROR(ENOMEM); |
129 | | |
130 | 4.42M | if (nb_rect_allocated && *nb_rect_allocated <= sub->num_rects) { |
131 | 14.1k | if (sub->num_rects < UINT_MAX / 17 * 16) { |
132 | 14.1k | new_nb = sub->num_rects + sub->num_rects/16 + 1; |
133 | 14.1k | } else |
134 | 0 | new_nb = UINT_MAX; |
135 | 4.41M | } else if (!nb_rect_allocated) |
136 | 1.42M | new_nb = sub->num_rects + 1; |
137 | | |
138 | 4.42M | if (new_nb) { |
139 | 1.43M | rects = av_realloc_array(rects, new_nb, sizeof(*sub->rects)); |
140 | 1.43M | if (!rects) |
141 | 0 | return AVERROR(ENOMEM); |
142 | 1.43M | if (nb_rect_allocated) |
143 | 14.1k | *nb_rect_allocated = new_nb; |
144 | 1.43M | sub->rects = rects; |
145 | 1.43M | } |
146 | | |
147 | 4.42M | rect = av_mallocz(sizeof(*rect)); |
148 | 4.42M | if (!rect) |
149 | 0 | return AVERROR(ENOMEM); |
150 | 4.42M | rects[sub->num_rects++] = rect; |
151 | 4.42M | rect->type = SUBTITLE_ASS; |
152 | 4.42M | ass_str = ff_ass_get_dialog(readorder, layer, style, speaker, dialog); |
153 | 4.42M | if (!ass_str) |
154 | 0 | return AVERROR(ENOMEM); |
155 | 4.42M | rect->ass = ass_str; |
156 | 4.42M | return 0; |
157 | 4.42M | } |
158 | | |
159 | | int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, |
160 | | int readorder, int layer, const char *style, |
161 | | const char *speaker) |
162 | 1.42M | { |
163 | 1.42M | return ff_ass_add_rect2(sub, dialog, readorder, layer, style, speaker, NULL); |
164 | 1.42M | } |
165 | | |
166 | | void ff_ass_decoder_flush(AVCodecContext *avctx) |
167 | 141k | { |
168 | 141k | FFASSDecoderContext *s = avctx->priv_data; |
169 | 141k | if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) |
170 | 141k | s->readorder = 0; |
171 | 141k | } |
172 | | |
173 | | void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size, |
174 | | const char *linebreaks, int keep_ass_markup) |
175 | 616k | { |
176 | 616k | const char *p_end = p + size; |
177 | | |
178 | 63.2M | for (; p < p_end && *p; p++) { |
179 | | |
180 | | /* forced custom line breaks, not accounted as "normal" EOL */ |
181 | 62.6M | if (linebreaks && strchr(linebreaks, *p)) { |
182 | 160k | av_bprintf(buf, "\\N"); |
183 | | |
184 | | /* cancel curly brackets to avoid bogus override tag blocks |
185 | | * hiding text. Standard ASS has no character escapes, |
186 | | * though (only) libass provides \{ and \}. |
187 | | * Unpaired closing brackets don't need escaping at all though and |
188 | | * to make the situation less bad in standard ASS insert an empty block |
189 | | */ |
190 | 62.5M | } else if (!keep_ass_markup && *p == '{') { |
191 | 27.8M | av_bprintf(buf, "\\{{}"); |
192 | | |
193 | | /* append word-joiner U+2060 as UTF-8 to break up sequences like \N */ |
194 | 34.6M | } else if (!keep_ass_markup && *p == '\\') { |
195 | 30.0M | if (p_end - p <= 3 || strncmp(p + 1, "\xe2\x81\xa0", 3)) |
196 | 30.0M | av_bprintf(buf, "\\\xe2\x81\xa0"); |
197 | 12.2k | else |
198 | 12.2k | av_bprintf(buf, "\\"); |
199 | | |
200 | | /* some packets might end abruptly (no \0 at the end, like for example |
201 | | * in some cases of demuxing from a classic video container), some |
202 | | * might be terminated with \n or \r\n which we have to remove (for |
203 | | * consistency with those who haven't), and we also have to deal with |
204 | | * evil cases such as \r at the end of the buffer (and no \0 terminated |
205 | | * character) */ |
206 | 30.0M | } else if (p[0] == '\n') { |
207 | | /* some stuff left so we can insert a line break */ |
208 | 728k | if (p < p_end - 1) |
209 | 520k | av_bprintf(buf, "\\N"); |
210 | 3.89M | } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') { |
211 | | /* \r followed by a \n, we can skip it. We don't insert the \N yet |
212 | | * because we don't know if it is followed by more text */ |
213 | 1.26k | continue; |
214 | | |
215 | | /* finally, a sane character */ |
216 | 3.88M | } else { |
217 | 3.88M | av_bprint_chars(buf, *p, 1); |
218 | 3.88M | } |
219 | 62.6M | } |
220 | 616k | } |