[FFmpeg-soc] [soc]: r795 - in libavfilter: Makefile allfilters.h avfilter.c avfiltergraph.c avfiltergraph.h avfiltergraphdesc.c
koorogi
subversion at mplayerhq.hu
Wed Aug 15 00:27:06 CEST 2007
Author: koorogi
Date: Wed Aug 15 00:27:05 2007
New Revision: 795
Log:
Allow creation of filter graphs from a graph description structure which
can be created programmatically or loaded from a file.
Added:
libavfilter/avfiltergraphdesc.c
Modified:
libavfilter/Makefile
libavfilter/allfilters.h
libavfilter/avfilter.c
libavfilter/avfiltergraph.c
libavfilter/avfiltergraph.h
Modified: libavfilter/Makefile
==============================================================================
--- libavfilter/Makefile (original)
+++ libavfilter/Makefile Wed Aug 15 00:27:05 2007
@@ -4,6 +4,7 @@ CFLAGS+=-I$(SRC_PATH)/libavcodec
OBJS = avfilter.o \
avfiltergraph.o \
+ avfiltergraphdesc.o \
defaults.o \
# TODO: real conditional compilation
Modified: libavfilter/allfilters.h
==============================================================================
--- libavfilter/allfilters.h (original)
+++ libavfilter/allfilters.h Wed Aug 15 00:27:05 2007
@@ -26,6 +26,8 @@ extern AVFilter vsrc_ppm;
extern AVFilter vf_crop;
extern AVFilter vf_fps;
extern AVFilter vf_graph;
+extern AVFilter vf_graphdesc;
+extern AVFilter vf_graphfile;
extern AVFilter vf_overlay;
extern AVFilter vf_passthrough;
extern AVFilter vf_rgb2bgr;
Modified: libavfilter/avfilter.c
==============================================================================
--- libavfilter/avfilter.c (original)
+++ libavfilter/avfilter.c Wed Aug 15 00:27:05 2007
@@ -220,6 +220,8 @@ void avfilter_init(void)
avfilter_register(&vf_crop);
avfilter_register(&vf_fps);
avfilter_register(&vf_graph);
+ avfilter_register(&vf_graphdesc);
+ avfilter_register(&vf_graphfile);
avfilter_register(&vf_overlay);
avfilter_register(&vf_passthrough);
avfilter_register(&vf_rgb2bgr);
Modified: libavfilter/avfiltergraph.c
==============================================================================
--- libavfilter/avfiltergraph.c (original)
+++ libavfilter/avfiltergraph.c Wed Aug 15 00:27:05 2007
@@ -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(AVFilterC
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, }},
+};
+
Modified: libavfilter/avfiltergraph.h
==============================================================================
--- libavfilter/avfiltergraph.h (original)
+++ libavfilter/avfiltergraph.h Wed Aug 15 00:27:05 2007
@@ -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
Added: libavfilter/avfiltergraphdesc.c
==============================================================================
--- (empty file)
+++ libavfilter/avfiltergraphdesc.c Wed Aug 15 00:27:05 2007
@@ -0,0 +1,251 @@
+/*
+ * Filter graph descriptions for file serialization
+ * copyright (c) 2007 Bobby Bingham
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "avfilter.h"
+#include "avfiltergraph.h"
+
+#define LINESIZE 240 ///< maximum length of an input line
+
+#define strFilters "[filters]"
+#define strLinks "[links]"
+#define strInputs "[inputs]"
+#define strOutputs "[outputs]"
+
+typedef enum
+{
+ SEC_NONE,
+ SEC_FILTERS,
+ SEC_LINKS,
+ SEC_INPUTS,
+ SEC_OUTPUTS
+} Section;
+
+/* a comment is a line which is empty, or starts with whitespace, ';' or '#' */
+static inline int is_line_comment(char *line)
+{
+ return line[0] == 0 ||
+ isspace(line[0]) ||
+ line[0] == ';' ||
+ line[0] == '#';
+}
+
+static Section parse_section_name(char *line)
+{
+ if(!strncmp(line, strFilters, strlen(strFilters))) return SEC_FILTERS;
+ else if(!strncmp(line, strLinks, strlen(strLinks))) return SEC_LINKS;
+ else if(!strncmp(line, strInputs, strlen(strInputs))) return SEC_INPUTS;
+ else if(!strncmp(line, strOutputs, strlen(strOutputs))) return SEC_OUTPUTS;
+
+ av_log(NULL, AV_LOG_ERROR, "unknown section name in graph description\n");
+ return SEC_NONE;
+}
+
+static AVFilterGraphDescFilter *parse_filter(char *line)
+{
+ AVFilterGraphDescFilter *ret = av_mallocz(sizeof(AVFilterGraphDescFilter));
+ char *tok;
+
+ if(!(tok = strchr(line, '='))) {
+ av_log(NULL, AV_LOG_ERROR, "filter line missing type of filter");
+ goto fail;
+ }
+ *tok = '\0';
+ ret->name = av_strdup(line);
+ line = tok+1;
+
+ if((tok = strchr(line, '='))) {
+ *tok ++ = '\0';
+ ret->args = av_strdup(tok);
+ }
+ ret->filter = av_strdup(line);
+
+ return ret;
+
+fail:
+ av_free(ret->name);
+ av_free(ret->filter);
+ av_free(ret->args);
+ av_free(ret);
+ return NULL;
+}
+
+/* TODO: allow referencing pad names, not just indices */
+static AVFilterGraphDescLink *parse_link(char *line)
+{
+ AVFilterGraphDescLink *ret = av_mallocz(sizeof(AVFilterGraphDescLink));
+ ret->src = av_malloc(32);
+ ret->dst = av_malloc(32);
+
+ if(sscanf(line, "%31[a-zA-Z0-9]:%u=%31[a-zA-Z0-9]:%u",
+ ret->src, &ret->srcpad, ret->dst, &ret->dstpad) < 4) {
+ av_free(ret->src);
+ av_free(ret->dst);
+ av_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* TODO: allow referencing pad names, not just indices */
+static AVFilterGraphDescExport *parse_export(char *line)
+{
+ AVFilterGraphDescExport *ret = av_mallocz(sizeof(AVFilterGraphDescLink));
+ ret->name = av_malloc(32);
+ ret->filter = av_malloc(32);
+
+ if(sscanf(line, "%31[a-zA-Z0-9]=%31[a-zA-Z0-9]:%u",
+ ret->name, ret->filter, &ret->pad) < 3) {
+ av_free(ret->name);
+ av_free(ret->filter);
+ av_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+AVFilterGraphDesc *avfilter_graph_load_desc(const char *filename)
+{
+ AVFilterGraphDesc *ret = NULL;
+ AVFilterGraphDescFilter *filter = NULL;
+ AVFilterGraphDescLink *link = NULL;
+ AVFilterGraphDescExport *input = NULL;
+ AVFilterGraphDescExport *output = NULL;
+
+ Section section;
+ char line[LINESIZE];
+ void *next;
+ FILE *in;
+
+ /* TODO: maybe allow searching in a predefined set of directories to
+ * allow users to build up libraries of useful graphs? */
+ if(!(in = fopen(filename, "r")))
+ goto fail;
+
+ if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc))))
+ goto fail;
+
+ /* loop through the input file */
+ while(fgets(line, LINESIZE, in)) {
+ int len;
+
+ /* ignore comments */
+ if(is_line_comment(line)) continue;
+
+ /* check if a new section is starting */
+ if(line[0] == '[') {
+ if((section = parse_section_name(line)) == SEC_NONE)
+ goto fail;
+ continue;
+ }
+
+ /* remove any trailing newline characters */
+ for(len = strlen(line); len && (line[len-1]=='\n'||line[len-1]=='\r');)
+ line[--len] = '\0';
+
+ /* parse lines depending on the section */
+ switch(section) {
+ case SEC_FILTERS:
+ if(!(next = parse_filter(line)))
+ goto fail;
+ if(filter)
+ filter = filter->next = next;
+ else
+ ret->filters = filter = next;
+ break;
+ case SEC_LINKS:
+ if(!(next = parse_link(line)))
+ goto fail;
+ if(link)
+ link = link->next = next;
+ else
+ ret->links = link = next;
+ break;
+ case SEC_INPUTS:
+ if(!(next = parse_export(line)))
+ goto fail;
+ if(input)
+ input = input->next = next;
+ else
+ ret->inputs = input = next;
+ break;
+ case SEC_OUTPUTS:
+ if(!(next = parse_export(line)))
+ goto fail;
+ if(output)
+ output = output->next = next;
+ else
+ ret->outputs = output = next;
+ break;
+ }
+ }
+
+ fclose(in);
+ return ret;
+
+fail:
+ av_free(ret);
+ if(in) fclose(in);
+
+ return NULL;
+}
+
+void avfilter_graph_free_desc(AVFilterGraphDesc *desc)
+{
+ void *next;
+
+ while(desc->filters) {
+ next = desc->filters->next;
+ av_free(desc->filters->name);
+ av_free(desc->filters->filter);
+ av_free(desc->filters->args);
+ av_free(desc->filters);
+ desc->filters = next;
+ }
+
+ while(desc->links) {
+ next = desc->links->next;
+ av_free(desc->links->src);
+ av_free(desc->links->dst);
+ av_free(desc->links);
+ desc->links = next;
+ }
+
+ while(desc->inputs) {
+ next = desc->inputs->next;
+ av_free(desc->inputs->filter);
+ av_free(desc->inputs);
+ desc->inputs = next;
+ }
+
+ while(desc->outputs) {
+ next = desc->outputs->next;
+ av_free(desc->outputs->filter);
+ av_free(desc->outputs);
+ desc->outputs = next;
+ }
+}
+
More information about the FFmpeg-soc
mailing list