summaryrefslogtreecommitdiff
path: root/libavfilter/f_select.c
diff options
context:
space:
mode:
authorStefano Sabatini <stefasab@gmail.com>2013-04-08 12:58:56 +0200
committerStefano Sabatini <stefasab@gmail.com>2013-04-17 22:34:05 +0200
commitdcc1b3236168cc7baf97ae9074b9d1b90a03be9b (patch)
treebc73492f76a6312c297a8b0acf9e247fc0a4d360 /libavfilter/f_select.c
parent565c50ac7b51112032cd48e81af4560cda72b5b0 (diff)
downloadffmpeg-dcc1b3236168cc7baf97ae9074b9d1b90a03be9b.tar.gz
lavfi/select: add support for dynamic number of outputs
Diffstat (limited to 'libavfilter/f_select.c')
-rw-r--r--libavfilter/f_select.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index ca9bdc9533..9413f059c2 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -23,6 +23,7 @@
* filter for selecting which frame passes in the filterchain
*/
+#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/fifo.h"
#include "libavutil/internal.h"
@@ -136,13 +137,16 @@ typedef struct {
#endif
AVFrame *prev_picref; ///< previous frame (scene detect only)
double select;
+ int select_out; ///< mark the selected output pad index
+ int nb_outputs;
} SelectContext;
+static int request_frame(AVFilterLink *outlink);
static av_cold int init(AVFilterContext *ctx)
{
SelectContext *select = ctx->priv;
- int ret;
+ int i, ret;
if ((ret = av_expr_parse(&select->expr, select->expr_str,
var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
@@ -152,6 +156,17 @@ static av_cold int init(AVFilterContext *ctx)
}
select->do_scene_detect = !!strstr(select->expr_str, "scene");
+ for (i = 0; i < select->nb_outputs; i++) {
+ AVFilterPad pad = { 0 };
+
+ pad.name = av_asprintf("output%d", i);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ pad.type = ctx->filter->inputs[0].type;
+ pad.request_frame = request_frame;
+ ff_insert_outpad(ctx, i, &pad);
+ }
+
return 0;
}
@@ -308,7 +323,15 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
break;
}
- av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f\n", res);
+ if (res == 0) {
+ select->select_out = -1; /* drop */
+ } else if (isnan(res) || res < 0) {
+ select->select_out = 0; /* first output */
+ } else {
+ select->select_out = FFMIN(ceilf(res)-1, select->nb_outputs-1); /* other outputs */
+ }
+
+ av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f select_out:%d\n", res, select->select_out);
if (res) {
select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
@@ -326,11 +349,12 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
- SelectContext *select = inlink->dst->priv;
+ AVFilterContext *ctx = inlink->dst;
+ SelectContext *select = ctx->priv;
- select_frame(inlink->dst, frame);
+ select_frame(ctx, frame);
if (select->select)
- return ff_filter_frame(inlink->dst->outputs[0], frame);
+ return ff_filter_frame(ctx->outputs[select->select_out], frame);
av_frame_free(&frame);
return 0;
@@ -341,13 +365,13 @@ static int request_frame(AVFilterLink *outlink)
AVFilterContext *ctx = outlink->src;
SelectContext *select = ctx->priv;
AVFilterLink *inlink = outlink->src->inputs[0];
- select->select = 0;
+ int out_no = FF_OUTLINK_IDX(outlink);
do {
int ret = ff_request_frame(inlink);
if (ret < 0)
return ret;
- } while (!select->select);
+ } while (select->select_out != out_no);
return 0;
}
@@ -355,10 +379,14 @@ static int request_frame(AVFilterLink *outlink)
static av_cold void uninit(AVFilterContext *ctx)
{
SelectContext *select = ctx->priv;
+ int i;
av_expr_free(select->expr);
select->expr = NULL;
+ for (i = 0; i < ctx->nb_outputs; i++)
+ av_freep(&ctx->output_pads[i].name);
+
#if CONFIG_AVCODEC
if (select->do_scene_detect) {
av_frame_free(&select->prev_picref);
@@ -393,6 +421,8 @@ static int query_formats(AVFilterContext *ctx)
static const AVOption aselect_options[] = {
{ "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = AFLAGS },
{ "e", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = AFLAGS },
+ { "outputs", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AFLAGS },
+ { "n", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AFLAGS },
{ NULL },
};
AVFILTER_DEFINE_CLASS(aselect);
@@ -424,14 +454,6 @@ static const AVFilterPad avfilter_af_aselect_inputs[] = {
{ NULL }
};
-static const AVFilterPad avfilter_af_aselect_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- },
- { NULL }
-};
-
AVFilter avfilter_af_aselect = {
.name = "aselect",
.description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."),
@@ -439,8 +461,8 @@ AVFilter avfilter_af_aselect = {
.uninit = uninit,
.priv_size = sizeof(SelectContext),
.inputs = avfilter_af_aselect_inputs,
- .outputs = avfilter_af_aselect_outputs,
.priv_class = &aselect_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
};
#endif /* CONFIG_ASELECT_FILTER */
@@ -451,6 +473,8 @@ AVFilter avfilter_af_aselect = {
static const AVOption select_options[] = {
{ "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
{ "e", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
+ { "outputs", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, FLAGS },
+ { "n", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, FLAGS },
{ NULL },
};
@@ -483,15 +507,6 @@ static const AVFilterPad avfilter_vf_select_inputs[] = {
{ NULL }
};
-static const AVFilterPad avfilter_vf_select_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = request_frame,
- },
- { NULL }
-};
-
AVFilter avfilter_vf_select = {
.name = "select",
.description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."),
@@ -503,6 +518,6 @@ AVFilter avfilter_vf_select = {
.priv_class = &select_class,
.inputs = avfilter_vf_select_inputs,
- .outputs = avfilter_vf_select_outputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
};
#endif /* CONFIG_SELECT_FILTER */