]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/avfilter.c
Merge commit 'e67a87eac814c7805d18c983c43033a8a1bd62af'
[ffmpeg] / libavfilter / avfilter.c
index 1d278178fe2443456fb317a9497d1d8861b73f1c..d81f672d74b37b7ddda7467ea5ef591de97a053c 100644 (file)
@@ -24,6 +24,7 @@
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/rational.h"
 #include "libavutil/samplefmt.h"
@@ -322,17 +323,27 @@ int ff_request_frame(AVFilterLink *link)
 
     if (link->closed)
         return AVERROR_EOF;
-    if (link->srcpad->request_frame)
-        ret = link->srcpad->request_frame(link);
-    else if (link->src->inputs[0])
-        ret = ff_request_frame(link->src->inputs[0]);
-    if (ret == AVERROR_EOF && link->partial_buf) {
-        AVFrame *pbuf = link->partial_buf;
-        link->partial_buf = NULL;
-        ret = ff_filter_frame_framed(link, pbuf);
+    av_assert0(!link->frame_requested);
+    link->frame_requested = 1;
+    while (link->frame_requested) {
+        if (link->srcpad->request_frame)
+            ret = link->srcpad->request_frame(link);
+        else if (link->src->inputs[0])
+            ret = ff_request_frame(link->src->inputs[0]);
+        if (ret == AVERROR_EOF && link->partial_buf) {
+            AVFrame *pbuf = link->partial_buf;
+            link->partial_buf = NULL;
+            ret = ff_filter_frame_framed(link, pbuf);
+        }
+        if (ret < 0) {
+            link->frame_requested = 0;
+            if (ret == AVERROR_EOF)
+                link->closed = 1;
+        } else {
+            av_assert0(!link->frame_requested ||
+                       link->flags & FF_LINK_FLAG_REQUEST_LOOP);
+        }
     }
-    if (ret == AVERROR_EOF)
-        link->closed = 1;
     return ret;
 }
 
@@ -505,6 +516,11 @@ int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *in
             goto err;
     }
 
+    if (filter->priv_class) {
+        *(const AVClass**)ret->priv = filter->priv_class;
+        av_opt_set_defaults(ret->priv);
+    }
+
     ret->nb_inputs = pad_count(filter->inputs);
     if (ret->nb_inputs ) {
         ret->input_pads   = av_malloc(sizeof(AVFilterPad) * ret->nb_inputs);
@@ -584,6 +600,9 @@ void avfilter_free(AVFilterContext *filter)
         avfilter_link_free(&link);
     }
 
+    if (filter->filter->priv_class || filter->filter->shorthand)
+        av_opt_free(filter->priv);
+
     av_freep(&filter->name);
     av_freep(&filter->input_pads);
     av_freep(&filter->output_pads);
@@ -596,14 +615,129 @@ void avfilter_free(AVFilterContext *filter)
     av_free(filter);
 }
 
+/* process a list of value1:value2:..., each value corresponding
+ * to subsequent AVOption, in the order they are declared */
+static int process_unnamed_options(AVFilterContext *ctx, AVDictionary **options,
+                                   const char *args)
+{
+    const AVOption *o = NULL;
+    const char *p = args;
+    char *val;
+
+    while (*p) {
+        o = av_opt_next(ctx->priv, o);
+        if (!o) {
+            av_log(ctx, AV_LOG_ERROR, "More options provided than "
+                   "this filter supports.\n");
+            return AVERROR(EINVAL);
+        }
+        if (o->type == AV_OPT_TYPE_CONST)
+            continue;
+
+        val = av_get_token(&p, ":");
+        if (!val)
+            return AVERROR(ENOMEM);
+
+        av_dict_set(options, o->name, val, 0);
+
+        av_freep(&val);
+        if (*p)
+            p++;
+    }
+
+    return 0;
+}
+
 int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque)
 {
+    AVDictionary *options = NULL;
+    AVDictionaryEntry *e;
     int ret=0;
+    int anton_options =
+        !strcmp(filter->filter->name,  "aformat") ||
+        !strcmp(filter->filter->name,   "format") ||
+        !strcmp(filter->filter->name, "noformat") ||
+        !strcmp(filter->filter->name, "resample")
+        ;
+
+    if (filter->filter->shorthand) {
+        av_assert0(filter->priv);
+        av_assert0(filter->filter->priv_class);
+        *(const AVClass **)filter->priv = filter->filter->priv_class;
+        av_opt_set_defaults(filter->priv);
+        ret = av_opt_set_from_string(filter->priv, args,
+                                     filter->filter->shorthand, "=", ":");
+        if (ret < 0)
+            return ret;
+        args = NULL;
+    }
+
+    if (anton_options && args && *args && filter->filter->priv_class) {
+        if (strchr(args, '=')) {
+            /* assume a list of key1=value1:key2=value2:... */
+            ret = av_dict_parse_string(&options, args, "=", ":", 0);
+            if (ret < 0)
+                goto fail;
+#if FF_API_OLD_FILTER_OPTS
+        } else if (!strcmp(filter->filter->name, "format") ||
+                   !strcmp(filter->filter->name, "noformat")) {
+            /* a hack for compatibility with the old syntax
+             * replace colons with |s */
+            char *copy = av_strdup(args);
+            char *p    = copy;
+
+            if (!copy) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            if (strchr(copy, ':')) {
+                av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use "
+                       "'|' to separate the list items.\n");
+            }
+
+            while ((p = strchr(p, ':')))
+                *p++ = '|';
+
+            ret = process_unnamed_options(filter, &options, copy);
+            av_freep(&copy);
+
+            if (ret < 0)
+                goto fail;
+#endif
+        } else {
+            ret = process_unnamed_options(filter, &options, args);
+            if (ret < 0)
+                goto fail;
+        }
+    }
+
+    if (anton_options && filter->filter->priv_class) {
+        ret = av_opt_set_dict(filter->priv, &options);
+        if (ret < 0) {
+            av_log(filter, AV_LOG_ERROR, "Error applying options to the filter.\n");
+            goto fail;
+        }
+    }
 
     if (filter->filter->init_opaque)
         ret = filter->filter->init_opaque(filter, args, opaque);
     else if (filter->filter->init)
         ret = filter->filter->init(filter, args);
+    else if (filter->filter->init_dict)
+        ret = filter->filter->init_dict(filter, &options);
+    if (ret < 0)
+        goto fail;
+
+    if ((e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
+        av_log(filter, AV_LOG_ERROR, "No such option: %s.\n", e->key);
+        ret = AVERROR_OPTION_NOT_FOUND;
+        goto fail;
+    }
+
+fail:
+    av_dict_free(&options);
+
     return ret;
 }
 
@@ -688,6 +822,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
 
     pts = out->pts;
     ret = filter_frame(link, out);
+    link->frame_requested = 0;
     ff_update_link_current_pts(link, pts);
     return ret;
 }
@@ -699,6 +834,7 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
     int nb_channels = av_frame_get_channels(frame);
     int ret = 0;
 
+    link->flags |= FF_LINK_FLAG_REQUEST_LOOP;
     /* Handle framing (min_samples, max_samples) */
     while (insamples) {
         if (!pbuf) {