[FFmpeg-soc] [soc]: r2027 - in libavfilter: README allfilters.c avfiltergraph.c avfiltergraph.h avfiltergraphdesc.c vsrc_movie.c

vitor subversion at mplayerhq.hu
Thu Mar 20 22:48:30 CET 2008


Author: vitor
Date: Thu Mar 20 22:48:30 2008
New Revision: 2027

Log:
Almost from scratch rewrite of filter parser.

Functional as is, but still work-in-progress in the
sense that some things need to be fixed before sending
it as a patch to SVN.


Modified:
   libavfilter/README
   libavfilter/allfilters.c
   libavfilter/avfiltergraph.c
   libavfilter/avfiltergraph.h
   libavfilter/avfiltergraphdesc.c
   libavfilter/vsrc_movie.c

Modified: libavfilter/README
==============================================================================
--- libavfilter/README	(original)
+++ libavfilter/README	Thu Mar 20 22:48:30 2008
@@ -82,38 +82,13 @@ input --> split ---> fifo --------------
 
 splits the stream into two streams, sends one stream through the crop filter
 and the vflip filter before merging it back with the other stream by overlaying
-it on top.  If you put the following text into a file graph.desc:
-
-;-----------------------------------------------------------------------
-[filters]
-split=split
-buf0=fifo
-buf1=fifo
-crop=crop=0:0:-1:240
-vflip=vflip
-overlay=overlay=0:240
-
-[links]
-split:0=buf0:0
-buf0:0=overlay:0
-split:1=buf1:0
-buf1:0=crop:0
-crop:0=vflip:0
-vflip:0=overlay:1
-
-[inputs]
-default=split:0
-
-[outputs]
-default=overlay:0
-;-----------------------------------------------------------------------
-
-and run the following command:
+it on top. You can use the following command to do this filtering
 
-./ffplay -vfilters graph_file=graph.desc input_video.avi
+./ffmpeg -i input_video.avi -s 240x320 -vfilters "(in)split (T1), fifo, (T2)overlay='0:240'(out); (T1)fifo, crop=0:0:-1:240, vflip(T2)" out.avi
 
 where input_video.avi has a vertical resolution of 480 pixels, the result
