[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