Originally committed as revision 25855 to svn://svn.ffmpeg.org/ffmpeg/trunk
| ... | ... |
@@ -283,6 +283,7 @@ The following command: |
| 283 | 283 |
|
| 284 | 284 |
will convert the input video to the format "yuv420p". |
| 285 | 285 |
|
| 286 |
+@anchor{frei0r}
|
|
| 286 | 287 |
@section frei0r |
| 287 | 288 |
|
| 288 | 289 |
Apply a frei0r effect to the input video. |
| ... | ... |
@@ -869,6 +870,34 @@ respectively 352 and 288 (corresponding to the CIF size format). |
| 869 | 869 |
timebase. The expression can contain the constants "PI", "E", "PHI", |
| 870 | 870 |
"AVTB" (the default timebase), and defaults to the value "AVTB". |
| 871 | 871 |
|
| 872 |
+@section frei0r_src |
|
| 873 |
+ |
|
| 874 |
+Provide a frei0r source. |
|
| 875 |
+ |
|
| 876 |
+To enable compilation of this filter you need to install the frei0r |
|
| 877 |
+header and configure FFmpeg with --enable-frei0r. |
|
| 878 |
+ |
|
| 879 |
+The source supports the syntax: |
|
| 880 |
+@example |
|
| 881 |
+@var{size}:@var{rate}:@var{src_name}[@{=|:@}@var{param1}:@var{param2}:...:@var{paramN}]
|
|
| 882 |
+@end example |
|
| 883 |
+ |
|
| 884 |
+@var{size} is the size of the video to generate, may be a string of the
|
|
| 885 |
+form @var{width}x@var{height} or a frame size abbreviation.
|
|
| 886 |
+@var{rate} is the rate of the video to generate, may be a string of
|
|
| 887 |
+the form @var{num}/@var{den} or a frame rate abbreviation.
|
|
| 888 |
+@var{src_name} is the name to the frei0r source to load. For more
|
|
| 889 |
+information regarding frei0r and how to set the parameters read the |
|
| 890 |
+section "frei0r" (@pxref{frei0r}) in the description of the video
|
|
| 891 |
+filters. |
|
| 892 |
+ |
|
| 893 |
+Some examples follow: |
|
| 894 |
+@example |
|
| 895 |
+# generate a frei0r partik0l source with size 200x200 and framerate 10 |
|
| 896 |
+# which is overlayed on the overlay filter main input |
|
| 897 |
+frei0r_src=200x200:10:partik0l=1234 [overlay]; [in][overlay] overlay |
|
| 898 |
+@end example |
|
| 899 |
+ |
|
| 872 | 900 |
@c man end VIDEO SOURCES |
| 873 | 901 |
|
| 874 | 902 |
@chapter Video Sinks |
| ... | ... |
@@ -46,6 +46,7 @@ OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o |
| 46 | 46 |
|
| 47 | 47 |
OBJS-$(CONFIG_BUFFER_FILTER) += vsrc_buffer.o |
| 48 | 48 |
OBJS-$(CONFIG_COLOR_FILTER) += vf_pad.o |
| 49 |
+OBJS-$(CONFIG_FREI0R_SRC_FILTER) += vf_frei0r.o |
|
| 49 | 50 |
OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_nullsrc.o |
| 50 | 51 |
|
| 51 | 52 |
OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o |
| ... | ... |
@@ -67,6 +67,7 @@ void avfilter_register_all(void) |
| 67 | 67 |
|
| 68 | 68 |
REGISTER_FILTER (BUFFER, buffer, vsrc); |
| 69 | 69 |
REGISTER_FILTER (COLOR, color, vsrc); |
| 70 |
+ REGISTER_FILTER (FREI0R, frei0r_src, vsrc); |
|
| 70 | 71 |
REGISTER_FILTER (NULLSRC, nullsrc, vsrc); |
| 71 | 72 |
|
| 72 | 73 |
REGISTER_FILTER (NULLSINK, nullsink, vsink); |
| ... | ... |
@@ -25,7 +25,7 @@ |
| 25 | 25 |
#include "libavutil/avutil.h" |
| 26 | 26 |
|
| 27 | 27 |
#define LIBAVFILTER_VERSION_MAJOR 1 |
| 28 |
-#define LIBAVFILTER_VERSION_MINOR 65 |
|
| 28 |
+#define LIBAVFILTER_VERSION_MINOR 66 |
|
| 29 | 29 |
#define LIBAVFILTER_VERSION_MICRO 0 |
| 30 | 30 |
|
| 31 | 31 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
| ... | ... |
@@ -27,6 +27,7 @@ |
| 27 | 27 |
#include <dlfcn.h> |
| 28 | 28 |
#include <frei0r.h> |
| 29 | 29 |
#include "libavutil/avstring.h" |
| 30 |
+#include "libavcore/imgutils.h" |
|
| 30 | 31 |
#include "libavcore/parseutils.h" |
| 31 | 32 |
#include "avfilter.h" |
| 32 | 33 |
|
| ... | ... |
@@ -54,6 +55,11 @@ typedef struct Frei0rContext {
|
| 54 | 54 |
f0r_destruct_f destruct; |
| 55 | 55 |
f0r_deinit_f deinit; |
| 56 | 56 |
char params[256]; |
| 57 |
+ |
|
| 58 |
+ /* only used by the source */ |
|
| 59 |
+ int w, h; |
|
| 60 |
+ AVRational time_base; |
|
| 61 |
+ uint64_t pts; |
|
| 57 | 62 |
} Frei0rContext; |
| 58 | 63 |
|
| 59 | 64 |
static void *load_sym(AVFilterContext *ctx, const char *sym_name) |
| ... | ... |
@@ -197,18 +203,14 @@ static void *load_path(AVFilterContext *ctx, const char *prefix, const char *nam |
| 197 | 197 |
return dlopen(path, RTLD_NOW|RTLD_LOCAL); |
| 198 | 198 |
} |
| 199 | 199 |
|
| 200 |
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
|
| 200 |
+static av_cold int frei0r_init(AVFilterContext *ctx, |
|
| 201 |
+ const char *dl_name, int type) |
|
| 201 | 202 |
{
|
| 202 | 203 |
Frei0rContext *frei0r = ctx->priv; |
| 203 | 204 |
f0r_init_f f0r_init; |
| 204 | 205 |
f0r_get_plugin_info_f f0r_get_plugin_info; |
| 205 | 206 |
f0r_plugin_info_t *pi; |
| 206 |
- char dl_name[1024], *path; |
|
| 207 |
- |
|
| 208 |
- *frei0r->params = 0; |
|
| 209 |
- |
|
| 210 |
- if (args) |
|
| 211 |
- sscanf(args, "%1023[^:]:%255c", dl_name, frei0r->params); |
|
| 207 |
+ char *path; |
|
| 212 | 208 |
|
| 213 | 209 |
/* see: http://piksel.org/frei0r/1.2/spec/1.2/spec/group__pluglocations.html */ |
| 214 | 210 |
if ((path = av_strdup(getenv("FREI0R_PATH")))) {
|
| ... | ... |
@@ -250,9 +252,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
| 250 | 250 |
|
| 251 | 251 |
f0r_get_plugin_info(&frei0r->plugin_info); |
| 252 | 252 |
pi = &frei0r->plugin_info; |
| 253 |
- if (pi->plugin_type != F0R_PLUGIN_TYPE_FILTER) {
|
|
| 253 |
+ if (pi->plugin_type != type) {
|
|
| 254 | 254 |
av_log(ctx, AV_LOG_ERROR, |
| 255 |
- "Invalid type '%s' for the plugin, a filter plugin was expected\n", |
|
| 255 |
+ "Invalid type '%s' for the plugin\n", |
|
| 256 |
+ pi->plugin_type == F0R_PLUGIN_TYPE_FILTER ? "filter" : |
|
| 256 | 257 |
pi->plugin_type == F0R_PLUGIN_TYPE_SOURCE ? "source" : |
| 257 | 258 |
pi->plugin_type == F0R_PLUGIN_TYPE_MIXER2 ? "mixer2" : |
| 258 | 259 |
pi->plugin_type == F0R_PLUGIN_TYPE_MIXER3 ? "mixer3" : "unknown"); |
| ... | ... |
@@ -271,6 +274,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
| 271 | 271 |
return 0; |
| 272 | 272 |
} |
| 273 | 273 |
|
| 274 |
+static av_cold int filter_init(AVFilterContext *ctx, const char *args, void *opaque) |
|
| 275 |
+{
|
|
| 276 |
+ Frei0rContext *frei0r = ctx->priv; |
|
| 277 |
+ char dl_name[1024]; |
|
| 278 |
+ *frei0r->params = 0; |
|
| 279 |
+ |
|
| 280 |
+ if (args) |
|
| 281 |
+ sscanf(args, "%1023[^:]:%255c", dl_name, frei0r->params); |
|
| 282 |
+ |
|
| 283 |
+ return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_FILTER); |
|
| 284 |
+} |
|
| 285 |
+ |
|
| 274 | 286 |
static av_cold void uninit(AVFilterContext *ctx) |
| 275 | 287 |
{
|
| 276 | 288 |
Frei0rContext *frei0r = ctx->priv; |
| ... | ... |
@@ -344,7 +359,7 @@ AVFilter avfilter_vf_frei0r = {
|
| 344 | 344 |
.description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."),
|
| 345 | 345 |
|
| 346 | 346 |
.query_formats = query_formats, |
| 347 |
- .init = init, |
|
| 347 |
+ .init = filter_init, |
|
| 348 | 348 |
.uninit = uninit, |
| 349 | 349 |
|
| 350 | 350 |
.priv_size = sizeof(Frei0rContext), |
| ... | ... |
@@ -361,3 +376,89 @@ AVFilter avfilter_vf_frei0r = {
|
| 361 | 361 |
.type = AVMEDIA_TYPE_VIDEO, }, |
| 362 | 362 |
{ .name = NULL}},
|
| 363 | 363 |
}; |
| 364 |
+ |
|
| 365 |
+static av_cold int source_init(AVFilterContext *ctx, const char *args, void *opaque) |
|
| 366 |
+{
|
|
| 367 |
+ Frei0rContext *frei0r = ctx->priv; |
|
| 368 |
+ char dl_name[1024], c; |
|
| 369 |
+ char frame_size[128] = ""; |
|
| 370 |
+ char frame_rate[128] = ""; |
|
| 371 |
+ AVRational frame_rate_q; |
|
| 372 |
+ |
|
| 373 |
+ memset(frei0r->params, 0, sizeof(frei0r->params)); |
|
| 374 |
+ |
|
| 375 |
+ if (args) |
|
| 376 |
+ sscanf(args, "%127[^:]:%127[^:]:%1023[^:=]%c%255c", |
|
| 377 |
+ frame_size, frame_rate, dl_name, &c, frei0r->params); |
|
| 378 |
+ |
|
| 379 |
+ if (av_parse_video_size(&frei0r->w, &frei0r->h, frame_size) < 0) {
|
|
| 380 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", frame_size); |
|
| 381 |
+ return AVERROR(EINVAL); |
|
| 382 |
+ } |
|
| 383 |
+ |
|
| 384 |
+ if (av_parse_video_rate(&frame_rate_q, frame_rate) < 0 || |
|
| 385 |
+ frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
|
|
| 386 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", frame_rate); |
|
| 387 |
+ return AVERROR(EINVAL); |
|
| 388 |
+ } |
|
| 389 |
+ frei0r->time_base.num = frame_rate_q.den; |
|
| 390 |
+ frei0r->time_base.den = frame_rate_q.num; |
|
| 391 |
+ |
|
| 392 |
+ return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_SOURCE); |
|
| 393 |
+} |
|
| 394 |
+ |
|
| 395 |
+static int source_config_props(AVFilterLink *outlink) |
|
| 396 |
+{
|
|
| 397 |
+ AVFilterContext *ctx = outlink->src; |
|
| 398 |
+ Frei0rContext *frei0r = ctx->priv; |
|
| 399 |
+ |
|
| 400 |
+ if (av_image_check_size(frei0r->w, frei0r->h, 0, ctx) < 0) |
|
| 401 |
+ return AVERROR(EINVAL); |
|
| 402 |
+ outlink->w = frei0r->w; |
|
| 403 |
+ outlink->h = frei0r->h; |
|
| 404 |
+ outlink->time_base = frei0r->time_base; |
|
| 405 |
+ |
|
| 406 |
+ if (!(frei0r->instance = frei0r->construct(outlink->w, outlink->h))) {
|
|
| 407 |
+ av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance"); |
|
| 408 |
+ return AVERROR(EINVAL); |
|
| 409 |
+ } |
|
| 410 |
+ |
|
| 411 |
+ return set_params(ctx, frei0r->params); |
|
| 412 |
+} |
|
| 413 |
+ |
|
| 414 |
+static int source_request_frame(AVFilterLink *outlink) |
|
| 415 |
+{
|
|
| 416 |
+ Frei0rContext *frei0r = outlink->src->priv; |
|
| 417 |
+ AVFilterBufferRef *picref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
|
| 418 |
+ picref->video->pixel_aspect = (AVRational) {1, 1};
|
|
| 419 |
+ picref->pts = frei0r->pts++; |
|
| 420 |
+ picref->pos = -1; |
|
| 421 |
+ |
|
| 422 |
+ avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0)); |
|
| 423 |
+ frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
|
|
| 424 |
+ NULL, (uint32_t *)picref->data[0]); |
|
| 425 |
+ avfilter_draw_slice(outlink, 0, outlink->h, 1); |
|
| 426 |
+ avfilter_end_frame(outlink); |
|
| 427 |
+ avfilter_unref_buffer(picref); |
|
| 428 |
+ |
|
| 429 |
+ return 0; |
|
| 430 |
+} |
|
| 431 |
+ |
|
| 432 |
+AVFilter avfilter_vsrc_frei0r_src = {
|
|
| 433 |
+ .name = "frei0r_src", |
|
| 434 |
+ .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."),
|
|
| 435 |
+ |
|
| 436 |
+ .priv_size = sizeof(Frei0rContext), |
|
| 437 |
+ .init = source_init, |
|
| 438 |
+ .uninit = uninit, |
|
| 439 |
+ |
|
| 440 |
+ .query_formats = query_formats, |
|
| 441 |
+ |
|
| 442 |
+ .inputs = (AVFilterPad[]) {{ .name = NULL}},
|
|
| 443 |
+ |
|
| 444 |
+ .outputs = (AVFilterPad[]) {{ .name = "default",
|
|
| 445 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
| 446 |
+ .request_frame = source_request_frame, |
|
| 447 |
+ .config_props = source_config_props }, |
|
| 448 |
+ { .name = NULL}},
|
|
| 449 |
+}; |