Browse code

lavfi/buffersink: accept parameters as options.

Move validation from init to query_formats().
Accept the formats lists as binary options.

Signed-off-by: Nicolas George <nicolas.george@normalesup.org>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Nicolas George authored on 2013/04/11 21:58:07
Showing 2 changed files
... ...
@@ -1768,9 +1768,10 @@ Below is a description of the currently available audio sinks.
1768 1768
 Buffer audio frames, and make them available to the end of filter chain.
1769 1769
 
1770 1770
 This sink is mainly intended for programmatic use, in particular
1771
-through the interface defined in @file{libavfilter/buffersink.h}.
1771
+through the interface defined in @file{libavfilter/buffersink.h}
1772
+or the options system.
1772 1773
 
1773
-It requires a pointer to an AVABufferSinkContext structure, which
1774
+It accepts a pointer to an AVABufferSinkContext structure, which
1774 1775
 defines the incoming buffers' formats, to be passed as the opaque
1775 1776
 parameter to @code{avfilter_init_filter} for initialization.
1776 1777
 
... ...
@@ -1780,13 +1781,6 @@ Null audio sink, do absolutely nothing with the input audio. It is
1780 1780
 mainly useful as a template and to be employed in analysis / debugging
1781 1781
 tools.
1782 1782
 
1783
-@section abuffersink
1784
-This sink is intended for programmatic use. Frames that arrive on this sink can
1785
-be retrieved by the calling program using the interface defined in
1786
-@file{libavfilter/buffersink.h}.
1787
-
1788
-This filter accepts no parameters.
1789
-
1790 1783
 @c man end AUDIO SINKS
1791 1784
 
1792 1785
 @chapter Video Filters
... ...
@@ -6298,12 +6292,12 @@ Buffer video frames, and make them available to the end of the filter
6298 6298
 graph.
6299 6299
 
6300 6300
 This sink is mainly intended for a programmatic use, in particular
6301
-through the interface defined in @file{libavfilter/buffersink.h}.
6301
+through the interface defined in @file{libavfilter/buffersink.h}
6302
+or the options system.
6302 6303
 
6303
-It does not require a string parameter in input, but you need to
6304
-specify a pointer to a list of supported pixel formats terminated by
6305
--1 in the opaque parameter provided to @code{avfilter_init_filter}
6306
-when initializing this sink.
6304
+It accepts a pointer to an AVBufferSinkContext structure, which
6305
+defines the incoming buffers' formats, to be passed as the opaque
6306
+parameter to @code{avfilter_init_filter} for initialization.
6307 6307
 
6308 6308
 @section nullsink
6309 6309
 
... ...
@@ -28,6 +28,7 @@
28 28
 #include "libavutil/channel_layout.h"
29 29
 #include "libavutil/common.h"
30 30
 #include "libavutil/mathematics.h"
31
+#include "libavutil/opt.h"
31 32
 
32 33
 #include "audio.h"
33 34
 #include "avfilter.h"
... ...
@@ -35,23 +36,32 @@
35 35
 #include "internal.h"
36 36
 
37 37
 typedef struct {
38
+    const AVClass *class;
38 39
     AVFifoBuffer *fifo;                      ///< FIFO buffer of video frame references
39 40
     unsigned warning_limit;
40 41
 
41 42
     /* only used for video */
42 43
     enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
44
+    int pixel_fmts_size;
43 45
 
44 46
     /* only used for audio */
45 47
     enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
48
+    int sample_fmts_size;
46 49
     int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
50
+    int channel_layouts_size;
51
+    int *channel_counts;                    ///< list of accepted channel counts, terminated by -1
52
+    int channel_counts_size;
47 53
     int all_channel_counts;
48 54
     int *sample_rates;                      ///< list of accepted sample rates, terminated by -1
55
+    int sample_rates_size;
49 56
 
50 57
     /* only used for compat API */
51 58
     AVAudioFifo  *audio_fifo;    ///< FIFO for audio samples
52 59
     int64_t next_pts;            ///< interpolating audio pts
53 60
 } BufferSinkContext;
54 61
 
62
+#define NB_ITEMS(list) (list ## _size / sizeof(*list))
63
+
55 64
 static av_cold void uninit(AVFilterContext *ctx)
