Browse code

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 authored on 2013/04/09 03:35:02
Showing 21 changed files
... ...
@@ -30,6 +30,7 @@ version <next>:
30 30
 - decent native animated GIF encoding
31 31
 - asetrate filter
32 32
 - interleave filter
33
+- timeline editing with filters
33 34
 
34 35
 
35 36
 version 1.2:
... ...
@@ -1683,6 +1683,8 @@ static void show_help_filter(const char *name)
1683 1683
     if (f->priv_class)
1684 1684
         show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
1685 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 1688
 #else
1687 1689
     av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; "
1688 1690
            "can not to satisfy request\n");
... ...
@@ -267,6 +267,36 @@ See the ``Quoting and escaping'' section in the ffmpeg-utils manual
267 267
 for more information about the escaping and quoting rules adopted by
268 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 300
 @c man end FILTERGRAPH DESCRIPTION
271 301
 
272 302
 @chapter Audio Filters
... ...
@@ -2409,6 +2439,7 @@ indicates never reset and return the largest area encountered during
2409 2409
 playback.
2410 2410
 @end table
2411 2411
 
2412
+@anchor{curves}
2412 2413
 @section curves
2413 2414
 
2414 2415
 Apply color adjustments using curves.
... ...
@@ -4013,6 +4044,7 @@ ffplay -i input -vf histogram
4013 4013
 
4014 4014
 @end itemize
4015 4015
 
4016
+@anchor{hqdn3d}
4016 4017
 @section hqdn3d
4017 4018
 
4018 4019
 High precision/quality 3d denoise filter. This filter aims to reduce
... ...
@@ -296,4 +296,5 @@ AVFilter avfilter_af_volume = {
296 296
     .init           = init,
297 297
     .inputs         = avfilter_af_volume_inputs,
298 298
     .outputs        = avfilter_af_volume_outputs,
299
+    .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE,
299 300
 };
... ...
@@ -23,6 +23,7 @@
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)
483 483
     return NULL;
484 484
 }
485 485
 
486
+#define OFFSET(x) offsetof(AVFilterContext, x)
487
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM
488
+static const AVOption filters_common_options[] = {
489
+    { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
490
+    { NULL }
491
+};
492
+
486 493
 static const AVClass avfilter_class = {
487 494
     .class_name = "AVFilter",
488 495
     .item_name  = default_filter_name,
489 496
     .version    = LIBAVUTIL_VERSION_INT,
490 497
     .category   = AV_CLASS_CATEGORY_FILTER,
491 498
     .child_next = filter_child_next,
499
+    .option     = filters_common_options,
492 500
     .child_class_next = filter_child_class_next,
493 501
 };
494 502
 
... ...
@@ -618,9 +627,16 @@ void avfilter_free(AVFilterContext *filter)
618 618
     while(filter->command_queue){
619 619
         ff_command_queue_pop(filter);
620 620
     }
621
+    av_opt_free(filter);
622
+    av_expr_free(filter->enable);
623
+    filter->enable = NULL;
624
+    av_freep(&filter->var_values);
621 625
     av_free(filter);
622 626
 }
623 627
 
628
+static const char *const var_names[] = {   "t",   "n",   "pos",        NULL };
629
+enum                                   { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB };
630
+
624 631
 static int process_options(AVFilterContext *ctx, AVDictionary **options,
625 632
                            const char *args)
626 633
 {
... ...
@@ -630,6 +646,8 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
630 630
     const char *key;
631 631
     int offset= -1;
632 632
 
633
+    av_opt_set_defaults(ctx);
634
+
633 635
     if (!args)
634 636
         return 0;
635 637
 
... ...
@@ -665,6 +683,12 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
665 665
         }
666 666
 
667 667
         av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
668
+
669
+        if (av_opt_find(ctx, key, NULL, 0, 0)) {
670
+            ret = av_opt_set(ctx, key, value, 0);
671
+            if (ret < 0)
672
+                return ret;
673
+        } else {
668 674
         av_dict_set(options, key, value, 0);
669 675
         if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
670 676
             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,
675 675
             return ret;
676 676
             }
677 677
         }
678
+        }
678 679
 
679 680
         av_free(value);
680 681
         av_free(parsed_key);
