lavfi/select: add support to options

Add options introspection, and improve error feedback.
This commit is contained in:
Stefano Sabatini 2012-12-12 00:21:26 +01:00
parent c214cd18e2
commit 6ba1f28008
3 changed files with 76 additions and 14 deletions

View File

@ -4637,9 +4637,14 @@ Below is a description of the currently available multimedia filters.
@section aselect, select @section aselect, select
Select frames to pass in output. Select frames to pass in output.
It accepts in input an expression, which is evaluated for each input These filters accept a single option @option{expr} or @option{e}
frame. If the expression is evaluated to a non-zero value, the frame specifying the select expression, which can be specified either by
is selected and passed to the output, otherwise it is discarded. specyfing @code{expr=VALUE} or specifying the expression
alone.
The select expression is evaluated for each input frame. If the
evaluation result is a non-zero value, the frame is selected and
passed to the output, otherwise it is discarded.
The expression can contain the following constants: The expression can contain the following constants:

View File

@ -26,6 +26,7 @@
#include "libavutil/eval.h" #include "libavutil/eval.h"
#include "libavutil/fifo.h" #include "libavutil/fifo.h"
#include "libavutil/internal.h" #include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avfilter.h" #include "avfilter.h"
#include "audio.h" #include "audio.h"
#include "formats.h" #include "formats.h"
@ -123,7 +124,9 @@ enum var_name {
}; };
typedef struct { typedef struct {
const AVClass *class;
AVExpr *expr; AVExpr *expr;
char *expr_str;
double var_values[VAR_VARS_NB]; double var_values[VAR_VARS_NB];
int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise
#if CONFIG_AVCODEC #if CONFIG_AVCODEC
@ -135,22 +138,33 @@ typedef struct {
double select; double select;
} SelectContext; } SelectContext;
static av_cold int init(AVFilterContext *ctx, const char *args) #define OFFSET(x) offsetof(SelectContext, x)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM
static const AVOption options[] = {
{ "expr", "set selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str = "1"}, 0, 0, FLAGS },
{ "e", "set selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str = "1"}, 0, 0, FLAGS },
{NULL},
};
static av_cold int init(AVFilterContext *ctx, const char *args, const AVClass *class)
{ {
SelectContext *select = ctx->priv; SelectContext *select = ctx->priv;
const char *shorthand[] = { "expr", NULL };
int ret; int ret;
if ((ret = av_expr_parse(&select->expr, args ? args : "1", select->class = class;
av_opt_set_defaults(select);
if ((ret = av_opt_set_from_string(select, args, shorthand, "=", ":")) < 0)
return ret;
if ((ret = av_expr_parse(&select->expr, select->expr_str,
var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) { var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args); av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", select->expr_str);
return ret; return ret;
} }
select->do_scene_detect = !!strstr(select->expr_str, "scene");
select->do_scene_detect = args && strstr(args, "scene");
if (select->do_scene_detect && !CONFIG_AVCODEC) {
av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n");
return AVERROR(EINVAL);
}
return 0; return 0;
} }
@ -347,6 +361,7 @@ static av_cold void uninit(AVFilterContext *ctx)
av_expr_free(select->expr); av_expr_free(select->expr);
select->expr = NULL; select->expr = NULL;
av_opt_free(select);
if (select->do_scene_detect) { if (select->do_scene_detect) {
avfilter_unref_bufferp(&select->prev_picref); avfilter_unref_bufferp(&select->prev_picref);
@ -374,6 +389,26 @@ static int query_formats(AVFilterContext *ctx)
} }
#if CONFIG_ASELECT_FILTER #if CONFIG_ASELECT_FILTER
#define aselect_options options
AVFILTER_DEFINE_CLASS(aselect);
static av_cold int aselect_init(AVFilterContext *ctx, const char *args)
{
SelectContext *select = ctx->priv;
int ret;
if ((ret = init(ctx, args, &aselect_class)) < 0)
return ret;
if (select->do_scene_detect) {
av_log(ctx, AV_LOG_ERROR, "Scene detection is ignored in aselect filter\n");
return AVERROR(EINVAL);
}
return 0;
}
static const AVFilterPad avfilter_af_aselect_inputs[] = { static const AVFilterPad avfilter_af_aselect_inputs[] = {
{ {
.name = "default", .name = "default",
@ -396,15 +431,36 @@ static const AVFilterPad avfilter_af_aselect_outputs[] = {
AVFilter avfilter_af_aselect = { AVFilter avfilter_af_aselect = {
.name = "aselect", .name = "aselect",
.description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."), .description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."),
.init = init, .init = aselect_init,
.uninit = uninit, .uninit = uninit,
.priv_size = sizeof(SelectContext), .priv_size = sizeof(SelectContext),
.inputs = avfilter_af_aselect_inputs, .inputs = avfilter_af_aselect_inputs,
.outputs = avfilter_af_aselect_outputs, .outputs = avfilter_af_aselect_outputs,
.priv_class = &aselect_class,
}; };
#endif /* CONFIG_ASELECT_FILTER */ #endif /* CONFIG_ASELECT_FILTER */
#if CONFIG_SELECT_FILTER #if CONFIG_SELECT_FILTER
#define select_options options
AVFILTER_DEFINE_CLASS(select);
static av_cold int select_init(AVFilterContext *ctx, const char *args)
{
SelectContext *select = ctx->priv;
int ret;
if ((ret = init(ctx, args, &select_class)) < 0)
return ret;
if (select->do_scene_detect && !CONFIG_AVCODEC) {
av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n");
return AVERROR(EINVAL);
}
return 0;
}
static const AVFilterPad avfilter_vf_select_inputs[] = { static const AVFilterPad avfilter_vf_select_inputs[] = {
{ {
.name = "default", .name = "default",
@ -429,7 +485,7 @@ static const AVFilterPad avfilter_vf_select_outputs[] = {
AVFilter avfilter_vf_select = { AVFilter avfilter_vf_select = {
.name = "select", .name = "select",
.description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."), .description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."),
.init = init, .init = select_init,
.uninit = uninit, .uninit = uninit,
.query_formats = query_formats, .query_formats = query_formats,
@ -437,5 +493,6 @@ AVFilter avfilter_vf_select = {
.inputs = avfilter_vf_select_inputs, .inputs = avfilter_vf_select_inputs,
.outputs = avfilter_vf_select_outputs, .outputs = avfilter_vf_select_outputs,
.priv_class = &select_class,
}; };
#endif /* CONFIG_SELECT_FILTER */ #endif /* CONFIG_SELECT_FILTER */

View File

@ -30,7 +30,7 @@
#define LIBAVFILTER_VERSION_MAJOR 3 #define LIBAVFILTER_VERSION_MAJOR 3
#define LIBAVFILTER_VERSION_MINOR 27 #define LIBAVFILTER_VERSION_MINOR 27
#define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \ LIBAVFILTER_VERSION_MINOR, \