1 /*
2 * TTML subtitle encoder
3 * Copyright (c) 2020 24i
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 /**
23 * @file
24 * TTML subtitle encoder
25 * @see https://www.w3.org/TR/ttml1/
26 * @see https://www.w3.org/TR/ttml2/
27 * @see https://www.w3.org/TR/ttml-imsc/rec
28 */
29
38
44
46 {
48 AVBPrint cur_line = { 0 };
50
52
56 "Failed to move the current subtitle dialog to AVBPrint!\n");
58 return;
59 }
60
61
63 0);
64
66 }
67
69 {
71
73 }
74
78 };
79
82 {
86
88
89 for (
i=0;
i<
sub->num_rects;
i++) {
90 const char *ass =
sub->rects[
i]->ass;
92
96 }
97
99 if (!dialog)
101
108 }
109
116 "Splitting received ASS dialog text %s failed: %s\n",
119
123 }
124 }
125
128
130 }
131
135 return 0;
136
137 // force null-termination, so in case our destination buffer is
138 // too small, the return value is larger than bufsize minus null.
139 if (
av_strlcpy(buf,
s->buffer.str, bufsize) > bufsize - 1) {
142 }
143
144 return s->buffer.len;
145 }
146
148 {
150
152
154
155 return 0;
156 }
157
159 {
160 switch (alignment) {
161 case 1:
162 case 2:
163 case 3:
164 return "after";
165 case 4:
166 case 5:
167 case 6:
168 return "center";
169 case 7:
170 case 8:
171 case 9:
172 return "before";
173 default:
175 }
176 }
177
179 {
180 switch (alignment) {
181 case 1:
182 case 4:
183 case 7:
184 return "left";
185 case 2:
186 case 5:
187 case 8:
188 return "center";
189 case 3:
190 case 6:
191 case 9:
192 return "right";
193 default:
195 }
196 }
197
199 int *origin_left, int *origin_top)
200 {
202 *origin_top =
205 }
206
209 {
216 }
217
220 {
221 const char *display_alignment =
NULL;
222 const char *text_alignment =
NULL;
223 int origin_left = 0;
224 int origin_top = 0;
227
231 }
232
237 }
238
241 "One or more negative margin values in subtitle style: "
242 "left: %d, right: %d, vertical: %d!\n",
245 }
246
249 if (!display_alignment || !text_alignment) {
251 "Failed to convert ASS style alignment %d of style %s to "
252 "TTML display and text alignment!\n",
256 }
257
260
265
266 av_bprintf(buf,
" tts:origin=\"%d%% %d%%\"\n",
267 origin_left, origin_top);
268 av_bprintf(buf,
" tts:extent=\"%d%% %d%%\"\n",
270
275
280
281 // if we set cell resolution to our script reference resolution,
282 // then a single line is a single "point" on our canvas. Thus, by setting
283 // our font size to font size in cells, we should gain a similar enough
284 // scale without resorting to explicit pixel based font sizing, which is
285 // frowned upon in the TTML community.
288
294 }
295
296 av_bprintf(buf,
" tts:overflow=\"visible\" />\n");
297
298 return 0;
299 }
300
302 {
308 size_t additional_extradata_size = 0;
309
310 if (script_info.play_res_x <= 0 || script_info.play_res_y <= 0) {
312 "Invalid subtitle reference resolution %dx%d!\n",
313 script_info.play_res_x, script_info.play_res_y);
315 }
316
317 // write the first string in extradata, attributes in the base "tt" element.
319 // the cell resolution is in character cells, so not exactly 1:1 against
320 // a pixel based resolution, but as the tts:extent in the root
321 // "tt" element is frowned upon (and disallowed in the EBU-TT profile),
322 // we mimic the reference resolution by setting it as the cell resolution.
323 av_bprintf(&
s->buffer,
" ttp:cellResolution=\"%d %d\"\n",
324 script_info.play_res_x, script_info.play_res_y);
326
327 // write the second string in extradata, head element containing the styles
330
336 }
337
341
344 }
345
346 additional_extradata_size =
s->buffer.len;
347
349 av_mallocz(base_extradata_size + additional_extradata_size))) {
351 }
352
357
358 if (additional_extradata_size)
360 s->buffer.str, additional_extradata_size);
361
363
364 return 0;
365 }
366
368 {
372
374
377 }
378
381 }
382
383 return 0;
384 }
385
396 };