-should be that ffplay mirrors the top half of the video onto the bottom half.
+should be that in output the top half of the video is mirroed onto the bottom
+half.
 
 KNOWN ISSUES:
 - if for some reason the filter chain cannot be setup (due to an unknown

Modified: libavfilter/allfilters.c
==============================================================================
--- libavfilter/allfilters.c	(original)
+++ libavfilter/allfilters.c	Thu Mar 20 22:48:30 2008
@@ -40,8 +40,6 @@ void avfilter_register_all(void)
     REGISTER_FILTER(FORMAT,format,vf);
     REGISTER_FILTER(FPS,fps,vf);
     REGISTER_FILTER(GRAPH,graph,vf);
-    REGISTER_FILTER(GRAPHDESC,graphdesc,vf);
-    REGISTER_FILTER(GRAPHFILE,graphfile,vf);
     REGISTER_FILTER(HFLIP,hflip,vf);
     REGISTER_FILTER(NEGATE,negate,vf);
     REGISTER_FILTER(NOFORMAT,noformat,vf);

Modified: libavfilter/avfiltergraph.c
==============================================================================
--- libavfilter/avfiltergraph.c	(original)
+++ libavfilter/avfiltergraph.c	Thu Mar 20 22:48:30 2008
@@ -463,9 +463,7 @@ static void pick_formats(GraphContext *g
     for(i = 0; i < graph->filter_count; i ++) {
         AVFilterContext *filter = graph->filters[i];
 
-        if(filter->filter == &avfilter_vf_graph     ||
-           filter->filter == &avfilter_vf_graphfile ||
-           filter->filter == &avfilter_vf_graphdesc)
+        if(filter->filter == &avfilter_vf_graph)
             pick_formats(filter->priv);
 
         for(j = 0; j < filter->input_count; j ++)
@@ -498,30 +496,34 @@ static int graph_load_from_desc(AVFilter
     AVFilterContext *filt, *filtb;
 
     AVFilter *filterdef;
+    char tmp[20];
 
     /* create all filters */
     for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) {
+        snprintf(tmp, 20, "%d", curfilt->index);
         if(!(filterdef = avfilter_get_by_name(curfilt->filter)) ||
-           !(filt = avfilter_open(filterdef, curfilt->name))) {
+           !(filt = avfilter_open(filterdef, tmp))) {
             av_log(ctx, AV_LOG_ERROR,
-               "error creating filter '%s'\n", curfilt->name);
+               "error creating filter '%s'\n", curfilt->filter);
             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 '%s'\n", curfilt->name);
+                "error initializing filter '%s'\n", curfilt->filter);
             goto fail;
         }
     }
 
     /* create all links */
     for(curlink = desc->links; curlink; curlink = curlink->next) {
-        if(!(filt = avfilter_graph_get_filter(ctx, curlink->src))) {
+        snprintf(tmp, 20, "%d", curlink->src);
+        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
             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))) {
+        snprintf(tmp, 20, "%d", curlink->dst);
+        if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) {
             av_log(ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
             goto fail;
         }
@@ -533,7 +535,8 @@ static int graph_load_from_desc(AVFilter
 
     /* export all input pads */
     for(curpad = desc->inputs; curpad; curpad = curpad->next) {
-        if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
+        snprintf(tmp, 20, "%d", curpad->filter);
+        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
             av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
             goto fail;
         }
@@ -542,7 +545,8 @@ static int graph_load_from_desc(AVFilter
 
     /* export all output pads */
     for(curpad = desc->outputs; curpad; curpad = curpad->next) {
-        if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
+        snprintf(tmp, 20, "%d", curpad->filter);
+        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
             av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
             goto fail;
         }
@@ -603,73 +607,3 @@ AVFilter avfilter_vf_graph =
     .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
 };
 
-static int init_desc(AVFilterContext *ctx, const char *args, void *opaque)
-{
-    GraphContext *gctx = ctx->priv;
-
-    if(!opaque)
-        return -1;
-
-    if(!(gctx->link_filter_in = avfilter_open(&vf_graph_dummy, NULL)))
-        return -1;
-    if(avfilter_init_filter(gctx->link_filter_in, NULL, ctx))
-        goto fail;
-    if(!(gctx->link_filter_out = avfilter_open(&vf_graph_dummy, NULL)))
-        goto fail;
-    if(avfilter_init_filter(gctx->link_filter_out, NULL, ctx))
-        goto fail;
-
-    return graph_load_from_desc(ctx, opaque);
-
-fail:
-    avfilter_destroy(gctx->link_filter_in);
-    if(gctx->link_filter_out)
-        avfilter_destroy(gctx->link_filter_out);
-    return -1;
-}
-
-AVFilter avfilter_vf_graphdesc =
-{
-    .name      = "graph_desc",
-
-    .priv_size = sizeof(GraphContext),
-
-    .init      = init_desc,
-    .uninit    = uninit,
-
-    .query_formats = query_formats,
-
-    .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 avfilter_vf_graphfile =
-{
-    .name      = "graph_file",
-
-    .priv_size = sizeof(GraphContext),
-
-    .init      = init_file,
-    .uninit    = uninit,
-
-    .query_formats = query_formats,
-
-    .inputs    = (AVFilterPad[]) {{ .name = NULL, }},
-    .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
-};
-

Modified: libavfilter/avfiltergraph.h
==============================================================================
--- libavfilter/avfiltergraph.h	(original)
+++ libavfilter/avfiltergraph.h	Thu Mar 20 22:48:30 2008
@@ -27,7 +27,7 @@
 /** Linked-list of filters to create for an AVFilterGraphDesc */
 typedef struct AVFilterGraphDescFilter
 {
-    char *name;             ///< filter instance name
+    int index;              ///< filter instance index
     char *filter;           ///< name of filter type
     char *args;             ///< filter parameters
     struct AVFilterGraphDescFilter *next;
@@ -37,10 +37,10 @@ typedef struct AVFilterGraphDescFilter
 typedef struct AVFilterGraphDescLink
 {
     /* TODO: allow referencing pads by name, not just by index */
-    char *src;              ///< name of the source filter
+    int src;                ///< index of the source filter
     unsigned srcpad;        ///< index of the output pad on the source filter
 
-    char *dst;              ///< name of the dest filter
+    int dst;                ///< index of the dest filter
     unsigned dstpad;        ///< index of the input pad on the dest filter
 
     struct AVFilterGraphDescLink *next;
@@ -51,7 +51,7 @@ 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
+    int filter;             ///< index of the filter
     unsigned pad;           ///< index of the pad to be exported
 
     struct AVFilterGraphDescExport *next;

Modified: libavfilter/avfiltergraphdesc.c
==============================================================================
--- libavfilter/avfiltergraphdesc.c	(original)
+++ libavfilter/avfiltergraphdesc.c	Thu Mar 20 22:48:30 2008
@@ -1,5 +1,6 @@
 /*
  * filter graph descriptions
+ * copyright (c) 2008 Vitor Sessak
  * copyright (c) 2007 Bobby Bingham
  *
  * This file is part of FFmpeg.
@@ -25,365 +26,329 @@
 #include "avfilter.h"
 #include "avfiltergraph.h"
 
-#define LINESIZE    240             ///< maximum length of an input line
-
-/** 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 AVFilterGraphDescSection parse_section_name(char *line)
-{
-    struct {
-        const char *str;
-        int section;
-    } *sec, sections[] = { { "[filters]", SEC_FILTERS },
-                           { "[links]",   SEC_LINKS   },
-                           { "[inputs]",  SEC_INPUTS  },
-                           { "[outputs]", SEC_OUTPUTS },
-                           { NULL, 0 } };
-
-    for(sec = sections; sec->str; sec ++)
-        if(!strncmp(line, sec->str, strlen(sec->str)))
-            return sec->section;
-
-    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;
-}
 
-int avfilter_graph_parse_desc(AVFilterGraphDesc **desc,
-                              AVFilterGraphDescParser **parser,
-                              char *line)
+/**
+ * For use in av_log
+ */
+static const char *log_name(void *p)
 {
-    void *next;
-    int len;
-
-    if(!*desc)
-        if(!(*desc = av_mallocz(sizeof(AVFilterGraphDesc))))
-            return AVERROR_NOMEM;
-
-    if(!*parser) {
-        if(!(*parser = av_mallocz(sizeof(AVFilterGraphDescParser))))
-            return AVERROR_NOMEM;
-
-        (*parser)->filterp = &(*desc)->filters;
-        (*parser)->linkp   = &(*desc)->links;
-        (*parser)->inputp  = &(*desc)->inputs;
-        (*parser)->outputp = &(*desc)->outputs;
-    }
-
-    /* ignore comments */
-    if(is_line_comment(line)) return 0;
-
-    /* check if a new section is starting */
-    if(line[0] == '[') {
-        if(((*parser)->section = parse_section_name(line)) == SEC_NONE)
-            return AVERROR_INVALIDDATA;
-        return 0;
-    }
-
-    /* remove any trailing newline characters */
-    for(len = strlen(line); len && (line[len-1]=='\n'||line[len-1]=='\r');)
-        line[--len] = '\0';
-
-    switch((*parser)->section) {
-    case SEC_FILTERS:
-        if(!(next = parse_filter(line)))
-            return AVERROR_INVALIDDATA;
-        *(*parser)->filterp = next;
-        (*parser)->filterp  = &(*(*parser)->filterp)->next;
-        break;
-    case SEC_LINKS:
-        if(!(next = parse_link(line)))
-            return AVERROR_INVALIDDATA;
-        *(*parser)->linkp = next;
-        (*parser)->linkp  = &(*(*parser)->linkp)->next;
-        break;
-    case SEC_INPUTS:
-        if(!(next = parse_export(line)))
-            return AVERROR_INVALIDDATA;
-        *(*parser)->inputp = next;
-        (*parser)->inputp  = &(*(*parser)->inputp)->next;
-        break;
-    case SEC_OUTPUTS:
-        if(!(next = parse_export(line)))
-            return AVERROR_INVALIDDATA;
-        *(*parser)->outputp = next;
-        (*parser)->outputp  = &(*(*parser)->outputp)->next;
-        break;
-    default:
-        return AVERROR_INVALIDDATA;
-    }
-
-    return 0;
+    return "Filter parser";
 }
 
-typedef struct Parser
-{
-    char next_chr;
-    char *buf;
-} Parser;
+static const AVClass filter_parser_class = {
+    "Filter parser",
+    log_name
+};
 
-static void consume_whitespace(Parser *p)
-{
-    while (p->next_chr == ' ' || p->next_chr == '\n' || p->next_chr == '\t') {
-        p->buf++;
-        p->next_chr = p->buf[0];
-    }
-}
+static const AVClass *log_ctx = &filter_parser_class;
 
-static void init_parser(Parser *p, char *buf)
+static void consume_whitespace(const char **buf)
 {
-    p->buf = buf;
-    p->next_chr = buf[0];
-    consume_whitespace(p);
+    *buf += strspn(*buf, " \n\t");
 }
 
-static char consume_char(Parser *p)
+/**
+ * get the next non-whitespace char
+ */
+static char consume_char(const char **buf)
 {
     char out;
-    consume_whitespace(p);
+    consume_whitespace(buf);
 
-    out = p->next_chr;
+    out = **buf;
 
-    if (out) {
-        p->buf++;
-        p->next_chr = p->buf[0];
-    }
+    if (out)
+        (*buf)++;
 
     return out;
 }
 
+/**
+ * remove the quotation marks from a string. Ex: "aaa'bb'cc" -> "aaabbcc"
+ */
 static void unquote(char *str)
 {
     char *p1, *p2;
     p1=p2=str;
-    while (p1[0] != 0) {
-        if (p1[0] == '\'') p1++;
-        p2[0] = p1[0];
+    while (*p1 != 0) {
+        if (*p1 != '\'')
+            *p2++ = *p1;
         p1++;
-        p2++;
     }
 
-    p2[0] = 0;
+    *p2 = 0;
 }
 
-static char *consume_string(Parser *p, int escaped)
+/**
+ * Consumes a string from *buf.
+ * @return a copy of the consumed string, which should be free'd after use
+ */
+static char *consume_string(const char **buf)
 {
-    char *out;
-    int has_quoted=0;
-    int quit=0;
+    const char *start;
+    char *ret;
+    int size;
 
-    while (p->buf[0] == ' ' || p->buf[0] == '\n' || p->buf[0] == '\t')
-        p->buf++;
+    consume_whitespace(buf);
 
-    if (!p->buf[0]) {
-        p->next_chr = 0;
-        return p->buf;
-    }
+    if (!(**buf))
+        return av_mallocz(1);
 
-    out = p->buf;
+    start = *buf;
 
-    while(!quit) {
-        switch(p->buf[0]) {
-        case   0:
-        case ' ':
-        case '(':
-        case ')':
-        case '=':
-        case ',':
-            quit=1;
-            break;
-        case '\'':
-            has_quoted = has_quoted || escaped;
-            do {
-                p->buf++;
-            } while(escaped && p->buf[0] && p->buf[0] != '\'');
-            if (p->buf[0] == '\'') p->buf++;
-            break;
-        default:
-            p->buf++;
-            break;
-        }
+    *buf += strcspn(*buf, " ()=,'");
+
+    if (**buf == '\'') {
+        char *p = strchr(*buf + 1, '\'');
+        if (p)
+            *buf = p + 1;
+        else
+            *buf += strlen(*buf); // Move the pointer to the null end byte
     }
-    p->next_chr = p->buf[0];
-    p->buf[0]=0;
 
-    if(has_quoted)
-        unquote(out);
-    return out;
+    size = *buf - start + 1;
+    ret = av_malloc(size);
+    memcpy(ret, start, size - 1);
+    ret[size-1] = 0;
+
+    unquote(ret);
+
+    return ret;
 }
 
-static int parse_link_name(Parser *p, char **name)
+/**
+ * Parse "(linkname)"
+ * @arg name a pointer (that need to be free'd after use) to the name between
+ *           parenthesis
+ */
+static void parse_link_name(const char **buf, char **name)
 {
-    if (consume_char(p) != '(')
-        goto fail;
+    consume_char(buf);
 
-    *name = consume_string(p,0);
+    *name = consume_string(buf);
 
     if (!*name[0])
         goto fail;
 
-    if (consume_char(p) != ')')
+    if (consume_char(buf) != ')')
         goto fail;
 
-    return 0;
-
+    return;
  fail:
-    *name = NULL;
-    return AVERROR_INVALIDDATA;
+    av_freep(name);
+    av_log(&log_ctx, AV_LOG_ERROR, "Could not parse link name!\n");
 }
 
-static int parse_filter2(Parser *p, char **name, char **opts)
+/**
+ * Parse "filter=params"
+ * @arg name a pointer (that need to be free'd after use) to the name of the
+ *           filter
+ * @arg ars  a pointer (that need to be free'd after use) to the args of the
+ *           filter
+ */
+static void parse_filter(const char **buf, char **name, char **opts)
 {
-    char *null_str;
+    *name = consume_string(buf);
 
-    *name = consume_string(p,0);
+    if (**buf == '=') {
+        consume_char(buf);
+        *opts = consume_string(buf);
+    } else {
+        *opts = NULL;
+    }
 
-    null_str = p->buf;
+}
 
-    if (p->next_chr == '=') {
-        consume_char(p);
-        *opts = consume_string(p,1);
-    } else {
-        *opts = null_str;
+enum LinkType {
+    LinkTypeIn,
+    LinkTypeOut,
+};
+
+/**
+ * A linked-list of the inputs/outputs of the filter chain.
+ */
+typedef struct AVFilterInOut {
+    enum LinkType type;
+    char *name;
+    int instance;
+    int pad_idx;
+
+    struct AVFilterInOut *next;
+} AVFilterInOut;
+
+static void free_inout(AVFilterInOut *head)
+{
+    while (head) {
+        AVFilterInOut *next;
+        next = head->next;
+        av_free(head);
+        head = next;
     }
-    return 0;
 }
 
-AVFilterGraphDesc *avfilter_graph_parse_chain(const char *filters)
+/**
+ * Parse "(a1)(link2) ... (etc)"
+ */
+static int parse_inouts(const char **buf, AVFilterInOut **inout, int firstpad,
+                        enum LinkType type, int instance)
+{
+    int pad = firstpad;
+    while (**buf == '(') {
+        AVFilterInOut *inoutn = av_malloc(sizeof(AVFilterInOut));
+        parse_link_name(buf, &inoutn->name);
+        inoutn->type = type;
+        inoutn->instance = instance;
+        inoutn->pad_idx = pad++;
+        inoutn->next = *inout;
+        *inout = inoutn;
+    }
+    return pad;
+}
+
+static AVFilterGraphDesc *parse_chain(const char *filters, int has_in)
 {
     AVFilterGraphDesc        *ret;
     AVFilterGraphDescFilter **filterp, *filtern;
     AVFilterGraphDescLink   **linkp,   *linkn;
-    Parser p;
-    char *str;
+    AVFilterInOut           *inout=NULL;
+    AVFilterInOut           *head;
+
     int index = 0;
+    char chr = 0;
+    int pad = 0;
+    int has_out = 0;
+
+    consume_whitespace(&filters);
 
     if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc))))
         return NULL;
 
-    str = av_strdup(filters);
-    init_parser(&p, str);
-
     filterp = &ret->filters;
     linkp   = &ret->links;
 
     do {
-        char *filter;
-        char *args;
+        if(chr == ',') {
+            linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
+            linkn->src = index-1;
+            linkn->srcpad = pad;
+            linkn->dst = index;
+            linkn->dstpad = 0;
+
+            *linkp = linkn;
+            linkp = &linkn->next;
+        }
+        pad = parse_inouts(&filters, &inout, chr == ',' || (!has_in),
+                           LinkTypeIn, index);
 
         filtern = av_mallocz(sizeof(AVFilterGraphDescFilter));
-        filtern->name = av_malloc(8);
-        snprintf(filtern->name, 8, "%d", index);
-        parse_filter2(&p, &filter, &args);
-        filtern->filter = av_strdup(filter);
-        filtern->args = av_strdup(args);
+        filtern->index = index;
+        parse_filter(&filters, &filtern->filter, &filtern->args);
         *filterp = filtern;
         filterp = &filtern->next;
 
-        if(index > 0) {
+        pad = parse_inouts(&filters, &inout, 0,
+                           LinkTypeOut, index);
+        chr = consume_char(&filters);
+        index++;
+    } while (chr == ',' || chr == ';');
+
+    head = inout;
+    for (; inout != NULL; inout = inout->next) {
+        if (inout->instance == -1)
+            continue; // Already processed
+
+        if (!strcmp(inout->name, "in")) {
+            if (!has_in)
+                goto fail;
+            ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
+            ret->inputs->filter = inout->instance;
+            ret->inputs->pad = inout->pad_idx;
+        } else if (!strcmp(inout->name, "out")) {
+            has_out = 1;
+            ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
+            ret->outputs->filter = inout->instance;
+            ret->outputs->pad = inout->pad_idx;
+        } else {
+            AVFilterInOut *p, *src, *dst;
+            for (p = inout->next;
+                 p && strcmp(p->name,inout->name); p = p->next);
+
+            if (!p) {
+                av_log(&log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
+                       inout->name);
+                goto fail;
+            }
+
+            if (p->type == LinkTypeIn && inout->type == LinkTypeOut) {
+                src = inout;
+                dst = p;
+            } else if (p->type == LinkTypeOut && inout->type == LinkTypeIn) {
+                src = p;
+                dst = inout;
+            } else {
+                av_log(&log_ctx, AV_LOG_ERROR, "Two links named '%s' are either both input or both output\n",
+                       inout->name);
+                goto fail;
+            }
             linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
-            linkn->src = av_malloc(8);
-            snprintf(linkn->src, 8, "%d", index-1);
-            linkn->dst = av_malloc(8);
-            snprintf(linkn->dst, 8, "%d", index);
+
+            linkn->src = src->instance;
+            linkn->srcpad = src->pad_idx;
+            linkn->dst = dst->instance;
+            linkn->dstpad = dst->pad_idx;
 
             *linkp = linkn;
             linkp = &linkn->next;
-        }
-        index ++;
-    } while (consume_char(&p) == ',');
 
-    av_free(str);
+            src->instance = -1;
+            dst->instance = -1;
+        }
+    }
 
-    ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
-    ret->inputs->filter = av_malloc(8);
-    snprintf(ret->inputs->filter, 8, "%d", 0);
+    free_inout(head);
 
-    ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
-    ret->outputs->filter = av_malloc(8);
-    snprintf(ret->outputs->filter, 8, "%d", index-1);
+    if (!has_in) {
+        ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
+        ret->inputs->filter = 0;
+    }
+    if (!has_out) {
+        ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
+        ret->outputs->filter = index-1;
+    }
 
     return ret;
+
+ fail:
+    free_inout(head);
+
+    avfilter_graph_free_desc(ret);
+    return NULL;
 }
 
+/**
+ * Parse a string describing a filter graph.
+ */
+AVFilterGraphDesc *avfilter_graph_parse_chain(const char *filters)
+{
+    AVFilterGraphDesc *ret;
+
+    /* Try first to parse supposing there is no (in) element */
+    if ((ret = parse_chain(filters, 0)))
+        return ret;
+
+    /* Parse supposing there is an (in) element */
+    return parse_chain(filters, 1);
+}
+
+/**
+ * Free a graph description.
+ */
 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);
@@ -392,22 +357,18 @@ void avfilter_graph_free_desc(AVFilterGr
 
     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;
     }

Modified: libavfilter/vsrc_movie.c
==============================================================================
--- libavfilter/vsrc_movie.c	(original)
+++ libavfilter/vsrc_movie.c	Thu Mar 20 22:48:30 2008
@@ -20,47 +20,22 @@
  */
 
  /*
- # One usage example follows, usable too as test scenario.
- #TODO Eventually move it into FFmpeg docs.
-
-;----------------------------movie.desc------------------------------
-;
-; Parameters of movie filter are
-; seekpoint in microseconds : string format : string filename
-;
-; We can overlay a second movie on top of a main one
-;
-; input -----------> deltapts0 --> overlay --> output
-;                                    ^
-; movie --> scale--> deltapts1 ------|
-;
-
-[filters]
-movie=movie=3200000:avi:input.avi
-
-; We make both the main movie and the overlaid one start at the same time
-deltapts0=setpts=PTS-STARTPTS
-deltapts1=setpts=PTS-STARTPTS
+ One usage example follows, usable too as test scenario.
 
-scale=scale=180:144
-overlay=overlay=16:16
+ TODO Eventually move it into FFmpeg docs.
 
-[links]
-deltapts0:0=overlay:0
+ Parameters of movie filter are
+ seekpoint in microseconds : string format : string filename
 
-movie:0=scale:0
-scale:0=deltapts1:0
-deltapts1:0=overlay:1
+ We can overlay a second movie on top of a main one
 
-[inputs]
-default=deltapts0:0
+ input -----------> deltapts0 --> overlay --> output
+                                    ^
+ movie --> scale--> deltapts1 ------|
 
-[outputs]
-default=overlay:0
-;----------------------------movie.desc------------------------------
+ To do that
 
-# Then launch it from command line
-ffmpeg -i input.avi -vfilters graph_file=movie.desc output.avi
+ ffmpeg -i in.avi -s 240x320 -vfilters "(in)setpts=PTS-STARTPTS,(T1)overlay=16:16(out);movie=3200000:avi:in.avi,scale=180:144,setpts=PTS-STARTPTS(T1)" -y out.avi
 
  */
 



More information about the FFmpeg-soc mailing list