Flag added in a few simple filters. A bunch of other filters can likely use the feature as well.
Unified · Split
| @@ -30,6 +30,7 @@ version <next>: · 29 unmodified lines | |||
| 30 | - decent native animated GIF encoding | 30 | - decent native animated GIF encoding |
| 31 | - asetrate filter | 31 | - asetrate filter |
| 32 | - interleave filter | 32 | - interleave filter |
| 33 | - timeline editing with filters | ||
| 33 | 34 | ||
| 34 | 35 | ||
| 35 | version 1.2: | 36 | version 1.2: |
| @@ -1683,6 +1683,8 @@ static void show_help_filter(const char *name) · 1682 unmodified lines | |||
| 1683 | if (f->priv_class) | 1683 | if (f->priv_class) |
| 1684 | show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | | 1684 | show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | |
| 1685 | AV_OPT_FLAG_AUDIO_PARAM); | 1685 | AV_OPT_FLAG_AUDIO_PARAM); |
| 1686 | if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) | ||
| 1687 | printf("This filter has support for timeline through the 'enable' option.\n"); | ||
| 1686 | #else | 1688 | #else |
| 1687 | av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; " | 1689 | av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; " |
| 1688 | "can not to satisfy request\n"); | 1690 | "can not to satisfy request\n"); |
| @@ -267,6 +267,36 @@ See the ``Quoting and escaping'' section in the ffmpeg-utils manual · 266 unmodified lines | |||
| 267 | for more information about the escaping and quoting rules adopted by | 267 | for more information about the escaping and quoting rules adopted by |
| 268 | FFmpeg. | 268 | FFmpeg. |
| 269 | 269 | ||
| 270 | @chapter Timeline editing | ||
| 271 | |||
| 272 | Some filters support a generic @option{enable} option. For the filters | ||
| 273 | supporting timeline editing, this option can be set to an expression which is | ||
| 274 | evaluated before sending a frame to the filter. If the evaluation is non-zero, | ||
| 275 | the filter will be enabled, otherwise the frame will be sent unchanged to the | ||
| 276 | next filter in the filtergraph. | ||
| 277 | |||
| 278 | The expression accepts the following values: | ||
| 279 | @table @samp | ||
| 280 | @item t | ||
| 281 | timestamp expressed in seconds, NAN if the input timestamp is unknown | ||
| 282 | |||
| 283 | @item n | ||
| 284 | sequential number of the input frame, starting from 0 | ||
| 285 | |||
| 286 | @item pos | ||
| 287 | the position in the file of the input frame, NAN if unknown | ||
| 288 | @end table | ||
| 289 | |||
| 290 | Like any other filtering option, the @option{enable} option follows the same | ||
| 291 | rules. | ||
| 292 | |||
| 293 | For example, to enable a denoiser filter (@ref{hqdn3d}) from 10 seconds to 3 | ||
| 294 | minutes, and a @ref{curves} filter starting at 3 seconds: | ||
| 295 | @example | ||
| 296 | hqdn3d = enable='between(t,10,3*60)', | ||
| 297 | curves = enable='gte(t,3)' : preset=cross_process | ||
| 298 | @end example | ||
| 299 | |||
| 270 | @c man end FILTERGRAPH DESCRIPTION | 300 | @c man end FILTERGRAPH DESCRIPTION |
| 271 | 301 | ||
| 272 | @chapter Audio Filters | 302 | @chapter Audio Filters |
| @@ -2409,6 +2439,7 @@ indicates never reset and return the largest area encountered during · 2136 unmodified lines | |||
| 2409 | playback. | 2439 | playback. |
| 2410 | @end table | 2440 | @end table |
| 2411 | 2441 | ||
| 2442 | @anchor{curves} | ||
| 2412 | @section curves | 2443 | @section curves |
| 2413 | 2444 | ||
| 2414 | Apply color adjustments using curves. | 2445 | Apply color adjustments using curves. |
| @@ -4013,6 +4044,7 @@ ffplay -i input -vf histogram · 1598 unmodified lines | |||
| 4013 | 4044 | ||
| 4014 | @end itemize | 4045 | @end itemize |
| 4015 | 4046 | ||
| 4047 | @anchor{hqdn3d} | ||
| 4016 | @section hqdn3d | 4048 | @section hqdn3d |
| 4017 | 4049 | ||
| 4018 | High precision/quality 3d denoise filter. This filter aims to reduce | 4050 | High precision/quality 3d denoise filter. This filter aims to reduce |
| @@ -296,4 +296,5 @@ AVFilter avfilter_af_volume = { · 295 unmodified lines | |||
| 296 | .init = init, | 296 | .init = init, |
| 297 | .inputs = avfilter_af_volume_inputs, | 297 | .inputs = avfilter_af_volume_inputs, |
| 298 | .outputs = avfilter_af_volume_outputs, | 298 | .outputs = avfilter_af_volume_outputs, |
| 299 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 299 | }; | 300 | }; |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | |||
| 23 | #include "libavutil/avstring.h" | 23 | #include "libavutil/avstring.h" |
| 24 | #include "libavutil/channel_layout.h" | 24 | #include "libavutil/channel_layout.h" |
| 25 | #include "libavutil/common.h" | 25 | #include "libavutil/common.h" |
| 26 | #include "libavutil/eval.h" | ||
| 26 | #include "libavutil/imgutils.h" | 27 | #include "libavutil/imgutils.h" |
| 27 | #include "libavutil/opt.h" | 28 | #include "libavutil/opt.h" |
| 28 | #include "libavutil/pixdesc.h" | 29 | #include "libavutil/pixdesc.h" |
| @@ -483,12 +484,20 @@ static const AVClass *filter_child_class_next(const AVClass *prev) · 454 unmodified lines | |||
| 483 | return NULL; | 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 | static const AVClass avfilter_class = { | 494 | static const AVClass avfilter_class = { |
| 487 | .class_name = "AVFilter", | 495 | .class_name = "AVFilter", |
| 488 | .item_name = default_filter_name, | 496 | .item_name = default_filter_name, |
| 489 | .version = LIBAVUTIL_VERSION_INT, | 497 | .version = LIBAVUTIL_VERSION_INT, |
| 490 | .category = AV_CLASS_CATEGORY_FILTER, | 498 | .category = AV_CLASS_CATEGORY_FILTER, |
| 491 | .child_next = filter_child_next, | 499 | .child_next = filter_child_next, |
| 500 | .option = filters_common_options, | ||
| 492 | .child_class_next = filter_child_class_next, | 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 | while(filter->command_queue){ | 627 | while(filter->command_queue){ |
| 619 | ff_command_queue_pop(filter); | 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 | av_free(filter); | 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 | static int process_options(AVFilterContext *ctx, AVDictionary **options, | 640 | static int process_options(AVFilterContext *ctx, AVDictionary **options, |
| 625 | const char *args) | 641 | const char *args) |
| 626 | { | 642 | { |
| @@ -630,6 +646,8 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, · 3 unmodified lines | |||
| 630 | const char *key; | 646 | const char *key; |
| 631 | int offset= -1; | 647 | int offset= -1; |
| 632 | 648 | ||
| 649 | av_opt_set_defaults(ctx); | ||
| 650 | |||
| 633 | if (!args) | 651 | if (!args) |
| 634 | return 0; | 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 | av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); | 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 | av_dict_set(options, key, value, 0); | 692 | av_dict_set(options, key, value, 0); |
| 669 | if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { | 693 | if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { |
| 670 | if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) { | 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 | return ret; | 699 | return ret; |
| 676 | } | 700 | } |
| 677 | } | 701 | } |
| 702 | } | ||
| 678 | 703 | ||
| 679 | av_free(value); | 704 | av_free(value); |
| 680 | av_free(parsed_key); | 705 | av_free(parsed_key); |
| 681 | count++; | 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 | return count; | 723 | return count; |
| 684 | } | 724 | } |
| 685 | 725 | ||
| @@ -852,6 +892,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame) · 166 unmodified lines | |||
| 852 | static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) | 892 | static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) |
| 853 | { | 893 | { |
| 854 | int (*filter_frame)(AVFilterLink *, AVFrame *); | 894 | int (*filter_frame)(AVFilterLink *, AVFrame *); |
| 895 | AVFilterContext *dstctx = link->dst; | ||
| 855 | AVFilterPad *dst = link->dstpad; | 896 | AVFilterPad *dst = link->dstpad; |
| 856 | AVFrame *out; | 897 | AVFrame *out; |
| 857 | int ret; | 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 | pts = out->pts; | 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 | ret = filter_frame(link, out); | 967 | ret = filter_frame(link, out); |
| 918 | link->frame_count++; | 968 | link->frame_count++; |
| 919 | link->frame_requested = 0; | 969 | link->frame_requested = 0; |
| @@ -385,6 +385,19 @@ struct AVFilterPad { · 384 unmodified lines | |||
| 385 | int needs_fifo; | 385 | int needs_fifo; |
| 386 | 386 | ||
| 387 | int needs_writable; | 387 | int needs_writable; |
| 388 | |||
| 389 | /** | ||
| 390 | * Passthrough filtering callback. | ||
| 391 | * | ||
| 392 | * If a filter supports timeline editing (in case | ||
| 393 | * AVFILTER_FLAG_SUPPORT_TIMELINE is enabled) then it can implement a | ||
| 394 | * custom passthrough callback to update its local context (for example to | ||
| 395 | * keep a frame reference, or simply send the filter to a custom outlink). | ||
| 396 | * The filter must not do any change to the frame in this callback. | ||
| 397 | * | ||
| 398 | * Input pads only. | ||
| 399 | */ | ||
| 400 | int (*passthrough_filter_frame)(AVFilterLink *link, AVFrame *frame); | ||
| 388 | }; | 401 | }; |
| 389 | #endif | 402 | #endif |
| 390 | 403 | ||
| @@ -428,6 +441,12 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); · 37 unmodified lines | |||
| 428 | * the options supplied to it. | 441 | * the options supplied to it. |
| 429 | */ | 442 | */ |
| 430 | #define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1) | 443 | #define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1) |
| 444 | /** | ||
| 445 | * Some filters support a generic "enable" expression option that can be used | ||
| 446 | * to enable or disable a filter in the timeline. Filters supporting this | ||
| 447 | * option have this flag set. | ||
| 448 | */ | ||
| 449 | #define AVFILTER_FLAG_SUPPORT_TIMELINE (1 << 16) | ||
| 431 | 450 | ||
| 432 | /** | 451 | /** |
| 433 | * Filter definition. This defines the pads a filter contains, and all the | 452 | * Filter definition. This defines the pads a filter contains, and all the |
| @@ -522,7 +541,7 @@ typedef struct AVFilter { · 88 unmodified lines | |||
| 522 | 541 | ||
| 523 | /** An instance of a filter */ | 542 | /** An instance of a filter */ |
| 524 | struct AVFilterContext { | 543 | struct AVFilterContext { |
| 525 | const AVClass *av_class; ///< needed for av_log() | 544 | const AVClass *av_class; ///< needed for av_log() and filters common options |
| 526 | 545 | ||
| 527 | const AVFilter *filter; ///< the AVFilter of which this is an instance | 546 | const AVFilter *filter; ///< the AVFilter of which this is an instance |
| 528 | 547 | ||
| @@ -547,6 +566,10 @@ struct AVFilterContext { · 18 unmodified lines | |||
| 547 | struct AVFilterGraph *graph; ///< filtergraph this filter belongs to | 566 | struct AVFilterGraph *graph; ///< filtergraph this filter belongs to |
| 548 | 567 | ||
| 549 | struct AVFilterCommand *command_queue; | 568 | struct AVFilterCommand *command_queue; |
| 569 | |||
| 570 | char *enable_str; ///< enable expression string | ||
| 571 | void *enable; ///< parsed expression (AVExpr*) | ||
| 572 | double *var_values; ///< variable values for the enable expression | ||
| 550 | }; | 573 | }; |
| 551 | 574 | ||
| 552 | /** | 575 | /** |
| @@ -383,4 +383,5 @@ AVFilter avfilter_vf_boxblur = { · 382 unmodified lines | |||
| 383 | 383 | ||
| 384 | .inputs = avfilter_vf_boxblur_inputs, | 384 | .inputs = avfilter_vf_boxblur_inputs, |
| 385 | .outputs = avfilter_vf_boxblur_outputs, | 385 | .outputs = avfilter_vf_boxblur_outputs, |
| 386 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 386 | }; | 387 | }; |
| @@ -385,4 +385,5 @@ AVFilter avfilter_vf_colormatrix = { · 384 unmodified lines | |||
| 385 | .inputs = colormatrix_inputs, | 385 | .inputs = colormatrix_inputs, |
| 386 | .outputs = colormatrix_outputs, | 386 | .outputs = colormatrix_outputs, |
| 387 | .priv_class = &colormatrix_class, | 387 | .priv_class = &colormatrix_class, |
| 388 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 388 | }; | 389 | }; |
| @@ -233,4 +233,5 @@ AVFilter avfilter_vf_cropdetect = { · 232 unmodified lines | |||
| 233 | .query_formats = query_formats, | 233 | .query_formats = query_formats, |
| 234 | .inputs = avfilter_vf_cropdetect_inputs, | 234 | .inputs = avfilter_vf_cropdetect_inputs, |
| 235 | .outputs = avfilter_vf_cropdetect_outputs, | 235 | .outputs = avfilter_vf_cropdetect_outputs, |
| 236 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 236 | }; | 237 | }; |
| @@ -514,4 +514,5 @@ AVFilter avfilter_vf_curves = { · 513 unmodified lines | |||
| 514 | .inputs = curves_inputs, | 514 | .inputs = curves_inputs, |
| 515 | .outputs = curves_outputs, | 515 | .outputs = curves_outputs, |
| 516 | .priv_class = &curves_class, | 516 | .priv_class = &curves_class, |
| 517 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 517 | }; | 518 | }; |
| @@ -181,4 +181,5 @@ AVFilter avfilter_vf_drawbox = { · 180 unmodified lines | |||
| 181 | .query_formats = query_formats, | 181 | .query_formats = query_formats, |
| 182 | .inputs = avfilter_vf_drawbox_inputs, | 182 | .inputs = avfilter_vf_drawbox_inputs, |
| 183 | .outputs = avfilter_vf_drawbox_outputs, | 183 | .outputs = avfilter_vf_drawbox_outputs, |
| 184 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 184 | }; | 185 | }; |
| @@ -327,4 +327,5 @@ AVFilter avfilter_vf_edgedetect = { · 326 unmodified lines | |||
| 327 | .inputs = edgedetect_inputs, | 327 | .inputs = edgedetect_inputs, |
| 328 | .outputs = edgedetect_outputs, | 328 | .outputs = edgedetect_outputs, |
| 329 | .priv_class = &edgedetect_class, | 329 | .priv_class = &edgedetect_class, |
| 330 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 330 | }; | 331 | }; |
| @@ -260,4 +260,5 @@ AVFilter avfilter_vf_gradfun = { · 259 unmodified lines | |||
| 260 | .query_formats = query_formats, | 260 | .query_formats = query_formats, |
| 261 | .inputs = avfilter_vf_gradfun_inputs, | 261 | .inputs = avfilter_vf_gradfun_inputs, |
| 262 | .outputs = avfilter_vf_gradfun_outputs, | 262 | .outputs = avfilter_vf_gradfun_outputs, |
| 263 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 263 | }; | 264 | }; |
| @@ -279,4 +279,5 @@ AVFilter avfilter_vf_histeq = { · 278 unmodified lines | |||
| 279 | .inputs = histeq_inputs, | 279 | .inputs = histeq_inputs, |
| 280 | .outputs = histeq_outputs, | 280 | .outputs = histeq_outputs, |
| 281 | .priv_class = &histeq_class, | 281 | .priv_class = &histeq_class, |
| 282 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 282 | }; | 283 | }; |
| @@ -355,6 +355,6 @@ AVFilter avfilter_vf_hqdn3d = { · 354 unmodified lines | |||
| 355 | .query_formats = query_formats, | 355 | .query_formats = query_formats, |
| 356 | 356 | ||
| 357 | .inputs = avfilter_vf_hqdn3d_inputs, | 357 | .inputs = avfilter_vf_hqdn3d_inputs, |
| 358 | |||
| 359 | .outputs = avfilter_vf_hqdn3d_outputs, | 358 | .outputs = avfilter_vf_hqdn3d_outputs, |
| 359 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 360 | }; | 360 | }; |
| @@ -349,4 +349,5 @@ AVFilter avfilter_vf_hue = { · 348 unmodified lines | |||
| 349 | .inputs = hue_inputs, | 349 | .inputs = hue_inputs, |
| 350 | .outputs = hue_outputs, | 350 | .outputs = hue_outputs, |
| 351 | .priv_class = &hue_class, | 351 | .priv_class = &hue_class, |
| 352 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 352 | }; | 353 | }; |
| @@ -350,6 +350,7 @@ static const AVFilterPad outputs[] = { · 349 unmodified lines | |||
| 350 | \ | 350 | \ |
| 351 | .inputs = inputs, \ | 351 | .inputs = inputs, \ |
| 352 | .outputs = outputs, \ | 352 | .outputs = outputs, \ |
| 353 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, \ | ||
| 353 | } | 354 | } |
| 354 | 355 | ||
| 355 | #if CONFIG_LUT_FILTER | 356 | #if CONFIG_LUT_FILTER |
| @@ -471,4 +471,5 @@ AVFilter avfilter_vf_noise = { · 470 unmodified lines | |||
| 471 | .inputs = noise_inputs, | 471 | .inputs = noise_inputs, |
| 472 | .outputs = noise_outputs, | 472 | .outputs = noise_outputs, |
| 473 | .priv_class = &noise_class, | 473 | .priv_class = &noise_class, |
| 474 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 474 | }; | 475 | }; |
| @@ -180,5 +180,5 @@ AVFilter avfilter_vf_pp = { · 179 unmodified lines | |||
| 180 | .outputs = pp_outputs, | 180 | .outputs = pp_outputs, |
| 181 | .process_command = pp_process_command, | 181 | .process_command = pp_process_command, |
| 182 | .priv_class = &pp_class, | 182 | .priv_class = &pp_class, |
| 183 | 183 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | |
| 184 | }; | 184 | }; |
| @@ -301,4 +301,5 @@ AVFilter avfilter_vf_smartblur = { · 300 unmodified lines | |||
| 301 | .inputs = smartblur_inputs, | 301 | .inputs = smartblur_inputs, |
| 302 | .outputs = smartblur_outputs, | 302 | .outputs = smartblur_outputs, |
| 303 | .priv_class = &smartblur_class, | 303 | .priv_class = &smartblur_class, |
| 304 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 304 | }; | 305 | }; |
| @@ -299,6 +299,6 @@ AVFilter avfilter_vf_unsharp = { · 298 unmodified lines | |||
| 299 | .query_formats = query_formats, | 299 | .query_formats = query_formats, |
| 300 | 300 | ||
| 301 | .inputs = avfilter_vf_unsharp_inputs, | 301 | .inputs = avfilter_vf_unsharp_inputs, |
| 302 | |||
| 303 | .outputs = avfilter_vf_unsharp_outputs, | 302 | .outputs = avfilter_vf_unsharp_outputs, |
| 303 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, | ||
| 304 | }; | 304 | }; |