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 #include "codec_internal.h"
30 
31 #define WEBVTT_STACK_SIZE 64
32 typedef struct {
35  AVBPrint buffer;
36  unsigned timestamp_end;
37  int count;
38  char stack[WEBVTT_STACK_SIZE];
39  int stack_ptr;
41 
42 #ifdef __GNUC__
43 __attribute__ ((__format__ (__printf__, 2, 3)))
44 #endif
45 static void webvtt_print(WebVTTContext *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 webvtt_stack_push(WebVTTContext *s, const char c)
54 {
55  if (s->stack_ptr >= WEBVTT_STACK_SIZE)
56  return -1;
57  s->stack[s->stack_ptr++] = c;
58  return 0;
59 }
60 
62 {
63  if (s->stack_ptr <= 0)
64  return 0;
65  return s->stack[--s->stack_ptr];
66 }
67 
68 static int webvtt_stack_find(WebVTTContext *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 webvtt_close_tag(WebVTTContext *s, char tag)
78 {
79  webvtt_print(s, "</%c>", tag);
80 }
81 
82 static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
83 {
84  if (close) {
85  int i = c ? webvtt_stack_find(s, c) : 0;
86  if (i < 0)
87  return;
88  while (s->stack_ptr != i)
90  } else if (webvtt_stack_push(s, c) < 0)
91  av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
92 }
93 
94 static void webvtt_style_apply(WebVTTContext *s, const char *style)
95 {
96  ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
97  if (st) {
98  if (st->bold != ASS_DEFAULT_BOLD) {
99  webvtt_print(s, "<b>");
100  webvtt_stack_push(s, 'b');
101  }
102  if (st->italic != ASS_DEFAULT_ITALIC) {
103  webvtt_print(s, "<i>");
104  webvtt_stack_push(s, 'i');
105  }
106  if (st->underline != ASS_DEFAULT_UNDERLINE) {
107  webvtt_print(s, "<u>");
108  webvtt_stack_push(s, 'u');
109  }
110  }
111 }
112 
113 static void webvtt_text_cb(void *priv, const char *text, int len)
114 {
115  WebVTTContext *s = priv;
116  av_bprint_append_data(&s->buffer, text, len);
117 }
118 
119 static void webvtt_new_line_cb(void *priv, int forced)
120 {
121  webvtt_print(priv, "\n");
122 }
123 
124 static void webvtt_style_cb(void *priv, char style, int close)
125 {
126  if (style == 's') // strikethrough unsupported
127  return;
128 
129  webvtt_stack_push_pop(priv, style, close);
130  if (!close)
131  webvtt_print(priv, "<%c>", style);
132 }
133 
134 static void webvtt_cancel_overrides_cb(void *priv, const char *style)
135 {
136  webvtt_stack_push_pop(priv, 0, 1);
137  webvtt_style_apply(priv, style);
138 }
139 
140 static void webvtt_end_cb(void *priv)
141 {
142  webvtt_stack_push_pop(priv, 0, 1);
143 }
144 
146  .text = webvtt_text_cb,
147  .new_line = webvtt_new_line_cb,
148  .style = webvtt_style_cb,
149  .color = NULL,
150  .font_name = NULL,
151  .font_size = NULL,
152  .alignment = NULL,
153  .cancel_overrides = webvtt_cancel_overrides_cb,
154  .move = NULL,
155  .end = webvtt_end_cb,
156 };
157 
159  unsigned char *buf, int bufsize, const AVSubtitle *sub)
160 {
161  WebVTTContext *s = avctx->priv_data;
162  ASSDialog *dialog;
163  int i;
164 
165  av_bprint_clear(&s->buffer);
166 
167  for (i=0; i<sub->num_rects; i++) {
168  const char *ass = sub->rects[i]->ass;
169 
170  if (sub->rects[i]->type != SUBTITLE_ASS) {
171  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
172  return AVERROR(EINVAL);
173  }
174 
175  dialog = ff_ass_split_dialog(s->ass_ctx, ass);
176  if (!dialog)
177  return AVERROR(ENOMEM);
178  webvtt_style_apply(s, dialog->style);
180  ff_ass_free_dialog(&dialog);
181  }
182 
183  if (!av_bprint_is_complete(&s->buffer))
184  return AVERROR(ENOMEM);
185  if (!s->buffer.len)
186  return 0;
187 
188  if (s->buffer.len > bufsize) {
189  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
191  }
192  memcpy(buf, s->buffer.str, s->buffer.len);
193 
194  return s->buffer.len;
195 }
196 
198 {
199  WebVTTContext *s = avctx->priv_data;
200  ff_ass_split_free(s->ass_ctx);
201  av_bprint_finalize(&s->buffer, NULL);
202  return 0;
203 }
204 
206 {
207  WebVTTContext *s = avctx->priv_data;
208  s->avctx = avctx;
209  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
211  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
212 }
213 
215  .p.name = "webvtt",
216  CODEC_LONG_NAME("WebVTT subtitle"),
217  .p.type = AVMEDIA_TYPE_SUBTITLE,
218  .p.id = AV_CODEC_ID_WEBVTT,
219  .priv_data_size = sizeof(WebVTTContext),
222  .close = webvtt_encode_close,
223 };
AVSubtitle
Definition: avcodec.h:2269
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
webvtt_print
static void webvtt_print(WebVTTContext *s, const char *str,...)
Definition: webvttenc.c:45
ASSCodesCallbacks
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:138
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:218
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
AVSubtitle::rects
AVSubtitleRect ** rects
Definition: avcodec.h:2274
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
webvtt_stack_pop
static char webvtt_stack_pop(WebVTTContext *s)
Definition: webvttenc.c:61
AVSubtitle::num_rects
unsigned num_rects
Definition: avcodec.h:2273
WebVTTContext
Definition: webvttenc.c:32
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
FFCodec
Definition: codec_internal.h:127
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:1776
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:2236
webvtt_encode_init
static av_cold int webvtt_encode_init(AVCodecContext *avctx)
Definition: webvttenc.c:205
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
ass_split.h
WEBVTT_STACK_SIZE
#define WEBVTT_STACK_SIZE
Definition: webvttenc.c:31
AVERROR_BUFFER_TOO_SMALL
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:53
AVSubtitleRect::ass
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2264
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
av_cold
#define av_cold
Definition: attributes.h:90
s
#define s(width, name)
Definition: cbs_vp9.c:198
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
WebVTTContext::stack_ptr
int stack_ptr
Definition: webvttenc.c:39
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
AV_CODEC_ID_WEBVTT
@ AV_CODEC_ID_WEBVTT
Definition: codec_id.h:568
NULL
#define NULL
Definition: coverity.c:32
webvtt_stack_find
static int webvtt_stack_find(WebVTTContext *s, const char c)
Definition: webvttenc.c:68
webvtt_encode_frame
static int webvtt_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: webvttenc.c:158
FF_CODEC_ENCODE_SUB_CB
#define FF_CODEC_ENCODE_SUB_CB(func)
Definition: codec_internal.h:318
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
webvtt_text_cb
static void webvtt_text_cb(void *priv, const char *text, int len)
Definition: webvttenc.c:113
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
ASSStyle::underline
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
webvtt_callbacks
static const ASSCodesCallbacks webvtt_callbacks
Definition: webvttenc.c:145
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
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
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
webvtt_stack_push
static int webvtt_stack_push(WebVTTContext *s, const char c)
Definition: webvttenc.c:53
WebVTTContext::count
int count
Definition: webvttenc.c:37
ASSStyle::italic
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:48
AVSubtitleRect::type
enum AVSubtitleType type
Definition: avcodec.h:2255
webvtt_cancel_overrides_cb
static void webvtt_cancel_overrides_cb(void *priv, const char *style)
Definition: webvttenc.c:134
ASS_DEFAULT_UNDERLINE
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
webvtt_end_cb
static void webvtt_end_cb(void *priv)
Definition: webvttenc.c:140
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
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
webvtt_style_cb
static void webvtt_style_cb(void *priv, char style, int close)
Definition: webvttenc.c:124
WebVTTContext::avctx
AVCodecContext * avctx
Definition: webvttenc.c:33
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
ASS_DEFAULT_ITALIC
#define ASS_DEFAULT_ITALIC
Definition: ass.h:40
len
int len
Definition: vorbis_enc_data.h:426
avcodec.h
tag
uint32_t tag
Definition: movenc.c:1737
WebVTTContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: webvttenc.c:34
webvtt_new_line_cb
static void webvtt_new_line_cb(void *priv, int forced)
Definition: webvttenc.c:119
AVCodecContext
main external API structure.
Definition: avcodec.h:441
WebVTTContext::buffer
AVBPrint buffer
Definition: webvttenc.c:35
webvtt_stack_push_pop
static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
Definition: webvttenc.c:82
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:122
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
ff_webvtt_encoder
const FFCodec ff_webvtt_encoder
Definition: webvttenc.c:214
ASSDialog
fields extracted from the [Events] section
Definition: ass_split.h:71
webvtt_style_apply
static void webvtt_style_apply(WebVTTContext *s, const char *style)
Definition: webvttenc.c:94
webvtt_encode_close
static int webvtt_encode_close(AVCodecContext *avctx)
Definition: webvttenc.c:197
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
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
avstring.h
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:163
webvtt_close_tag
static void webvtt_close_tag(WebVTTContext *s, char tag)
Definition: webvttenc.c:77
ASSStyle::bold
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:47
WebVTTContext::timestamp_end
unsigned timestamp_end
Definition: webvttenc.c:36
ASSCodesCallbacks::text
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:143