#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
return min;
}
+static const char *const var_names[] = { "t", "n", "pos", NULL };
+enum { VAR_T, VAR_N, VAR_POS, VAR_VARS_NB };
+
+static int set_enable_expr(AVFilterContext *ctx, const char *expr)
+{
+ int ret;
+ char *expr_dup;
+ AVExpr *old = ctx->enable;
+
+ if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) {
+ av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported "
+ "with filter '%s'\n", ctx->filter->name);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ expr_dup = av_strdup(expr);
+ if (!expr_dup)
+ return AVERROR(ENOMEM);
+
+ if (!ctx->var_values) {
+ ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values));
+ if (!ctx->var_values) {
+ av_free(expr_dup);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ ret = av_expr_parse((AVExpr**)&ctx->enable, expr_dup, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx->priv);
+ if (ret < 0) {
+ av_log(ctx->priv, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s' for enable\n",
+ expr_dup);
+ av_free(expr_dup);
+ return ret;
+ }
+
+ av_expr_free(old);
+ av_free(ctx->enable_str);
+ ctx->enable_str = expr_dup;
+ return 0;
+}
+
void ff_update_link_current_pts(AVFilterLink *link, int64_t pts)
{
if (pts == AV_NOPTS_VALUE)
if(!strcmp(cmd, "ping")){
av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
return 0;
+ }else if(!strcmp(cmd, "enable")) {
+ return set_enable_expr(filter, arg);
}else if(filter->filter->process_command) {
return filter->filter->process_command(filter, cmd, arg, res, res_len, flags);
}
return AVERROR(ENOSYS);
}
-#define MAX_REGISTERED_AVFILTERS_NB 256
-
-static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1];
-
-static int next_registered_avfilter_idx = 0;
+static AVFilter *first_filter;
AVFilter *avfilter_get_by_name(const char *name)
{
- int i;
+ AVFilter *f = NULL;
+
+ if (!name)
+ return NULL;
- for (i = 0; registered_avfilters[i]; i++)
- if (!strcmp(registered_avfilters[i]->name, name))
- return registered_avfilters[i];
+ while ((f = avfilter_next(f)))
+ if (!strcmp(f->name, name))
+ return f;
return NULL;
}
int avfilter_register(AVFilter *filter)
{
+ AVFilter **f = &first_filter;
int i;
- if (next_registered_avfilter_idx == MAX_REGISTERED_AVFILTERS_NB) {
- av_log(NULL, AV_LOG_ERROR,
- "Maximum number of registered filters %d reached, "
- "impossible to register filter with name '%s'\n",
- MAX_REGISTERED_AVFILTERS_NB, filter->name);
- return AVERROR(ENOMEM);
- }
-
for(i=0; filter->inputs && filter->inputs[i].name; i++) {
const AVFilterPad *input = &filter->inputs[i];
av_assert0( !input->filter_frame
|| (!input->start_frame && !input->end_frame));
}
- registered_avfilters[next_registered_avfilter_idx++] = filter;
+ while (*f)
+ f = &(*f)->next;
+ *f = filter;
+ filter->next = NULL;
+
return 0;
}
+const AVFilter *avfilter_next(const AVFilter *prev)
+{
+ return prev ? prev->next : first_filter;
+}
+
+#if FF_API_OLD_FILTER_REGISTER
AVFilter **av_filter_next(AVFilter **filter)
{
- return filter ? ++filter : ®istered_avfilters[0];
+ return filter ? &(*filter)->next : &first_filter;
}
void avfilter_uninit(void)
{
- memset(registered_avfilters, 0, sizeof(registered_avfilters));
- next_registered_avfilter_idx = 0;
}
+#endif
int avfilter_pad_count(const AVFilterPad *pads)
{
static const AVClass *filter_child_class_next(const AVClass *prev)
{
- AVFilter **f = NULL;
+ AVFilter *f = NULL;
/* find the filter that corresponds to prev */
- while (prev && *(f = av_filter_next(f)))
- if ((*f)->priv_class == prev)
+ while (prev && (f = avfilter_next(f)))
+ if (f->priv_class == prev)
break;
/* could not find filter corresponding to prev */
- if (prev && !(*f))
+ if (prev && !f)
return NULL;
/* find next filter with specific options */
- while (*(f = av_filter_next(f)))
- if ((*f)->priv_class)
- return (*f)->priv_class;
+ while ((f = avfilter_next(f)))
+ if (f->priv_class)
+ return f->priv_class;
+
return NULL;
}
+#define OFFSET(x) offsetof(AVFilterContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption filters_common_options[] = {
+ { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { NULL }
+};
+
static const AVClass avfilter_class = {
.class_name = "AVFilter",
.item_name = default_filter_name,
.version = LIBAVUTIL_VERSION_INT,
.category = AV_CLASS_CATEGORY_FILTER,
.child_next = filter_child_next,
+ .option = filters_common_options,
.child_class_next = filter_child_class_next,
};
avfilter_link_free(&link);
}
- if (filter->filter->priv_class || filter->filter->shorthand)
+ if (filter->filter->priv_class)
av_opt_free(filter->priv);
av_freep(&filter->name);
while(filter->command_queue){
ff_command_queue_pop(filter);
}
+ av_opt_free(filter);
+ av_expr_free(filter->enable);
+ filter->enable = NULL;
+ av_freep(&filter->var_values);
av_free(filter);
}
const char *key;
int offset= -1;
+ av_opt_set_defaults(ctx);
+
if (!args)
return 0;
}
av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
+
+ if (av_opt_find(ctx, key, NULL, 0, 0)) {
+ ret = av_opt_set(ctx, key, value, 0);
+ if (ret < 0)
+ return ret;
+ } else {
av_dict_set(options, key, value, 0);
if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) {
return ret;
}
}
+ }
av_free(value);
av_free(parsed_key);
count++;
}
+
+ if (ctx->enable_str) {
+ ret = set_enable_expr(ctx, ctx->enable_str);
+ if (ret < 0)
+ return ret;
+ }
return count;
}
static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
{
int (*filter_frame)(AVFilterLink *, AVFrame *);
+ AVFilterContext *dstctx = link->dst;
AVFilterPad *dst = link->dstpad;
AVFrame *out;
int ret;
}
pts = out->pts;
+ if (dstctx->enable_str) {
+ int64_t pos = av_frame_get_pkt_pos(out);
+ dstctx->var_values[VAR_N] = link->frame_count;
+ dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base);
+ dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos;
+ if (!av_expr_eval(dstctx->enable, dstctx->var_values, NULL))
+ filter_frame = dst->passthrough_filter_frame ? dst->passthrough_filter_frame
+ : default_filter_frame;
+ }
ret = filter_frame(link, out);
+ link->frame_count++;
link->frame_requested = 0;
ff_update_link_current_pts(link, pts);
return ret;