FFmpeg
ttmlenc.c
Go to the documentation of this file.
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 
30 #include "avcodec.h"
31 #include "codec_internal.h"
32 #include "libavutil/bprint.h"
33 #include "libavutil/internal.h"
34 #include "ass_split.h"
35 #include "ttmlenc.h"
36 
37 typedef struct {
40  AVBPrint buffer;
41 } TTMLContext;
42 
43 static void ttml_text_cb(void *priv, const char *text, int len)
44 {
45  TTMLContext *s = priv;
46  AVBPrint cur_line;
47  AVBPrint *buffer = &s->buffer;
48 
50 
51  av_bprint_append_data(&cur_line, text, len);
52  if (!av_bprint_is_complete(&cur_line)) {
53  av_log(s->avctx, AV_LOG_ERROR,
54  "Failed to move the current subtitle dialog to AVBPrint!\n");
55  av_bprint_finalize(&cur_line, NULL);
56  return;
57  }
58 
59 
61  0);
62 
63  av_bprint_finalize(&cur_line, NULL);
64 }
65 
66 static void ttml_new_line_cb(void *priv, int forced)
67 {
68  TTMLContext *s = priv;
69 
70  av_bprintf(&s->buffer, "<br/>");
71 }
72 
74  .text = ttml_text_cb,
75  .new_line = ttml_new_line_cb,
76 };
77 
78 static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
79  int bufsize, const AVSubtitle *sub)
80 {
81  TTMLContext *s = avctx->priv_data;
82  ASSDialog *dialog;
83  int i;
84 
85  av_bprint_init_for_buffer(&s->buffer, buf, bufsize);
86 
87  for (i=0; i<sub->num_rects; i++) {
88  const char *ass = sub->rects[i]->ass;
89  int ret;
90 
91  if (sub->rects[i]->type != SUBTITLE_ASS) {
92  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
93  return AVERROR(EINVAL);
94  }
95 
96  dialog = ff_ass_split_dialog(s->ass_ctx, ass);
97  if (!dialog)
98  return AVERROR(ENOMEM);
99 
100  if (dialog->style) {
101  av_bprintf(&s->buffer, "<span region=\"");
102  av_bprint_escape(&s->buffer, dialog->style, NULL,
105  av_bprintf(&s->buffer, "\">");
106  }
107 
109  if (ret < 0) {
110  int log_level = (ret != AVERROR_INVALIDDATA ||
111  avctx->err_recognition & AV_EF_EXPLODE) ?
113  av_log(avctx, log_level,
114  "Splitting received ASS dialog text %s failed: %s\n",
115  dialog->text,
116  av_err2str(ret));
117 
118  if (log_level == AV_LOG_ERROR) {
119  ff_ass_free_dialog(&dialog);
120  return ret;
121  }
122  }
123 
124  if (dialog->style)
125  av_bprintf(&s->buffer, "</span>");
126 
127  ff_ass_free_dialog(&dialog);
128  }
129 
130  if (!s->buffer.len)
131  return 0;
132  if (!av_bprint_is_complete(&s->buffer)) {
133  av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n");
135  }
136 
137  return s->buffer.len;
138 }
139 
141 {
142  TTMLContext *s = avctx->priv_data;
143 
144  ff_ass_split_free(s->ass_ctx);
145 
146  return 0;
147 }
148 
149 static const char *ttml_get_display_alignment(int alignment)
150 {
151  switch (alignment) {
152  case 1:
153  case 2:
154  case 3:
155  return "after";
156  case 4:
157  case 5:
158  case 6:
159  return "center";
160  case 7:
161  case 8:
162  case 9:
163  return "before";
164  default:
165  return NULL;
166  }
167 }
168 
169 static const char *ttml_get_text_alignment(int alignment)
170 {
171  switch (alignment) {
172  case 1:
173  case 4:
174  case 7:
175  return "left";
176  case 2:
177  case 5:
178  case 8:
179  return "center";
180  case 3:
181  case 6:
182  case 9:
183  return "right";
184  default:
185  return NULL;
186  }
187 }
188 
189 static void ttml_get_origin(ASSScriptInfo script_info, ASSStyle style,
190  int *origin_left, int *origin_top)
191 {
192  *origin_left = av_rescale(style.margin_l, 100, script_info.play_res_x);
193  *origin_top =
194  av_rescale((style.alignment >= 7) ? style.margin_v : 0,
195  100, script_info.play_res_y);
196 }
197 
198 static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style,
199  int *width, int *height)
200 {
201  *width = av_rescale(script_info.play_res_x - style.margin_r,
202  100, script_info.play_res_x);
203  *height = av_rescale((style.alignment <= 3) ?
204  script_info.play_res_y - style.margin_v :
205  script_info.play_res_y,
206  100, script_info.play_res_y);
207 }
208 
209 static int ttml_write_region(AVCodecContext *avctx, AVBPrint *buf,
210  ASSScriptInfo script_info, ASSStyle style)
211 {
212  const char *display_alignment = NULL;
213  const char *text_alignment = NULL;
214  int origin_left = 0;
215  int origin_top = 0;
216  int width = 0;
217  int height = 0;
218 
219  if (!style.name) {
220  av_log(avctx, AV_LOG_ERROR, "Subtitle style name not set!\n");
221  return AVERROR_INVALIDDATA;
222  }
223 
224  if (style.font_size < 0) {
225  av_log(avctx, AV_LOG_ERROR, "Invalid font size for TTML: %d!\n",
226  style.font_size);
227  return AVERROR_INVALIDDATA;
228  }
229 
230  if (style.margin_l < 0 || style.margin_r < 0 || style.margin_v < 0) {
231  av_log(avctx, AV_LOG_ERROR,
232  "One or more negative margin values in subtitle style: "
233  "left: %d, right: %d, vertical: %d!\n",
234  style.margin_l, style.margin_r, style.margin_v);
235  return AVERROR_INVALIDDATA;
236  }
237 
238  display_alignment = ttml_get_display_alignment(style.alignment);
240  if (!display_alignment || !text_alignment) {
241  av_log(avctx, AV_LOG_ERROR,
242  "Failed to convert ASS style alignment %d of style %s to "
243  "TTML display and text alignment!\n",
244  style.alignment,
245  style.name);
246  return AVERROR_INVALIDDATA;
247  }
248 
249  ttml_get_origin(script_info, style, &origin_left, &origin_top);
250  ttml_get_extent(script_info, style, &width, &height);
251 
252  av_bprintf(buf, " <region xml:id=\"");
255  av_bprintf(buf, "\"\n");
256 
257  av_bprintf(buf, " tts:origin=\"%d%% %d%%\"\n",
258  origin_left, origin_top);
259  av_bprintf(buf, " tts:extent=\"%d%% %d%%\"\n",
260  width, height);
261 
262  av_bprintf(buf, " tts:displayAlign=\"");
263  av_bprint_escape(buf, display_alignment, NULL, AV_ESCAPE_MODE_XML,
265  av_bprintf(buf, "\"\n");
266 
267  av_bprintf(buf, " tts:textAlign=\"");
270  av_bprintf(buf, "\"\n");
271 
272  // if we set cell resolution to our script reference resolution,
273  // then a single line is a single "point" on our canvas. Thus, by setting
274  // our font size to font size in cells, we should gain a similar enough
275  // scale without resorting to explicit pixel based font sizing, which is
276  // frowned upon in the TTML community.
277  av_bprintf(buf, " tts:fontSize=\"%dc\"\n",
278  style.font_size);
279 
280  if (style.font_name) {
281  av_bprintf(buf, " tts:fontFamily=\"");
284  av_bprintf(buf, "\"\n");
285  }
286 
287  av_bprintf(buf, " tts:overflow=\"visible\" />\n");
288 
289  return 0;
290 }
291 
293 {
294  TTMLContext *s = avctx->priv_data;
295  ASS *ass = (ASS *)s->ass_ctx;
296  ASSScriptInfo script_info = ass->script_info;
297  const size_t base_extradata_size = TTMLENC_EXTRADATA_SIGNATURE_SIZE + 1 +
299  size_t additional_extradata_size = 0;
300  int ret;
301 
302  if (script_info.play_res_x <= 0 || script_info.play_res_y <= 0) {
303  av_log(avctx, AV_LOG_ERROR,
304  "Invalid subtitle reference resolution %dx%d!\n",
305  script_info.play_res_x, script_info.play_res_y);
306  return AVERROR_INVALIDDATA;
307  }
308 
309  av_bprint_init(&s->buffer, 0, INT_MAX - base_extradata_size);
310 
311  // write the first string in extradata, attributes in the base "tt" element.
313  // the cell resolution is in character cells, so not exactly 1:1 against
314  // a pixel based resolution, but as the tts:extent in the root
315  // "tt" element is frowned upon (and disallowed in the EBU-TT profile),
316  // we mimic the reference resolution by setting it as the cell resolution.
317  av_bprintf(&s->buffer, " ttp:cellResolution=\"%d %d\"\n",
318  script_info.play_res_x, script_info.play_res_y);
319  av_bprint_chars(&s->buffer, '\0', 1);
320 
321  // write the second string in extradata, head element containing the styles
322  av_bprintf(&s->buffer, " <head>\n");
323  av_bprintf(&s->buffer, " <layout>\n");
324 
325  for (int i = 0; i < ass->styles_count; i++) {
326  ret = ttml_write_region(avctx, &s->buffer, script_info,
327  ass->styles[i]);
328  if (ret < 0)
329  goto fail;
330  }
331 
332  av_bprintf(&s->buffer, " </layout>\n");
333  av_bprintf(&s->buffer, " </head>\n");
334  av_bprint_chars(&s->buffer, '\0', 1);
335 
336  if (!av_bprint_is_complete(&s->buffer)) {
337  ret = AVERROR(ENOMEM);
338  goto fail;
339  }
340 
341  additional_extradata_size = s->buffer.len;
342 
343  if (!(avctx->extradata =
344  av_mallocz(base_extradata_size + additional_extradata_size))) {
345  ret = AVERROR(ENOMEM);
346  goto fail;
347  }
348 
349  avctx->extradata_size =
350  TTMLENC_EXTRADATA_SIGNATURE_SIZE + additional_extradata_size;
351  memcpy(avctx->extradata, TTMLENC_EXTRADATA_SIGNATURE,
353 
355  s->buffer.str, additional_extradata_size);
356 
357  ret = 0;
358 fail:
359  av_bprint_finalize(&s->buffer, NULL);
360 
361  return ret;
362 }
363 
365 {
366  TTMLContext *s = avctx->priv_data;
367  int ret = AVERROR_BUG;
368  s->avctx = avctx;
369 
370  if (!(s->ass_ctx = ff_ass_split(avctx->subtitle_header))) {
371  return AVERROR_INVALIDDATA;
372  }
373 
374  if ((ret = ttml_write_header_content(avctx)) < 0) {
375  return ret;
376  }
377 
378  return 0;
379 }
380 
382  .p.name = "ttml",
383  CODEC_LONG_NAME("TTML subtitle"),
384  .p.type = AVMEDIA_TYPE_SUBTITLE,
385  .p.id = AV_CODEC_ID_TTML,
386  .priv_data_size = sizeof(TTMLContext),
389  .close = ttml_encode_close,
390  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
391 };
AVSubtitle
Definition: avcodec.h:2227
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
AV_EF_EXPLODE
#define AV_EF_EXPLODE
abort decoding on minor error detection
Definition: defs.h:51
FF_CODEC_CAP_INIT_CLEANUP
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: codec_internal.h:42
ASSCodesCallbacks
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:138
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVSubtitle::rects
AVSubtitleRect ** rects
Definition: avcodec.h:2232
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
ASSStyle::margin_r
int margin_r
Definition: ass_split.h:62
ASSStyle::alignment
int alignment
position of the text (left, center, top...), defined after the layout of the numpad (1-3 sub,...
Definition: ass_split.h:58
AVCodecContext::err_recognition
int err_recognition
Error recognition; may misdetect some more or less valid parts as errors.
Definition: avcodec.h:1420
AVSubtitle::num_rects
unsigned num_rects
Definition: avcodec.h:2231
ff_ass_split_dialog
ASSDialog * ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:433
ff_ttml_encoder
const FFCodec ff_ttml_encoder
Definition: ttmlenc.c:381
ASS::styles
ASSStyle * styles
array of split out styles
Definition: ass_split.h:92
ASSStyle::font_size
int font_size
font height
Definition: ass_split.h:42
FFCodec
Definition: codec_internal.h:127
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Definition: avcodec.h:1891
ttml_get_extent
static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style, int *width, int *height)
Definition: ttmlenc.c:198
ASSDialog::style
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:76
SUBTITLE_ASS
@ SUBTITLE_ASS
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:2195
TTMLENC_EXTRADATA_SIGNATURE_SIZE
#define TTMLENC_EXTRADATA_SIGNATURE_SIZE
Definition: ttmlenc.h:26
ASSStyle::font_name
char * font_name
font face (case sensitive)
Definition: ass_split.h:41
ttml_text_cb
static void ttml_text_cb(void *priv, const char *text, int len)
Definition: ttmlenc.c:43
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
av_bprint_init_for_buffer
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition: bprint.c:85
fail
#define fail()
Definition: checkasm.h:179
ass_split.h
AVERROR_BUFFER_TOO_SMALL
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:53
TTMLContext::avctx
AVCodecContext * avctx
Definition: ttmlenc.c:38
ttml_write_header_content
static int ttml_write_header_content(AVCodecContext *avctx)
Definition: ttmlenc.c:292
AVSubtitleRect::ass
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2224
TTMLENC_EXTRADATA_SIGNATURE
#define TTMLENC_EXTRADATA_SIGNATURE
Definition: ttmlenc.h:25
ff_ass_free_dialog
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog().
Definition: ass_split.c:421
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
ttml_get_origin
static void ttml_get_origin(ASSScriptInfo script_info, ASSStyle style, int *origin_left, int *origin_top)
Definition: ttmlenc.c:189
AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double quoted attributes.
Definition: avstring.h:348
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:524
width
#define width
s
#define s(width, name)
Definition: cbs_vp9.c:198
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
if
if(ret)
Definition: filter_design.txt:179
ASSScriptInfo::play_res_y
int play_res_y
video height that ASS coords are referring to
Definition: ass_split.h:32
ASS
structure containing the whole split ASS data
Definition: ass_split.h:90
ttml_callbacks
static const ASSCodesCallbacks ttml_callbacks
Definition: ttmlenc.c:73
NULL
#define NULL
Definition: coverity.c:32
ASSScriptInfo::play_res_x
int play_res_x
video width that ASS coords are referring to
Definition: ass_split.h:31
ASSStyle::margin_l
int margin_l
Definition: ass_split.h:61
av_bprint_escape
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition: bprint.c:268
ttml_new_line_cb
static void ttml_new_line_cb(void *priv, int forced)
Definition: ttmlenc.c:66
ttml_encode_frame
static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, int bufsize, const AVSubtitle *sub)
Definition: ttmlenc.c:78
ASSScriptInfo
fields extracted from the [Script Info] section
Definition: ass_split.h:28
TTMLContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: ttmlenc.c:39
FF_CODEC_ENCODE_SUB_CB
#define FF_CODEC_ENCODE_SUB_CB(func)
Definition: codec_internal.h:299
ASSSplitContext
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:205
ff_ass_split
ASSSplitContext * ff_ass_split(const char *buf)
Split a full ASS file or a ASS header from a string buffer and store the split structure in a newly a...
Definition: ass_split.c:382
ASSStyle
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:365
ff_ass_split_free
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:470
TTMLContext
Definition: ttmlenc.c:37
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
codec_internal.h
ASSDialog::text
char * text
actual text which will be displayed as a subtitle, can include style override control codes (see ff_a...
Definition: ass_split.h:82
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
ASSStyle::name
char * name
name of the tyle (case sensitive)
Definition: ass_split.h:40
AV_ESCAPE_MODE_XML
@ AV_ESCAPE_MODE_XML
Use XML non-markup character data escaping.
Definition: avstring.h:318
ttml_encode_init
static av_cold int ttml_encode_init(AVCodecContext *avctx)
Definition: ttmlenc.c:364
AVSubtitleRect::type
enum AVSubtitleType type
Definition: avcodec.h:2215
height
#define height
ttml_get_text_alignment
static const char * ttml_get_text_alignment(int alignment)
Definition: ttmlenc.c:169
text_alignment
text_alignment
Definition: vf_drawtext.c:174
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:523
internal.h
AV_CODEC_ID_TTML
@ AV_CODEC_ID_TTML
Definition: codec_id.h:573
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
ASS::styles_count
int styles_count
number of ASSStyle in the styles array
Definition: ass_split.h:93
len
int len
Definition: vorbis_enc_data.h:426
av_rescale
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
ASSStyle::margin_v
int margin_v
Definition: ass_split.h:63
avcodec.h
ret
ret
Definition: filter_design.txt:187
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
TTMLContext::buffer
AVBPrint buffer
Definition: ttmlenc.c:40
AVCodecContext
main external API structure.
Definition: avcodec.h:445
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
ASSDialog
fields extracted from the [Events] section
Definition: ass_split.h:71
ttml_write_region
static int ttml_write_region(AVCodecContext *avctx, AVBPrint *buf, ASSScriptInfo script_info, ASSStyle style)
Definition: ttmlenc.c:209
ttmlenc.h
TTML_DEFAULT_NAMESPACING
#define TTML_DEFAULT_NAMESPACING
Definition: ttmlenc.h:28
ttml_get_display_alignment
static const char * ttml_get_display_alignment(int alignment)
Definition: ttmlenc.c:149
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
ttml_encode_close
static av_cold int ttml_encode_close(AVCodecContext *avctx)
Definition: ttmlenc.c:140
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
ff_ass_split_override_codes
int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv, const char *buf)
Split override codes out of a ASS "Dialogue" Text field.
Definition: ass_split.c:483
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:145
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:163
ASSCodesCallbacks::text
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:143
ASS::script_info
ASSScriptInfo script_info
general information about the SSA script
Definition: ass_split.h:91