From: Vitor Sessak Date: Sat, 24 May 2008 20:40:40 +0000 (+0000) Subject: Change the parser logic following Michael's review X-Git-Tag: v0.5~4608 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c9987633b15746581e53058aac2a1acb043679eb;p=platform%2Fupstream%2Flibav.git 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 --- diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c index 46ebfdc..6a1904f 100644 --- a/libavfilter/graphparser.c +++ b/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; }