Libav 0.7.1
|
00001 /* 00002 * filter graphs 00003 * Copyright (c) 2008 Vitor Sessak 00004 * Copyright (c) 2007 Bobby Bingham 00005 * 00006 * This file is part of Libav. 00007 * 00008 * Libav is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * Libav is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with Libav; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include <ctype.h> 00024 #include <string.h> 00025 00026 #include "avfilter.h" 00027 #include "avfiltergraph.h" 00028 #include "internal.h" 00029 00030 AVFilterGraph *avfilter_graph_alloc(void) 00031 { 00032 return av_mallocz(sizeof(AVFilterGraph)); 00033 } 00034 00035 void avfilter_graph_free(AVFilterGraph **graph) 00036 { 00037 if (!*graph) 00038 return; 00039 for (; (*graph)->filter_count > 0; (*graph)->filter_count--) 00040 avfilter_free((*graph)->filters[(*graph)->filter_count - 1]); 00041 av_freep(&(*graph)->scale_sws_opts); 00042 av_freep(&(*graph)->filters); 00043 av_freep(graph); 00044 } 00045 00046 int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter) 00047 { 00048 AVFilterContext **filters = av_realloc(graph->filters, 00049 sizeof(AVFilterContext*) * (graph->filter_count+1)); 00050 if (!filters) 00051 return AVERROR(ENOMEM); 00052 00053 graph->filters = filters; 00054 graph->filters[graph->filter_count++] = filter; 00055 00056 return 0; 00057 } 00058 00059 int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt, 00060 const char *name, const char *args, void *opaque, 00061 AVFilterGraph *graph_ctx) 00062 { 00063 int ret; 00064 00065 if ((ret = avfilter_open(filt_ctx, filt, name)) < 0) 00066 goto fail; 00067 if ((ret = avfilter_init_filter(*filt_ctx, args, opaque)) < 0) 00068 goto fail; 00069 if ((ret = avfilter_graph_add_filter(graph_ctx, *filt_ctx)) < 0) 00070 goto fail; 00071 return 0; 00072 00073 fail: 00074 if (*filt_ctx) 00075 avfilter_free(*filt_ctx); 00076 *filt_ctx = NULL; 00077 return ret; 00078 } 00079 00080 int ff_avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx) 00081 { 00082 AVFilterContext *filt; 00083 int i, j; 00084 00085 for (i = 0; i < graph->filter_count; i++) { 00086 filt = graph->filters[i]; 00087 00088 for (j = 0; j < filt->input_count; j++) { 00089 if (!filt->inputs[j] || !filt->inputs[j]->src) { 00090 av_log(log_ctx, AV_LOG_ERROR, 00091 "Input pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any source\n", 00092 filt->input_pads[j].name, filt->name, filt->filter->name); 00093 return AVERROR(EINVAL); 00094 } 00095 } 00096 00097 for (j = 0; j < filt->output_count; j++) { 00098 if (!filt->outputs[j] || !filt->outputs[j]->dst) { 00099 av_log(log_ctx, AV_LOG_ERROR, 00100 "Output pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any destination\n", 00101 filt->output_pads[j].name, filt->name, filt->filter->name); 00102 return AVERROR(EINVAL); 00103 } 00104 } 00105 } 00106 00107 return 0; 00108 } 00109 00110 int ff_avfilter_graph_config_links(AVFilterGraph *graph, AVClass *log_ctx) 00111 { 00112 AVFilterContext *filt; 00113 int i, ret; 00114 00115 for (i=0; i < graph->filter_count; i++) { 00116 filt = graph->filters[i]; 00117 00118 if (!filt->output_count) { 00119 if ((ret = avfilter_config_links(filt))) 00120 return ret; 00121 } 00122 } 00123 00124 return 0; 00125 } 00126 00127 AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name) 00128 { 00129 int i; 00130 00131 for (i = 0; i < graph->filter_count; i++) 00132 if (graph->filters[i]->name && !strcmp(name, graph->filters[i]->name)) 00133 return graph->filters[i]; 00134 00135 return NULL; 00136 } 00137 00138 static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) 00139 { 00140 int i, j, ret; 00141 int scaler_count = 0; 00142 char inst_name[30]; 00143 00144 /* ask all the sub-filters for their supported media formats */ 00145 for (i = 0; i < graph->filter_count; i++) { 00146 if (graph->filters[i]->filter->query_formats) 00147 graph->filters[i]->filter->query_formats(graph->filters[i]); 00148 else 00149 avfilter_default_query_formats(graph->filters[i]); 00150 } 00151 00152 /* go through and merge as many format lists as possible */ 00153 for (i = 0; i < graph->filter_count; i++) { 00154 AVFilterContext *filter = graph->filters[i]; 00155 00156 for (j = 0; j < filter->input_count; j++) { 00157 AVFilterLink *link = filter->inputs[j]; 00158 if (link && link->in_formats != link->out_formats) { 00159 if (!avfilter_merge_formats(link->in_formats, 00160 link->out_formats)) { 00161 AVFilterContext *scale; 00162 char scale_args[256]; 00163 /* couldn't merge format lists. auto-insert scale filter */ 00164 snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", 00165 scaler_count++); 00166 snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); 00167 if ((ret = avfilter_graph_create_filter(&scale, avfilter_get_by_name("scale"), 00168 inst_name, scale_args, NULL, graph)) < 0) 00169 return ret; 00170 if ((ret = avfilter_insert_filter(link, scale, 0, 0)) < 0) 00171 return ret; 00172 00173 scale->filter->query_formats(scale); 00174 if (((link = scale-> inputs[0]) && 00175 !avfilter_merge_formats(link->in_formats, link->out_formats)) || 00176 ((link = scale->outputs[0]) && 00177 !avfilter_merge_formats(link->in_formats, link->out_formats))) { 00178 av_log(log_ctx, AV_LOG_ERROR, 00179 "Impossible to convert between the formats supported by the filter " 00180 "'%s' and the filter '%s'\n", link->src->name, link->dst->name); 00181 return AVERROR(EINVAL); 00182 } 00183 } 00184 } 00185 } 00186 } 00187 00188 return 0; 00189 } 00190 00191 static void pick_format(AVFilterLink *link) 00192 { 00193 if (!link || !link->in_formats) 00194 return; 00195 00196 link->in_formats->format_count = 1; 00197 link->format = link->in_formats->formats[0]; 00198 00199 avfilter_formats_unref(&link->in_formats); 00200 avfilter_formats_unref(&link->out_formats); 00201 } 00202 00203 static void pick_formats(AVFilterGraph *graph) 00204 { 00205 int i, j; 00206 00207 for (i = 0; i < graph->filter_count; i++) { 00208 AVFilterContext *filter = graph->filters[i]; 00209 00210 for (j = 0; j < filter->input_count; j++) 00211 pick_format(filter->inputs[j]); 00212 for (j = 0; j < filter->output_count; j++) 00213 pick_format(filter->outputs[j]); 00214 } 00215 } 00216 00217 int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) 00218 { 00219 int ret; 00220 00221 /* find supported formats from sub-filters, and merge along links */ 00222 if ((ret = query_formats(graph, log_ctx)) < 0) 00223 return ret; 00224 00225 /* Once everything is merged, it's possible that we'll still have 00226 * multiple valid media format choices. We pick the first one. */ 00227 pick_formats(graph); 00228 00229 return 0; 00230 } 00231 00232 int avfilter_graph_config(AVFilterGraph *graphctx, AVClass *log_ctx) 00233 { 00234 int ret; 00235 00236 if ((ret = ff_avfilter_graph_check_validity(graphctx, log_ctx))) 00237 return ret; 00238 if ((ret = ff_avfilter_graph_config_formats(graphctx, log_ctx))) 00239 return ret; 00240 if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx))) 00241 return ret; 00242 00243 return 0; 00244 }