Change the parser logic following Michael's review

Commited in SoC by Vitor Sessak on 2008-04-21 18:45:01

Originally committed as revision 13323 to svn://svn.ffmpeg.org/ffmpeg/trunk
pull/126/head
Vitor Sessak 17 years ago
parent 498f030583
commit c9987633b1
  1. 327
      libavfilter/graphparser.c

@ -149,29 +149,6 @@ static void parse_link_name(const char **buf, char **name, AVClass *log_ctx)
}
}
/**
* 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 AVFilterContext *parse_filter(const char **buf,
AVFilterGraph *graph, int index,
AVClass *log_ctx)
{
char *name, *opts;
name = consume_string(buf);
if(**buf == '=') {
(*buf)++;
opts = consume_string(buf);
} else {
opts = NULL;
}
return create_filter(graph, index, name, opts, log_ctx);
}
enum LinkType {
LinkTypeIn,
@ -199,68 +176,206 @@ static void free_inout(AVFilterInOut *head)
}
}
static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
{
AVFilterInOut *ret;
AVFilterInOut *p;
if(!links || !*links)
return NULL;
if(!strcmp((*links)->name, label)) {
ret = *links;
*links = (*links)->next;
return ret;
}
/* First check if the label is not in the openLinks list */
for(p = *links; p->next && strcmp(p->next->name, label); p = p->next);
if(!p->next)
return NULL;
ret = p->next;
p->next = p->next->next;
return ret;
}
static int link_filter_inouts(AVFilterContext *filter,
AVFilterInOut **currInputs,
AVFilterInOut **openLinks, AVClass *log_ctx)
{
AVFilterInOut *p;
int pad = 0;
pad = filter->input_count;
while(pad) {
p = *currInputs;
pad--;
if(!p) {
av_log(log_ctx, AV_LOG_ERROR,
"Not enough inputs specified for the \"%s\" filter.\n",
filter->name);
return -1;
}
if(p->filter) {
if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx))
return -1;
*currInputs = (*currInputs)->next;
av_free(p);
} else {
p = *currInputs;
*currInputs = (*currInputs)->next;
p->filter = filter;
p->pad_idx = pad;
p->next = *openLinks;
*openLinks = p;
}
}
if(*currInputs) {
av_log(log_ctx, AV_LOG_ERROR,
"Too many inputs specified for the \"%s\" filter.\n",
filter->name);
return -1;
}
pad = filter->output_count;
while(pad) {
AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
pad--;
currlinkn->name = NULL;
currlinkn->type = LinkTypeOut;
currlinkn->filter = filter;
currlinkn->pad_idx = pad;
currlinkn->next = *currInputs;
*currInputs = currlinkn;
}
return 0;
}
/**
* Parse "[a1][link2] ... [etc]"
* 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 int parse_inouts(const char **buf, AVFilterInOut **inout, int pad,
enum LinkType type, AVFilterContext *filter,
AVClass *log_ctx)
static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph,
int index, AVClass *log_ctx)
{
char *opts;
char *name = consume_string(buf);
if(**buf == '=') {
(*buf)++;
opts = consume_string(buf);
} else {
opts = NULL;
}
return create_filter(graph, index, name, opts, log_ctx);
}
static int parse_inputs(const char **buf, AVFilterInOut **currInputs,
AVFilterInOut **openLinks, AVClass *log_ctx)
{
int pad = 0;
AVFilterInOut *p;
while (**buf == '[') {
char *name;
AVFilterInOut *p = *inout;
parse_link_name(buf, &name, log_ctx);
if(!name)
return -1;
for (; p && strcmp(p->name, name); p = p->next);
/* First check if the label is not in the openLinks list */
p = extract_inout(name, openLinks);
/* Not in the list, so add it as an input */
if(!p) {
// First label apearence, add it to the linked list
AVFilterInOut *inoutn = av_malloc(sizeof(AVFilterInOut));
inoutn->name = name;
inoutn->type = type;
inoutn->filter = filter;
inoutn->pad_idx = pad;
inoutn->next = *inout;
*inout = inoutn;
AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
currlinkn->name = name;
currlinkn->type = LinkTypeIn;
currlinkn->filter = NULL;
currlinkn->pad_idx = pad;
currlinkn->next = *currInputs;
*currInputs = currlinkn;
} else {
if(p->type == LinkTypeIn && type == LinkTypeOut) {
if(link_filter(filter, pad, p->filter, p->pad_idx, log_ctx) < 0)
return -1;
} else if(p->type == LinkTypeOut && type == LinkTypeIn) {
if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx) < 0)
return -1;
} else {
/* A label of a open link. Make it one of the inputs of the next
filter */
AVFilterInOut *currlinkn = p;
if (p->type != LinkTypeOut) {
av_log(log_ctx, AV_LOG_ERROR,
"Two links named '%s' are either both input or both output\n",
name);
"Label \"%s\" appears twice as input!\n", p->name);
return -1;
}
p->filter = NULL;
currlinkn->next = *currInputs;
*currInputs = currlinkn;
}
pad++;
consume_whitespace(buf);
pad++;
}
return pad;
}
static const char *skip_inouts(const char *buf)
static int parse_outputs(const char **buf, AVFilterInOut **currInputs,
AVFilterInOut **openLinks, AVClass *log_ctx)
{
while (*buf == '[') {
buf += strcspn(buf, "]") + 1;
consume_whitespace(&buf);
int pad = 0;
while (**buf == '[') {
char *name;
AVFilterInOut *match;
parse_link_name(buf, &name, log_ctx);
if(!name)
return -1;
/* First check if the label is not in the openLinks list */
match = extract_inout(name, openLinks);
/* Not in the list, so add the first input as a openLink */
if(!match) {
AVFilterInOut *p = *currInputs;
*currInputs = (*currInputs)->next;
p->next = *openLinks;
p->type = LinkTypeOut;
p->name = name;
*openLinks = p;
} else {
/* A label of a open link. Link it. */
AVFilterInOut *p = *currInputs;
if (match->type != LinkTypeIn) {
av_log(log_ctx, AV_LOG_ERROR,
"Label \"%s\" appears twice as output!\n", match->name);
return -1;
}
*currInputs = (*currInputs)->next;
if(link_filter(p->filter, p->pad_idx,
match->filter, match->pad_idx, log_ctx) < 0)
return -1;
av_free(match);
av_free(p);
}
consume_whitespace(buf);
pad++;
}
return buf;
}
return pad;
}
/**
* Parse a string describing a filter graph.
@ -270,95 +385,77 @@ int avfilter_parse_graph(AVFilterGraph *graph, const char *filters,
AVFilterContext *out, int outpad,
AVClass *log_ctx)
{
AVFilterInOut *inout=NULL;
AVFilterInOut *head=NULL;
int index = 0;
char chr = 0;
int pad = 0;
int has_out = 0;
AVFilterContext *last_filt = NULL;
AVFilterInOut *currInputs=NULL;
AVFilterInOut *openLinks = av_malloc(sizeof(AVFilterInOut));
openLinks->name = "in";
openLinks->filter = in;
openLinks->type = LinkTypeOut;
openLinks->pad_idx = inpad;
openLinks->next = av_malloc(sizeof(AVFilterInOut));
openLinks->next->name = "out";
openLinks->next->filter = out;
openLinks->next->type = LinkTypeIn;
openLinks->next->pad_idx = outpad;
openLinks->next->next = NULL;
do {
AVFilterContext *filter;
int oldpad = pad;
const char *inouts;
consume_whitespace(&filters);
inouts = filters;
// We need to parse the inputs of the filter after we create it, so
// skip it by now
filters = skip_inouts(filters);
pad = parse_inputs(&filters, &currInputs, &openLinks, log_ctx);
if(!(filter = parse_filter(&filters, graph, index, log_ctx)))
if(pad < 0)
goto fail;
pad = parse_inouts(&inouts, &inout, chr == ',', LinkTypeIn, filter,
log_ctx);
if(pad < 0)
if(!(filter = parse_filter(&filters, graph, index, log_ctx)))
goto fail;
// If the first filter has an input and none was given, it is
// implicitly the input of the whole graph.
if(pad == 0 && filter->input_count == 1) {
if(link_filter(in, inpad, filter, 0, log_ctx))
if(filter->input_count == 1 && !currInputs && !index) {
// First input can be ommitted if it is "[in]"
const char *tmp = "[in]";
pad = parse_inputs(&tmp, &currInputs, &openLinks, log_ctx);
if (pad < 0)
goto fail;
}
if(chr == ',') {
if(link_filter(last_filt, oldpad, filter, 0, log_ctx) < 0)
goto fail;
}
if(link_filter_inouts(filter, &currInputs, &openLinks, log_ctx) < 0)
goto fail;
pad = parse_inouts(&filters, &inout, 0, LinkTypeOut, filter, log_ctx);
pad = parse_outputs(&filters, &currInputs, &openLinks, log_ctx);
if (pad < 0)
if(pad < 0)
goto fail;
consume_whitespace(&filters);
chr = *filters++;
index++;
last_filt = filter;
} while (chr == ',' || chr == ';');
head = inout;
// Process remaining labels. Only inputs and outputs should be left.
for (; inout; inout = inout->next) {
if(!inout->filter)
continue; // Already processed
if(!strcmp(inout->name, "in")) {
if(link_filter(in, inpad, inout->filter, inout->pad_idx, log_ctx))
goto fail;
} else if(!strcmp(inout->name, "out")) {
has_out = 1;
if(link_filter(inout->filter, inout->pad_idx, out, outpad, log_ctx))
goto fail;
} else {
av_log(log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
inout->name);
goto fail;
if (chr == ';' && currInputs) {
av_log(log_ctx, AV_LOG_ERROR,
"Could not find a output to link when parsing \"%s\"\n",
filters - 1);
goto fail;
}
}
free_inout(head);
index++;
} while (chr == ',' || chr == ';');
if(!has_out) {
if(link_filter(last_filt, pad, out, outpad, log_ctx))
if(openLinks && !strcmp(openLinks->name, "out") && currInputs) {
// Last output can be ommitted if it is "[out]"
const char *tmp = "[out]";
if(parse_outputs(&tmp, &currInputs, &openLinks, log_ctx) < 0)
goto fail;
}
return 0;
fail:
free_inout(head);
avfilter_destroy_graph(graph);
free_inout(openLinks);
free_inout(currInputs);
return -1;
}

Loading…
Cancel
Save