summaryrefslogtreecommitdiff
path: root/libavfilter/avfiltergraph.c
diff options
context:
space:
mode:
authorVitor Sessak <vitor1001@gmail.com>2008-04-04 20:06:37 +0000
committerVitor Sessak <vitor1001@gmail.com>2008-04-04 20:06:37 +0000
commit57d4a1575cf348719fa5f3205c97eada9eac8818 (patch)
tree89b6e1cbb0259fd7b47db1882efb9b987e9a307d /libavfilter/avfiltergraph.c
parent1d2067e2c7033a95a6160ff25e3455cb2c30c35f (diff)
Allow creation of filter graphs from a graph description structure which
can be created programmatically or loaded from a file. Commited in SoC by Bobby Bingham on 2007-08-14 22:27:05 Originally committed as revision 12700 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavfilter/avfiltergraph.c')
-rw-r--r--libavfilter/avfiltergraph.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index baac83c238..c3436d8226 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -26,6 +26,8 @@
#include "avfilter.h"
#include "avfiltergraph.h"
+#include "allfilters.h"
+
typedef struct AVFilterGraph {
unsigned filter_count;
AVFilterContext **filters;
@@ -376,6 +378,7 @@ static void uninit(AVFilterContext *ctx)
av_freep(&graph->filters);
}
+/* TODO: insert in sorted order */
void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter)
{
GraphContext *graph = graphctx->priv;
@@ -385,15 +388,38 @@ void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filte
graph->filters[graph->filter_count - 1] = filter;
}
+/* search intelligently, once we insert in order */
+AVFilterContext *avfilter_graph_get_filter(AVFilterContext *ctx, char *name)
+{
+ GraphContext *graph = ctx->priv;
+ int i;
+
+ if(!name)
+ return NULL;
+
+ for(i = 0; i < graph->filter_count; i ++)
+ if(graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
+ return graph->filters[i];
+
+ return NULL;
+}
+
int avfilter_graph_config_links(AVFilterContext *graphctx)
{
GraphContext *graph = graphctx->priv;
int i, j;
for(i = 0; i < graph->filter_count; i ++) {
- for(j = 0; j < graph->filters[i]->input_count; j ++)
+ for(j = 0; j < graph->filters[i]->input_count; j ++) {
+ /* ensure that graphs contained within graphs are configured */
+ if((graph->filters[i]->filter == &vf_graph ||
+ graph->filters[i]->filter == &vf_graphfile ||
+ graph->filters[i]->filter == &vf_graphdesc) &&
+ avfilter_graph_config_links(graph->filters[i]))
+ return -1;
if(avfilter_config_link(graph->filters[i]->inputs[j]))
return -1;
+ }
}
return 0;
@@ -542,3 +568,126 @@ AVFilter vf_graph =
.outputs = (AVFilterPad[]) {{ .name = NULL, }},
};
+static int graph_load_from_desc(AVFilterContext *ctx, AVFilterGraphDesc *desc)
+{
+ AVFilterGraphDescFilter *curfilt;
+ AVFilterGraphDescLink *curlink;
+ AVFilterGraphDescExport *curpad;
+ AVFilterContext *filt, *filtb;
+
+ /* create all filters */
+ for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) {
+ if(!(filt = avfilter_create_by_name(curfilt->filter, curfilt->name))) {
+ av_log(ctx, AV_LOG_ERROR, "error creating filter\n");
+ goto fail;
+ }
+ avfilter_graph_add_filter(ctx, filt);
+ if(avfilter_init_filter(filt, curfilt->args, NULL)) {
+ av_log(ctx, AV_LOG_ERROR, "error initializing filter\n");
+ goto fail;
+ }
+ }
+
+ /* create all links */
+ for(curlink = desc->links; curlink; curlink = curlink->next) {
+ if(!(filt = avfilter_graph_get_filter(ctx, curlink->src))) {
+ av_log(ctx, AV_LOG_ERROR, "link source does not exist in graph\n");
+ goto fail;
+ }
+ if(!(filtb = avfilter_graph_get_filter(ctx, curlink->dst))) {
+ av_log(ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
+ goto fail;
+ }
+ if(avfilter_link(filt, curlink->srcpad, filtb, curlink->dstpad)) {
+ av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
+ goto fail;
+ }
+ }
+
+ /* export all input pads */
+ for(curpad = desc->inputs; curpad; curpad = curpad->next) {
+ if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
+ av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
+ goto fail;
+ }
+ add_graph_input(ctx, filt, curpad->pad, curpad->name);
+ }
+
+ /* export all output pads */
+ for(curpad = desc->outputs; curpad; curpad = curpad->next) {
+ if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
+ av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
+ goto fail;
+ }
+ add_graph_output(ctx, filt, curpad->pad, curpad->name);
+ }
+
+ return 0;
+
+fail:
+ uninit(ctx);
+ return -1;
+}
+
+static int init_desc(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ GraphContext *gctx = ctx->priv;
+
+ if(!opaque)
+ return -1;
+
+ if(!(gctx->link_filter = avfilter_create(&vf_graph_dummy, NULL)))
+ return -1;
+ if(avfilter_init_filter(gctx->link_filter, NULL, ctx))
+ goto fail;
+
+ return graph_load_from_desc(ctx, opaque);
+
+fail:
+ avfilter_destroy(gctx->link_filter);
+ return -1;
+}
+
+AVFilter vf_graphdesc =
+{
+ .name = "graph_desc",
+ .author = "Bobby Bingham",
+
+ .priv_size = sizeof(GraphContext),
+
+ .init = init_desc,
+ .uninit = uninit,
+
+ .inputs = (AVFilterPad[]) {{ .name = NULL, }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL, }},
+};
+
+static int init_file(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ AVFilterGraphDesc *desc;
+ int ret;
+
+ if(!args)
+ return -1;
+ if(!(desc = avfilter_graph_load_desc(args)))
+ return -1;
+
+ ret = init_desc(ctx, NULL, desc);
+ avfilter_graph_free_desc(desc);
+ return ret;
+}
+
+AVFilter vf_graphfile =
+{
+ .name = "graph_file",
+ .author = "Bobby Bingham",
+
+ .priv_size = sizeof(GraphContext),
+
+ .init = init_file,
+ .uninit = uninit,
+
+ .inputs = (AVFilterPad[]) {{ .name = NULL, }},
+ .outputs = (AVFilterPad[]) {{ .name = NULL, }},
+};
+