Flag added in a few simple filters. A bunch of other filters can likely use the feature as well.
Showing the changes to libavfilter/avfilter.c (1 of 21 files). Show all
Unified · Split
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include "libavutil/avstring.h" |
| 24 | 24 | #include "libavutil/channel_layout.h" |
| 25 | 25 | #include "libavutil/common.h" |
| 26 | +#include "libavutil/eval.h" | |
| 26 | 27 | #include "libavutil/imgutils.h" |
| 27 | 28 | #include "libavutil/opt.h" |
| 28 | 29 | #include "libavutil/pixdesc.h" |
| @@ -483,12 +484,20 @@ static const AVClass *filter_child_class_next(const AVClass *prev) · 454 unmodified lines | ||
| 483 | 484 | return NULL; |
| 484 | 485 | } |
| 485 | 486 | |
| 487 | +#define OFFSET(x) offsetof(AVFilterContext, x) | |
| 488 | +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | |
| 489 | +static const AVOption filters_common_options[] = { | |
| 490 | + { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, | |
| 491 | + { NULL } | |
| 492 | +}; | |
| 493 | + | |
| 486 | 494 | static const AVClass avfilter_class = { |
| 487 | 495 | .class_name = "AVFilter", |
| 488 | 496 | .item_name = default_filter_name, |
| 489 | 497 | .version = LIBAVUTIL_VERSION_INT, |
| 490 | 498 | .category = AV_CLASS_CATEGORY_FILTER, |
| 491 | 499 | .child_next = filter_child_next, |
| 500 | + .option = filters_common_options, | |
| 492 | 501 | .child_class_next = filter_child_class_next, |
| 493 | 502 | }; |
| 494 | 503 | |
| @@ -618,9 +627,16 @@ void avfilter_free(AVFilterContext *filter) · 123 unmodified lines | ||
| 618 | 627 | while(filter->command_queue){ |
| 619 | 628 | ff_command_queue_pop(filter); |
| 620 | 629 | } |
| 630 | + av_opt_free(filter); | |
| 631 | + av_expr_free(filter->enable); | |
| 632 | + filter->enable = NULL; | |
| 633 | + av_freep(&filter->var_values); | |
| 621 | 634 | av_free(filter); |
| 622 | 635 | } |
| 623 | 636 | |
| 637 | +static const char *const var_names[] = { "t", "n", "pos", NULL }; | |
| 638 | +enum { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB }; | |
| 639 | + | |
| 624 | 640 | static int process_options(AVFilterContext *ctx, AVDictionary **options, |
| 625 | 641 | const char *args) |
| 626 | 642 | { |
| @@ -630,6 +646,8 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, · 3 unmodified lines | ||
| 630 | 646 | const char *key; |
| 631 | 647 | int offset= -1; |
| 632 | 648 | |
| 649 | + av_opt_set_defaults(ctx); | |
| 650 | + | |
| 633 | 651 | if (!args) |
| 634 | 652 | return 0; |
| 635 | 653 | |
| @@ -665,6 +683,12 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, · 29 unmodified lines | ||
| 665 | 683 | } |
| 666 | 684 | |
| 667 | 685 | av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); |
| 686 | + | |
| 687 | + if (av_opt_find(ctx, key, NULL, 0, 0)) { | |
| 688 | + ret = av_opt_set(ctx, key, value, 0); | |
| 689 | + if (ret < 0) | |
| 690 | + return ret; | |
| 691 | + } else { | |
| 668 | 692 | av_dict_set(options, key, value, 0); |
| 669 | 693 | if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { |
| 670 | 694 | if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) { |
| @@ -675,11 +699,27 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, · 4 unmodified lines | ||
| 675 | 699 | return ret; |
| 676 | 700 | } |
| 677 | 701 | } |
| 702 | + } | |
| 678 | 703 | |
| 679 | 704 | av_free(value); |
| 680 | 705 | av_free(parsed_key); |
| 681 | 706 | count++; |
| 682 | 707 | } |
| 708 | + | |
| 709 | + if (ctx->enable_str) { | |
| 710 | + if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) { | |
| 711 | + av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported " | |
| 712 | + "with filter '%s'\n", ctx->filter->name); | |
| 713 | + return AVERROR_PATCHWELCOME; | |
| 714 | + } | |
| 715 | + ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values)); | |
| 716 | + if (!ctx->var_values) | |
| 717 | + return AVERROR(ENOMEM); | |
| 718 | + ret = av_expr_parse((AVExpr**)&ctx->enable, ctx->enable_str, var_names, | |
| 719 | + NULL, NULL, NULL, NULL, 0, ctx->priv); | |
| 720 | + if (ret < 0) | |
| 721 | + return ret; | |
| 722 | + } | |
| 683 | 723 | return count; |
| 684 | 724 | } |
| 685 | 725 | |
| @@ -852,6 +892,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame) · 166 unmodified lines | ||
| 852 | 892 | static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) |
| 853 | 893 | { |
| 854 | 894 | int (*filter_frame)(AVFilterLink *, AVFrame *); |
| 895 | + AVFilterContext *dstctx = link->dst; | |
| 855 | 896 | AVFilterPad *dst = link->dstpad; |
| 856 | 897 | AVFrame *out; |
| 857 | 898 | int ret; |
| @@ -914,6 +955,15 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) · 56 unmodified lines | ||
| 914 | 955 | } |
| 915 | 956 | |
| 916 | 957 | pts = out->pts; |
| 958 | + if (dstctx->enable_str) { | |
| 959 | + int64_t pos = av_frame_get_pkt_pos(out); | |
| 960 | + dstctx->var_values[VAR_N] = link->frame_count; | |
| 961 | + dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); | |
| 962 | + dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos; | |
| 963 | + if (!av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) | |
| 964 | + filter_frame = dst->passthrough_filter_frame ? dst->passthrough_filter_frame | |
| 965 | + : default_filter_frame; | |
| 966 | + } | |
| 917 | 967 | ret = filter_frame(link, out); |
| 918 | 968 | link->frame_count++; |
| 919 | 969 | link->frame_requested = 0; |