... | ... |
@@ -1970,6 +1970,7 @@ removelogo_filter_deps="avcodec avformat swscale" |
1970 | 1970 |
scale_filter_deps="swscale" |
1971 | 1971 |
smartblur_filter_deps="gpl swscale" |
1972 | 1972 |
showspectrum_filter_deps="avcodec rdft" |
1973 |
+subtitles_filter_deps="avformat avcodec libass" |
|
1973 | 1974 |
super2xsai_filter_deps="gpl" |
1974 | 1975 |
tinterlace_filter_deps="gpl" |
1975 | 1976 |
yadif_filter_deps="gpl" |
... | ... |
@@ -1274,38 +1274,9 @@ overlay to a video stream, consider the @var{overlay} filter instead. |
1274 | 1274 |
|
1275 | 1275 |
@section ass |
1276 | 1276 |
|
1277 |
-Draw ASS (Advanced Substation Alpha) subtitles on top of input video |
|
1278 |
-using the libass library. |
|
1279 |
- |
|
1280 |
-To enable compilation of this filter you need to configure FFmpeg with |
|
1281 |
-@code{--enable-libass}. |
|
1282 |
- |
|
1283 |
-This filter accepts the following named options, expressed as a |
|
1284 |
-sequence of @var{key}=@var{value} pairs, separated by ":". |
|
1285 |
- |
|
1286 |
-@table @option |
|
1287 |
-@item filename, f |
|
1288 |
-Set the filename of the ASS file to read. It must be specified. |
|
1289 |
- |
|
1290 |
-@item original_size |
|
1291 |
-Specify the size of the original video, the video for which the ASS file |
|
1292 |
-was composed. Due to a misdesign in ASS aspect ratio arithmetic, this is |
|
1293 |
-necessary to correctly scale the fonts if the aspect ratio has been changed. |
|
1294 |
-@end table |
|
1295 |
- |
|
1296 |
-If the first key is not specified, it is assumed that the first value |
|
1297 |
-specifies the @option{filename}. |
|
1298 |
- |
|
1299 |
-For example, to render the file @file{sub.ass} on top of the input |
|
1300 |
-video, use the command: |
|
1301 |
-@example |
|
1302 |
-ass=sub.ass |
|
1303 |
-@end example |
|
1304 |
- |
|
1305 |
-which is equivalent to: |
|
1306 |
-@example |
|
1307 |
-ass=filename=sub.ass |
|
1308 |
-@end example |
|
1277 |
+Same as the @ref{subtitles} filter, except that it doesn't require libavcodec |
|
1278 |
+and libavformat to work. On the other hand, it is limited to ASS (Advanced |
|
1279 |
+Substation Alpha) subtitles files. |
|
1309 | 1280 |
|
1310 | 1281 |
@section bbox |
1311 | 1282 |
|
... | ... |
@@ -3745,6 +3716,43 @@ a pixel should be blurred or not. A value of 0 will filter all the |
3745 | 3745 |
image, a value included in [0,30] will filter flat areas and a value |
3746 | 3746 |
included in [-30,0] will filter edges. |
3747 | 3747 |
|
3748 |
+@anchor{subtitles} |
|
3749 |
+@section subtitles |
|
3750 |
+ |
|
3751 |
+Draw subtitles on top of input video using the libass library. |
|
3752 |
+ |
|
3753 |
+To enable compilation of this filter you need to configure FFmpeg with |
|
3754 |
+@code{--enable-libass}. This filter also requires a build with libavcodec and |
|
3755 |
+libavformat to convert the passed subtitles file to ASS (Advanced Substation |
|
3756 |
+Alpha) subtitles format. |
|
3757 |
+ |
|
3758 |
+This filter accepts the following named options, expressed as a |
|
3759 |
+sequence of @var{key}=@var{value} pairs, separated by ":". |
|
3760 |
+ |
|
3761 |
+@table @option |
|
3762 |
+@item filename, f |
|
3763 |
+Set the filename of the subtitle file to read. It must be specified. |
|
3764 |
+ |
|
3765 |
+@item original_size |
|
3766 |
+Specify the size of the original video, the video for which the ASS file |
|
3767 |
+was composed. Due to a misdesign in ASS aspect ratio arithmetic, this is |
|
3768 |
+necessary to correctly scale the fonts if the aspect ratio has been changed. |
|
3769 |
+@end table |
|
3770 |
+ |
|
3771 |
+If the first key is not specified, it is assumed that the first value |
|
3772 |
+specifies the @option{filename}. |
|
3773 |
+ |
|
3774 |
+For example, to render the file @file{sub.srt} on top of the input |
|
3775 |
+video, use the command: |
|
3776 |
+@example |
|
3777 |
+subtitles=sub.srt |
|
3778 |
+@end example |
|
3779 |
+ |
|
3780 |
+which is equivalent to: |
|
3781 |
+@example |
|
3782 |
+subtitles=filename=sub.srt |
|
3783 |
+@end example |
|
3784 |
+ |
|
3748 | 3785 |
@section split |
3749 | 3786 |
|
3750 | 3787 |
Split input video into several identical outputs. |
... | ... |
@@ -134,6 +134,7 @@ OBJS-$(CONFIG_SETTB_FILTER) += f_settb.o |
134 | 134 |
OBJS-$(CONFIG_SHOWINFO_FILTER) += vf_showinfo.o |
135 | 135 |
OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o |
136 | 136 |
OBJS-$(CONFIG_SPLIT_FILTER) += split.o |
137 |
+OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_ass.o |
|
137 | 138 |
OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o |
138 | 139 |
OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o |
139 | 140 |
OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o |
... | ... |
@@ -126,6 +126,7 @@ void avfilter_register_all(void) |
126 | 126 |
REGISTER_FILTER (SHOWINFO, showinfo, vf); |
127 | 127 |
REGISTER_FILTER (SMARTBLUR, smartblur, vf); |
128 | 128 |
REGISTER_FILTER (SPLIT, split, vf); |
129 |
+ REGISTER_FILTER (SUBTITLES, subtitles, vf); |
|
129 | 130 |
REGISTER_FILTER (SUPER2XSAI, super2xsai, vf); |
130 | 131 |
REGISTER_FILTER (SWAPUV, swapuv, vf); |
131 | 132 |
REGISTER_FILTER (THUMBNAIL, thumbnail, vf); |
... | ... |
@@ -29,8 +29,8 @@ |
29 | 29 |
#include "libavutil/avutil.h" |
30 | 30 |
|
31 | 31 |
#define LIBAVFILTER_VERSION_MAJOR 3 |
32 |
-#define LIBAVFILTER_VERSION_MINOR 23 |
|
33 |
-#define LIBAVFILTER_VERSION_MICRO 105 |
|
32 |
+#define LIBAVFILTER_VERSION_MINOR 24 |
|
33 |
+#define LIBAVFILTER_VERSION_MICRO 100 |
|
34 | 34 |
|
35 | 35 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
36 | 36 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -1,6 +1,7 @@ |
1 | 1 |
/* |
2 | 2 |
* Copyright (c) 2011 Baptiste Coudurier |
3 | 3 |
* Copyright (c) 2011 Stefano Sabatini |
4 |
+ * Copyright (c) 2012 Clément Bœsch |
|
4 | 5 |
* |
5 | 6 |
* This file is part of FFmpeg. |
6 | 7 |
* |
... | ... |
@@ -28,6 +29,11 @@ |
28 | 28 |
|
29 | 29 |
#include <ass/ass.h> |
30 | 30 |
|
31 |
+#include "config.h" |
|
32 |
+#if CONFIG_SUBTITLES_FILTER |
|
33 |
+# include "libavcodec/avcodec.h" |
|
34 |
+# include "libavformat/avformat.h" |
|
35 |
+#endif |
|
31 | 36 |
#include "libavutil/avstring.h" |
32 | 37 |
#include "libavutil/imgutils.h" |
33 | 38 |
#include "libavutil/opt.h" |
... | ... |
@@ -53,15 +59,13 @@ typedef struct { |
53 | 53 |
#define OFFSET(x) offsetof(AssContext, x) |
54 | 54 |
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
55 | 55 |
|
56 |
-static const AVOption ass_options[] = { |
|
57 |
- {"filename", "set the filename of the ASS file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
58 |
- {"f", "set the filename of the ASS file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
56 |
+static const AVOption options[] = { |
|
57 |
+ {"filename", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
58 |
+ {"f", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
59 | 59 |
{"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 }, |
60 | 60 |
{NULL}, |
61 | 61 |
}; |
62 | 62 |
|
63 |
-AVFILTER_DEFINE_CLASS(ass); |
|
64 |
- |
|
65 | 63 |
/* libass supports a log level ranging from 0 to 7 */ |
66 | 64 |
static const int ass_libavfilter_log_level_map[] = { |
67 | 65 |
AV_LOG_QUIET, /* 0 */ |
... | ... |
@@ -82,13 +86,13 @@ static void ass_log(int ass_level, const char *fmt, va_list args, void *ctx) |
82 | 82 |
av_log(ctx, level, "\n"); |
83 | 83 |
} |
84 | 84 |
|
85 |
-static av_cold int init(AVFilterContext *ctx, const char *args) |
|
85 |
+static av_cold int init(AVFilterContext *ctx, const char *args, const AVClass *class) |
|
86 | 86 |
{ |
87 | 87 |
AssContext *ass = ctx->priv; |
88 | 88 |
static const char *shorthand[] = { "filename", NULL }; |
89 | 89 |
int ret; |
90 | 90 |
|
91 |
- ass->class = &ass_class; |
|
91 |
+ ass->class = class; |
|
92 | 92 |
av_opt_set_defaults(ass); |
93 | 93 |
|
94 | 94 |
if ((ret = av_opt_set_from_string(ass, args, shorthand, "=", ":")) < 0) |
... | ... |
@@ -112,14 +116,6 @@ static av_cold int init(AVFilterContext *ctx, const char *args) |
112 | 112 |
return AVERROR(EINVAL); |
113 | 113 |
} |
114 | 114 |
|
115 |
- ass->track = ass_read_file(ass->library, ass->filename, NULL); |
|
116 |
- if (!ass->track) { |
|
117 |
- av_log(ctx, AV_LOG_ERROR, |
|
118 |
- "Could not create a libass track when reading file '%s'\n", |
|
119 |
- ass->filename); |
|
120 |
- return AVERROR(EINVAL); |
|
121 |
- } |
|
122 |
- |
|
123 | 115 |
ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1); |
124 | 116 |
return 0; |
125 | 117 |
} |
... | ... |
@@ -215,14 +211,143 @@ static const AVFilterPad ass_outputs[] = { |
215 | 215 |
{ NULL } |
216 | 216 |
}; |
217 | 217 |
|
218 |
+#if CONFIG_ASS_FILTER |
|
219 |
+ |
|
220 |
+#define ass_options options |
|
221 |
+AVFILTER_DEFINE_CLASS(ass); |
|
222 |
+ |
|
223 |
+static av_cold int init_ass(AVFilterContext *ctx, const char *args) |
|
224 |
+{ |
|
225 |
+ AssContext *ass = ctx->priv; |
|
226 |
+ int ret = init(ctx, args, &ass_class); |
|
227 |
+ |
|
228 |
+ if (ret < 0) |
|
229 |
+ return ret; |
|
230 |
+ |
|
231 |
+ ass->track = ass_read_file(ass->library, ass->filename, NULL); |
|
232 |
+ if (!ass->track) { |
|
233 |
+ av_log(ctx, AV_LOG_ERROR, |
|
234 |
+ "Could not create a libass track when reading file '%s'\n", |
|
235 |
+ ass->filename); |
|
236 |
+ return AVERROR(EINVAL); |
|
237 |
+ } |
|
238 |
+ return 0; |
|
239 |
+} |
|
240 |
+ |
|
218 | 241 |
AVFilter avfilter_vf_ass = { |
219 | 242 |
.name = "ass", |
220 | 243 |
.description = NULL_IF_CONFIG_SMALL("Render subtitles onto input video using the libass library."), |
221 | 244 |
.priv_size = sizeof(AssContext), |
222 |
- .init = init, |
|
245 |
+ .init = init_ass, |
|
223 | 246 |
.uninit = uninit, |
224 | 247 |
.query_formats = query_formats, |
225 | 248 |
.inputs = ass_inputs, |
226 | 249 |
.outputs = ass_outputs, |
227 | 250 |
.priv_class = &ass_class, |
228 | 251 |
}; |
252 |
+#endif |
|
253 |
+ |
|
254 |
+#if CONFIG_SUBTITLES_FILTER |
|
255 |
+ |
|
256 |
+#define subtitles_options options |
|
257 |
+AVFILTER_DEFINE_CLASS(subtitles); |
|
258 |
+ |
|
259 |
+static av_cold int init_subtitles(AVFilterContext *ctx, const char *args) |
|
260 |
+{ |
|
261 |
+ int ret, sid; |
|
262 |
+ AVFormatContext *fmt = NULL; |
|
263 |
+ AVCodecContext *dec_ctx = NULL; |
|
264 |
+ AVCodec *dec = NULL; |
|
265 |
+ AVStream *st; |
|
266 |
+ AVPacket pkt; |
|
267 |
+ AssContext *ass = ctx->priv; |
|
268 |
+ |
|
269 |
+ /* Init libass */ |
|
270 |
+ ret = init(ctx, args, &subtitles_class); |
|
271 |
+ if (ret < 0) |
|
272 |
+ return ret; |
|
273 |
+ ass->track = ass_new_track(ass->library); |
|
274 |
+ if (!ass->track) { |
|
275 |
+ av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n"); |
|
276 |
+ return AVERROR(EINVAL); |
|
277 |
+ } |
|
278 |
+ |
|
279 |
+ /* Open subtitles file */ |
|
280 |
+ ret = avformat_open_input(&fmt, ass->filename, NULL, NULL); |
|
281 |
+ if (ret < 0) { |
|
282 |
+ av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename); |
|
283 |
+ goto end; |
|
284 |
+ } |
|
285 |
+ ret = avformat_find_stream_info(fmt, NULL); |
|
286 |
+ if (ret < 0) |
|
287 |
+ goto end; |
|
288 |
+ |
|
289 |
+ /* Locate subtitles stream */ |
|
290 |
+ ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0); |
|
291 |
+ if (ret < 0) { |
|
292 |
+ av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n", |
|
293 |
+ ass->filename); |
|
294 |
+ goto end; |
|
295 |
+ } |
|
296 |
+ sid = ret; |
|
297 |
+ st = fmt->streams[sid]; |
|
298 |
+ |
|
299 |
+ /* Open decoder */ |
|
300 |
+ dec_ctx = st->codec; |
|
301 |
+ dec = avcodec_find_decoder(dec_ctx->codec_id); |
|
302 |
+ if (!dec) { |
|
303 |
+ av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n", |
|
304 |
+ avcodec_get_name(dec_ctx->codec_id)); |
|
305 |
+ return AVERROR(EINVAL); |
|
306 |
+ } |
|
307 |
+ ret = avcodec_open2(dec_ctx, dec, NULL); |
|
308 |
+ if (ret < 0) |
|
309 |
+ goto end; |
|
310 |
+ |
|
311 |
+ /* Decode subtitles and push them into the renderer (libass) */ |
|
312 |
+ if (dec_ctx->subtitle_header) |
|
313 |
+ ass_process_codec_private(ass->track, |
|
314 |
+ dec_ctx->subtitle_header, |
|
315 |
+ dec_ctx->subtitle_header_size); |
|
316 |
+ av_init_packet(&pkt); |
|
317 |
+ pkt.data = NULL; |
|
318 |
+ pkt.size = 0; |
|
319 |
+ while (av_read_frame(fmt, &pkt) >= 0) { |
|
320 |
+ int i, got_subtitle; |
|
321 |
+ AVSubtitle sub; |
|
322 |
+ |
|
323 |
+ if (pkt.stream_index == sid) { |
|
324 |
+ ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt); |
|
325 |
+ if (ret < 0 || !got_subtitle) |
|
326 |
+ break; |
|
327 |
+ for (i = 0; i < sub.num_rects; i++) { |
|
328 |
+ char *ass_line = sub.rects[i]->ass; |
|
329 |
+ if (!ass_line) |
|
330 |
+ break; |
|
331 |
+ ass_process_data(ass->track, ass_line, strlen(ass_line)); |
|
332 |
+ } |
|
333 |
+ } |
|
334 |
+ av_free_packet(&pkt); |
|
335 |
+ avsubtitle_free(&sub); |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+end: |
|
339 |
+ if (fmt) |
|
340 |
+ avformat_close_input(&fmt); |
|
341 |
+ if (dec_ctx) |
|
342 |
+ avcodec_close(dec_ctx); |
|
343 |
+ return ret; |
|
344 |
+} |
|
345 |
+ |
|
346 |
+AVFilter avfilter_vf_subtitles = { |
|
347 |
+ .name = "subtitles", |
|
348 |
+ .description = NULL_IF_CONFIG_SMALL("Render subtitles onto input video using the libass library."), |
|
349 |
+ .priv_size = sizeof(AssContext), |
|
350 |
+ .init = init_subtitles, |
|
351 |
+ .uninit = uninit, |
|
352 |
+ .query_formats = query_formats, |
|
353 |
+ .inputs = ass_inputs, |
|
354 |
+ .outputs = ass_outputs, |
|
355 |
+ .priv_class = &subtitles_class, |
|
356 |
+}; |
|
357 |
+#endif |