| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * filter graph parser | 
					
						
							|  |  |  |  * copyright (c) 2008 Vitor Sessak | 
					
						
							|  |  |  |  * copyright (c) 2007 Bobby Bingham | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "avfilter.h"
 | 
					
						
							|  |  |  | #include "avfiltergraph.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | static AVFilterContext *create_filter(AVFilterGraph *ctx, int index, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |                                       const char *name, const char *args, | 
					
						
							|  |  |  |                                       AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     AVFilterContext *filt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AVFilter *filterdef; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:05 +00:00
										 |  |  |     char inst_name[30]; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:05 +00:00
										 |  |  |     snprintf(inst_name, sizeof(inst_name), "Parsed filter %d", index); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(!(filterdef = avfilter_get_by_name(name))) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:32 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:23 +00:00
										 |  |  |                "no such filter: '%s'\n", name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:05 +00:00
										 |  |  |     if(!(filt = avfilter_open(filterdef, inst_name))) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |                "error creating filter '%s'\n", name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:32 +00:00
										 |  |  |     if(avfilter_graph_add_filter(ctx, filt) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     if(avfilter_init_filter(filt, args, NULL)) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:23 +00:00
										 |  |  |                "error initializing filter '%s' with args '%s'\n", name, args); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |     return filt; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | static int link_filter(AVFilterContext *src, int srcpad, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |                        AVFilterContext *dst, int dstpad, | 
					
						
							|  |  |  |                        AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |     if(avfilter_link(src, srcpad, dst, dstpad)) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |                "cannot create the link %s:%d -> %s:%d\n", | 
					
						
							|  |  |  |                src->filter->name, srcpad, dst->filter->name, dstpad); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void consume_whitespace(const char **buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     *buf += strspn(*buf, " \n\t"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:26 +00:00
										 |  |  |     char *out = av_malloc(strlen(*buf) + 1); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |     char *ret = out; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     consume_whitespace(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |     do{ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |         char c = *(*buf)++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |         switch (c) { | 
					
						
							|  |  |  |         case '\\': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |             *out++= *(*buf)++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |         case '\'': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |             while(**buf && **buf != '\'') | 
					
						
							|  |  |  |                 *out++= *(*buf)++; | 
					
						
							|  |  |  |             if(**buf) (*buf)++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         case 0: | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:22 +00:00
										 |  |  |         case ']': | 
					
						
							|  |  |  |         case '[': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |         case '=': | 
					
						
							|  |  |  |         case ',': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:35 +00:00
										 |  |  |         case ';': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:55 +00:00
										 |  |  |         case ' ': | 
					
						
							|  |  |  |         case '\n': | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |             *out++= 0; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             *out++= c; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } while(out[-1]); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |     (*buf)--; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:55 +00:00
										 |  |  |     consume_whitespace(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:29 +00:00
										 |  |  |  * Parse "[linkname]" | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |  * @arg name a pointer (that need to be free'd after use) to the name between | 
					
						
							|  |  |  |  *           parenthesis | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  | static void parse_link_name(const char **buf, char **name, AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     const char *start = *buf; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     (*buf)++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *name = consume_string(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     if(!*name[0]) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |                "Bad (empty?) label found in the following: \"%s\".\n", start); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     if(*(*buf)++ != ']') { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |                "Mismatched '[' found in the following: \"%s\".\n", start); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:10 +00:00
										 |  |  |     fail: | 
					
						
							|  |  |  |         av_freep(name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum LinkType { | 
					
						
							|  |  |  |     LinkTypeIn, | 
					
						
							|  |  |  |     LinkTypeOut, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * A linked-list of the inputs/outputs of the filter chain. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef struct AVFilterInOut { | 
					
						
							|  |  |  |     enum LinkType type; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:37 +00:00
										 |  |  |     const char *name; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:16 +00:00
										 |  |  |     AVFilterContext *filter; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     int pad_idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct AVFilterInOut *next; | 
					
						
							|  |  |  | } AVFilterInOut; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void free_inout(AVFilterInOut *head) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     while (head) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:34 +00:00
										 |  |  |         AVFilterInOut *next = head->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         av_free(head); | 
					
						
							|  |  |  |         head = next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AVFilterInOut *ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:44 +00:00
										 |  |  |     while(*links && strcmp((*links)->name, label)) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |         links = &((*links)->next); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |     ret = *links; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:44 +00:00
										 |  |  |     if(ret) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |         *links = ret->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int link_filter_inouts(AVFilterContext *filter, | 
					
						
							|  |  |  |                               AVFilterInOut **currInputs, | 
					
						
							|  |  |  |                               AVFilterInOut **openLinks, AVClass *log_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int pad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pad = filter->input_count; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:51 +00:00
										 |  |  |     while(pad--) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:16 +00:00
										 |  |  |         AVFilterInOut *p= *currInputs; | 
					
						
							|  |  |  |         *currInputs = (*currInputs)->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         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; | 
					
						
							|  |  |  |             av_free(p); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             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; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:51 +00:00
										 |  |  |     while(pad--) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut)); | 
					
						
							|  |  |  |         currlinkn->name    = NULL; | 
					
						
							|  |  |  |         currlinkn->type    = LinkTypeOut; | 
					
						
							|  |  |  |         currlinkn->filter  = filter; | 
					
						
							|  |  |  |         currlinkn->pad_idx = pad; | 
					
						
							|  |  |  |         currlinkn->next    = *currInputs; | 
					
						
							|  |  |  |         *currInputs = currlinkn; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     int pad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:22 +00:00
										 |  |  |     while (**buf == '[') { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:08 +00:00
										 |  |  |         char *name; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  |         AVFilterInOut *link_to_add; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |         AVFilterInOut *match; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |         parse_link_name(buf, &name, log_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:17 +00:00
										 |  |  |         if(!name) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         /* First check if the label is not in the openLinks list */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |         match = extract_inout(name, openLinks); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |         if(match) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             /* A label of a open link. Make it one of the inputs of the next
 | 
					
						
							|  |  |  |                filter */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:19 +00:00
										 |  |  |             if(match->type != LinkTypeOut) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  |                 av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |                        "Label \"%s\" appears twice as input!\n", match->name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             link_to_add = match; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             /* Not in the list, so add it as an input */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  |             link_to_add = av_malloc(sizeof(AVFilterInOut)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             link_to_add->name    = name; | 
					
						
							|  |  |  |             link_to_add->type    = LinkTypeIn; | 
					
						
							|  |  |  |             link_to_add->filter  = NULL; | 
					
						
							|  |  |  |             link_to_add->pad_idx = pad; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  |         link_to_add->next = *currInputs; | 
					
						
							|  |  |  |         *currInputs = link_to_add; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:01 +00:00
										 |  |  |         consume_whitespace(buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         pad++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     return pad; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | static int parse_outputs(const char **buf, AVFilterInOut **currInputs, | 
					
						
							|  |  |  |                          AVFilterInOut **openLinks, AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     int pad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (**buf == '[') { | 
					
						
							|  |  |  |         char *name; | 
					
						
							|  |  |  |         AVFilterInOut *match; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  |         AVFilterInOut *input = *currInputs; | 
					
						
							|  |  |  |         *currInputs = (*currInputs)->next; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         if(match) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             /* A label of a open link. Link it. */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:19 +00:00
										 |  |  |             if(match->type != LinkTypeIn) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |                 av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							|  |  |  |                        "Label \"%s\" appears twice as output!\n", match->name); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:06 +00:00
										 |  |  |             if(link_filter(input->filter, input->pad_idx, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |                            match->filter, match->pad_idx, log_ctx) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             av_free(match); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:06 +00:00
										 |  |  |             av_free(input); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             /* Not in the list, so add the first input as a openLink */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:06 +00:00
										 |  |  |             input->next = *openLinks; | 
					
						
							|  |  |  |             input->type = LinkTypeOut; | 
					
						
							|  |  |  |             input->name = name; | 
					
						
							|  |  |  |             *openLinks = input; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         consume_whitespace(buf); | 
					
						
							|  |  |  |         pad++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:01 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     return pad; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Parse a string describing a filter graph. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:19 +00:00
										 |  |  | int avfilter_parse_graph(AVFilterGraph *graph, const char *filters, | 
					
						
							|  |  |  |                          AVFilterContext *in, int inpad, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:22 +00:00
										 |  |  |                          AVFilterContext *out, int outpad, | 
					
						
							|  |  |  |                          AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int index = 0; | 
					
						
							|  |  |  |     char chr = 0; | 
					
						
							|  |  |  |     int pad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     AVFilterInOut *currInputs=NULL; | 
					
						
							|  |  |  |     AVFilterInOut *openLinks  = av_malloc(sizeof(AVFilterInOut)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |     openLinks->name    = "in"; | 
					
						
							|  |  |  |     openLinks->filter  = in; | 
					
						
							|  |  |  |     openLinks->type    = LinkTypeOut; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     openLinks->pad_idx = inpad; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |     openLinks->next    = av_malloc(sizeof(AVFilterInOut)); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |     openLinks->next->name    = "out"; | 
					
						
							|  |  |  |     openLinks->next->filter  = out; | 
					
						
							|  |  |  |     openLinks->next->type    = LinkTypeIn; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     openLinks->next->pad_idx = outpad; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:11 +00:00
										 |  |  |     openLinks->next->next    = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         AVFilterContext *filter; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:57 +00:00
										 |  |  |         consume_whitespace(&filters); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         pad = parse_inputs(&filters, &currInputs, &openLinks, log_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(pad < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(!(filter = parse_filter(&filters, graph, index, log_ctx))) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         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); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:19 +00:00
										 |  |  |             if(pad < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |                 goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(link_filter_inouts(filter, &currInputs, &openLinks, log_ctx) < 0) | 
					
						
							|  |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         pad = parse_outputs(&filters, &currInputs, &openLinks, log_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(pad < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:14 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:57 +00:00
										 |  |  |         consume_whitespace(&filters); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         chr = *filters++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:19 +00:00
										 |  |  |         if(chr == ';' && currInputs) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							|  |  |  |                    "Could not find a output to link when parsing \"%s\"\n", | 
					
						
							|  |  |  |                    filters - 1); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         index++; | 
					
						
							|  |  |  |     } while (chr == ',' || chr == ';'); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     avfilter_destroy_graph(graph); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     free_inout(openLinks); | 
					
						
							|  |  |  |     free_inout(currInputs); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     return -1; | 
					
						
							|  |  |  | } |