1/* 2 * filter graphs 3 * Copyright (c) 2008 Vitor Sessak 4 * Copyright (c) 2007 Bobby Bingham 5 * 6 * This file is part of Libav. 7 * 8 * Libav is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * Libav is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with Libav; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <ctype.h> 24#include <string.h> 25 26#include "libavutil/avstring.h" 27#include "avfilter.h" 28#include "avfiltergraph.h" 29#include "internal.h" 30 31AVFilterGraph *avfilter_graph_alloc(void) 32{ 33 return av_mallocz(sizeof(AVFilterGraph)); 34} 35 36void avfilter_graph_free(AVFilterGraph **graph) 37{ 38 if (!*graph) 39 return; 40 for (; (*graph)->filter_count > 0; (*graph)->filter_count--) 41 avfilter_free((*graph)->filters[(*graph)->filter_count - 1]); 42 av_freep(&(*graph)->scale_sws_opts); 43 av_freep(&(*graph)->filters); 44 av_freep(graph); 45} 46 47int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter) 48{ 49 AVFilterContext **filters = av_realloc(graph->filters, 50 sizeof(AVFilterContext*) * (graph->filter_count+1)); 51 if (!filters) 52 return AVERROR(ENOMEM); 53 54 graph->filters = filters; 55 graph->filters[graph->filter_count++] = filter; 56 57 return 0; 58} 59 60int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt, 61 const char *name, const char *args, void *opaque, 62 AVFilterGraph *graph_ctx) 63{ 64 int ret; 65 66 if ((ret = avfilter_open(filt_ctx, filt, name)) < 0) 67 goto fail; 68 if ((ret = avfilter_init_filter(*filt_ctx, args, opaque)) < 0) 69 goto fail; 70 if ((ret = avfilter_graph_add_filter(graph_ctx, *filt_ctx)) < 0) 71 goto fail; 72 return 0; 73 74fail: 75 if (*filt_ctx) 76 avfilter_free(*filt_ctx); 77 *filt_ctx = NULL; 78 return ret; 79} 80 81int ff_avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx) 82{ 83 AVFilterContext *filt; 84 int i, j; 85 86 for (i = 0; i < graph->filter_count; i++) { 87 filt = graph->filters[i]; 88 89 for (j = 0; j < filt->input_count; j++) { 90 if (!filt->inputs[j] || !filt->inputs[j]->src) { 91 av_log(log_ctx, AV_LOG_ERROR, 92 "Input pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any source\n", 93 filt->input_pads[j].name, filt->name, filt->filter->name); 94 return AVERROR(EINVAL); 95 } 96 } 97 98 for (j = 0; j < filt->output_count; j++) { 99 if (!filt->outputs[j] || !filt->outputs[j]->dst) { 100 av_log(log_ctx, AV_LOG_ERROR, 101 "Output pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any destination\n", 102 filt->output_pads[j].name, filt->name, filt->filter->name); 103 return AVERROR(EINVAL); 104 } 105 } 106 } 107 108 return 0; 109} 110 111int ff_avfilter_graph_config_links(AVFilterGraph *graph, AVClass *log_ctx) 112{ 113 AVFilterContext *filt; 114 int i, ret; 115 116 for (i=0; i < graph->filter_count; i++) { 117 filt = graph->filters[i]; 118 119 if (!filt->output_count) { 120 if ((ret = avfilter_config_links(filt))) 121 return ret; 122 } 123 } 124 125 return 0; 126} 127 128AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name) 129{ 130 int i; 131 132 for (i = 0; i < graph->filter_count; i++) 133 if (graph->filters[i]->name && !strcmp(name, graph->filters[i]->name)) 134 return graph->filters[i]; 135 136 return NULL; 137} 138 139static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) 140{ 141 int i, j, ret; 142 int scaler_count = 0; 143 char inst_name[30]; 144 145 /* ask all the sub-filters for their supported media formats */ 146 for (i = 0; i < graph->filter_count; i++) { 147 if (graph->filters[i]->filter->query_formats) 148 graph->filters[i]->filter->query_formats(graph->filters[i]); 149 else 150 avfilter_default_query_formats(graph->filters[i]); 151 } 152 153 /* go through and merge as many format lists as possible */ 154 for (i = 0; i < graph->filter_count; i++) { 155 AVFilterContext *filter = graph->filters[i]; 156 157 for (j = 0; j < filter->input_count; j++) { 158 AVFilterLink *link = filter->inputs[j]; 159 if (link && link->in_formats != link->out_formats) { 160 if (!avfilter_merge_formats(link->in_formats, 161 link->out_formats)) { 162 AVFilterContext *scale; 163 char scale_args[256]; 164 /* couldn't merge format lists. auto-insert scale filter */ 165 snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", 166 scaler_count++); 167 av_strlcpy(scale_args, "0:0", sizeof(scale_args)); 168 if (graph->scale_sws_opts) { 169 av_strlcat(scale_args, ":", sizeof(scale_args)); 170 av_strlcat(scale_args, graph->scale_sws_opts, sizeof(scale_args)); 171 } 172 if ((ret = avfilter_graph_create_filter(&scale, avfilter_get_by_name("scale"), 173 inst_name, scale_args, NULL, graph)) < 0) 174 return ret; 175 if ((ret = avfilter_insert_filter(link, scale, 0, 0)) < 0) 176 return ret; 177 178 scale->filter->query_formats(scale); 179 if (((link = scale-> inputs[0]) && 180 !avfilter_merge_formats(link->in_formats, link->out_formats)) || 181 ((link = scale->outputs[0]) && 182 !avfilter_merge_formats(link->in_formats, link->out_formats))) { 183 av_log(log_ctx, AV_LOG_ERROR, 184 "Impossible to convert between the formats supported by the filter " 185 "'%s' and the filter '%s'\n", link->src->name, link->dst->name); 186 return AVERROR(EINVAL); 187 } 188 } 189 } 190 } 191 } 192 193 return 0; 194} 195 196static void pick_format(AVFilterLink *link) 197{ 198 if (!link || !link->in_formats) 199 return; 200 201 link->in_formats->format_count = 1; 202 link->format = link->in_formats->formats[0]; 203 204 avfilter_formats_unref(&link->in_formats); 205 avfilter_formats_unref(&link->out_formats); 206} 207 208static void pick_formats(AVFilterGraph *graph) 209{ 210 int i, j; 211 212 for (i = 0; i < graph->filter_count; i++) { 213 AVFilterContext *filter = graph->filters[i]; 214 215 for (j = 0; j < filter->input_count; j++) 216 pick_format(filter->inputs[j]); 217 for (j = 0; j < filter->output_count; j++) 218 pick_format(filter->outputs[j]); 219 } 220} 221 222int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) 223{ 224 int ret; 225 226 /* find supported formats from sub-filters, and merge along links */ 227 if ((ret = query_formats(graph, log_ctx)) < 0) 228 return ret; 229 230 /* Once everything is merged, it's possible that we'll still have 231 * multiple valid media format choices. We pick the first one. */ 232 pick_formats(graph); 233 234 return 0; 235} 236 237int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) 238{ 239 int ret; 240 241 if ((ret = ff_avfilter_graph_check_validity(graphctx, log_ctx))) 242 return ret; 243 if ((ret = ff_avfilter_graph_config_formats(graphctx, log_ctx))) 244 return ret; 245 if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx))) 246 return ret; 247 248 return 0; 249} 250