FFmpeg
webvttenc.c
Go to the documentation of this file.
1 /*
2  * WebVTT subtitle encoder
3  * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4  * Copyright (c) 2014 Aman Gupta <ffmpeg@tmm1.net>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <stdarg.h>
24 #include "avcodec.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/bprint.h"
27 #include "ass_split.h"
28 #include "ass.h"
29 
30 #define WEBVTT_STACK_SIZE 64
31 typedef struct {
34  AVBPrint buffer;
35  unsigned timestamp_end;
36  int count;
37  char stack[WEBVTT_STACK_SIZE];
38  int stack_ptr;
40 
41 #ifdef __GNUC__
42 __attribute__ ((__format__ (__printf__, 2, 3)))
43 #endif
44 static void webvtt_print(WebVTTContext *s, const char *str, ...)
45 {
46  va_list vargs;
47  va_start(vargs, str);
48  av_vbprintf(&s->buffer, str, vargs);
49  va_end(vargs);
50 }
51 
52 static int webvtt_stack_push(WebVTTContext *s, const char c)
53 {
54  if (s->stack_ptr >= WEBVTT_STACK_SIZE)
55  return -1;
56  s->stack[s->stack_ptr++] = c;
57  return 0;
58 }
59 
61 {
62  if (s->stack_ptr <= 0)
63  return 0;
64  return s->stack[--s->stack_ptr];
65 }
66 
67 static int webvtt_stack_find(WebVTTContext *s, const char c)
68 {
69  int i;
70  for (i = s->stack_ptr-1; i >= 0; i--)
71  if (s->stack[i] == c)
72  break;
73  return i;
74 }
75 
76 static void webvtt_close_tag(WebVTTContext *s, char tag)
77 {
78  webvtt_print(s, "</%c>", tag);
79 }
80 
81 static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
82 {
83  if (close) {
84  int i = c ? webvtt_stack_find(s, c) : 0;
85  if (i < 0)
86  return;
87  while (s->stack_ptr != i)
89  } else if (webvtt_stack_push(s, c) < 0)
90  av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
91 }
92 
93 static void webvtt_style_apply(WebVTTContext *s, const char *style)
94 {
95  ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
96  if (st) {
97  if (st->bold != ASS_DEFAULT_BOLD) {
98  webvtt_print(s, "<b>");
99  webvtt_stack_push(s, 'b');
100  }
101  if (st->italic != ASS_DEFAULT_ITALIC) {
102  webvtt_print(s, "<i>");
103  webvtt_stack_push(s, 'i');
104  }
105  if (st->underline != ASS_DEFAULT_UNDERLINE) {
106  webvtt_print(s, "<u>");
107  webvtt_stack_push(s, 'u');
108  }
109  }
110 }
111 
112 static void webvtt_text_cb(void *priv, const char *text, int len)
113 {
114  WebVTTContext *s = priv;
115  av_bprint_append_data(&s->buffer, text, len);
116 }
117 
118 static void webvtt_new_line_cb(void *priv, int forced)
119 {
120  webvtt_print(priv, "\n");
121 }
122 
123 static void webvtt_style_cb(void *priv, char style, int close)
124 {
125  if (style == 's') // strikethrough unsupported
126  return;
127 
128  webvtt_stack_push_pop(priv, style, close);
129  if (!close)
130  webvtt_print(priv, "<%c>", style);
131 }
132 
133 static void webvtt_cancel_overrides_cb(void *priv, const char *style)
134 {
135  webvtt_stack_push_pop(priv, 0, 1);
136  webvtt_style_apply(priv, style);
137 }
138 
139 static void webvtt_end_cb(void *priv)
140 {
141  webvtt_stack_push_pop(priv, 0, 1);
142 }
143 
145  .text = webvtt_text_cb,
146  .new_line = webvtt_new_line_cb,
147  .style = webvtt_style_cb,
148  .color = NULL,
149  .font_name = NULL,
150  .font_size = NULL,
151  .alignment = NULL,
152  .cancel_overrides = webvtt_cancel_overrides_cb,
153  .move = NULL,
154  .end = webvtt_end_cb,
155 };
156 
158  unsigned char *buf, int bufsize, const AVSubtitle *sub)
159 {
160  WebVTTContext *s = avctx->priv_data;
161  ASSDialog *dialog;
162  int i;
163 
164  av_bprint_clear(&s->buffer);
165 
166  for (i=0; i<sub->num_rects; i++) {
167  const char *ass = sub->rects[i]->ass;
168 
169  if (sub->rects[i]->type != SUBTITLE_ASS) {
170  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
171  return AVERROR(ENOSYS);
172  }
173 
174 #if FF_API_ASS_TIMING
175  if (!strncmp(ass, "Dialogue: ", 10)) {
176  int num;
177  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
178  // TODO reindent
179  for (; dialog && num--; dialog++) {
180  webvtt_style_apply(s, dialog->style);
181  ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
182  }
183  } else {
184 #endif
185  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
186  if (!dialog)
187  return AVERROR(ENOMEM);
188  webvtt_style_apply(s, dialog->style);
189  ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
190  ff_ass_free_dialog(&dialog);
191 #if FF_API_ASS_TIMING
192  }
193 #endif
194  }
195 
196  if (!av_bprint_is_complete(&s->buffer))
197  return AVERROR(ENOMEM);
198  if (!s->buffer.len)
199  return 0;
200 
201  if (s->buffer.len > bufsize) {
202  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
203  return -1;
204  }
205  memcpy(buf, s->buffer.str, s->buffer.len);
206 
207  return s->buffer.len;
208 }
209 
211 {
212  WebVTTContext *s = avctx->priv_data;
215  return 0;
216 }
217 
219 {
220  WebVTTContext *s = avctx->priv_data;
221  s->avctx = avctx;
222  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
224  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
225 }
226 
228  .name = "webvtt",
229  .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
230  .type = AVMEDIA_TYPE_SUBTITLE,
231  .id = AV_CODEC_ID_WEBVTT,
232  .priv_data_size = sizeof(WebVTTContext),
234  .encode_sub = webvtt_encode_frame,
235  .close = webvtt_encode_close,
236 };
AVCodec ff_webvtt_encoder
Definition: webvttenc.c:227
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
char stack[WEBVTT_STACK_SIZE]
Definition: webvttenc.c:37
fields extracted from the [Events] section
Definition: ass_split.h:71
static int webvtt_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: webvttenc.c:157
static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
Definition: webvttenc.c:81
AVBPrint buffer
Definition: webvttenc.c:34
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
static void webvtt_style_cb(void *priv, char style, int close)
Definition: webvttenc.c:123
unsigned num_rects
Definition: avcodec.h:3948
AVCodec.
Definition: avcodec.h:3492
static void webvtt_print(WebVTTContext *s, const char *str,...)
Definition: webvttenc.c:44
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
static void webvtt_cancel_overrides_cb(void *priv, const char *style)
Definition: webvttenc.c:133
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
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
#define av_cold
Definition: attributes.h:82
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:430
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 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
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,...)
static void webvtt_end_cb(void *priv)
Definition: webvttenc.c:139
#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 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
const char * name
Name of the codec implementation.
Definition: avcodec.h:3499
static int webvtt_stack_push(WebVTTContext *s, const char c)
Definition: webvttenc.c:52
static av_cold int webvtt_encode_init(AVCodecContext *avctx)
Definition: webvttenc.c:218
static void webvtt_text_cb(void *priv, const char *text, int len)
Definition: webvttenc.c:112
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
static void webvtt_close_tag(WebVTTContext *s, char tag)
Definition: webvttenc.c:76
static void webvtt_new_line_cb(void *priv, int forced)
Definition: webvttenc.c:118
static char webvtt_stack_pop(WebVTTContext *s)
Definition: webvttenc.c:60
Libavcodec external API header.
static int webvtt_encode_close(AVCodecContext *avctx)
Definition: webvttenc.c:210
main external API structure.
Definition: avcodec.h:1568
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
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
ASSSplitContext * ass_ctx
Definition: webvttenc.c:33
static void webvtt_style_apply(WebVTTContext *s, const char *style)
Definition: webvttenc.c:93
ASSStyle * ff_ass_style_get(ASSSplitContext *ctx, const char *style)
Find an ASSStyle structure by its name.
Definition: ass_split.c:587
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
unsigned timestamp_end
Definition: webvttenc.c:35
AVCodecContext * avctx
Definition: webvttenc.c:32
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
int len
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:3939
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:479
#define WEBVTT_STACK_SIZE
Definition: webvttenc.c:30
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
static int webvtt_stack_find(WebVTTContext *s, const char c)
Definition: webvttenc.c:67
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
static const ASSCodesCallbacks webvtt_callbacks
Definition: webvttenc.c:144
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:3053