From 57d4a1575cf348719fa5f3205c97eada9eac8818 Mon Sep 17 00:00:00 2001 From: Vitor Sessak Date: Fri, 4 Apr 2008 20:06:37 +0000 Subject: [PATCH] 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 --- libavfilter/avfiltergraph.c | 151 +++++++++++++++++++++++++++++++++++- libavfilter/avfiltergraph.h | 55 +++++++++++++ 2 files changed, 205 insertions(+), 1 deletion(-) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index baac83c2380..c3436d82269 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, }}, +}; + diff --git a/libavfilter/avfiltergraph.h b/libavfilter/avfiltergraph.h index 309921c800d..9a70868182c 100644 --- a/libavfilter/avfiltergraph.h +++ b/libavfilter/avfiltergraph.h @@ -24,6 +24,61 @@ #include "avfilter.h" +/** Linked-list of filters to create for an AVFilterGraphDesc */ +typedef struct AVFilterGraphDescFilter +{ + char *name; ///< filter instance name + char *filter; ///< name of filter type + char *args; ///< filter parameters + struct AVFilterGraphDescFilter *next; +} AVFilterGraphDescFilter; + +/** Linked-list of links between filters */ +typedef struct AVFilterGraphDescLink +{ + /* TODO: allow referencing pads by name, not just by index */ + char *src; ///< name of the source filter + unsigned srcpad; ///< index of the output pad on the source filter + + char *dst; ///< name of the dest filter + unsigned dstpad; ///< index of the input pad on the dest filter + + struct AVFilterGraphDescLink *next; +} AVFilterGraphDescLink; + +/** Linked-list of filter pads to be exported from the graph */ +typedef struct AVFilterGraphDescExport +{ + /* TODO: allow referencing pads by name, not just by index */ + char *name; ///< name of the exported pad + char *filter; ///< name of the filter + unsigned pad; ///< index of the pad to be exported + + struct AVFilterGraphDescExport *next; +} AVFilterGraphDescExport; + +/** Description of a graph to be loaded from a file, etc */ +typedef struct +{ + AVFilterGraphDescFilter *filters; ///< filters in the graph + AVFilterGraphDescLink *links; ///< links between the filters + AVFilterGraphDescExport *inputs; ///< inputs to export + AVFilterGraphDescExport *outputs; ///< outputs to export +} AVFilterGraphDesc; + +/** + * Load a filter graph description from a file + * @param filename Name of the file from which to load the description + * @return Pointer to the description on success. NULL on failure + */ +AVFilterGraphDesc *avfilter_graph_load_desc(const char *filename); + +/** + * Free a filter graph description + * @param desc The graph description to free + */ +void avfilter_graph_free_desc(AVFilterGraphDesc *desc); + /** * Add an existing filter instance to a filter graph. * @param graph The filter graph -- 2.39.5