Allow code to pass data to filters it creates.
[ffmpeg.git] / libavfilter / avfiltergraph.c
index 7b9d963..ac2fb00 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <string.h>
+#include <stddef.h>
+
+#include "avstring.h"
 #include "avfilter.h"
 #include "avfiltergraph.h"
 
@@ -32,13 +36,16 @@ AVFilterGraph *avfilter_create_graph(void)
     return av_mallocz(sizeof(AVFilterGraph));
 }
 
-void avfilter_destroy_graph(AVFilterGraph *graph)
+static void destroy_graph_filters(AVFilterGraph *graph)
 {
-    unsigned i;
+    for(; graph->filter_count > 0; graph->filter_count --)
+        avfilter_destroy(graph->filters[graph->filter_count - 1]);
+    av_freep(&graph->filters);
+}
 
-    for(i = 0; i < graph->filter_count; i ++)
-        avfilter_destroy(graph->filters[i]);
-    av_free(graph->filters);
+void avfilter_destroy_graph(AVFilterGraph *graph)
+{
+    destroy_graph_filters(graph);
     av_free(graph);
 }
 
@@ -49,3 +56,73 @@ void avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
     graph->filters[graph->filter_count - 1] = filter;
 }
 
+static AVFilterContext *create_filter_with_args(const char *filt, void *opaque)
+{
+    AVFilterContext *ret;
+    char *filter = av_strdup(filt); /* copy - don't mangle the input string */
+    char *name, *args;
+
+    name = filter;
+    if((args = strchr(filter, '='))) {
+        /* ensure we at least have a name */
+        if(args == filter)
+            goto fail;
+
+        *args ++ = 0;
+    }
+
+    av_log(NULL, AV_LOG_INFO, "creating filter \"%s\" with args \"%s\"\n",
+           name, args ? args : "(none)");
+
+    if((ret = avfilter_create_by_name(name, NULL))) {
+        if(avfilter_init_filter(ret, args, opaque)) {
+            av_log(NULL, AV_LOG_ERROR, "error initializing filter!\n");
+            avfilter_destroy(ret);
+            goto fail;
+        }
+    } else av_log(NULL, AV_LOG_ERROR, "error creating filter!\n");
+
+    return ret;
+
+fail:
+    av_free(filter);
+    return NULL;
+}
+
+int avfilter_graph_load_chain(AVFilterGraph *graph,
+                              unsigned count, char **filter_list, void **opaque,
+                              AVFilterContext **first, AVFilterContext **last)
+{
+    unsigned i;
+    AVFilterContext *filters[2] = {NULL,NULL};
+
+    for(i = 0; i < count; i ++) {
+        void *op;
+
+        if(opaque) op = opaque[i];
+        else       op = NULL;
+
+        if(!(filters[1] = create_filter_with_args(filter_list[i], op)))
+            goto fail;
+        if(i == 0) {
+            if(first) *first = filters[1];
+        } else {
+            if(avfilter_link(filters[0], 0, filters[1], 0)) {
+                av_log(NULL, AV_LOG_ERROR, "error linking filters!\n");
+                goto fail;
+            }
+        }
+        avfilter_graph_add_filter(graph, filters[1]);
+        filters[0] = filters[1];
+    }
+
+    if(last) *last = filters[1];
+    return 0;
+
+fail:
+    destroy_graph_filters(graph);
+    if(first) *first = NULL;
+    if(last)  *last  = NULL;
+    return -1;
+}
+