| 
									
										
										
										
											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>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:27 +00:00
										 |  |  | #include "graphparser.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | #include "avfilter.h"
 | 
					
						
							|  |  |  | #include "avfiltergraph.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  | static int consume_whitespace(const char *buf) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |     return strspn(buf, " \n\t"); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |     *buf += consume_whitespace(*buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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:41:25 +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 != '\'') | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:25 +00:00
										 |  |  |                 *out++ = *(*buf)++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |             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:41:25 +00:00
										 |  |  |             *out++ = 0; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:25 +00:00
										 |  |  |             *out++ = c; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:12 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } while(out[-1]); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:51 +00:00
										 |  |  |     (*buf)--; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |     *buf += consume_whitespace(*buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:29 +00:00
										 |  |  |  * Parse "[linkname]" | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:45 +00:00
										 |  |  |  * @param name a pointer (that need to be free'd after use) to the name between | 
					
						
							|  |  |  |  *        parenthesis | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  | static char *parse_link_name(const char **buf, 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:41:42 +00:00
										 |  |  |     char *name; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     (*buf)++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  |     name = consume_string(buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41: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: | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  |         av_freep(&name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return name; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  | static AVFilterContext *create_filter(AVFilterGraph *ctx, int index, | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |                                       const char *filt_name, const char *args, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |                                       AVClass *log_ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     AVFilterContext *filt_ctx; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     AVFilter *filt; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |     char inst_name[30]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     snprintf(inst_name, sizeof(inst_name), "Parsed filter %d", index); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     filt = avfilter_get_by_name(filt_name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     if(!filt) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |                "no such filter: '%s'\n", filt_name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     filt_ctx = avfilter_open(filt, inst_name); | 
					
						
							|  |  |  |     if(!filt_ctx) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |                "error creating filter '%s'\n", filt_name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     if(avfilter_graph_add_filter(ctx, filt_ctx) < 0) { | 
					
						
							|  |  |  |         avfilter_destroy(filt_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     if(avfilter_init_filter(filt_ctx, args, NULL)) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |                "error initializing filter '%s' with args '%s'\n", filt_name, args); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-26 10:54:16 +00:00
										 |  |  |     return filt_ctx; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Parse "filter=params" | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph, | 
					
						
							|  |  |  |                                      int index, AVClass *log_ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:54 +00:00
										 |  |  |     char *opts = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  |     char *name = consume_string(buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |     AVFilterContext *ret; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:57 +00:00
										 |  |  |     if(**buf == '=') { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  |         (*buf)++; | 
					
						
							|  |  |  |         opts = consume_string(buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:57 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |     ret = create_filter(graph, index, name, opts, log_ctx); | 
					
						
							|  |  |  |     av_free(name); | 
					
						
							|  |  |  |     av_free(opts); | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:38 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | static void free_inout(AVFilterInOut *head) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:22 +00:00
										 |  |  |     while(head) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:34 +00:00
										 |  |  |         AVFilterInOut *next = head->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |         av_free(head->name); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:09 +00:00
										 |  |  | static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     element->next = *inouts; | 
					
						
							|  |  |  |     *inouts = element; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int link_filter_inouts(AVFilterContext *filter, | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |                               AVFilterInOut **curr_inputs, | 
					
						
							|  |  |  |                               AVFilterInOut **open_inputs, AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:24 +00:00
										 |  |  |     int pad = filter->input_count; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:51 +00:00
										 |  |  |     while(pad--) { | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         AVFilterInOut *p = *curr_inputs; | 
					
						
							| 
									
										
										
										
											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", | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:00 +00:00
										 |  |  |                    filter->filter->name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         *curr_inputs = (*curr_inputs)->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(p->filter) { | 
					
						
							|  |  |  |             if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx)) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |             av_free(p->name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             av_free(p); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             p->filter = filter; | 
					
						
							|  |  |  |             p->pad_idx = pad; | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |             insert_inout(open_inputs, p); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |     if(*curr_inputs) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							|  |  |  |                "Too many inputs specified for the \"%s\" filter.\n", | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:00 +00:00
										 |  |  |                filter->filter->name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pad = filter->output_count; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:51 +00:00
										 |  |  |     while(pad--) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:11 +00:00
										 |  |  |         AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut)); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         currlinkn->filter  = filter; | 
					
						
							|  |  |  |         currlinkn->pad_idx = pad; | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         insert_inout(curr_inputs, currlinkn); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  | static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs, | 
					
						
							|  |  |  |                         AVFilterInOut **open_outputs, 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:41:22 +00:00
										 |  |  |     while(**buf == '[') { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  |         char *name = parse_link_name(buf, log_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |         AVFilterInOut *match; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:17 +00:00
										 |  |  |         if(!name) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         /* First check if the label is not in the open_outputs list */ | 
					
						
							|  |  |  |         match = extract_inout(name, open_outputs); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:03 +00:00
										 |  |  |         if(match) { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:32 +00:00
										 |  |  |             av_free(name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             /* Not in the list, so add it as an input */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:16 +00:00
										 |  |  |             match = av_mallocz(sizeof(AVFilterInOut)); | 
					
						
							|  |  |  |             match->name    = name; | 
					
						
							|  |  |  |             match->pad_idx = pad; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:30 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         insert_inout(curr_inputs, match); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |         *buf += 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-12-27 09:31:05 +00:00
										 |  |  | static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs, | 
					
						
							|  |  |  |                          AVFilterInOut **open_inputs, | 
					
						
							|  |  |  |                          AVFilterInOut **open_outputs, AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |     int pad = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:22 +00:00
										 |  |  |     while(**buf == '[') { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:42 +00:00
										 |  |  |         char *name = parse_link_name(buf, log_ctx); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         AVFilterInOut *match; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         AVFilterInOut *input = *curr_inputs; | 
					
						
							|  |  |  |         *curr_inputs = (*curr_inputs)->next; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         if(!name) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         /* First check if the label is not in the open_inputs list */ | 
					
						
							|  |  |  |         match = extract_inout(name, open_inputs); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         if(match) { | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:26 +00:00
										 |  |  |             av_free(match->name); | 
					
						
							|  |  |  |             av_free(name); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             av_free(match); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:06 +00:00
										 |  |  |             av_free(input); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:58 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |             /* Not in the list, so add the first input as a open_output */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:06 +00:00
										 |  |  |             input->name = name; | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |             insert_inout(open_outputs, input); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |         *buf += consume_whitespace(*buf); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         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:39:19 +00:00
										 |  |  | int avfilter_parse_graph(AVFilterGraph *graph, const char *filters, | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |                          AVFilterInOut *open_inputs, | 
					
						
							|  |  |  |                          AVFilterInOut *open_outputs, AVClass *log_ctx) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int index = 0; | 
					
						
							|  |  |  |     char chr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |     AVFilterInOut *curr_inputs = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							| 
									
										
										
										
											2008-05-24 20:38:25 +00:00
										 |  |  |         AVFilterContext *filter; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |         filters += consume_whitespace(filters); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:48 +00:00
										 |  |  |         filter = parse_filter(&filters, graph, index, log_ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(!filter) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:42 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(filter->input_count == 1 && !curr_inputs && !index) { | 
					
						
							| 
									
										
										
										
											2008-12-26 20:26:44 +00:00
										 |  |  |             /* First input can be omitted if it is "[in]" */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             const char *tmp = "[in]"; | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |             if(parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |                 goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:39:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs, | 
					
						
							| 
									
										
										
										
											2008-05-24 20:42:34 +00:00
										 |  |  |                          log_ctx) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:14 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:36 +00:00
										 |  |  |         filters += consume_whitespace(filters); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |         chr = *filters++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(chr == ';' && curr_inputs) { | 
					
						
							| 
									
										
										
										
											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++; | 
					
						
							| 
									
										
										
										
											2008-05-24 20:41:22 +00:00
										 |  |  |     } while(chr == ',' || chr == ';'); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-14 11:47:42 +00:00
										 |  |  |     if (chr) { | 
					
						
							| 
									
										
										
										
											2009-01-16 23:56:53 +00:00
										 |  |  |         av_log(log_ctx, AV_LOG_ERROR, | 
					
						
							|  |  |  |                "Unable to parse graph description substring: \"%s\"\n", | 
					
						
							|  |  |  |                filters - 1); | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |     if(open_inputs && !strcmp(open_inputs->name, "out") && curr_inputs) { | 
					
						
							| 
									
										
										
										
											2008-12-26 20:26:44 +00:00
										 |  |  |         /* Last output can be omitted if it is "[out]" */ | 
					
						
							| 
									
										
										
										
											2008-05-24 20:40:40 +00:00
										 |  |  |         const char *tmp = "[out]"; | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |         if(parse_outputs(&tmp, &curr_inputs, &open_inputs, | 
					
						
							|  |  |  |                          &open_outputs, log_ctx) < 0) | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							| 
									
										
										
										
											2009-02-26 22:02:09 +00:00
										 |  |  |     avfilter_graph_destroy(graph); | 
					
						
							| 
									
										
										
										
											2008-12-27 09:31:05 +00:00
										 |  |  |     free_inout(open_inputs); | 
					
						
							|  |  |  |     free_inout(open_outputs); | 
					
						
							|  |  |  |     free_inout(curr_inputs); | 
					
						
							| 
									
										
										
										
											2008-05-24 20:35:43 +00:00
										 |  |  |     return -1; | 
					
						
							|  |  |  | } |