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/avstring.h"
33 #include "libavutil/bprint.h"
34 #include "libavutil/internal.h"
35 #include "ass_split.h"
36 #include "ass.h"
37 #include "ttmlenc.h"
38 
39 typedef struct {
42  AVBPrint buffer;
43 } TTMLContext;
44 
45 static void ttml_text_cb(void *priv, const char *text, int len)
46 {
47  TTMLContext *s = priv;
48  AVBPrint cur_line = { 0 };
49  AVBPrint *buffer = &s->buffer;
50 
52 
53  av_bprint_append_data(&cur_line, text, len);
54  if (!av_bprint_is_complete(&cur_line)) {
55  av_log(s->avctx, AV_LOG_ERROR,
56  "Failed to move the current subtitle dialog to AVBPrint!\n");
57  av_bprint_finalize(&cur_line, NULL);
58  return;
59  }
60 
61 
63  0);
64 
65  av_bprint_finalize(&cur_line, NULL);
66 }
67 
68 static void ttml_new_line_cb(void *priv, int forced)
69 {
70  TTMLContext *s = priv;
71 
72  av_bprintf(&s->buffer, "<br/>");
73 }
74 
76  .text = ttml_text_cb,
77  .new_line = ttml_new_line_cb,
78 };
79 
80 static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
81  int bufsize, const AVSubtitle *sub)
82 {
83  TTMLContext *s = avctx->priv_data;
84  ASSDialog *dialog;
85  int i;
86 
87  av_bprint_clear(&s->buffer);
88 
89  for (i=0; i<sub->num_rects; i++) {
90  const char *ass = sub->rects[i]->ass;
91  int ret;
92 
93  if (sub->rects[i]->type != SUBTITLE_ASS) {
94  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
95  return AVERROR(EINVAL);
96  }
97 
98  dialog = ff_ass_split_dialog(s->ass_ctx, ass);
99  if (!dialog)
100  return AVERROR(ENOMEM);
101 
102  if (dialog->style) {
103  av_bprintf(&s->buffer, "<span region=\"");
104  av_bprint_escape(&s->buffer, dialog->style, NULL,
107  av_bprintf(&s->buffer, "\">");
108  }
109 
111  if (ret < 0) {
112  int log_level = (ret != AVERROR_INVALIDDATA ||
113  avctx->err_recognition & AV_EF_EXPLODE) ?
115  av_log(avctx, log_level,
116  "Splitting received ASS dialog text %s failed: %s\n",
117  dialog->text,
118  av_err2str(ret));
119 
120  if (log_level == AV_LOG_ERROR) {
121  ff_ass_free_dialog(&dialog);
122  return ret;
123  }
124  }
125 
126  if (dialog->style)
127  av_bprintf(&s->buffer, "</span>");
128 
129  ff_ass_free_dialog(&dialog);
130  }
131 
132  if (!av_bprint_is_complete(&s->buffer))
133  return AVERROR(ENOMEM);
134  if (!s->buffer.len)
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) {
140  av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n");
142  }
143 
144  return s->buffer.len;
145 }
146 
148 {
149  TTMLContext *s = avctx->priv_data;
150 
151  ff_ass_split_free(s->ass_ctx);
152 
153  av_bprint_finalize(&s->buffer, NULL);
154 
155  return 0;
156 }
157 
158 static const char *ttml_get_display_alignment(int alignment)
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:
174  return NULL;
175  }
176 }
177 
178 static const char *ttml_get_text_alignment(int alignment)
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:
194  return NULL;
195  }
196 }
197 
198 static void ttml_get_origin(ASSScriptInfo script_info, ASSStyle style,
199  int *origin_left, int *origin_top)
200 {
201  *origin_left = av_rescale(style.margin_l, 100, script_info.play_res_x);
202  *origin_top =
203  av_rescale((style.alignment >= 7) ? style.margin_v : 0,
204  100, script_info.play_res_y);
205 }
206 
207 static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style,
208  int *width, int *height)
209 {
210  *width = av_rescale(script_info.play_res_x - style.margin_r,
211  100, script_info.play_res_x);
212  *height = av_rescale((style.alignment <= 3) ?
213  script_info.play_res_y - style.margin_v :
214  script_info.play_res_y,
215  100, script_info.play_res_y);
216 }
217 
218 static int ttml_write_region(AVCodecContext *avctx, AVBPrint *buf,
219  ASSScriptInfo script_info, ASSStyle style)
220 {
221  const char *display_alignment = NULL;
222  const char *text_alignment = NULL;
223  int origin_left = 0;
224  int origin_top = 0;
225  int width = 0;
226  int height = 0;
227 
228  if (!style.name) {
229  av_log(avctx, AV_LOG_ERROR, "Subtitle style name not set!\n");
230  return AVERROR_INVALIDDATA;
231  }
232 
233  if (style.font_size < 0) {
234  av_log(avctx, AV_LOG_ERROR, "Invalid font size for TTML: %d!\n",
235  style.font_size);
236  return AVERROR_INVALIDDATA;
237  }
238 
239  if (style.margin_l < 0 || style.margin_r < 0 || style.margin_v < 0) {
240  av_log(avctx, AV_LOG_ERROR,
241  "One or more negative margin values in subtitle style: "
242  "left: %d, right: %d, vertical: %d!\n",
243  style.margin_l, style.margin_r, style.margin_v);
244  return AVERROR_INVALIDDATA;
245  }
246 
247  display_alignment = ttml_get_display_alignment(style.alignment);
248  text_alignment = ttml_get_text_alignment(style.alignment);
249  if (!display_alignment || !text_alignment) {
250  av_log(avctx, AV_LOG_ERROR,
251  "Failed to convert ASS style alignment %d of style %s to "
252  "TTML display and text alignment!\n",
253  style.alignment,
254  style.name);
255  return AVERROR_INVALIDDATA;
256  }
257 
258  ttml_get_origin(script_info, style, &origin_left, &origin_top);
259  ttml_get_extent(script_info, style, &width, &height);
260 
261  av_bprintf(buf, " <region xml:id=\"");
264  av_bprintf(buf, "\"\n");
265 
266  av_bprintf(buf, " tts:origin=\"%d%% %d%%\"\n",
267  origin_left, origin_top);
268  av_bprintf(buf, " tts:extent=\"%d%% %d%%\"\n",
269  width, height);
270 
271  av_bprintf(buf, " tts:displayAlign=\"");
272  av_bprint_escape(buf, display_alignment, NULL, AV_ESCAPE_MODE_XML,
274  av_bprintf(buf, "\"\n");
275 
276  av_bprintf(buf, " tts:textAlign=\"");
277  av_bprint_escape(buf, text_alignment, NULL, AV_ESCAPE_MODE_XML,
279  av_bprintf(buf, "\"\n");
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.
286  av_bprintf(buf, " tts:fontSize=\"%dc\"\n",
287  style.font_size);
288 
289  if (style.font_name) {
290  av_bprintf(buf, " tts:fontFamily=\"");
293  av_bprintf(buf, "\"\n");
294  }
295 
296  av_bprintf(buf, " tts:overflow=\"visible\" />\n");
297 
298  return 0;
299 }
300 
302 {
303  TTMLContext *s = avctx->priv_data;
304  ASS *ass = (ASS *)s->ass_ctx;
305  ASSScriptInfo script_info = ass->script_info;
306  const size_t base_extradata_size = TTMLENC_EXTRADATA_SIGNATURE_SIZE + 1 +
308  size_t additional_extradata_size = 0;
309 
310  if (script_info.play_res_x <= 0 || script_info.play_res_y <= 0) {
311  av_log(avctx, AV_LOG_ERROR,
312  "Invalid subtitle reference resolution %dx%d!\n",
313  script_info.play_res_x, script_info.play_res_y);
314  return AVERROR_INVALIDDATA;
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);
325  av_bprint_chars(&s->buffer, '\0', 1);
326 
327  // write the second string in extradata, head element containing the styles
328  av_bprintf(&s->buffer, " <head>\n");
329  av_bprintf(&s->buffer, " <layout>\n");
330 
331  for (int i = 0; i < ass->styles_count; i++) {
332  int ret = ttml_write_region(avctx, &s->buffer, script_info,
333  ass->styles[i]);
334  if (ret < 0)
335  return ret;
336  }
337 
338  av_bprintf(&s->buffer, " </layout>\n");
339  av_bprintf(&s->buffer, " </head>\n");
340  av_bprint_chars(&s->buffer, '\0', 1);
341 
342  if (!av_bprint_is_complete(&s->buffer)) {
343  return AVERROR(ENOMEM);
344  }
345 
346  additional_extradata_size = s->buffer.len;
347 
348  if (!(avctx->extradata =
349  av_mallocz(base_extradata_size + additional_extradata_size))) {
350  return AVERROR(ENOMEM);
351  }
352 
353  avctx->extradata_size =
354  TTMLENC_EXTRADATA_SIGNATURE_SIZE + additional_extradata_size;
355  memcpy(avctx->extradata, TTMLENC_EXTRADATA_SIGNATURE,
357 
358  if (additional_extradata_size)
360  s->buffer.str, additional_extradata_size);
361 
362  av_bprint_clear(&s->buffer);
363 
364  return 0;
365 }
366 
368 {
369  TTMLContext *s = avctx->priv_data;
370  int ret = AVERROR_BUG;
371  s->avctx = avctx;
372 
374 
375  if (!(s->ass_ctx = ff_ass_split(avctx->subtitle_header))) {
376  return AVERROR_INVALIDDATA;
377  }
378 
379  if ((ret = ttml_write_header_content(avctx)) < 0) {
380  return ret;
381  }
382 
383  return 0;
384 }
385 
387  .p.name = "ttml",
388  CODEC_LONG_NAME("TTML subtitle"),
389  .p.type = AVMEDIA_TYPE_SUBTITLE,
390  .p.id = AV_CODEC_ID_TTML,
391  .priv_data_size = sizeof(TTMLContext),
394  .close = ttml_encode_close,
395  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
396 };
AVSubtitle
Definition: avcodec.h:2330
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:215
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
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
sub
static float sub(float src0, float src1)
Definition: dnn_backend_native_layer_mathbinary.c:31
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:1382
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:386
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
Header containing style information for text subtitles.
Definition: avcodec.h:1723
ttml_get_extent
static void ttml_get_extent(ASSScriptInfo script_info, ASSStyle style, int *width, int *height)
Definition: ttmlenc.c:207
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:2297
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:45
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
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:40
ttml_write_header_content
static int ttml_write_header_content(AVCodecContext *avctx)
Definition: ttmlenc.c:301
TTMLENC_EXTRADATA_SIGNATURE
#define TTMLENC_EXTRADATA_SIGNATURE
Definition: ttmlenc.h:25
ass.h
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:198
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:349
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:528
width
#define width
s
#define s(width, name)
Definition: cbs_vp9.c:256
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
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:75
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:263
ttml_new_line_cb
static void ttml_new_line_cb(void *priv, int forced)
Definition: ttmlenc.c:68
ttml_encode_frame
static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, int bufsize, const AVSubtitle *sub)
Definition: ttmlenc.c:80
ASSScriptInfo
fields extracted from the [Script Info] section
Definition: ass_split.h:28
TTMLContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: ttmlenc.c:41
FF_CODEC_ENCODE_SUB_CB
#define FF_CODEC_ENCODE_SUB_CB(func)
Definition: codec_internal.h:318
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
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:39
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
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:319
ttml_encode_init
static av_cold int ttml_encode_init(AVCodecContext *avctx)
Definition: ttmlenc.c:367
height
#define height
ttml_get_text_alignment
static const char * ttml_get_text_alignment(int alignment)
Definition: ttmlenc.c:178
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:527
internal.h
AV_CODEC_ID_TTML
@ AV_CODEC_ID_TTML
Definition: codec_id.h:568
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:191
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:94
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
TTMLContext::buffer
AVBPrint buffer
Definition: ttmlenc.c:42
AVCodecContext
main external API structure.
Definition: avcodec.h:426
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
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
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:218
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:158
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:453
ttml_encode_close
static av_cold int ttml_encode_close(AVCodecContext *avctx)
Definition: ttmlenc.c:147
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:86
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:140
avstring.h
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:158
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