681 682
         count++;
682 683
     }
684
+
685
+    if (ctx->enable_str) {
686
+        if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) {
687
+            av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported "
688
+                   "with filter '%s'\n", ctx->filter->name);
689
+            return AVERROR_PATCHWELCOME;
690
+        }
691
+        ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values));
692
+        if (!ctx->var_values)
693
+            return AVERROR(ENOMEM);
694
+        ret = av_expr_parse((AVExpr**)&ctx->enable, ctx->enable_str, var_names,
695
+                            NULL, NULL, NULL, NULL, 0, ctx->priv);
696
+        if (ret < 0)
697
+            return ret;
698
+    }
683 699
     return count;
684 700
 }
685 701
 
... ...
@@ -852,6 +892,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame)
852 852
 static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
853 853
 {
854 854
     int (*filter_frame)(AVFilterLink *, AVFrame *);
855
+    AVFilterContext *dstctx = link->dst;
855 856
     AVFilterPad *dst = link->dstpad;
856 857
     AVFrame *out;
857 858
     int ret;
... ...
@@ -914,6 +955,15 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
914 914
     }
915 915
 
916 916
     pts = out->pts;
917
+    if (dstctx->enable_str) {
918
+        int64_t pos = av_frame_get_pkt_pos(out);
919
+        dstctx->var_values[VAR_N] = link->frame_count;
920
+        dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base);
921
+        dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos;
922
+        if (!av_expr_eval(dstctx->enable, dstctx->var_values, NULL))
923
+            filter_frame = dst->passthrough_filter_frame ? dst->passthrough_filter_frame
924
+                                                         : default_filter_frame;
925
+    }
917 926
     ret = filter_frame(link, out);
918 927
     link->frame_count++;
919 928
     link->frame_requested = 0;