56 65
 {
57 66
     BufferSinkContext *sink = ctx->priv;
... ...
@@ -68,10 +78,6 @@ static av_cold void uninit(AVFilterContext *ctx)
68 68
         av_fifo_free(sink->fifo);
69 69
         sink->fifo = NULL;
70 70
     }
71
-    av_freep(&sink->pixel_fmts);
72
-    av_freep(&sink->sample_fmts);
73
-    av_freep(&sink->sample_rates);
74
-    av_freep(&sink->channel_layouts);
75 71
 }
76 72
 
77 73
 static int add_buffer_ref(AVFilterContext *ctx, AVFrame *ref)
... ...
@@ -286,6 +292,7 @@ static int attribute_align_arg compat_read(AVFilterContext *ctx, AVFilterBufferR
286 286
     if (ret < 0)
287 287
         goto fail;
288 288
 
289
+    AV_NOWARN_DEPRECATED(
289 290
     if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
290 291
         buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
291 292
                                                         AV_PERM_READ,
... ...
@@ -304,6 +311,7 @@ static int attribute_align_arg compat_read(AVFilterContext *ctx, AVFilterBufferR
304 304
     }
305 305
 
306 306
     avfilter_copy_frame_props(buf, frame);
307
+    )
307 308
 
308 309
     buf->buf->priv = frame;
309 310
     buf->buf->free = compat_free_buffer;
... ...
@@ -366,13 +374,11 @@ static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
366 366
 {
367 367
     BufferSinkContext *buf = ctx->priv;
368 368
     AVBufferSinkParams *params = opaque;
369
+    int ret;
369 370
 
370
-    if (params && params->pixel_fmts) {
371
-        const int *pixel_fmts = params->pixel_fmts;
372
-
373
-        buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
374
-        if (!buf->pixel_fmts)
375
-            return AVERROR(ENOMEM);
371
+    if (params) {
372
+        if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
373
+            return ret;
376 374
     }
377 375
 
378 376
     return common_init(ctx);
... ...
@@ -381,64 +387,41 @@ static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
381 381
 static int vsink_query_formats(AVFilterContext *ctx)
382 382
 {
383 383
     BufferSinkContext *buf = ctx->priv;
384
+    AVFilterFormats *formats = NULL;
385
+    unsigned i;
386
+    int ret;
384 387
 
385
-    if (buf->pixel_fmts)
386
-        ff_set_common_formats(ctx, ff_make_format_list(buf->pixel_fmts));
387
-    else
388
+    if (buf->pixel_fmts_size % sizeof(*buf->pixel_fmts)) {
389
+        av_log(ctx, AV_LOG_ERROR, "Invalid size for format list\n");
390
+        return AVERROR(EINVAL);
391
+    }
392
+
393
+    if (buf->pixel_fmts_size) {
394
+        for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
395
+            if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
396
+                return ret;
397
+        ff_set_common_formats(ctx, formats);
398
+    } else {
388 399
         ff_default_query_formats(ctx);
400
+    }
389 401
 
390 402
     return 0;
391 403
 }
392 404
 
393
-static int64_t *concat_channels_lists(const int64_t *layouts, const int *counts)
394
-{
395
-    int nb_layouts = 0, nb_counts = 0, i;
396
-    int64_t *list;
397
-
398
-    if (layouts)
399
-        for (; layouts[nb_layouts] != -1; nb_layouts++);
400
-    if (counts)
401
-        for (; counts[nb_counts] != -1; nb_counts++);
402
-    if (nb_counts > INT_MAX - 1 - nb_layouts)
403
-        return NULL;
404
-    if (!(list = av_calloc(nb_layouts + nb_counts + 1, sizeof(*list))))
405
-        return NULL;
406
-    for (i = 0; i < nb_layouts; i++)
407
-        list[i] = layouts[i];
408
-    for (i = 0; i < nb_counts; i++)
409
-        list[nb_layouts + i] = FF_COUNT2LAYOUT(counts[i]);
410
-    list[nb_layouts + nb_counts] = -1;
411
-    return list;
412
-}
413
-
414 405
 static av_cold int asink_init(AVFilterContext *ctx, void *opaque)
415 406
 {
416 407
     BufferSinkContext *buf = ctx->priv;
417 408
     AVABufferSinkParams *params = opaque;
409
+    int ret;
418 410
 
419
-    if (params && params->sample_fmts) {
420
-        buf->sample_fmts = ff_copy_int_list(params->sample_fmts);
421
-        if (!buf->sample_fmts)
422
-            return AVERROR(ENOMEM);
423
-    }
424
-    if (params && params->sample_rates) {
425
-        buf->sample_rates = ff_copy_int_list(params->sample_rates);
426
-        if (!buf->sample_rates)
427
-            return AVERROR(ENOMEM);
428
-    }
429
-    if (params && (params->channel_layouts || params->channel_counts)) {
430
-        if (params->all_channel_counts) {
431
-            av_log(ctx, AV_LOG_ERROR,
432
-                   "Conflicting all_channel_counts and list in parameters\n");
433
-            return AVERROR(EINVAL);
434
-        }
435
-        buf->channel_layouts = concat_channels_lists(params->channel_layouts,
436
-                                                     params->channel_counts);
437
-        if (!buf->channel_layouts)
438
-            return AVERROR(ENOMEM);
411
+    if (params) {
412
+        if ((ret = av_opt_set_int_list(buf, "sample_fmts",     params->sample_fmts,  AV_SAMPLE_FMT_NONE, 0)) < 0 ||
413
+            (ret = av_opt_set_int_list(buf, "sample_rates",    params->sample_rates,    -1, 0)) < 0 ||
414
+            (ret = av_opt_set_int_list(buf, "channel_layouts", params->channel_layouts, -1, 0)) < 0 ||
415
+            (ret = av_opt_set_int_list(buf, "channel_counts",  params->channel_counts,  -1, 0)) < 0 ||
416
+            (ret = av_opt_set_int(buf, "all_channel_counts", params->all_channel_counts, 0)) < 0)
417
+            return ret;
439 418
     }
440
-    if (params)
441
-        buf->all_channel_counts = params->all_channel_counts;
442 419
     return common_init(ctx);
443 420
 }
444 421
 
... ...
@@ -447,32 +430,92 @@ static int asink_query_formats(AVFilterContext *ctx)
447 447
     BufferSinkContext *buf = ctx->priv;
448 448
     AVFilterFormats *formats = NULL;
449 449
     AVFilterChannelLayouts *layouts = NULL;
450
+    unsigned i;
451
+    int ret;
450 452
 
451
-    if (buf->sample_fmts) {
452
-        if (!(formats = ff_make_format_list(buf->sample_fmts)))
453
-            return AVERROR(ENOMEM);
453
+    if (buf->sample_fmts_size     % sizeof(*buf->sample_fmts)     ||
454
+        buf->sample_rates_size    % sizeof(*buf->sample_rates)    ||
455
+        buf->channel_layouts_size % sizeof(*buf->channel_layouts) ||
456
+        buf->channel_counts_size  % sizeof(*buf->channel_counts)) {
457
+        av_log(ctx, AV_LOG_ERROR, "Invalid size for format lists\n");
458
+#define LOG_ERROR(field) \
459
+        if (buf->field ## _size % sizeof(*buf->field)) \
460
+            av_log(ctx, AV_LOG_ERROR, "  " #field " is %d, should be " \
461
+                   "multiple of %d\n", \
462
+                   buf->field ## _size, (int)sizeof(*buf->field));
463
+        LOG_ERROR(sample_fmts);
464
+        LOG_ERROR(sample_rates);
465
+        LOG_ERROR(channel_layouts);
466
+        LOG_ERROR(channel_counts);
467
+#undef LOG_ERROR
468
+        return AVERROR(EINVAL);
469
+    }
470
+
471
+    if (buf->sample_fmts_size) {
472
+        for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++)
473
+            if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0)
474
+                return ret;
454 475
         ff_set_common_formats(ctx, formats);
455 476
     }
456 477
 
457
-    if (buf->channel_layouts || buf->all_channel_counts) {
458
-            layouts = buf->all_channel_counts ? ff_all_channel_counts() :
459
-                      avfilter_make_format64_list(buf->channel_layouts);
460
-        if (!layouts)
461
-            return AVERROR(ENOMEM);
478
+    if (buf->channel_layouts_size || buf->channel_counts_size ||
479
+        buf->all_channel_counts) {
480
+        for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
481
+            if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0)
482
+                return ret;
483
+        for (i = 0; i < NB_ITEMS(buf->channel_counts); i++)
484
+            if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0)
485
+                return ret;
486
+        if (buf->all_channel_counts) {
487
+            if (layouts)
488
+                av_log(ctx, AV_LOG_WARNING,
489
+                       "Conflicting all_channel_counts and list in options\n");
490
+            else if (!(layouts = ff_all_channel_counts()))
491
+                return AVERROR(ENOMEM);
492
+        }
462 493
         ff_set_common_channel_layouts(ctx, layouts);
463 494
     }
464 495
 
465
-    if (buf->sample_rates) {
466
-        formats = ff_make_format_list(buf->sample_rates);
467
-        if (!formats)
468
-            return AVERROR(ENOMEM);
496
+    if (buf->sample_rates_size) {
497
+        formats = NULL;
498
+        for (i = 0; i < NB_ITEMS(buf->sample_rates); i++)
499
+            if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0)
500
+                return ret;
469 501
         ff_set_common_samplerates(ctx, formats);
470 502
     }
471 503
 
472 504
     return 0;
473 505
 }
474 506
 
507
+#define OFFSET(x) offsetof(BufferSinkContext, x)
508
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
509
+static const AVOption buffersink_options[] = {
510
+    { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
511
+    { NULL },
512
+};
513
+#undef FLAGS
514
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
515
+static const AVOption abuffersink_options[] = {
516
+    { "sample_fmts",     "set the supported sample formats",  OFFSET(sample_fmts),     AV_OPT_TYPE_BINARY, .flags = FLAGS },
517
+    { "sample_rates",    "set the supported sample rates",    OFFSET(sample_rates),    AV_OPT_TYPE_BINARY, .flags = FLAGS },
518
+    { "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
519
+    { "channel_counts",  "set the supported channel counts",  OFFSET(channel_counts),  AV_OPT_TYPE_BINARY, .flags = FLAGS },
520
+    { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
521
+    { NULL },
522
+};
523
+#undef FLAGS
524
+static const char *const shorthand[] = { NULL };
525
+
526
+AVFILTER_DEFINE_CLASS(buffersink);
527
+AVFILTER_DEFINE_CLASS(abuffersink);
528
+
475 529
 #if FF_API_AVFILTERBUFFER
530
+
531
+#define ffbuffersink_options buffersink_options
532
+#define ffabuffersink_options abuffersink_options
533
+AVFILTER_DEFINE_CLASS(ffbuffersink);
534
+AVFILTER_DEFINE_CLASS(ffabuffersink);
535
+
476 536
 static const AVFilterPad ffbuffersink_inputs[] = {
477 537
     {
478 538
         .name      = "default",
... ...
@@ -486,6 +529,8 @@ AVFilter avfilter_vsink_ffbuffersink = {
486 486
     .name      = "ffbuffersink",
487 487
     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
488 488
     .priv_size = sizeof(BufferSinkContext),
489
+    .priv_class = &ffbuffersink_class,
490
+    .shorthand = shorthand,
489 491
     .init_opaque = vsink_init,
490 492
     .uninit    = uninit,
491 493
 
... ...
@@ -509,6 +554,8 @@ AVFilter avfilter_asink_ffabuffersink = {
509 509
     .init_opaque = asink_init,
510 510
     .uninit    = uninit,
511 511
     .priv_size = sizeof(BufferSinkContext),
512
+    .priv_class = &ffabuffersink_class,
513
+    .shorthand = shorthand,
512 514
     .query_formats = asink_query_formats,
513 515
     .inputs        = ffabuffersink_inputs,
514 516
     .outputs       = NULL,
... ...
@@ -528,6 +575,8 @@ AVFilter avfilter_vsink_buffer = {
528 528
     .name      = "buffersink",
529 529
     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
530 530
     .priv_size = sizeof(BufferSinkContext),
531
+    .priv_class = &buffersink_class,
532
+    .shorthand = shorthand,
531 533
     .init_opaque = vsink_init,
532 534
     .uninit    = uninit,
533 535
 
... ...
@@ -548,6 +597,8 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
548 548
 AVFilter avfilter_asink_abuffer = {
549 549
     .name      = "abuffersink",
550 550
     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
551
+    .priv_class = &abuffersink_class,
552
+    .shorthand = shorthand,
551 553
     .priv_size = sizeof(BufferSinkContext),
552 554
     .init_opaque = asink_init,
553 555
     .uninit    = uninit,