FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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, num;
236 
237  av_bprint_clear(&s->buffer);
238 
239  for (i=0; i<sub->num_rects; i++) {
240 
241  if (sub->rects[i]->type != SUBTITLE_ASS) {
242  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
243  return AVERROR(ENOSYS);
244  }
245 
246  dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
247  for (; dialog && num--; dialog++) {
248  s->alignment_applied = 0;
249  srt_style_apply(s, dialog->style);
250  ff_ass_split_override_codes(cb, s, dialog->text);
251  }
252  }
253 
254  if (!av_bprint_is_complete(&s->buffer))
255  return AVERROR(ENOMEM);
256  if (!s->buffer.len)
257  return 0;
258 
259  if (s->buffer.len > bufsize) {
260  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
261  return -1;
262  }
263  memcpy(buf, s->buffer.str, s->buffer.len);
264 
265  return s->buffer.len;
266 }
267 
269  unsigned char *buf, int bufsize, const AVSubtitle *sub)
270 {
271  return encode_frame(avctx, buf, bufsize, sub, &srt_callbacks);
272 }
273 
275  unsigned char *buf, int bufsize, const AVSubtitle *sub)
276 {
277  return encode_frame(avctx, buf, bufsize, sub, &text_callbacks);
278 }
279 
281 {
282  SRTContext *s = avctx->priv_data;
285  return 0;
286 }
287 
288 #if CONFIG_SRT_ENCODER
289 /* deprecated encoder */
290 AVCodec ff_srt_encoder = {
291  .name = "srt",
292  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
293  .type = AVMEDIA_TYPE_SUBTITLE,
294  .id = AV_CODEC_ID_SUBRIP,
295  .priv_data_size = sizeof(SRTContext),
297  .encode_sub = srt_encode_frame,
298  .close = srt_encode_close,
299 };
300 #endif
301 
302 #if CONFIG_SUBRIP_ENCODER
303 AVCodec ff_subrip_encoder = {
304  .name = "subrip",
305  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
306  .type = AVMEDIA_TYPE_SUBTITLE,
307  .id = AV_CODEC_ID_SUBRIP,
308  .priv_data_size = sizeof(SRTContext),
310  .encode_sub = srt_encode_frame,
311  .close = srt_encode_close,
312 };
313 #endif
314 
315 #if CONFIG_TEXT_ENCODER
316 AVCodec ff_text_encoder = {
317  .name = "text",
318  .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
319  .type = AVMEDIA_TYPE_SUBTITLE,
320  .id = AV_CODEC_ID_TEXT,
321  .priv_data_size = sizeof(SRTContext),
323  .encode_sub = text_encode_frame,
324  .close = srt_encode_close,
325 };
326 #endif
#define SRT_STACK_SIZE
Definition: srtenc.c:30
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:75
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:631
#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:274
fields extracted from the [Events] section
Definition: ass_split.h:71
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
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:356
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:268
unsigned num_rects
Definition: avcodec.h:3737
AVCodec.
Definition: avcodec.h:3392
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
AVSubtitleRect ** rects
Definition: avcodec.h:3738
char * text
actual text which will be displayed as a subtitle, can include style override control codes (see ff_a...
Definition: ass_split.h:81
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:97
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
static void srt_font_size_cb(void *priv, int size)
Definition: srtenc.c:177
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:425
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:1348
static int srt_encode_close(AVCodecContext *avctx)
Definition: srtenc.c:280
ptrdiff_t size
Definition: opengl_enc.c:101
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 a already initialize...
Definition: ass_split.c:393
#define av_log(a,...)
int alignment_applied
Definition: srtenc.c:38
AVCodecContext * avctx
Definition: srtenc.c:33
#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 AVERROR(e)
Definition: error.h:43
#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:176
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:3399
#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
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:144
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
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:139
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.
main external API structure.
Definition: avcodec.h:1532
ASSSplitContext * ass_ctx
Definition: srtenc.c:34
void * buf
Definition: avisynth_c.h:553
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
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:520
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
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:508
static double c[64]
static void srt_new_line_cb(void *priv, int forced)
Definition: srtenc.c:148
void * priv_data
Definition: avcodec.h:1574
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:3693
#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:3728
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:412
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
enum AVSubtitleType type
Definition: avcodec.h:3719
#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:103
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:3149