vf_subtitles.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Baptiste Coudurier
3  * Copyright (c) 2011 Stefano Sabatini
4  * Copyright (c) 2012 Clément Bœsch
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 /**
24  * @file
25  * Libass subtitles burning filter.
26  *
27  * @see{http://www.matroska.org/technical/specs/subtitles/ssa.html}
28  */
29 
30 #include <ass/ass.h>
31 
32 #include "config.h"
33 #if CONFIG_SUBTITLES_FILTER
34 # include "libavcodec/avcodec.h"
35 # include "libavformat/avformat.h"
36 #endif
37 #include "libavutil/avstring.h"
38 #include "libavutil/imgutils.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/parseutils.h"
41 #include "drawutils.h"
42 #include "avfilter.h"
43 #include "internal.h"
44 #include "formats.h"
45 #include "video.h"
46 
47 typedef struct {
48  const AVClass *class;
49  ASS_Library *library;
50  ASS_Renderer *renderer;
51  ASS_Track *track;
52  char *filename;
53  char *charenc;
54  uint8_t rgba_map[4];
55  int pix_step[4]; ///< steps per pixel for each plane of the main output
56  int original_w, original_h;
58 } AssContext;
59 
60 #define OFFSET(x) offsetof(AssContext, x)
61 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
62 
63 #define COMMON_OPTIONS \
64  {"filename", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
65  {"f", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
66  {"original_size", "set the size of the original video (used to scale fonts)", OFFSET(original_w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
67 
68 /* libass supports a log level ranging from 0 to 7 */
69 static const int ass_libavfilter_log_level_map[] = {
70  AV_LOG_QUIET, /* 0 */
71  AV_LOG_PANIC, /* 1 */
72  AV_LOG_FATAL, /* 2 */
73  AV_LOG_ERROR, /* 3 */
74  AV_LOG_WARNING, /* 4 */
75  AV_LOG_INFO, /* 5 */
76  AV_LOG_VERBOSE, /* 6 */
77  AV_LOG_DEBUG, /* 7 */
78 };
79 
80 static void ass_log(int ass_level, const char *fmt, va_list args, void *ctx)
81 {
82  int level = ass_libavfilter_log_level_map[ass_level];
83 
84  av_vlog(ctx, level, fmt, args);
85  av_log(ctx, level, "\n");
86 }
87 
88 static av_cold int init(AVFilterContext *ctx)
89 {
90  AssContext *ass = ctx->priv;
91 
92  if (!ass->filename) {
93  av_log(ctx, AV_LOG_ERROR, "No filename provided!\n");
94  return AVERROR(EINVAL);
95  }
96 
97  ass->library = ass_library_init();
98  if (!ass->library) {
99  av_log(ctx, AV_LOG_ERROR, "Could not initialize libass.\n");
100  return AVERROR(EINVAL);
101  }
102  ass_set_message_cb(ass->library, ass_log, ctx);
103 
104  ass->renderer = ass_renderer_init(ass->library);
105  if (!ass->renderer) {
106  av_log(ctx, AV_LOG_ERROR, "Could not initialize libass renderer.\n");
107  return AVERROR(EINVAL);
108  }
109 
110  ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1);
111  return 0;
112 }
113 
114 static av_cold void uninit(AVFilterContext *ctx)
115 {
116  AssContext *ass = ctx->priv;
117 
118  if (ass->track)
119  ass_free_track(ass->track);
120  if (ass->renderer)
121  ass_renderer_done(ass->renderer);
122  if (ass->library)
123  ass_library_done(ass->library);
124 }
125 
127 {
129  return 0;
130 }
131 
132 static int config_input(AVFilterLink *inlink)
133 {
134  AssContext *ass = inlink->dst->priv;
135 
136  ff_draw_init(&ass->draw, inlink->format, 0);
137 
138  ass_set_frame_size (ass->renderer, inlink->w, inlink->h);
139  if (ass->original_w && ass->original_h)
140  ass_set_aspect_ratio(ass->renderer, (double)inlink->w / inlink->h,
141  (double)ass->original_w / ass->original_h);
142 
143  return 0;
144 }
145 
146 /* libass stores an RGBA color in the format RRGGBBTT, where TT is the transparency level */
147 #define AR(c) ( (c)>>24)
148 #define AG(c) (((c)>>16)&0xFF)
149 #define AB(c) (((c)>>8) &0xFF)
150 #define AA(c) ((0xFF-c) &0xFF)
151 
152 static void overlay_ass_image(AssContext *ass, AVFrame *picref,
153  const ASS_Image *image)
154 {
155  for (; image; image = image->next) {
156  uint8_t rgba_color[] = {AR(image->color), AG(image->color), AB(image->color), AA(image->color)};
158  ff_draw_color(&ass->draw, &color, rgba_color);
159  ff_blend_mask(&ass->draw, &color,
160  picref->data, picref->linesize,
161  picref->width, picref->height,
162  image->bitmap, image->stride, image->w, image->h,
163  3, 0, image->dst_x, image->dst_y);
164  }
165 }
166 
167 static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
168 {
169  AVFilterContext *ctx = inlink->dst;
170  AVFilterLink *outlink = ctx->outputs[0];
171  AssContext *ass = ctx->priv;
172  int detect_change = 0;
173  double time_ms = picref->pts * av_q2d(inlink->time_base) * 1000;
174  ASS_Image *image = ass_render_frame(ass->renderer, ass->track,
175  time_ms, &detect_change);
176 
177  if (detect_change)
178  av_log(ctx, AV_LOG_DEBUG, "Change happened at time ms:%f\n", time_ms);
179 
180  overlay_ass_image(ass, picref, image);
181 
182  return ff_filter_frame(outlink, picref);
183 }
184 
185 static const AVFilterPad ass_inputs[] = {
186  {
187  .name = "default",
188  .type = AVMEDIA_TYPE_VIDEO,
189  .filter_frame = filter_frame,
190  .config_props = config_input,
191  .needs_writable = 1,
192  },
193  { NULL }
194 };
195 
196 static const AVFilterPad ass_outputs[] = {
197  {
198  .name = "default",
199  .type = AVMEDIA_TYPE_VIDEO,
200  },
201  { NULL }
202 };
203 
204 #if CONFIG_ASS_FILTER
205 
206 static const AVOption ass_options[] = {
208  {NULL},
209 };
210 
212 
213 static av_cold int init_ass(AVFilterContext *ctx)
214 {
215  AssContext *ass = ctx->priv;
216  int ret = init(ctx);
217 
218  if (ret < 0)
219  return ret;
220 
221  ass->track = ass_read_file(ass->library, ass->filename, NULL);
222  if (!ass->track) {
223  av_log(ctx, AV_LOG_ERROR,
224  "Could not create a libass track when reading file '%s'\n",
225  ass->filename);
226  return AVERROR(EINVAL);
227  }
228  return 0;
229 }
230 
231 AVFilter avfilter_vf_ass = {
232  .name = "ass",
233  .description = NULL_IF_CONFIG_SMALL("Render ASS subtitles onto input video using the libass library."),
234  .priv_size = sizeof(AssContext),
235  .init = init_ass,
236  .uninit = uninit,
238  .inputs = ass_inputs,
239  .outputs = ass_outputs,
240  .priv_class = &ass_class,
241 };
242 #endif
243 
244 #if CONFIG_SUBTITLES_FILTER
245 
246 static const AVOption subtitles_options[] = {
248  {"charenc", "set input character encoding", OFFSET(charenc), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
249  {NULL},
250 };
251 
252 AVFILTER_DEFINE_CLASS(subtitles);
253 
254 static av_cold int init_subtitles(AVFilterContext *ctx)
255 {
256  int ret, sid;
260  AVCodec *dec = NULL;
261  const AVCodecDescriptor *dec_desc;
262  AVStream *st;
263  AVPacket pkt;
264  AssContext *ass = ctx->priv;
265 
266  /* Init libass */
267  ret = init(ctx);
268  if (ret < 0)
269  return ret;
270  ass->track = ass_new_track(ass->library);
271  if (!ass->track) {
272  av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n");
273  return AVERROR(EINVAL);
274  }
275 
276  /* Open subtitles file */
277  ret = avformat_open_input(&fmt, ass->filename, NULL, NULL);
278  if (ret < 0) {
279  av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename);
280  goto end;
281  }
282  ret = avformat_find_stream_info(fmt, NULL);
283  if (ret < 0)
284  goto end;
285 
286  /* Locate subtitles stream */
287  ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
288  if (ret < 0) {
289  av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n",
290  ass->filename);
291  goto end;
292  }
293  sid = ret;
294  st = fmt->streams[sid];
295 
296  /* Open decoder */
297  dec_ctx = st->codec;
298  dec = avcodec_find_decoder(dec_ctx->codec_id);
299  if (!dec) {
300  av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n",
301  avcodec_get_name(dec_ctx->codec_id));
302  return AVERROR(EINVAL);
303  }
304  dec_desc = avcodec_descriptor_get(dec_ctx->codec_id);
305  if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) {
306  av_log(ctx, AV_LOG_ERROR,
307  "Only text based subtitles are currently supported\n");
308  return AVERROR_PATCHWELCOME;
309  }
310  if (ass->charenc)
311  av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0);
312  ret = avcodec_open2(dec_ctx, dec, &codec_opts);
313  if (ret < 0)
314  goto end;
315 
316  /* Decode subtitles and push them into the renderer (libass) */
317  if (dec_ctx->subtitle_header)
318  ass_process_codec_private(ass->track,
319  dec_ctx->subtitle_header,
320  dec_ctx->subtitle_header_size);
321  av_init_packet(&pkt);
322  pkt.data = NULL;
323  pkt.size = 0;
324  while (av_read_frame(fmt, &pkt) >= 0) {
325  int i, got_subtitle;
326  AVSubtitle sub;
327 
328  if (pkt.stream_index == sid) {
329  ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
330  if (ret < 0) {
331  av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
332  av_err2str(ret));
333  } else if (got_subtitle) {
334  for (i = 0; i < sub.num_rects; i++) {
335  char *ass_line = sub.rects[i]->ass;
336  if (!ass_line)
337  break;
338  ass_process_data(ass->track, ass_line, strlen(ass_line));
339  }
340  }
341  }
342  av_free_packet(&pkt);
343  avsubtitle_free(&sub);
344  }
345 
346 end:
347  av_dict_free(&codec_opts);
348  if (dec_ctx)
349  avcodec_close(dec_ctx);
350  if (fmt)
351  avformat_close_input(&fmt);
352  return ret;
353 }
354 
355 AVFilter avfilter_vf_subtitles = {
356  .name = "subtitles",
357  .description = NULL_IF_CONFIG_SMALL("Render text subtitles onto input video using the libass library."),
358  .priv_size = sizeof(AssContext),
359  .init = init_subtitles,
360  .uninit = uninit,
362  .inputs = ass_inputs,
363  .outputs = ass_outputs,
364  .priv_class = &subtitles_class,
365 };
366 #endif
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0)
Blend an alpha mask with an uniform color.
Definition: drawutils.c:429
static void overlay_ass_image(AssContext *ass, AVFrame *picref, const ASS_Image *image)
Definition: vf_subtitles.c:152
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:501
static int config_input(AVFilterLink *inlink)
Definition: vf_subtitles.c:132
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
FFDrawContext draw
Definition: vf_subtitles.c:57
AVOption.
Definition: opt.h:251
#define AV_LOG_PANIC
Something went really wrong and we will crash now.
Definition: log.h:135
static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
Definition: vf_subtitles.c:167
const char * fmt
Definition: avisynth_c.h:669
misc image utilities
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
external API header
ASS_Track * track
Definition: vf_subtitles.c:51
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
#define AV_CODEC_PROP_TEXT_SUB
Subtitle codec is text based.
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt)
Decode a subtitle message.
static void ass_log(int ass_level, const char *fmt, va_list args, void *ctx)
Definition: vf_subtitles.c:80
AVSubtitleRect ** rects
Format I/O context.
Definition: avformat.h:944
const char * name
Pad name.
static int query_formats(AVFilterContext *ctx)
Definition: vf_subtitles.c:126
uint8_t
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
ASS_Library * library
Definition: vf_subtitles.c:49
AVOptions.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
static AVPacket pkt
Definition: demuxing.c:56
end end
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
#define AV_LOG_QUIET
Definition: log.h:130
AVStream ** streams
Definition: avformat.h:992
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:142
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
uint8_t * data
void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:545
void av_vlog(void *avcl, int level, const char *fmt, va_list vl)
Definition: log.c:258
A filter pad used for either input or output.
int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream_nb, int related_stream, AVCodec **decoder_ret, int flags)
Find the "best" stream in the file.
int avcodec_close(AVCodecContext *avctx)
Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext its...
#define AA(c)
Definition: vf_subtitles.c:150
int width
width and height of the video frame
Definition: frame.h:122
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
Definition: avfilter.h:545
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:179
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
external API header
const AVCodecDescriptor * avcodec_descriptor_get(enum AVCodecID id)
Definition: codec_desc.c:2566
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
int props
Codec properties, a combination of AV_CODEC_PROP_* flags.
#define AV_LOG_VERBOSE
Definition: log.h:157
ret
Definition: avfilter.c:821
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:110
FIXME Range Coding of cr are level
Definition: snow.txt:367
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Stream structure.
Definition: avformat.h:643
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
NULL
Definition: eval.c:55
misc drawing utilities
#define AG(c)
Definition: vf_subtitles.c:148
ASS_Renderer * renderer
Definition: vf_subtitles.c:50
enum AVCodecID codec_id
static const int ass_libavfilter_log_level_map[]
Definition: vf_subtitles.c:69
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
main external API structure.
AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
void avsubtitle_free(AVSubtitle *sub)
Free all allocated data in the given subtitle struct.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:62
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
synthesis window for stochastic i
char * filename
Definition: vf_subtitles.c:52
const char * name
filter name
Definition: avfilter.h:437
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:135
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
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
misc parsing utilities
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
#define AB(c)
Definition: vf_subtitles.c:149
This struct describes the properties of a single codec described by an AVCodecID. ...
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
static av_cold int init(AVFilterContext *ctx)
Definition: vf_subtitles.c:88
Main libavformat public API header.
AVDictionary * codec_opts
Definition: cmdutils.c:68
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
#define OFFSET(x)
Definition: vf_subtitles.c:60
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
#define FLAGS
Definition: vf_subtitles.c:61
static AVCodecContext * dec_ctx
static const AVFilterPad ass_inputs[]
Definition: vf_subtitles.c:185
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:56
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
#define COMMON_OPTIONS
Definition: vf_subtitles.c:63
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_subtitles.c:114
#define AVFILTER_DEFINE_CLASS(fname)
char * ass
0 terminated ASS/SSA compatible event line.
An instance of a filter.
Definition: avfilter.h:524
int height
Definition: frame.h:122
#define AV_LOG_INFO
Definition: log.h:156
char * charenc
Definition: vf_subtitles.c:53
internal API functions
This structure stores compressed data.
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
static const AVFilterPad ass_outputs[]
Definition: vf_subtitles.c:196
int original_w
Definition: vf_subtitles.c:56
#define AR(c)
Definition: vf_subtitles.c:147
uint8_t * subtitle_header
Header containing style information for text subtitles.
int original_h
Definition: vf_subtitles.c:56