| @@ -27,6 +27,7 @@ · 26 unmodified lines |
| 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 { · 21 unmodified lines |
| 54 | 55 | f0r_destruct_f destruct; |
| 55 | 56 | f0r_deinit_f deinit; |
| 56 | 57 | char params[256]; |
| 58 | + |
| 59 | + /* only used by the source */ |
| 60 | + int w, h; |
| 61 | + AVRational time_base; |
| 62 | + uint64_t pts; |
| 57 | 63 | } Frei0rContext; |
| 58 | 64 | |
| 59 | 65 | 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 · 137 unmodified lines |
| 197 | 203 | return dlopen(path, RTLD_NOW|RTLD_LOCAL); |
| 198 | 204 | } |
| 199 | 205 | |
| 200 | | −static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
| 206 | +static av_cold int frei0r_init(AVFilterContext *ctx, |
| 207 | + const char *dl_name, int type) |
| 201 | 208 | { |
| 202 | 209 | Frei0rContext *frei0r = ctx->priv; |
| 203 | 210 | f0r_init_f f0r_init; |
| 204 | 211 | f0r_get_plugin_info_f f0r_get_plugin_info; |
| 205 | 212 | 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); |
| 213 | + char *path; |
| 212 | 214 | |
| 213 | 215 | /* see: http://piksel.org/frei0r/1.2/spec/1.2/spec/group__pluglocations.html */ |
| 214 | 216 | if ((path = av_strdup(getenv("FREI0R_PATH")))) { |
| @@ -250,9 +252,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) · 35 unmodified lines |
| 250 | 252 | |
| 251 | 253 | f0r_get_plugin_info(&frei0r->plugin_info); |
| 252 | 254 | pi = &frei0r->plugin_info; |
| 253 | | − if (pi->plugin_type != F0R_PLUGIN_TYPE_FILTER) { |
| 255 | + if (pi->plugin_type != type) { |
| 254 | 256 | av_log(ctx, AV_LOG_ERROR, |
| 255 | | − "Invalid type '%s' for the plugin, a filter plugin was expected\n", |
| 257 | + "Invalid type '%s' for the plugin\n", |
| 258 | + pi->plugin_type == F0R_PLUGIN_TYPE_FILTER ? "filter" : |
| 256 | 259 | pi->plugin_type == F0R_PLUGIN_TYPE_SOURCE ? "source" : |
| 257 | 260 | pi->plugin_type == F0R_PLUGIN_TYPE_MIXER2 ? "mixer2" : |
| 258 | 261 | 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) · 12 unmodified lines |
| 271 | 274 | return 0; |
| 272 | 275 | } |
| 273 | 276 | |
| 277 | +static av_cold int filter_init(AVFilterContext *ctx, const char *args, void *opaque) |
| 278 | +{ |
| 279 | + Frei0rContext *frei0r = ctx->priv; |
| 280 | + char dl_name[1024]; |
| 281 | + *frei0r->params = 0; |
| 282 | + |
| 283 | + if (args) |
| 284 | + sscanf(args, "%1023[^:]:%255c", dl_name, frei0r->params); |
| 285 | + |
| 286 | + return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_FILTER); |
| 287 | +} |
| 288 | + |
| 274 | 289 | static av_cold void uninit(AVFilterContext *ctx) |
| 275 | 290 | { |
| 276 | 291 | Frei0rContext *frei0r = ctx->priv; |
| @@ -344,7 +359,7 @@ AVFilter avfilter_vf_frei0r = { · 67 unmodified lines |
| 344 | 359 | .description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."), |
| 345 | 360 | |
| 346 | 361 | .query_formats = query_formats, |
| 347 | | − .init = init, |
| 362 | + .init = filter_init, |
| 348 | 363 | .uninit = uninit, |
| 349 | 364 | |
| 350 | 365 | .priv_size = sizeof(Frei0rContext), |
| @@ -361,3 +376,89 @@ AVFilter avfilter_vf_frei0r = { · 10 unmodified lines |
| 361 | 376 | .type = AVMEDIA_TYPE_VIDEO, }, |
| 362 | 377 | { .name = NULL}}, |
| 363 | 378 | }; |
| 379 | + |
| 380 | +static av_cold int source_init(AVFilterContext *ctx, const char *args, void *opaque) |
| 381 | +{ |
| 382 | + Frei0rContext *frei0r = ctx->priv; |
| 383 | + char dl_name[1024], c; |
| 384 | + char frame_size[128] = ""; |
| 385 | + char frame_rate[128] = ""; |
| 386 | + AVRational frame_rate_q; |
| 387 | + |
| 388 | + memset(frei0r->params, 0, sizeof(frei0r->params)); |
| 389 | + |
| 390 | + if (args) |
| 391 | + sscanf(args, "%127[^:]:%127[^:]:%1023[^:=]%c%255c", |
| 392 | + frame_size, frame_rate, dl_name, &c, frei0r->params); |
| 393 | + |
| 394 | + if (av_parse_video_size(&frei0r->w, &frei0r->h, frame_size) < 0) { |
| 395 | + av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", frame_size); |
| 396 | + return AVERROR(EINVAL); |
| 397 | + } |
| 398 | + |
| 399 | + if (av_parse_video_rate(&frame_rate_q, frame_rate) < 0 || |
| 400 | + frame_rate_q.den <= 0 || frame_rate_q.num <= 0) { |
| 401 | + av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", frame_rate); |
| 402 | + return AVERROR(EINVAL); |
| 403 | + } |
| 404 | + frei0r->time_base.num = frame_rate_q.den; |
| 405 | + frei0r->time_base.den = frame_rate_q.num; |
| 406 | + |
| 407 | + return frei0r_init(ctx, dl_name, F0R_PLUGIN_TYPE_SOURCE); |
| 408 | +} |
| 409 | + |
| 410 | +static int source_config_props(AVFilterLink *outlink) |
| 411 | +{ |
| 412 | + AVFilterContext *ctx = outlink->src; |
| 413 | + Frei0rContext *frei0r = ctx->priv; |
| 414 | + |
| 415 | + if (av_image_check_size(frei0r->w, frei0r->h, 0, ctx) < 0) |
| 416 | + return AVERROR(EINVAL); |
| 417 | + outlink->w = frei0r->w; |
| 418 | + outlink->h = frei0r->h; |
| 419 | + outlink->time_base = frei0r->time_base; |
| 420 | + |
| 421 | + if (!(frei0r->instance = frei0r->construct(outlink->w, outlink->h))) { |
| 422 | + av_log(ctx, AV_LOG_ERROR, "Impossible to load frei0r instance"); |
| 423 | + return AVERROR(EINVAL); |
| 424 | + } |
| 425 | + |
| 426 | + return set_params(ctx, frei0r->params); |
| 427 | +} |
| 428 | + |
| 429 | +static int source_request_frame(AVFilterLink *outlink) |
| 430 | +{ |
| 431 | + Frei0rContext *frei0r = outlink->src->priv; |
| 432 | + AVFilterBufferRef *picref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
| 433 | + picref->video->pixel_aspect = (AVRational) {1, 1}; |
| 434 | + picref->pts = frei0r->pts++; |
| 435 | + picref->pos = -1; |
| 436 | + |
| 437 | + avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0)); |
| 438 | + frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}), |
| 439 | + NULL, (uint32_t *)picref->data[0]); |
| 440 | + avfilter_draw_slice(outlink, 0, outlink->h, 1); |
| 441 | + avfilter_end_frame(outlink); |
| 442 | + avfilter_unref_buffer(picref); |
| 443 | + |
| 444 | + return 0; |
| 445 | +} |
| 446 | + |
| 447 | +AVFilter avfilter_vsrc_frei0r_src = { |
| 448 | + .name = "frei0r_src", |
| 449 | + .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."), |
| 450 | + |
| 451 | + .priv_size = sizeof(Frei0rContext), |
| 452 | + .init = source_init, |
| 453 | + .uninit = uninit, |
| 454 | + |
| 455 | + .query_formats = query_formats, |
| 456 | + |
| 457 | + .inputs = (AVFilterPad[]) {{ .name = NULL}}, |
| 458 | + |
| 459 | + .outputs = (AVFilterPad[]) {{ .name = "default", |
| 460 | + .type = AVMEDIA_TYPE_VIDEO, |
| 461 | + .request_frame = source_request_frame, |
| 462 | + .config_props = source_config_props }, |
| 463 | + { .name = NULL}}, |
| 464 | +}; |