• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavfilter/graphparser.c

Go to the documentation of this file.
00001 /*
00002  * filter graph parser
00003  * copyright (c) 2008 Vitor Sessak
00004  * copyright (c) 2007 Bobby Bingham
00005  *
00006  * This file is part of FFmpeg.
00007  *
00008  * FFmpeg is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * FFmpeg is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with FFmpeg; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 #include <ctype.h>
00024 #include <string.h>
00025 
00026 #include "graphparser.h"
00027 #include "avfilter.h"
00028 #include "avfiltergraph.h"
00029 
00030 static int link_filter(AVFilterContext *src, int srcpad,
00031                        AVFilterContext *dst, int dstpad,
00032                        AVClass *log_ctx)
00033 {
00034     if(avfilter_link(src, srcpad, dst, dstpad)) {
00035         av_log(log_ctx, AV_LOG_ERROR,
00036                "cannot create the link %s:%d -> %s:%d\n",
00037                src->filter->name, srcpad, dst->filter->name, dstpad);
00038         return -1;
00039     }
00040 
00041     return 0;
00042 }
00043 
00044 static int consume_whitespace(const char *buf)
00045 {
00046     return strspn(buf, " \n\t");
00047 }
00048 
00053 static char *consume_string(const char **buf)
00054 {
00055     char *out = av_malloc(strlen(*buf) + 1);
00056     char *ret = out;
00057 
00058     *buf += consume_whitespace(*buf);
00059 
00060     do{
00061         char c = *(*buf)++;
00062         switch (c) {
00063         case '\\':
00064             *out++ = *(*buf)++;
00065             break;
00066         case '\'':
00067             while(**buf && **buf != '\'')
00068                 *out++ = *(*buf)++;
00069             if(**buf) (*buf)++;
00070             break;
00071         case 0:
00072         case ']':
00073         case '[':
00074         case '=':
00075         case ',':
00076         case ';':
00077         case ' ':
00078         case '\n':
00079             *out++ = 0;
00080             break;
00081         default:
00082             *out++ = c;
00083         }
00084     } while(out[-1]);
00085 
00086     (*buf)--;
00087     *buf += consume_whitespace(*buf);
00088 
00089     return ret;
00090 }
00091 
00097 static char *parse_link_name(const char **buf, AVClass *log_ctx)
00098 {
00099     const char *start = *buf;
00100     char *name;
00101     (*buf)++;
00102 
00103     name = consume_string(buf);
00104 
00105     if(!name[0]) {
00106         av_log(log_ctx, AV_LOG_ERROR,
00107                "Bad (empty?) label found in the following: \"%s\".\n", start);
00108         goto fail;
00109     }
00110 
00111     if(*(*buf)++ != ']') {
00112         av_log(log_ctx, AV_LOG_ERROR,
00113                "Mismatched '[' found in the following: \"%s\".\n", start);
00114     fail:
00115         av_freep(&name);
00116     }
00117 
00118     return name;
00119 }
00120 
00121 static AVFilterContext *create_filter(AVFilterGraph *ctx, int index,
00122                                       const char *filt_name, const char *args,
00123                                       AVClass *log_ctx)
00124 {
00125     AVFilterContext *filt_ctx;
00126 
00127     AVFilter *filt;
00128     char inst_name[30];
00129 
00130     snprintf(inst_name, sizeof(inst_name), "Parsed filter %d", index);
00131 
00132     filt = avfilter_get_by_name(filt_name);
00133 
00134     if(!filt) {
00135         av_log(log_ctx, AV_LOG_ERROR,
00136                "no such filter: '%s'\n", filt_name);
00137         return NULL;
00138     }
00139 
00140     filt_ctx = avfilter_open(filt, inst_name);
00141     if(!filt_ctx) {
00142         av_log(log_ctx, AV_LOG_ERROR,
00143                "error creating filter '%s'\n", filt_name);
00144         return NULL;
00145     }
00146 
00147     if(avfilter_graph_add_filter(ctx, filt_ctx) < 0) {
00148         avfilter_destroy(filt_ctx);
00149         return NULL;
00150     }
00151 
00152     if(avfilter_init_filter(filt_ctx, args, NULL)) {
00153         av_log(log_ctx, AV_LOG_ERROR,
00154                "error initializing filter '%s' with args '%s'\n", filt_name, args);
00155         return NULL;
00156     }
00157 
00158     return filt_ctx;
00159 }
00160 
00164 static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph,
00165                                      int index, AVClass *log_ctx)
00166 {
00167     char *opts = NULL;
00168     char *name = consume_string(buf);
00169     AVFilterContext *ret;
00170 
00171     if(**buf == '=') {
00172         (*buf)++;
00173         opts = consume_string(buf);
00174     }
00175 
00176     ret = create_filter(graph, index, name, opts, log_ctx);
00177     av_free(name);
00178     av_free(opts);
00179     return ret;
00180 }
00181 
00182 static void free_inout(AVFilterInOut *head)
00183 {
00184     while(head) {
00185         AVFilterInOut *next = head->next;
00186         av_free(head->name);
00187         av_free(head);
00188         head = next;
00189     }
00190 }
00191 
00192 static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
00193 {
00194     AVFilterInOut *ret;
00195 
00196     while(*links && strcmp((*links)->name, label))
00197         links = &((*links)->next);
00198 
00199     ret = *links;
00200 
00201     if(ret)
00202         *links = ret->next;
00203 
00204     return ret;
00205 }
00206 
00207 static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
00208 {
00209     element->next = *inouts;
00210     *inouts = element;
00211 }
00212 
00213 static int link_filter_inouts(AVFilterContext *filter,
00214                               AVFilterInOut **curr_inputs,
00215                               AVFilterInOut **open_inputs, AVClass *log_ctx)
00216 {
00217     int pad = filter->input_count;
00218 
00219     while(pad--) {
00220         AVFilterInOut *p = *curr_inputs;
00221         if(!p) {
00222             av_log(log_ctx, AV_LOG_ERROR,
00223                    "Not enough inputs specified for the \"%s\" filter.\n",
00224                    filter->filter->name);
00225             return -1;
00226         }
00227 
00228         *curr_inputs = (*curr_inputs)->next;
00229 
00230         if(p->filter) {
00231             if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx))
00232                 return -1;
00233             av_free(p->name);
00234             av_free(p);
00235         } else {
00236             p->filter = filter;
00237             p->pad_idx = pad;
00238             insert_inout(open_inputs, p);
00239         }
00240     }
00241 
00242     if(*curr_inputs) {
00243         av_log(log_ctx, AV_LOG_ERROR,
00244                "Too many inputs specified for the \"%s\" filter.\n",
00245                filter->filter->name);
00246         return -1;
00247     }
00248 
00249     pad = filter->output_count;
00250     while(pad--) {
00251         AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut));
00252         currlinkn->filter  = filter;
00253         currlinkn->pad_idx = pad;
00254         insert_inout(curr_inputs, currlinkn);
00255     }
00256 
00257     return 0;
00258 }
00259 
00260 static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs,
00261                         AVFilterInOut **open_outputs, AVClass *log_ctx)
00262 {
00263     int pad = 0;
00264 
00265     while(**buf == '[') {
00266         char *name = parse_link_name(buf, log_ctx);
00267         AVFilterInOut *match;
00268 
00269         if(!name)
00270             return -1;
00271 
00272         /* First check if the label is not in the open_outputs list */
00273         match = extract_inout(name, open_outputs);
00274 
00275         if(match) {
00276             av_free(name);
00277         } else {
00278             /* Not in the list, so add it as an input */
00279             match = av_mallocz(sizeof(AVFilterInOut));
00280             match->name    = name;
00281             match->pad_idx = pad;
00282         }
00283 
00284         insert_inout(curr_inputs, match);
00285 
00286         *buf += consume_whitespace(*buf);
00287         pad++;
00288     }
00289 
00290     return pad;
00291 }
00292 
00293 static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
00294                          AVFilterInOut **open_inputs,
00295                          AVFilterInOut **open_outputs, AVClass *log_ctx)
00296 {
00297     int pad = 0;
00298 
00299     while(**buf == '[') {
00300         char *name = parse_link_name(buf, log_ctx);
00301         AVFilterInOut *match;
00302 
00303         AVFilterInOut *input = *curr_inputs;
00304         *curr_inputs = (*curr_inputs)->next;
00305 
00306         if(!name)
00307             return -1;
00308 
00309         /* First check if the label is not in the open_inputs list */
00310         match = extract_inout(name, open_inputs);
00311 
00312         if(match) {
00313             if(link_filter(input->filter, input->pad_idx,
00314                            match->filter, match->pad_idx, log_ctx) < 0)
00315                 return -1;
00316             av_free(match->name);
00317             av_free(name);
00318             av_free(match);
00319             av_free(input);
00320         } else {
00321             /* Not in the list, so add the first input as a open_output */
00322             input->name = name;
00323             insert_inout(open_outputs, input);
00324         }
00325         *buf += consume_whitespace(*buf);
00326         pad++;
00327     }
00328 
00329     return pad;
00330 }
00331 
00332 int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
00333                          AVFilterInOut *open_inputs,
00334                          AVFilterInOut *open_outputs, AVClass *log_ctx)
00335 {
00336     int index = 0;
00337     char chr = 0;
00338 
00339     AVFilterInOut *curr_inputs = NULL;
00340 
00341     do {
00342         AVFilterContext *filter;
00343         filters += consume_whitespace(filters);
00344 
00345         if(parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx) < 0)
00346             goto fail;
00347 
00348         filter = parse_filter(&filters, graph, index, log_ctx);
00349 
00350         if(!filter)
00351             goto fail;
00352 
00353         if(filter->input_count == 1 && !curr_inputs && !index) {
00354             /* First input can be omitted if it is "[in]" */
00355             const char *tmp = "[in]";
00356             if(parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx) < 0)
00357                 goto fail;
00358         }
00359 
00360         if(link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx) < 0)
00361             goto fail;
00362 
00363         if(parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
00364                          log_ctx) < 0)
00365             goto fail;
00366 
00367         filters += consume_whitespace(filters);
00368         chr = *filters++;
00369 
00370         if(chr == ';' && curr_inputs) {
00371             av_log(log_ctx, AV_LOG_ERROR,
00372                    "Could not find a output to link when parsing \"%s\"\n",
00373                    filters - 1);
00374             goto fail;
00375         }
00376         index++;
00377     } while(chr == ',' || chr == ';');
00378 
00379     if (chr) {
00380         av_log(log_ctx, AV_LOG_ERROR,
00381                "Unable to parse graph description substring: \"%s\"\n",
00382                filters - 1);
00383         goto fail;
00384     }
00385 
00386     if(open_inputs && !strcmp(open_inputs->name, "out") && curr_inputs) {
00387         /* Last output can be omitted if it is "[out]" */
00388         const char *tmp = "[out]";
00389         if(parse_outputs(&tmp, &curr_inputs, &open_inputs,
00390                          &open_outputs, log_ctx) < 0)
00391             goto fail;
00392     }
00393 
00394     return 0;
00395 
00396  fail:
00397     avfilter_graph_destroy(graph);
00398     free_inout(open_inputs);
00399     free_inout(open_outputs);
00400     free_inout(curr_inputs);
00401     return -1;
00402 }

Generated on Sat Feb 16 2013 09:23:14 for ffmpeg by  doxygen 1.7.1