FFmpeg
srtenc.c
Go to the documentation of this file.
1 /*
2  * SubRip subtitle encoder
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 "config_components.h"
23 
24 #include <stdarg.h>
25 #include "avcodec.h"
26 #include "libavutil/avstring.h"
27 #include "libavutil/bprint.h"
28 #include "ass_split.h"
29 #include "ass.h"
30 #include "codec_internal.h"
31 
32 
33 #define SRT_STACK_SIZE 64
34 
35 typedef struct {
38  AVBPrint buffer;
39  char stack[SRT_STACK_SIZE];
40  int stack_ptr;
42 } SRTContext;
43 
44 
45 #ifdef __GNUC__
46 __attribute__ ((__format__ (__printf__, 2, 3)))
47 #endif
48 static void srt_print(SRTContext *s, const char *str, ...)
49 {
50  va_list vargs;
51  va_start(vargs, str);
52  av_vbprintf(&s->buffer, str, vargs);
53  va_end(vargs);
54 }
55 
56 static int srt_stack_push(SRTContext *s, const char c)
57 {
58  if (s->stack_ptr >= SRT_STACK_SIZE)
59  return -1;
60  s->stack[s->stack_ptr++] = c;
61  return 0;
62 }
63 
64 static char srt_stack_pop(SRTContext *s)
65 {
66  if (s->stack_ptr <= 0)
67  return 0;
68  return s->stack[--s->stack_ptr];
69 }
70 
71 static int srt_stack_find(SRTContext *s, const char c)
72 {
73  int i;
74  for (i = s->stack_ptr-1; i >= 0; i--)
75  if (s->stack[i] == c)
76  break;
77  return i;
78 }
79 
80 static void srt_close_tag(SRTContext *s, char tag)
81 {
82  srt_print(s, "</%c%s>", tag, tag == 'f' ? "ont" : "");
83 }
84 
85 static void srt_stack_push_pop(SRTContext *s, const char c, int close)
86 {
87  if (close) {
88  int i = c ? srt_stack_find(s, c) : 0;
89  if (i < 0)
90  return;
91  while (s->stack_ptr != i)
93  } else if (srt_stack_push(s, c) < 0)
94  av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
95 }
96 
97 static void srt_style_apply(SRTContext *s, const char *style)
98 {
99  ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
100  if (st) {
101  int c = st->primary_color & 0xFFFFFF;
102  if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT) ||
104  c != ASS_DEFAULT_COLOR) {
105  srt_print(s, "<font");
106  if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT))
107  srt_print(s, " face=\"%s\"", st->font_name);
108  if (st->font_size != ASS_DEFAULT_FONT_SIZE)
109  srt_print(s, " size=\"%d\"", st->font_size);
110  if (c != ASS_DEFAULT_COLOR)
111  srt_print(s, " color=\"#%06x\"",
112  (c & 0xFF0000) >> 16 | c & 0xFF00 | (c & 0xFF) << 16);
113  srt_print(s, ">");
114  srt_stack_push(s, 'f');
115  }
116  if (st->bold != ASS_DEFAULT_BOLD) {
117  srt_print(s, "<b>");
118  srt_stack_push(s, 'b');
119  }
120  if (st->italic != ASS_DEFAULT_ITALIC) {
121  srt_print(s, "<i>");
122  srt_stack_push(s, 'i');
123  }
124  if (st->underline != ASS_DEFAULT_UNDERLINE) {
125  srt_print(s, "<u>");
126  srt_stack_push(s, 'u');
127  }
128  if (st->alignment != ASS_DEFAULT_ALIGNMENT) {
129  srt_print(s, "{\\an%d}", st->alignment);
130  s->alignment_applied = 1;
131  }
132  }
133 }
134 
135 
137 {
138  SRTContext *s = avctx->priv_data;
139  s->avctx = avctx;
140  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
142  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
143 }
144 
145 static void srt_text_cb(void *priv, const char *text, int len)
146 {
147  SRTContext *s = priv;
148  av_bprint_append_data(&s->buffer, text, len);
149 }
150 
151 static void srt_new_line_cb(void *priv, int forced)
152 {
153  srt_print(priv, "\r\n");
154 }
155 
156 static void srt_style_cb(void *priv, char style, int close)
157 {
158  srt_stack_push_pop(priv, style, close);
159  if (!close)
160  srt_print(priv, "<%c>", style);
161 }
162 
163 static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
164 {
165  if (color_id > 1)
166  return;
167  srt_stack_push_pop(priv, 'f', color == 0xFFFFFFFF);
168  if (color != 0xFFFFFFFF)
169  srt_print(priv, "<font color=\"#%06x\">",
170  (color & 0xFF0000) >> 16 | color & 0xFF00 | (color & 0xFF) << 16);
171 }
172 
173 static void srt_font_name_cb(void *priv, const char *name)
174 {
175  srt_stack_push_pop(priv, 'f', !name);
176  if (name)
177  srt_print(priv, "<font face=\"%s\">", name);
178 }
179 
180 static void srt_font_size_cb(void *priv, int size)
181 {
182  srt_stack_push_pop(priv, 'f', size < 0);
183  if (size >= 0)
184  srt_print(priv, "<font size=\"%d\">", size);
185 }
186 
187 static void srt_alignment_cb(void *priv, int alignment)
188 {
189  SRTContext *s = priv;
190  if (!s->alignment_applied && alignment >= 0) {
191  srt_print(s, "{\\an%d}", alignment);
192  s->alignment_applied = 1;
193  }
194 }
195 
196 static void srt_cancel_overrides_cb(void *priv, const char *style)
197 {
198  srt_stack_push_pop(priv, 0, 1);
199  srt_style_apply(priv, style);
200 }
201 
202 static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2,
203  int t1, int t2)
204 {
205  // TODO: add a AV_PKT_DATA_SUBTITLE_POSITION side data when a new subtitles
206  // encoding API passing the AVPacket is available.
207 }
208 
209 static void srt_end_cb(void *priv)
210 {
211  srt_stack_push_pop(priv, 0, 1);
212 }
213 
215  .text = srt_text_cb,
216  .new_line = srt_new_line_cb,
217  .style = srt_style_cb,
218  .color = srt_color_cb,
219  .font_name = srt_font_name_cb,
220  .font_size = srt_font_size_cb,
221  .alignment = srt_alignment_cb,
222  .cancel_overrides = srt_cancel_overrides_cb,
223  .move = srt_move_cb,
224  .end = srt_end_cb,
225 };
226 
228  .text = srt_text_cb,
229  .new_line = srt_new_line_cb,
230 };
231 
232 static int encode_frame(AVCodecContext *avctx,
233  unsigned char *buf, int bufsize, const AVSubtitle *sub,
234  const ASSCodesCallbacks *cb)
235 {
236  SRTContext *s = avctx->priv_data;
237  ASSDialog *dialog;
238  int i;
239 
240  av_bprint_clear(&s->buffer);
241 
242  for (i=0; i<sub->num_rects; i++) {
243  const char *ass = sub->rects[i]->ass;
244 
245  if (sub->rects[i]->type != SUBTITLE_ASS) {
246  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
247  return AVERROR(EINVAL);
248  }
249 
250  dialog = ff_ass_split_dialog(s->ass_ctx, ass);
251  if (!dialog)
252  return AVERROR(ENOMEM);
253  s->alignment_applied = 0;
254  if (avctx->codec_id == AV_CODEC_ID_SUBRIP)
255  srt_style_apply(s, dialog->style);
257  ff_ass_free_dialog(&dialog);
258  }
259 
260  if (!av_bprint_is_complete(&s->buffer))
261  return AVERROR(ENOMEM);
262  if (!s->buffer.len)
263  return 0;
264 
265  if (s->buffer.len > bufsize) {
266  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
268  }
269  memcpy(buf, s->buffer.str, s->buffer.len);
270 
271  return s->buffer.len;
272 }
273 
275  unsigned char *buf, int bufsize, const AVSubtitle *sub)
276 {
277  return encode_frame(avctx, buf, bufsize, sub, &srt_callbacks);
278 }
279 
281  unsigned char *buf, int bufsize, const AVSubtitle *sub)
282 {
283  return encode_frame(avctx, buf, bufsize, sub, &text_callbacks);
284 }
285 
287 {
288  SRTContext *s = avctx->priv_data;
289  ff_ass_split_free(s->ass_ctx);
290  av_bprint_finalize(&s->buffer, NULL);
291  return 0;
292 }
293 
294 #if CONFIG_SRT_ENCODER
295 /* deprecated encoder */
296 const FFCodec ff_srt_encoder = {
297  .p.name = "srt",
298  .p.long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
299  .p.type = AVMEDIA_TYPE_SUBTITLE,
300  .p.id = AV_CODEC_ID_SUBRIP,
301  .priv_data_size = sizeof(SRTContext),
304  .close = srt_encode_close,
305  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
306 };
307 #endif
308 
309 #if CONFIG_SUBRIP_ENCODER
310 const FFCodec ff_subrip_encoder = {
311  .p.name = "subrip",
312  .p.long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
313  .p.type = AVMEDIA_TYPE_SUBTITLE,
314  .p.id = AV_CODEC_ID_SUBRIP,
315  .priv_data_size = sizeof(SRTContext),
318  .close = srt_encode_close,
319  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
320 };
321 #endif
322 
323 #if CONFIG_TEXT_ENCODER
324 const FFCodec ff_text_encoder = {
325  .p.name = "text",
326  .p.long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
327  .p.type = AVMEDIA_TYPE_SUBTITLE,
328  .p.id = AV_CODEC_ID_TEXT,
329  .priv_data_size = sizeof(SRTContext),
332  .close = srt_encode_close,
333  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
334 };
335 #endif
srt_new_line_cb
static void srt_new_line_cb(void *priv, int forced)
Definition: srtenc.c:151
AVSubtitle
Definition: avcodec.h:2305
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
srt_stack_find
static int srt_stack_find(SRTContext *s, const char c)
Definition: srtenc.c:71
ASSCodesCallbacks
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:138
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
srt_stack_push_pop
static void srt_stack_push_pop(SRTContext *s, const char c, int close)
Definition: srtenc.c:85
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
color
Definition: vf_paletteuse.c:600
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
cb
static double cb(void *priv, double x, double y)
Definition: vf_geq.c:239
text_callbacks
static const ASSCodesCallbacks text_callbacks
Definition: srtenc.c:227
sub
static float sub(float src0, float src1)
Definition: dnn_backend_native_layer_mathbinary.c:31
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
SRT_STACK_SIZE
#define SRT_STACK_SIZE
Definition: srtenc.c:33
srt_alignment_cb
static void srt_alignment_cb(void *priv, int alignment)
Definition: srtenc.c:187
SRTContext
Definition: srtenc.c:35
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
ASS_DEFAULT_ALIGNMENT
#define ASS_DEFAULT_ALIGNMENT
Definition: ass.h:42
ASSStyle::font_size
int font_size
font height
Definition: ass_split.h:42
FFCodec
Definition: codec_internal.h:112
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:1705
t1
#define t1
Definition: regdef.h:29
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
srt_encode_init
static av_cold int srt_encode_init(AVCodecContext *avctx)
Definition: srtenc.c:136
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:2272
init
static int init
Definition: av_tx.c:47
srt_encode_frame
static int srt_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: srtenc.c:274
ASSStyle::font_name
char * font_name
font face (case sensitive)
Definition: ass_split.h:41
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
ass_split.h
ff_srt_encoder
const FFCodec ff_srt_encoder
AVERROR_BUFFER_TOO_SMALL
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:53
srt_stack_pop
static char srt_stack_pop(SRTContext *s)
Definition: srtenc.c:64
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
ASS_DEFAULT_FONT
#define ASS_DEFAULT_FONT
Definition: ass.h:35
av_cold
#define av_cold
Definition: attributes.h:90
SRTContext::alignment_applied
int alignment_applied
Definition: srtenc.c:41
s
#define s(width, name)
Definition: cbs_vp9.c:256
ff_text_encoder
const FFCodec ff_text_encoder
SRTContext::stack_ptr
int stack_ptr
Definition: srtenc.c:40
srt_font_size_cb
static void srt_font_size_cb(void *priv, int size)
Definition: srtenc.c:180
AVCodecContext::codec_id
enum AVCodecID codec_id
Definition: avcodec.h:399
av_vbprintf
void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
Append a formatted string to a print buffer.
Definition: bprint.c:117
NULL
#define NULL
Definition: coverity.c:32
ASSStyle::primary_color
int primary_color
color that a subtitle will normally appear in
Definition: ass_split.h:43
srt_stack_push
static int srt_stack_push(SRTContext *s, const char c)
Definition: srtenc.c:56
srt_encode_close
static int srt_encode_close(AVCodecContext *avctx)
Definition: srtenc.c:286
FF_CODEC_ENCODE_SUB_CB
#define FF_CODEC_ENCODE_SUB_CB(func)
Definition: codec_internal.h:266
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
srt_cancel_overrides_cb
static void srt_cancel_overrides_cb(void *priv, const char *style)
Definition: srtenc.c:196
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ASSStyle
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
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:185
srt_close_tag
static void srt_close_tag(SRTContext *s, char tag)
Definition: srtenc.c:80
ASSStyle::underline
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
ff_ass_split_free
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:470
ASS_DEFAULT_BOLD
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
SRTContext::avctx
AVCodecContext * avctx
Definition: srtenc.c:36
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
SRTContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: srtenc.c:37
size
int size
Definition: twinvq_data.h:10344
srt_move_cb
static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, int t1, int t2)
Definition: srtenc.c:202
ASSStyle::italic
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:48
encode_frame
static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub, const ASSCodesCallbacks *cb)
Definition: srtenc.c:232
srt_color_cb
static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
Definition: srtenc.c:163
ASS_DEFAULT_UNDERLINE
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
ff_ass_style_get
ASSStyle * ff_ass_style_get(ASSSplitContext *ctx, const char *style)
Find an ASSStyle structure by its name.
Definition: ass_split.c:578
bprint.h
srt_style_apply
static void srt_style_apply(SRTContext *s, const char *style)
Definition: srtenc.c:97
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AV_CODEC_ID_SUBRIP
@ AV_CODEC_ID_SUBRIP
Definition: codec_id.h:544
srt_print
static void srt_print(SRTContext *s, const char *str,...)
Definition: srtenc.c:48
ff_subrip_encoder
const FFCodec ff_subrip_encoder
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: codec_internal.h:31
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
ASS_DEFAULT_ITALIC
#define ASS_DEFAULT_ITALIC
Definition: ass.h:40
len
int len
Definition: vorbis_enc_data.h:426
ASS_DEFAULT_COLOR
#define ASS_DEFAULT_COLOR
Definition: ass.h:37
avcodec.h
tag
uint32_t tag
Definition: movenc.c:1646
SRTContext::buffer
AVBPrint buffer
Definition: srtenc.c:38
AV_CODEC_ID_TEXT
@ AV_CODEC_ID_TEXT
raw UTF-8 text
Definition: codec_id.h:529
srt_end_cb
static void srt_end_cb(void *priv)
Definition: srtenc.c:209
ASS_DEFAULT_FONT_SIZE
#define ASS_DEFAULT_FONT_SIZE
Definition: ass.h:36
AVCodecContext
main external API structure.
Definition: avcodec.h:389
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
t2
#define t2
Definition: regdef.h:30
srt_style_cb
static void srt_style_cb(void *priv, char style, int close)
Definition: srtenc.c:156
ASSDialog
fields extracted from the [Events] section
Definition: ass_split.h:71
srt_text_cb
static void srt_text_cb(void *priv, const char *text, int len)
Definition: srtenc.c:145
srt_font_name_cb
static void srt_font_name_cb(void *priv, const char *name)
Definition: srtenc.c:173
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
convert_header.str
string str
Definition: convert_header.py:20
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
srt_callbacks
static const ASSCodesCallbacks srt_callbacks
Definition: srtenc.c:214
avstring.h
text_encode_frame
static int text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: srtenc.c:280
ASSStyle::bold
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:47
ASSCodesCallbacks::text
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:143