History

lavfi: add timeline support.

Flag added in a few simple filters. A bunch of other filters can likely use the feature as well.

Clément Bœsch committed 13 years ago

Commit fdd93ea1 parent b8a5c7621 files · +125 −4Browse files

Unified · Split

21 files
  1. Changelog +1 −0
  2. cmdutils.c +2 −0
  3. doc/filters.texi +32 −0
  4. libavfilter/af_volume.c +1 −0
  5. libavfilter/avfilter.c +50 −0
  6. libavfilter/avfilter.h +24 −1
  7. libavfilter/vf_boxblur.c +1 −0
  8. libavfilter/vf_colormatrix.c +1 −0
  9. libavfilter/vf_cropdetect.c +1 −0
  10. libavfilter/vf_curves.c +1 −0
  11. libavfilter/vf_drawbox.c +1 −0
  12. libavfilter/vf_edgedetect.c +1 −0
  13. libavfilter/vf_gradfun.c +1 −0
  14. libavfilter/vf_histeq.c +1 −0
  15. libavfilter/vf_hqdn3d.c +1 −1
  16. libavfilter/vf_hue.c +1 −0
  17. libavfilter/vf_lut.c +1 −0
  18. libavfilter/vf_noise.c +1 −0
  19. libavfilter/vf_pp.c +1 −1
  20. libavfilter/vf_smartblur.c +1 −0
  21. libavfilter/vf_unsharp.c +1 −1
Changelog+1−0
@@ -30,6 +30,7 @@ version <next>: · 29 unmodified lines
30- decent native animated GIF encoding30- decent native animated GIF encoding
31- asetrate filter31- asetrate filter
32- interleave filter32- interleave filter
33- timeline editing with filters
33 34
34 35
35version 1.2:36version 1.2:
cmdutils.c+2−0
@@ -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#else1688#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");
doc/filters.texi+32−0
@@ -267,6 +267,36 @@ See the ``Quoting and escaping'' section in the ffmpeg-utils manual · 266 unmodified lines
267for more information about the escaping and quoting rules adopted by267for more information about the escaping and quoting rules adopted by
268FFmpeg.268FFmpeg.
269 269
270@chapter Timeline editing
271
272Some filters support a generic @option{enable} option. For the filters
273supporting timeline editing, this option can be set to an expression which is
274evaluated before sending a frame to the filter. If the evaluation is non-zero,
275the filter will be enabled, otherwise the frame will be sent unchanged to the
276next filter in the filtergraph.
277
278The expression accepts the following values:
279@table @samp
280@item t
281timestamp expressed in seconds, NAN if the input timestamp is unknown
282
283@item n
284sequential number of the input frame, starting from 0
285
286@item pos
287the position in the file of the input frame, NAN if unknown
288@end table
289
290Like any other filtering option, the @option{enable} option follows the same
291rules.
292
293For example, to enable a denoiser filter (@ref{hqdn3d}) from 10 seconds to 3
294minutes, and a @ref{curves} filter starting at 3 seconds:
295@example
296hqdn3d = enable='between(t,10,3*60)',
297curves = enable='gte(t,3)' : preset=cross_process
298@end example
299
270@c man end FILTERGRAPH DESCRIPTION300@c man end FILTERGRAPH DESCRIPTION
271 301
272@chapter Audio Filters302@chapter Audio Filters
@@ -2409,6 +2439,7 @@ indicates never reset and return the largest area encountered during · 2136 unmodified lines
2409playback.2439playback.
2410@end table2440@end table
2411 2441
2442@anchor{curves}
2412@section curves2443@section curves
2413 2444
2414Apply color adjustments using curves.2445Apply color adjustments using curves.
@@ -4013,6 +4044,7 @@ ffplay -i input -vf histogram · 1598 unmodified lines
4013 4044
4014@end itemize4045@end itemize
4015 4046
4047@anchor{hqdn3d}
4016@section hqdn3d4048@section hqdn3d
4017 4049
4018High precision/quality 3d denoise filter. This filter aims to reduce4050High precision/quality 3d denoise filter. This filter aims to reduce
libavfilter/af_volume.c+1−0
@@ -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};
libavfilter/avfilter.c+50−0
@@ -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
489static 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
486static const AVClass avfilter_class = {494static 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
637static const char *const var_names[] = { "t", "n", "pos", NULL };
638enum { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB };
639
624static int process_options(AVFilterContext *ctx, AVDictionary **options,640static 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
852static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)892static 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;
libavfilter/avfilter.h+24−1
@@ -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#endif402#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 the452 * 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 */
524struct AVFilterContext {543struct 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 instance546 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 to566 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/**
libavfilter/vf_boxblur.c+1−0
@@ -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};
libavfilter/vf_colormatrix.c+1−0
@@ -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};
libavfilter/vf_cropdetect.c+1−0
@@ -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};
libavfilter/vf_curves.c+1−0
@@ -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};
libavfilter/vf_drawbox.c+1−0
@@ -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};
libavfilter/vf_edgedetect.c+1−0
@@ -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};
libavfilter/vf_gradfun.c+1−0
@@ -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};
libavfilter/vf_histeq.c+1−0
@@ -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};
libavfilter/vf_hqdn3d.c+1−1
@@ -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};
libavfilter/vf_hue.c+1−0
@@ -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};
libavfilter/vf_lut.c+1−0
@@ -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_FILTER356#if CONFIG_LUT_FILTER
libavfilter/vf_noise.c+1−0
@@ -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};
libavfilter/vf_pp.c+1−1
@@ -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};
libavfilter/vf_smartblur.c+1−0
@@ -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};
libavfilter/vf_unsharp.c+1−1
@@ -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};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t