diff options
author | Clément Bœsch <ubitux@gmail.com> | 2013-04-08 20:35:02 +0200 |
---|---|---|
committer | Clément Bœsch <ubitux@gmail.com> | 2013-04-23 01:02:27 +0200 |
commit | fdd93eabfb2644f541f7aac9943abce26776ea73 (patch) | |
tree | f4639f69007ce523d30856769d246c07fb7fe3b9 | |
parent | b8a5c76131944b4cc17c6db609288d0000d56a43 (diff) | |
download | ffmpeg-fdd93eabfb2644f541f7aac9943abce26776ea73.tar.gz |
lavfi: add timeline support.
Flag added in a few simple filters. A bunch of other filters can likely
use the feature as well.
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | cmdutils.c | 2 | ||||
-rw-r--r-- | doc/filters.texi | 32 | ||||
-rw-r--r-- | libavfilter/af_volume.c | 1 | ||||
-rw-r--r-- | libavfilter/avfilter.c | 50 | ||||
-rw-r--r-- | libavfilter/avfilter.h | 25 | ||||
-rw-r--r-- | libavfilter/vf_boxblur.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_colormatrix.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_cropdetect.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_curves.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_drawbox.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_edgedetect.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_gradfun.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_histeq.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_hqdn3d.c | 2 | ||||
-rw-r--r-- | libavfilter/vf_hue.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_lut.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_noise.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_pp.c | 2 | ||||
-rw-r--r-- | libavfilter/vf_smartblur.c | 1 | ||||
-rw-r--r-- | libavfilter/vf_unsharp.c | 2 |
21 files changed, 125 insertions, 4 deletions
@@ -30,6 +30,7 @@ version <next>: - decent native animated GIF encoding - asetrate filter - interleave filter +- timeline editing with filters version 1.2: diff --git a/cmdutils.c b/cmdutils.c index cc886977e8..b9985d620e 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -1683,6 +1683,8 @@ static void show_help_filter(const char *name) if (f->priv_class) show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM); + if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) + printf("This filter has support for timeline through the 'enable' option.\n"); #else av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; " "can not to satisfy request\n"); diff --git a/doc/filters.texi b/doc/filters.texi index ada992e08b..798d04befc 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -267,6 +267,36 @@ See the ``Quoting and escaping'' section in the ffmpeg-utils manual for more information about the escaping and quoting rules adopted by FFmpeg. +@chapter Timeline editing + +Some filters support a generic @option{enable} option. For the filters +supporting timeline editing, this option can be set to an expression which is +evaluated before sending a frame to the filter. If the evaluation is non-zero, +the filter will be enabled, otherwise the frame will be sent unchanged to the +next filter in the filtergraph. + +The expression accepts the following values: +@table @samp +@item t +timestamp expressed in seconds, NAN if the input timestamp is unknown + +@item n +sequential number of the input frame, starting from 0 + +@item pos +the position in the file of the input frame, NAN if unknown +@end table + +Like any other filtering option, the @option{enable} option follows the same +rules. + +For example, to enable a denoiser filter (@ref{hqdn3d}) from 10 seconds to 3 +minutes, and a @ref{curves} filter starting at 3 seconds: +@example +hqdn3d = enable='between(t,10,3*60)', +curves = enable='gte(t,3)' : preset=cross_process +@end example + @c man end FILTERGRAPH DESCRIPTION @chapter Audio Filters @@ -2409,6 +2439,7 @@ indicates never reset and return the largest area encountered during playback. @end table +@anchor{curves} @section curves Apply color adjustments using curves. @@ -4013,6 +4044,7 @@ ffplay -i input -vf histogram @end itemize +@anchor{hqdn3d} @section hqdn3d High precision/quality 3d denoise filter. This filter aims to reduce diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index 7d2b9bad55..a55e1a3518 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -296,4 +296,5 @@ AVFilter avfilter_af_volume = { .init = init, .inputs = avfilter_af_volume_inputs, .outputs = avfilter_af_volume_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 43340d1004..0c6f1f1690 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -23,6 +23,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/eval.h" #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -483,12 +484,20 @@ static const AVClass *filter_child_class_next(const AVClass *prev) return NULL; } +#define OFFSET(x) offsetof(AVFilterContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM +static const AVOption filters_common_options[] = { + { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { NULL } +}; + static const AVClass avfilter_class = { .class_name = "AVFilter", .item_name = default_filter_name, .version = LIBAVUTIL_VERSION_INT, .category = AV_CLASS_CATEGORY_FILTER, .child_next = filter_child_next, + .option = filters_common_options, .child_class_next = filter_child_class_next, }; @@ -618,9 +627,16 @@ void avfilter_free(AVFilterContext *filter) while(filter->command_queue){ ff_command_queue_pop(filter); } + av_opt_free(filter); + av_expr_free(filter->enable); + filter->enable = NULL; + av_freep(&filter->var_values); av_free(filter); } +static const char *const var_names[] = { "t", "n", "pos", NULL }; +enum { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB }; + static int process_options(AVFilterContext *ctx, AVDictionary **options, const char *args) { @@ -630,6 +646,8 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, const char *key; int offset= -1; + av_opt_set_defaults(ctx); + if (!args) return 0; @@ -665,6 +683,12 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, } av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); + + if (av_opt_find(ctx, key, NULL, 0, 0)) { + ret = av_opt_set(ctx, key, value, 0); + if (ret < 0) + return ret; + } else { av_dict_set(options, key, value, 0); if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) { 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, return ret; } } + } av_free(value); av_free(parsed_key); count++; } + + if (ctx->enable_str) { + if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) { + av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported " + "with filter '%s'\n", ctx->filter->name); + return AVERROR_PATCHWELCOME; + } + ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values)); + if (!ctx->var_values) + return AVERROR(ENOMEM); + ret = av_expr_parse((AVExpr**)&ctx->enable, ctx->enable_str, var_names, + NULL, NULL, NULL, NULL, 0, ctx->priv); + if (ret < 0) + return ret; + } return count; } @@ -852,6 +892,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame) static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) { int (*filter_frame)(AVFilterLink *, AVFrame *); + AVFilterContext *dstctx = link->dst; AVFilterPad *dst = link->dstpad; AVFrame *out; int ret; @@ -914,6 +955,15 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) } pts = out->pts; + if (dstctx->enable_str) { + int64_t pos = av_frame_get_pkt_pos(out); + dstctx->var_values[VAR_N] = link->frame_count; + dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base); + dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos; + if (!av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) + filter_frame = dst->passthrough_filter_frame ? dst->passthrough_filter_frame + : default_filter_frame; + } ret = filter_frame(link, out); link->frame_count++; link->frame_requested = 0; diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 047208c02b..e7e979eed1 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -385,6 +385,19 @@ struct AVFilterPad { int needs_fifo; int needs_writable; + + /** + * Passthrough filtering callback. + * + * If a filter supports timeline editing (in case + * AVFILTER_FLAG_SUPPORT_TIMELINE is enabled) then it can implement a + * custom passthrough callback to update its local context (for example to + * keep a frame reference, or simply send the filter to a custom outlink). + * The filter must not do any change to the frame in this callback. + * + * Input pads only. + */ + int (*passthrough_filter_frame)(AVFilterLink *link, AVFrame *frame); }; #endif @@ -428,6 +441,12 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); * the options supplied to it. */ #define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1) +/** + * Some filters support a generic "enable" expression option that can be used + * to enable or disable a filter in the timeline. Filters supporting this + * option have this flag set. + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE (1 << 16) /** * Filter definition. This defines the pads a filter contains, and all the @@ -522,7 +541,7 @@ typedef struct AVFilter { /** An instance of a filter */ struct AVFilterContext { - const AVClass *av_class; ///< needed for av_log() + const AVClass *av_class; ///< needed for av_log() and filters common options const AVFilter *filter; ///< the AVFilter of which this is an instance @@ -547,6 +566,10 @@ struct AVFilterContext { struct AVFilterGraph *graph; ///< filtergraph this filter belongs to struct AVFilterCommand *command_queue; + + char *enable_str; ///< enable expression string + void *enable; ///< parsed expression (AVExpr*) + double *var_values; ///< variable values for the enable expression }; /** diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c index 758964476b..b0106708c3 100644 --- a/libavfilter/vf_boxblur.c +++ b/libavfilter/vf_boxblur.c @@ -383,4 +383,5 @@ AVFilter avfilter_vf_boxblur = { .inputs = avfilter_vf_boxblur_inputs, .outputs = avfilter_vf_boxblur_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_colormatrix.c b/libavfilter/vf_colormatrix.c index d25ce60a97..8db5fcf8d1 100644 --- a/libavfilter/vf_colormatrix.c +++ b/libavfilter/vf_colormatrix.c @@ -385,4 +385,5 @@ AVFilter avfilter_vf_colormatrix = { .inputs = colormatrix_inputs, .outputs = colormatrix_outputs, .priv_class = &colormatrix_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c index 3d109f8a59..cb170d08fb 100644 --- a/libavfilter/vf_cropdetect.c +++ b/libavfilter/vf_cropdetect.c @@ -233,4 +233,5 @@ AVFilter avfilter_vf_cropdetect = { .query_formats = query_formats, .inputs = avfilter_vf_cropdetect_inputs, .outputs = avfilter_vf_cropdetect_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 9f5d8bd166..626b4ea324 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -514,4 +514,5 @@ AVFilter avfilter_vf_curves = { .inputs = curves_inputs, .outputs = curves_outputs, .priv_class = &curves_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c index edb77cc79f..c2ffbf3210 100644 --- a/libavfilter/vf_drawbox.c +++ b/libavfilter/vf_drawbox.c @@ -181,4 +181,5 @@ AVFilter avfilter_vf_drawbox = { .query_formats = query_formats, .inputs = avfilter_vf_drawbox_inputs, .outputs = avfilter_vf_drawbox_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c index f29c7ee944..b4698a8fe3 100644 --- a/libavfilter/vf_edgedetect.c +++ b/libavfilter/vf_edgedetect.c @@ -327,4 +327,5 @@ AVFilter avfilter_vf_edgedetect = { .inputs = edgedetect_inputs, .outputs = edgedetect_outputs, .priv_class = &edgedetect_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c index 9e21560de9..48ac378e6a 100644 --- a/libavfilter/vf_gradfun.c +++ b/libavfilter/vf_gradfun.c @@ -260,4 +260,5 @@ AVFilter avfilter_vf_gradfun = { .query_formats = query_formats, .inputs = avfilter_vf_gradfun_inputs, .outputs = avfilter_vf_gradfun_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c index 33cddaadbe..a4166c674f 100644 --- a/libavfilter/vf_histeq.c +++ b/libavfilter/vf_histeq.c @@ -279,4 +279,5 @@ AVFilter avfilter_vf_histeq = { .inputs = histeq_inputs, .outputs = histeq_outputs, .priv_class = &histeq_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c index a722d8f131..003f1756df 100644 --- a/libavfilter/vf_hqdn3d.c +++ b/libavfilter/vf_hqdn3d.c @@ -355,6 +355,6 @@ AVFilter avfilter_vf_hqdn3d = { .query_formats = query_formats, .inputs = avfilter_vf_hqdn3d_inputs, - .outputs = avfilter_vf_hqdn3d_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c index a1280bef13..9f632405ce 100644 --- a/libavfilter/vf_hue.c +++ b/libavfilter/vf_hue.c @@ -349,4 +349,5 @@ AVFilter avfilter_vf_hue = { .inputs = hue_inputs, .outputs = hue_outputs, .priv_class = &hue_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c index 4c0cdfc29c..4313e77204 100644 --- a/libavfilter/vf_lut.c +++ b/libavfilter/vf_lut.c @@ -350,6 +350,7 @@ static const AVFilterPad outputs[] = { \ .inputs = inputs, \ .outputs = outputs, \ + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, \ } #if CONFIG_LUT_FILTER diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c index ae64b76961..996311a661 100644 --- a/libavfilter/vf_noise.c +++ b/libavfilter/vf_noise.c @@ -471,4 +471,5 @@ AVFilter avfilter_vf_noise = { .inputs = noise_inputs, .outputs = noise_outputs, .priv_class = &noise_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c index d2c1965a13..0571cfc1e7 100644 --- a/libavfilter/vf_pp.c +++ b/libavfilter/vf_pp.c @@ -180,5 +180,5 @@ AVFilter avfilter_vf_pp = { .outputs = pp_outputs, .process_command = pp_process_command, .priv_class = &pp_class, - + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c index aed3fa6e83..4dd1664676 100644 --- a/libavfilter/vf_smartblur.c +++ b/libavfilter/vf_smartblur.c @@ -301,4 +301,5 @@ AVFilter avfilter_vf_smartblur = { .inputs = smartblur_inputs, .outputs = smartblur_outputs, .priv_class = &smartblur_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c index 038ba4bafe..2d7aab26aa 100644 --- a/libavfilter/vf_unsharp.c +++ b/libavfilter/vf_unsharp.c @@ -299,6 +299,6 @@ AVFilter avfilter_vf_unsharp = { .query_formats = query_formats, .inputs = avfilter_vf_unsharp_inputs, - .outputs = avfilter_vf_unsharp_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE, }; |