[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