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 "libavutil/mem.h"
35 #include "ass_split.h"
36 #include "ttmlenc.h"
37 
38 typedef struct {
41  AVBPrint buffer;
42 } TTMLContext;
43 
44 static void ttml_text_cb(void *priv, const char *text, int len)
45 {
46  TTMLContext *s = priv;
47  AVBPrint cur_line;
48  AVBPrint *buffer = &s->buffer;
49 
51 
52  av_bprint_append_data(&cur_line, text, len);
53  if (!av_bprint_is_complete(&cur_line)) {
54  av_log(s->avctx, AV_LOG_ERROR,
55  "Failed to move the current subtitle dialog to AVBPrint!\n");
56  av_bprint_finalize(&cur_line, NULL);
57  return;
58  }
59 
60 
62  0);
63 
64  av_bprint_finalize(&cur_line, NULL);
65 }
66 
67 static void ttml_new_line_cb(void *priv, int forced)
68 {
69  TTMLContext *s = priv;
70 
71  av_bprintf(&s->buffer, "<br/>");
72 }
73 
75  .text = ttml_text_cb,
76  .new_line = ttml_new_line_cb,
77 };
78 
79 static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
80  int bufsize, const AVSubtitle *sub)
81 {
82  TTMLContext *s = avctx->priv_data;
83  ASSDialog *dialog;
84  int i;
85 
86  av_bprint_init_for_buffer(&s->buffer, buf, bufsize);
87 
88  for (i=0; i<sub->num_rects; i++) {
89  const char *ass = sub->rects[i]->ass;
90  int ret;
91 
92  if (sub->rects[i]->type != SUBTITLE_ASS) {
93  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
94  return AVERROR(EINVAL);
95  }
96 
97  dialog = ff_ass_split_dialog(s->ass_ctx, ass);
98  if (!dialog)
99  return AVERROR(ENOMEM);
100 
101  if (dialog->style) {
102  av_bprintf(&s->buffer, "<span region=\"");
103  av_bprint_escape(&s->buffer, dialog->style, NULL,
106  av_bprintf(&s->buffer, "\">");
107  }
108 
110  if (ret < 0) {
111  int log_level = (ret != AVERROR_INVALIDDATA ||
112  avctx->err_recognition & AV_EF_EXPLODE) ?
114  av_log(avctx, log_level,
115  "Splitting received ASS dialog text %s failed: %s\n",
116  dialog->text,
117  av_err2str(ret));
118 
119  if (log_level == AV_LOG_ERROR) {
120  ff_ass_free_dialog(&dialog);
121  return ret;
122  }
123  }
124 
125  if (dialog->style)
126  av_bprintf(&s->buffer, "</span>");
127 
128  ff_ass_free_dialog(&dialog);
129  }
130 
131  if (!s->buffer.len)
132  return 0;
133  if (!av_bprint_is_complete(&s->buffer)) {
134  av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n");
136  }
137 
138  return s->buffer.len;
139 }
140 
142 {
143  TTMLContext *s = avctx->priv_data;
144 
145  ff_ass_split_free(s->ass_ctx);
146 
147  return 0;
148 }
149 
150 static const char *ttml_get_display_alignment(int alignment)
151 {
152  switch (alignment) {
153  case 1:
154  case 2:
155  case 3:
156  return "after";
157  case 4:
158  case 5:
159  case 6:
160  return "center";
161  case 7:
162  case 8:
163  case 9:
164  return "before";
165  default:
166  return NULL;
167  }
168 }
169 
170 static const char *ttml_get_text_alignment(int alignment)
171 {
172  switch (alignment) {
173  case 1:
174  case 4:
175  case 7:
176  return "left";
177  case 2:
178  case 5:
179  case 8:
180  return "center";
181  case 3:
182  case 6:
183  case 9:
184  return "right";
185  default:
186  return NULL;
187  }
188 }
189 
190 static void ttml_get_origin(ASSScriptInfo script_info, ASSStyle style,
191  int *origin_left, int *origin_top)
192 {
193  *origin_left = av_rescale(style.margin_l, 100, script_info.play_res_x);
194  *origin_top =
195  av_rescale((style.alignment >= 7) ? style.margin_v : 0,
196  100, script_info.play_res_y);
197 }
198 
199 static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style,
200  int *width, int *height)
201 {
202  *width = av_rescale(script_info.play_res_x - style.margin_r,
203  100, script_info.play_res_x);
204  *height = av_rescale((style.alignment <= 3) ?
205  script_info.play_res_y - style.margin_v :
206  script_info.play_res_y,
207  100, script_info.play_res_y);
208 }
209 
210 static int ttml_write_region(AVCodecContext *avctx, AVBPrint *buf,
211  ASSScriptInfo script_info, ASSStyle style)
212 {
213  const char *display_alignment = NULL;
214  const char *text_alignment = NULL;
215  int origin_left = 0;
216  int origin_top = 0;
217  int width = 0;
218  int height = 0;
219 
220  if (!style.name) {
221  av_log(avctx, AV_LOG_ERROR, "Subtitle style name not set!\n");
222  return AVERROR_INVALIDDATA;
223  }
224 
225  if (style.font_size < 0) {
226  av_log(avctx, AV_LOG_ERROR, "Invalid font size for TTML: %d!\n",
227  style.font_size);
228  return AVERROR_INVALIDDATA;
229  }
230 
231  if (style.margin_l < 0 || style.margin_r < 0 || style.margin_v < 0) {
232  av_log(avctx, AV_LOG_ERROR,
233  "One or more negative margin values in subtitle style: "
234  "left: %d, right: %d, vertical: %d!\n",
235  style.margin_l, style.margin_r, style.margin_v);
236  return AVERROR_INVALIDDATA;
237  }
238 
239  display_alignment = ttml_get_display_alignment(style.alignment);
241  if (!display_alignment || !text_alignment) {
242  av_log(avctx, AV_LOG_ERROR,
243  "Failed to convert ASS style alignment %d of style %s to "
244  "TTML display and text alignment!\n",
245  style.alignment,
246  style.name);
247  return AVERROR_INVALIDDATA;
248  }
249 
250  ttml_get_origin(script_info, style, &origin_left, &origin_top);
251  ttml_get_extent(script_info, style, &width, &height);
252 
253  av_bprintf(buf, " <region xml:id=\"");
256  av_bprintf(buf, "\"\n");
257 
258  av_bprintf(buf, " tts:origin=\"%d%% %d%%\"\n",
259  origin_left, origin_top);
260  av_bprintf(buf, " tts:extent=\"%d%% %d%%\"\n",
261  width, height);
262 
263  av_bprintf(buf, " tts:displayAlign=\"");
264  av_bprint_escape(buf, display_alignment, NULL, AV_ESCAPE_MODE_XML,
266  av_bprintf(buf, "\"\n");
267 
268  av_bprintf(buf, " tts:textAlign=\"");
271  av_bprintf(buf, "\"\n");
272 
273  // if we set cell resolution to our script reference resolution,
274  // then a single line is a single "point" on our canvas. Thus, by setting
275  // our font size to font size in cells, we should gain a similar enough
276  // scale without resorting to explicit pixel based font sizing, which is
277  // frowned upon in the TTML community.
278  av_bprintf(buf, " tts:fontSize=\"%dc\"\n",
279  style.font_size);
280 
281  if (style.font_name) {
282  av_bprintf(buf, " tts:fontFamily=\"");
285  av_bprintf(buf, "\"\n");
286  }
287 
288  av_bprintf(buf, " tts:overflow=\"visible\" />\n");
289 
290  return 0;
291 }
292 
294 {
295  TTMLContext *s = avctx->priv_data;
296  ASS *ass = (ASS *)s->ass_ctx;
297  ASSScriptInfo script_info = ass->script_info;
298  const size_t base_extradata_size = TTMLENC_EXTRADATA_SIGNATURE_SIZE + 1 +
300  size_t additional_extradata_size = 0;
301  int ret;
302 
303  if (script_info.play_res_x <= 0 || script_info.play_res_y <= 0) {
304  av_log(avctx, AV_LOG_ERROR,
305  "Invalid subtitle reference resolution %dx%d!\n",
306  script_info.play_res_x, script_info.play_res_y);
307  return AVERROR_INVALIDDATA;
308  }
309 
310  av_bprint_init(&s->buffer, 0, INT_MAX - base_extradata_size);
311 
312  // write the first string in extradata, attributes in the base "tt" element.
314  // the cell resolution is in character cells, so not exactly 1:1 against
315  // a pixel based resolution, but as the tts:extent in the root
316  // "tt" element is frowned upon (and disallowed in the EBU-TT profile),
317  // we mimic the reference resolution by setting it as the cell resolution.
318  av_bprintf(&s->buffer, " ttp:cellResolution=\"%d %d\"\n",
319  script_info.play_res_x, script_info.play_res_y);
320  av_bprint_chars(&s->buffer, '\0', 1);
321 
322  // write the second string in extradata, head element containing the styles
323  av_bprintf(&s->buffer, " <head>\n");
324  av_bprintf(&s->buffer, " <layout>\n");
325 
326  for (int i = 0; i < ass->styles_count; i++) {
327  ret = ttml_write_region(avctx, &s->buffer, script_info,
328  ass->styles[i]);
329  if (ret < 0)
330  goto fail;
331  }
332 
333  av_bprintf(&s->buffer, " </layout>\n");
334  av_bprintf(&s->buffer, " </head>\n");
335  av_bprint_chars(&s->buffer, '\0', 1);
336 
337  if (!av_bprint_is_complete(&s->buffer)) {
338  ret = AVERROR(ENOMEM);
339  goto fail;
340  }
341 
342  additional_extradata_size = s->buffer.len;
343 
344  if (!(avctx->extradata =
345  av_mallocz(base_extradata_size + additional_extradata_size))) {
346  ret = AVERROR(ENOMEM);
347  goto fail;
348  }
349 
350  avctx->extradata_size =
351  TTMLENC_EXTRADATA_SIGNATURE_SIZE + additional_extradata_size;
352  memcpy(avctx->extradata, TTMLENC_EXTRADATA_SIGNATURE,
354 
356  s->buffer.str, additional_extradata_size);
357 
358  ret = 0;
359 fail:
360  av_bprint_finalize(&s->buffer, NULL);
361 
362  return ret;
363 }
364 
366 {
367  TTMLContext *s = avctx->priv_data;
368  int ret = AVERROR_BUG;
369  s->avctx = avctx;
370 
371  if (!(s->ass_ctx = ff_ass_split(avctx->subtitle_header))) {
372  return AVERROR_INVALIDDATA;
373  }
374 
375  if ((ret = ttml_write_header_content(avctx)) < 0) {
376  return ret;
377  }
378 
379  return 0;
380 }
381 
383  .p.name = "ttml",
384  CODEC_LONG_NAME("TTML subtitle"),
385  .p.type = AVMEDIA_TYPE_SUBTITLE,
386  .p.id = AV_CODEC_ID_TTML,
387  .priv_data_size = sizeof(TTMLContext),
390  .close = ttml_encode_close,
391  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
392 };
AVSubtitle
Definition: avcodec.h:2228
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:2233
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:2232
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:382
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:126
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Definition: avcodec.h:1892
ttml_get_extent
static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style, int *width, int *height)
Definition: ttmlenc.c:199
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:2196
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:44
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:130
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:185
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:39
ttml_write_header_content
static int ttml_write_header_content(AVCodecContext *avctx)
Definition: ttmlenc.c:293
AVSubtitleRect::ass
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2225
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:190
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:271
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:74
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:67
ttml_encode_frame
static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, int bufsize, const AVSubtitle *sub)
Definition: ttmlenc.c:79
ASSScriptInfo
fields extracted from the [Script Info] section
Definition: ass_split.h:28
TTMLContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: ttmlenc.c:40
FF_CODEC_ENCODE_SUB_CB
#define FF_CODEC_ENCODE_SUB_CB(func)
Definition: codec_internal.h:298
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:366
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:38
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:122
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:365
AVSubtitleRect::type
enum AVSubtitleType type
Definition: avcodec.h:2216
height
#define height
ttml_get_text_alignment
static const char * ttml_get_text_alignment(int alignment)
Definition: ttmlenc.c:170
text_alignment
text_alignment
Definition: vf_drawtext.c:175
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
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:574
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:256
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:41
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:210
ttmlenc.h
mem.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:150
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:141
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