libavcodec/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 "ass_split.h"
26 #include "ass.h"
27 
28 
29 #define SRT_STACK_SIZE 64
30 
31 typedef struct {
34  char buffer[2048];
35  char *ptr;
36  char *end;
37  char *dialog_start;
38  int count;
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  s->ptr += vsnprintf(s->ptr, s->end - s->ptr, 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);
141  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
142 }
143 
144 static void srt_text_cb(void *priv, const char *text, int len)
145 {
146  SRTContext *s = priv;
147  av_strlcpy(s->ptr, text, FFMIN(s->end-s->ptr, len+1));
148  s->ptr += 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  SRTContext *s = priv;
206 
207  if (s->avctx->codec->id == AV_CODEC_ID_SRT) {
208  char buffer[32];
209  int len = snprintf(buffer, sizeof(buffer),
210  " X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2);
211  if (s->end - s->ptr > len) {
212  memmove(s->dialog_start+len, s->dialog_start, s->ptr-s->dialog_start+1);
213  memcpy(s->dialog_start, buffer, len);
214  s->ptr += len;
215  }
216  }
217 }
218 
219 static void srt_end_cb(void *priv)
220 {
221  SRTContext *s = priv;
222 
223  srt_stack_push_pop(priv, 0, 1);
224  if (s->avctx->codec->id == AV_CODEC_ID_SRT)
225  srt_print(priv, "\r\n\r\n");
226 }
227 
229  .text = srt_text_cb,
230  .new_line = srt_new_line_cb,
231  .style = srt_style_cb,
232  .color = srt_color_cb,
233  .font_name = srt_font_name_cb,
234  .font_size = srt_font_size_cb,
235  .alignment = srt_alignment_cb,
236  .cancel_overrides = srt_cancel_overrides_cb,
237  .move = srt_move_cb,
238  .end = srt_end_cb,
239 };
240 
242  unsigned char *buf, int bufsize, const AVSubtitle *sub)
243 {
244  SRTContext *s = avctx->priv_data;
245  ASSDialog *dialog;
246  int i, len, num;
247 
248  s->ptr = s->buffer;
249  s->end = s->ptr + sizeof(s->buffer);
250 
251  for (i=0; i<sub->num_rects; i++) {
252 
253  if (sub->rects[i]->type != SUBTITLE_ASS) {
254  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
255  return AVERROR(ENOSYS);
256  }
257 
258  dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
259  for (; dialog && num--; dialog++) {
260  if (avctx->codec->id == AV_CODEC_ID_SRT) {
261  int sh, sm, ss, sc = 10 * dialog->start;
262  int eh, em, es, ec = 10 * dialog->end;
263  sh = sc/3600000; sc -= 3600000*sh;
264  sm = sc/ 60000; sc -= 60000*sm;
265  ss = sc/ 1000; sc -= 1000*ss;
266  eh = ec/3600000; ec -= 3600000*eh;
267  em = ec/ 60000; ec -= 60000*em;
268  es = ec/ 1000; ec -= 1000*es;
269  srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n",
270  ++s->count, sh, sm, ss, sc, eh, em, es, ec);
271  s->dialog_start = s->ptr - 2;
272  }
273  s->alignment_applied = 0;
274  srt_style_apply(s, dialog->style);
275  ff_ass_split_override_codes(&srt_callbacks, s, dialog->text);
276  }
277  }
278 
279  if (s->ptr == s->buffer)
280  return 0;
281 
282  len = av_strlcpy(buf, s->buffer, bufsize);
283 
284  if (len > bufsize-1) {
285  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
286  return -1;
287  }
288 
289  return len;
290 }
291 
293 {
294  SRTContext *s = avctx->priv_data;
296  return 0;
297 }
298 
299 #if CONFIG_SRT_ENCODER
300 /* deprecated encoder */
301 AVCodec ff_srt_encoder = {
302  .name = "srt",
303  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
304  .type = AVMEDIA_TYPE_SUBTITLE,
305  .id = AV_CODEC_ID_SRT,
306  .priv_data_size = sizeof(SRTContext),
308  .encode_sub = srt_encode_frame,
310 };
311 #endif
312 
313 #if CONFIG_SUBRIP_ENCODER
314 AVCodec ff_subrip_encoder = {
315  .name = "subrip",
316  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
317  .type = AVMEDIA_TYPE_SUBTITLE,
318  .id = AV_CODEC_ID_SUBRIP,
319  .priv_data_size = sizeof(SRTContext),
321  .encode_sub = srt_encode_frame,
323 };
324 #endif
#define SRT_STACK_SIZE
const char * name
Definition: avisynth_c.h:675
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:60
const struct AVCodec * codec
const char * s
Definition: avisynth_c.h:668
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
fields extracted from the [Events] section
Definition: ass_split.h:56
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:303
#define vsnprintf
Definition: snprintf.h:36
static const ASSCodesCallbacks srt_callbacks
static av_cold int srt_encode_init(AVCodecContext *avctx)
y1
Definition: lab5.m:33
static int srt_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
x1
Definition: genspecsines3.m:7
text(-8, 1,'a)')
AVSubtitleRect ** rects
char * text
actual text which will be displayed as a subtitle, can include style override control codes (see ff_a...
Definition: ass_split.h:61
struct SRTContext SRTContext
int alignment
position of the text (left, center, top...), defined after the layout of the numpad (1-3 sub...
Definition: ass_split.h:48
static const float even_table[] __attribute__((aligned(8)))
#define ASS_DEFAULT_ALIGNMENT
Definition: ass.h:38
#define av_cold
Definition: attributes.h:78
static char srt_stack_pop(SRTContext *s)
static void srt_font_size_cb(void *priv, int size)
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:45
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:370
char * dialog_start
uint32_t tag
Definition: movenc.c:894
static int srt_encode_close(AVCodecContext *avctx)
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:338
AVCodecContext * avctx
enum AVCodecID id
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:37
#define ASS_DEFAULT_FONT
Definition: ass.h:31
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
#define t1
Definition: regdef.h:29
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
int font_size
font height
Definition: ass_split.h:42
const char * name
Name of the codec implementation.
int end
end time of the dialog in centiseconds
Definition: ass_split.h:59
external API header
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:82
int size
#define ASS_DEFAULT_FONT_SIZE
Definition: ass.h:32
char stack[SRT_STACK_SIZE]
static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
static void srt_close_tag(SRTContext *s, char tag)
#define FFMIN(a, b)
Definition: common.h:58
static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, int t1, int t2)
static int srt_stack_push(SRTContext *s, const char c)
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:46
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:119
y2
Definition: lab5.m:34
static void srt_style_apply(SRTContext *s, const char *style)
int primary_color
color that a subtitle will normally appear in
Definition: ass_split.h:43
main external API structure.
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:375
ASSSplitContext * ass_ctx
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
static void srt_cancel_overrides_cb(void *priv, const char *style)
x2
Definition: genspecsines3.m:8
int start
start time of the dialog in centiseconds
Definition: ass_split.h:58
synthesis window for stochastic i
#define snprintf
Definition: snprintf.h:34
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
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:465
static void srt_style_cb(void *priv, char style, int close)
static void srt_font_name_cb(void *priv, const char *name)
char buffer[2048]
#define ASS_DEFAULT_COLOR
Definition: ass.h:33
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:124
static double c[64]
the buffer and buffer 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 AVFilterBuffer structures They must not be accessed but through references stored in AVFilterBufferRef structures Several references can point to the same buffer
static void srt_new_line_cb(void *priv, int forced)
Formatted text, the ass field must be set by the decoder and is authoritative.
#define ASS_DEFAULT_ITALIC
Definition: ass.h:36
static int srt_stack_find(SRTContext *s, const char c)
static void srt_print(SRTContext *s, const char *str,...)
int len
#define ASS_DEFAULT_BOLD
Definition: ass.h:35
char * ass
0 terminated ASS/SSA compatible event line.
static void srt_alignment_cb(void *priv, int alignment)
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:357
static void srt_text_cb(void *priv, const char *text, int len)
static void srt_end_cb(void *priv)
enum AVSubtitleType type
#define t2
Definition: regdef.h:30
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:47
static void srt_stack_push_pop(SRTContext *s, const char c, int close)
uint8_t * subtitle_header
Header containing style information for text subtitles.