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 <stdarg.h>
23 #include "avcodec.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/bprint.h"
26 #include "ass_split.h"
27 #include "ass.h"
28 
29 
30 #define SRT_STACK_SIZE 64
31 
32 typedef struct {
35  AVBPrint buffer;
36  char stack[SRT_STACK_SIZE];
37  int stack_ptr;
39 } SRTContext;
40 
41 
42 #ifdef __GNUC__
43 __attribute__ ((__format__ (__printf__, 2, 3)))
44 #endif
45 static void srt_print(SRTContext *s, const char *str, ...)
46 {
47  va_list vargs;
48  va_start(vargs, str);
49  av_vbprintf(&s->buffer, str, vargs);
50  va_end(vargs);
51 }
52 
53 static int srt_stack_push(SRTContext *s, const char c)
54 {
55  if (s->stack_ptr >= SRT_STACK_SIZE)
56  return -1;
57  s->stack[s->stack_ptr++] = c;
58  return 0;
59 }
60 
61 static char srt_stack_pop(SRTContext *s)
62 {
63  if (s->stack_ptr <= 0)
64  return 0;
65  return s->stack[--s->stack_ptr];
66 }
67 
68 static int srt_stack_find(SRTContext *s, const char c)
69 {
70  int i;
71  for (i = s->stack_ptr-1; i >= 0; i--)
72  if (s->stack[i] == c)
73  break;
74  return i;
75 }
76 
77 static void srt_close_tag(SRTContext *s, char tag)
78 {
79  srt_print(s, "</%c%s>", tag, tag == 'f' ? "ont" : "");
80 }
81 
82 static void srt_stack_push_pop(SRTContext *s, const char c, int close)
83 {
84  if (close) {
85  int i = c ? srt_stack_find(s, c) : 0;
86  if (i < 0)
87  return;
88  while (s->stack_ptr != i)
90  } else if (srt_stack_push(s, c) < 0)
91  av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
92 }
93 
94 static void srt_style_apply(SRTContext *s, const char *style)
95 {
96  ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
97  if (st) {
98  int c = st->primary_color & 0xFFFFFF;
99  if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT) ||
101  c != ASS_DEFAULT_COLOR) {
102  srt_print(s, "<font");
103  if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT))
104  srt_print(s, " face=\"%s\"", st->font_name);
105  if (st->font_size != ASS_DEFAULT_FONT_SIZE)
106  srt_print(s, " size=\"%d\"", st->font_size);
107  if (c != ASS_DEFAULT_COLOR)
108  srt_print(s, " color=\"#%06x\"",
109  (c & 0xFF0000) >> 16 | c & 0xFF00 | (c & 0xFF) << 16);
110  srt_print(s, ">");
111  srt_stack_push(s, 'f');
112  }
113  if (st->bold != ASS_DEFAULT_BOLD) {
114  srt_print(s, "<b>");
115  srt_stack_push(s, 'b');
116  }
117  if (st->italic != ASS_DEFAULT_ITALIC) {
118  srt_print(s, "<i>");
119  srt_stack_push(s, 'i');
120  }
121  if (st->underline != ASS_DEFAULT_UNDERLINE) {
122  srt_print(s, "<u>");
123  srt_stack_push(s, 'u');
124  }
125  if (st->alignment != ASS_DEFAULT_ALIGNMENT) {
126  srt_print(s, "{\\an%d}", st->alignment);
127  s->alignment_applied = 1;
128  }
129  }
130 }
131 
132 
134 {
135  SRTContext *s = avctx->priv_data;
136  s->avctx = avctx;
137  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
139  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
140 }
141 
142 static void srt_text_cb(void *priv, const char *text, int len)
143 {
144  SRTContext *s = priv;
145  av_bprint_append_data(&s->buffer, text, len);
146 }
147 
148 static void srt_new_line_cb(void *priv, int forced)
149 {
150  srt_print(priv, "\r\n");
151 }
152 
153 static void srt_style_cb(void *priv, char style, int close)
154 {
155  srt_stack_push_pop(priv, style, close);
156  if (!close)
157  srt_print(priv, "<%c>", style);
158 }
159 
160 static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
161 {
162  if (color_id > 1)
163  return;
164  srt_stack_push_pop(priv, 'f', color == 0xFFFFFFFF);
165  if (color != 0xFFFFFFFF)
166  srt_print(priv, "<font color=\"#%06x\">",
167  (color & 0xFF0000) >> 16 | color & 0xFF00 | (color & 0xFF) << 16);
168 }
169 
170 static void srt_font_name_cb(void *priv, const char *name)
171 {
172  srt_stack_push_pop(priv, 'f', !name);
173  if (name)
174  srt_print(priv, "<font face=\"%s\">", name);
175 }
176 
177 static void srt_font_size_cb(void *priv, int size)
178 {
179  srt_stack_push_pop(priv, 'f', size < 0);
180  if (size >= 0)
181  srt_print(priv, "<font size=\"%d\">", size);
182 }
183 
184 static void srt_alignment_cb(void *priv, int alignment)
185 {
186  SRTContext *s = priv;
187  if (!s->alignment_applied && alignment >= 0) {
188  srt_print(s, "{\\an%d}", alignment);
189  s->alignment_applied = 1;
190  }
191 }
192 
193 static void srt_cancel_overrides_cb(void *priv, const char *style)
194 {
195  srt_stack_push_pop(priv, 0, 1);
196  srt_style_apply(priv, style);
197 }
198 
199 static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2,
200  int t1, int t2)
201 {
202  // TODO: add a AV_PKT_DATA_SUBTITLE_POSITION side data when a new subtitles
203  // encoding API passing the AVPacket is available.
204 }
205 
206 static void srt_end_cb(void *priv)
207 {
208  srt_stack_push_pop(priv, 0, 1);
209 }
210 
212  .text = srt_text_cb,
213  .new_line = srt_new_line_cb,
214  .style = srt_style_cb,
215  .color = srt_color_cb,
216  .font_name = srt_font_name_cb,
217  .font_size = srt_font_size_cb,
218  .alignment = srt_alignment_cb,
219  .cancel_overrides = srt_cancel_overrides_cb,
220  .move = srt_move_cb,
221  .end = srt_end_cb,
222 };
223 
225  .text = srt_text_cb,
226  .new_line = srt_new_line_cb,
227 };
228 
229 static int encode_frame(AVCodecContext *avctx,
230  unsigned char *buf, int bufsize, const AVSubtitle *sub,
231  const ASSCodesCallbacks *cb)
232 {
233  SRTContext *s = avctx->priv_data;
234  ASSDialog *dialog;
235  int i;
236 
237  av_bprint_clear(&s->buffer);
238 
239  for (i=0; i<sub->num_rects; i++) {
240  const char *ass = sub->rects[i]->ass;
241 
242  if (sub->rects[i]->type != SUBTITLE_ASS) {
243  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
244  return AVERROR(ENOSYS);
245  }
246 
247 #if FF_API_ASS_TIMING
248  if (!strncmp(ass, "Dialogue: ", 10)) {
249  int num;
250  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
251  for (; dialog && num--; dialog++) {
252  s->alignment_applied = 0;
253  if (avctx->codec_id == AV_CODEC_ID_SUBRIP)
254  srt_style_apply(s, dialog->style);
255  ff_ass_split_override_codes(cb, s, dialog->text);
256  }
257  } else {
258 #endif
259  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
260  if (!dialog)
261  return AVERROR(ENOMEM);
262  s->alignment_applied = 0;
263  if (avctx->codec_id == AV_CODEC_ID_SUBRIP)
264  srt_style_apply(s, dialog->style);
265  ff_ass_split_override_codes(cb, s, dialog->text);
266  ff_ass_free_dialog(&dialog);
267 #if FF_API_ASS_TIMING
268  }
269 #endif
270  }
271 
272  if (!av_bprint_is_complete(&s->buffer))
273  return AVERROR(ENOMEM);
274  if (!s->buffer.len)
275  return 0;
276 
277  if (s->buffer.len > bufsize) {
278  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
279  return -1;
280  }
281  memcpy(buf, s->buffer.str, s->buffer.len);
282 
283  return s->buffer.len;
284 }
285 
287  unsigned char *buf, int bufsize, const AVSubtitle *sub)
288 {
289  return encode_frame(avctx, buf, bufsize, sub, &srt_callbacks);
290 }
291 
293  unsigned char *buf, int bufsize, const AVSubtitle *sub)
294 {
295  return encode_frame(avctx, buf, bufsize, sub, &text_callbacks);
296 }
297 
299 {
300  SRTContext *s = avctx->priv_data;
303  return 0;
304 }
305 
306 #if CONFIG_SRT_ENCODER
307 /* deprecated encoder */
309  .name = "srt",
310  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
311  .type = AVMEDIA_TYPE_SUBTITLE,
312  .id = AV_CODEC_ID_SUBRIP,
313  .priv_data_size = sizeof(SRTContext),
315  .encode_sub = srt_encode_frame,
316  .close = srt_encode_close,
317 };
318 #endif
319 
320 #if CONFIG_SUBRIP_ENCODER
322  .name = "subrip",
323  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
324  .type = AVMEDIA_TYPE_SUBTITLE,
325  .id = AV_CODEC_ID_SUBRIP,
326  .priv_data_size = sizeof(SRTContext),
328  .encode_sub = srt_encode_frame,
329  .close = srt_encode_close,
330 };
331 #endif
332 
333 #if CONFIG_TEXT_ENCODER
335  .name = "text",
336  .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
337  .type = AVMEDIA_TYPE_SUBTITLE,
338  .id = AV_CODEC_ID_TEXT,
339  .priv_data_size = sizeof(SRTContext),
341  .encode_sub = text_encode_frame,
342  .close = srt_encode_close,
343 };
344 #endif
#define SRT_STACK_SIZE
Definition: srtenc.c:30
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:76
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static int text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: srtenc.c:292
fields extracted from the [Events] section
Definition: ass_split.h:71
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
ASSDialog * ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:442
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:374
int32_t y2
Definition: srtdec.c:66
static const ASSCodesCallbacks srt_callbacks
Definition: srtenc.c:211
static av_cold int srt_encode_init(AVCodecContext *avctx)
Definition: srtenc.c:133
static int srt_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: srtenc.c:286
unsigned num_rects
Definition: avcodec.h:3948
int32_t x1
Definition: srtdec.c:66
AVCodec.
Definition: avcodec.h:3492
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
AVSubtitleRect ** rects
Definition: avcodec.h:3949
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
int alignment
position of the text (left, center, top...), defined after the layout of the numpad (1-3 sub...
Definition: ass_split.h:58
static double cb(void *priv, double x, double y)
Definition: vf_geq.c:139
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
#define ASS_DEFAULT_ALIGNMENT
Definition: ass.h:42
#define av_cold
Definition: attributes.h:82
static char srt_stack_pop(SRTContext *s)
Definition: srtenc.c:61
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:430
static void srt_font_size_cb(void *priv, int size)
Definition: srtenc.c:177
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
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:47
int stack_ptr
Definition: srtenc.c:37
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:492
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
uint32_t tag
Definition: movenc.c:1531
static int srt_encode_close(AVCodecContext *avctx)
Definition: srtenc.c:298
ptrdiff_t size
Definition: opengl_enc.c:100
ASSDialog * ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf, int cache, int *number)
Split one or several ASS "Dialogue" lines from a string buffer and store them in an already initializ...
Definition: ass_split.c:411
#define av_log(a,...)
int alignment_applied
Definition: srtenc.c:38
AVCodecContext * avctx
Definition: srtenc.c:33
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AV_BPRINT_SIZE_UNLIMITED
#define ASS_DEFAULT_FONT
Definition: ass.h:35
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
#define t1
Definition: regdef.h:29
int font_size
font height
Definition: ass_split.h:42
const char * name
Name of the codec implementation.
Definition: avcodec.h:3499
#define ASS_DEFAULT_FONT_SIZE
Definition: ass.h:36
char stack[SRT_STACK_SIZE]
Definition: srtenc.c:36
static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub, const ASSCodesCallbacks *cb)
Definition: srtenc.c:229
static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
Definition: srtenc.c:160
static void srt_close_tag(SRTContext *s, char tag)
Definition: srtenc.c:77
static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, int t1, int t2)
Definition: srtenc.c:199
static int srt_stack_push(SRTContext *s, const char c)
Definition: srtenc.c:53
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:48
#define s(width, name)
Definition: cbs_vp9.c:257
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:154
int32_t y1
Definition: srtdec.c:66
static void srt_style_apply(SRTContext *s, const char *style)
Definition: srtenc.c:94
int primary_color
color that a subtitle will normally appear in
Definition: ass_split.h:43
Libavcodec external API header.
enum AVCodecID codec_id
Definition: avcodec.h:1578
main external API structure.
Definition: avcodec.h:1568
ASSSplitContext * ass_ctx
Definition: srtenc.c:34
int32_t x2
Definition: srtdec.c:66
AVCodec ff_subrip_encoder
void * buf
Definition: avisynth_c.h:766
void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
Append a formatted string to a print buffer.
Definition: bprint.c:117
static void srt_cancel_overrides_cb(void *priv, const char *style)
Definition: srtenc.c:193
AVCodec ff_srt_encoder
char * font_name
font face (case sensitive)
Definition: ass_split.h:41
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
ASSStyle * ff_ass_style_get(ASSSplitContext *ctx, const char *style)
Find an ASSStyle structure by its name.
Definition: ass_split.c:587
static void srt_style_cb(void *priv, char style, int close)
Definition: srtenc.c:153
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
AVCodec ff_text_encoder
static void srt_font_name_cb(void *priv, const char *name)
Definition: srtenc.c:170
AVBPrint buffer
Definition: srtenc.c:35
#define ASS_DEFAULT_COLOR
Definition: ass.h:37
raw UTF-8 text
Definition: avcodec.h:662
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
static void srt_new_line_cb(void *priv, int forced)
Definition: srtenc.c:148
void * priv_data
Definition: avcodec.h:1595
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:3904
#define ASS_DEFAULT_ITALIC
Definition: ass.h:40
static int srt_stack_find(SRTContext *s, const char c)
Definition: srtenc.c:68
static void srt_print(SRTContext *s, const char *str,...)
Definition: srtenc.c:45
int len
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:3939
static void srt_alignment_cb(void *priv, int alignment)
Definition: srtenc.c:184
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:479
static void srt_text_cb(void *priv, const char *text, int len)
Definition: srtenc.c:142
static void srt_end_cb(void *priv)
Definition: srtenc.c:206
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
enum AVSubtitleType type
Definition: avcodec.h:3930
#define t2
Definition: regdef.h:30
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
static void srt_stack_push_pop(SRTContext *s, const char c, int close)
Definition: srtenc.c:82
static const ASSCodesCallbacks text_callbacks
Definition: srtenc.c:224
const char * name
Definition: opengl_enc.c:102
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:3053