... ...
@@ -385,6 +385,19 @@ struct AVFilterPad {
385 385
     int needs_fifo;
386 386
 
387 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 402
 #endif
390 403
 
... ...
@@ -428,6 +441,12 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
428 428
  * the options supplied to it.
429 429
  */
430 430
 #define AVFILTER_FLAG_DYNAMIC_OUTPUTS       (1 << 1)
431
+/**
432
+ * Some filters support a generic "enable" expression option that can be used
433
+ * to enable or disable a filter in the timeline. Filters supporting this
434
+ * option have this flag set.
435
+ */
436
+#define AVFILTER_FLAG_SUPPORT_TIMELINE      (1 << 16)
431 437
 
432 438
 /**
433 439
  * Filter definition. This defines the pads a filter contains, and all the
... ...
@@ -522,7 +541,7 @@ typedef struct AVFilter {
522 522
 
523 523
 /** An instance of a filter */
524 524
 struct AVFilterContext {
525
-    const AVClass *av_class;        ///< needed for av_log()
525
+    const AVClass *av_class;        ///< needed for av_log() and filters common options
526 526
 
527 527
     const AVFilter *filter;         ///< the AVFilter of which this is an instance
528 528
 
... ...
@@ -547,6 +566,10 @@ struct AVFilterContext {
547 547
     struct AVFilterGraph *graph;    ///< filtergraph this filter belongs to
548 548
 
549 549
     struct AVFilterCommand *command_queue;
550
+
551
+    char *enable_str;               ///< enable expression string
552
+    void *enable;                   ///< parsed expression (AVExpr*)
553
+    double *var_values;             ///< variable values for the enable expression
550 554
 };
551 555
 
552 556
 /**
... ...
@@ -383,4 +383,5 @@ AVFilter avfilter_vf_boxblur = {
383 383
 
384 384
     .inputs    = avfilter_vf_boxblur_inputs,
385 385
     .outputs   = avfilter_vf_boxblur_outputs,
386
+    .flags     = AVFILTER_FLAG_SUPPORT_TIMELINE,
386 387
 };
... ...
@@ -385,4 +385,5 @@ AVFilter avfilter_vf_colormatrix = {
385 385
     .inputs        = colormatrix_inputs,
386 386
     .outputs       = colormatrix_outputs,
387 387
     .priv_class    = &colormatrix_class,
388
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
388 389
 };
... ...
@@ -233,4 +233,5 @@ AVFilter avfilter_vf_cropdetect = {
233 233
     .query_formats = query_formats,
234 234
     .inputs    = avfilter_vf_cropdetect_inputs,
235 235
     .outputs   = avfilter_vf_cropdetect_outputs,
236
+    .flags     = AVFILTER_FLAG_SUPPORT_TIMELINE,
236 237
 };
... ...
@@ -514,4 +514,5 @@ AVFilter avfilter_vf_curves = {
514 514
     .inputs        = curves_inputs,
515 515
     .outputs       = curves_outputs,
516 516
     .priv_class    = &curves_class,
517
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
517 518
 };
... ...
@@ -181,4 +181,5 @@ AVFilter avfilter_vf_drawbox = {
181 181
     .query_formats   = query_formats,
182 182
     .inputs    = avfilter_vf_drawbox_inputs,
183 183
     .outputs   = avfilter_vf_drawbox_outputs,
184
+    .flags     = AVFILTER_FLAG_SUPPORT_TIMELINE,
184 185
 };
... ...
@@ -327,4 +327,5 @@ AVFilter avfilter_vf_edgedetect = {
327 327
     .inputs        = edgedetect_inputs,
328 328
     .outputs       = edgedetect_outputs,
329 329
     .priv_class    = &edgedetect_class,
330
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
330 331
 };
... ...
@@ -260,4 +260,5 @@ AVFilter avfilter_vf_gradfun = {
260 260
     .query_formats = query_formats,
261 261
     .inputs        = avfilter_vf_gradfun_inputs,
262 262
     .outputs       = avfilter_vf_gradfun_outputs,
263
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
263 264
 };
... ...
@@ -279,4 +279,5 @@ AVFilter avfilter_vf_histeq = {
279 279
     .inputs        = histeq_inputs,
280 280
     .outputs       = histeq_outputs,
281 281
     .priv_class    = &histeq_class,
282
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
282 283
 };
... ...
@@ -355,6 +355,6 @@ AVFilter avfilter_vf_hqdn3d = {
355 355
     .query_formats = query_formats,
356 356
 
357 357
     .inputs    = avfilter_vf_hqdn3d_inputs,
358
-
359 358
     .outputs   = avfilter_vf_hqdn3d_outputs,
359
+    .flags     = AVFILTER_FLAG_SUPPORT_TIMELINE,
360 360
 };
... ...
@@ -349,4 +349,5 @@ AVFilter avfilter_vf_hue = {
349 349
     .inputs          = hue_inputs,
350 350
     .outputs         = hue_outputs,
351 351
     .priv_class      = &hue_class,
352
+    .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE,
352 353
 };
... ...
@@ -350,6 +350,7 @@ static const AVFilterPad outputs[] = {
350 350
                                                                         \
351 351
         .inputs        = inputs,                                        \
352 352
         .outputs       = outputs,                                       \
353
+        .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,                \
353 354
     }
354 355
 
355 356
 #if CONFIG_LUT_FILTER
... ...
@@ -471,4 +471,5 @@ AVFilter avfilter_vf_noise = {
471 471
     .inputs        = noise_inputs,
472 472
     .outputs       = noise_outputs,
473 473
     .priv_class    = &noise_class,
474
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
474 475
 };
... ...
@@ -180,5 +180,5 @@ AVFilter avfilter_vf_pp = {
180 180
     .outputs         = pp_outputs,
181 181
     .process_command = pp_process_command,
182 182
     .priv_class      = &pp_class,
183
-
183
+    .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE,
184 184
 };
... ...
@@ -301,4 +301,5 @@ AVFilter avfilter_vf_smartblur = {
301 301
     .inputs        = smartblur_inputs,
302 302
     .outputs       = smartblur_outputs,
303 303
     .priv_class    = &smartblur_class,
304
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE,
304 305
 };
... ...
@@ -299,6 +299,6 @@ AVFilter avfilter_vf_unsharp = {
299 299
     .query_formats = query_formats,
300 300
 
301 301
     .inputs    = avfilter_vf_unsharp_inputs,
302
-
303 302
     .outputs   = avfilter_vf_unsharp_outputs,
303
+    .flags     = AVFILTER_FLAG_SUPPORT_TIMELINE,
304 304
 };