libavfilter/avfiltergraph.c
Go to the documentation of this file.
00001 /*
00002  * filter graphs
00003  * Copyright (c) 2008 Vitor Sessak
00004  * Copyright (c) 2007 Bobby Bingham
00005  *
00006  * This file is part of FFmpeg.
00007  *
00008  * FFmpeg is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * FFmpeg is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with FFmpeg; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 #include <ctype.h>
00024 #include <string.h>
00025 
00026 #include "libavutil/audioconvert.h"
00027 #include "avfilter.h"
00028 #include "avfiltergraph.h"
00029 #include "internal.h"
00030 
00031 AVFilterGraph *avfilter_graph_alloc(void)
00032 {
00033     return av_mallocz(sizeof(AVFilterGraph));
00034 }
00035 
00036 void avfilter_graph_free(AVFilterGraph **graph)
00037 {
00038     if (!*graph)
00039         return;
00040     for (; (*graph)->filter_count > 0; (*graph)->filter_count--)
00041         avfilter_free((*graph)->filters[(*graph)->filter_count - 1]);
00042     av_freep(&(*graph)->scale_sws_opts);
00043     av_freep(&(*graph)->filters);
00044     av_freep(graph);
00045 }
00046 
00047 int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
00048 {
00049     AVFilterContext **filters = av_realloc(graph->filters,
00050                                            sizeof(AVFilterContext*) * (graph->filter_count+1));
00051     if (!filters)
00052         return AVERROR(ENOMEM);
00053 
00054     graph->filters = filters;
00055     graph->filters[graph->filter_count++] = filter;
00056 
00057     return 0;
00058 }
00059 
00060 int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt,
00061                                  const char *name, const char *args, void *opaque,
00062                                  AVFilterGraph *graph_ctx)
00063 {
00064     int ret;
00065 
00066     if ((ret = avfilter_open(filt_ctx, filt, name)) < 0)
00067         goto fail;
00068     if ((ret = avfilter_init_filter(*filt_ctx, args, opaque)) < 0)
00069         goto fail;
00070     if ((ret = avfilter_graph_add_filter(graph_ctx, *filt_ctx)) < 0)
00071         goto fail;
00072     return 0;
00073 
00074 fail:
00075     if (*filt_ctx)
00076         avfilter_free(*filt_ctx);
00077     *filt_ctx = NULL;
00078     return ret;
00079 }
00080 
00081 int ff_avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
00082 {
00083     AVFilterContext *filt;
00084     int i, j;
00085 
00086     for (i = 0; i < graph->filter_count; i++) {
00087         filt = graph->filters[i];
00088 
00089         for (j = 0; j < filt->input_count; j++) {
00090             if (!filt->inputs[j] || !filt->inputs[j]->src) {
00091                 av_log(log_ctx, AV_LOG_ERROR,
00092                        "Input pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any source\n",
00093                        filt->input_pads[j].name, filt->name, filt->filter->name);
00094                 return AVERROR(EINVAL);
00095             }
00096         }
00097 
00098         for (j = 0; j < filt->output_count; j++) {
00099             if (!filt->outputs[j] || !filt->outputs[j]->dst) {
00100                 av_log(log_ctx, AV_LOG_ERROR,
00101                        "Output pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any destination\n",
00102                        filt->output_pads[j].name, filt->name, filt->filter->name);
00103                 return AVERROR(EINVAL);
00104             }
00105         }
00106     }
00107 
00108     return 0;
00109 }
00110 
00111 int ff_avfilter_graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
00112 {
00113     AVFilterContext *filt;
00114     int i, ret;
00115 
00116     for (i=0; i < graph->filter_count; i++) {
00117         filt = graph->filters[i];
00118 
00119         if (!filt->output_count) {
00120             if ((ret = avfilter_config_links(filt)))
00121                 return ret;
00122         }
00123     }
00124 
00125     return 0;
00126 }
00127 
00128 AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
00129 {
00130     int i;
00131 
00132     for (i = 0; i < graph->filter_count; i++)
00133         if (graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
00134             return graph->filters[i];
00135 
00136     return NULL;
00137 }
00138 
00139 static int insert_conv_filter(AVFilterGraph *graph, AVFilterLink *link,
00140                               const char *filt_name, const char *filt_args)
00141 {
00142     static int auto_count = 0, ret;
00143     char inst_name[32];
00144     AVFilterContext *filt_ctx;
00145 
00146     snprintf(inst_name, sizeof(inst_name), "auto-inserted %s %d",
00147             filt_name, auto_count++);
00148 
00149     if ((ret = avfilter_graph_create_filter(&filt_ctx,
00150                                             avfilter_get_by_name(filt_name),
00151                                             inst_name, filt_args, NULL, graph)) < 0)
00152         return ret;
00153     if ((ret = avfilter_insert_filter(link, filt_ctx, 0, 0)) < 0)
00154         return ret;
00155 
00156     filt_ctx->filter->query_formats(filt_ctx);
00157 
00158     if ( ((link = filt_ctx-> inputs[0]) &&
00159            !avfilter_merge_formats(link->in_formats, link->out_formats)) ||
00160          ((link = filt_ctx->outputs[0]) &&
00161            !avfilter_merge_formats(link->in_formats, link->out_formats))
00162        ) {
00163         av_log(NULL, AV_LOG_ERROR,
00164                "Impossible to convert between the formats supported by the filter "
00165                "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
00166         return AVERROR(EINVAL);
00167     }
00168 
00169     if (link->type == AVMEDIA_TYPE_AUDIO &&
00170          (((link = filt_ctx-> inputs[0]) &&
00171            (!avfilter_merge_formats(link->in_chlayouts, link->out_chlayouts) ||
00172             !avfilter_merge_formats(link->in_packing,   link->out_packing))) ||
00173          ((link = filt_ctx->outputs[0]) &&
00174            (!avfilter_merge_formats(link->in_chlayouts, link->out_chlayouts) ||
00175             !avfilter_merge_formats(link->in_packing,   link->out_packing))))
00176        ) {
00177         av_log(NULL, AV_LOG_ERROR,
00178                "Impossible to convert between the channel layouts/packing formats supported by the filter "
00179                "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
00180         return AVERROR(EINVAL);
00181     }
00182 
00183     return 0;
00184 }
00185 
00186 static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
00187 {
00188     int i, j, ret;
00189     char filt_args[128];
00190 
00191     /* ask all the sub-filters for their supported media formats */
00192     for (i = 0; i < graph->filter_count; i++) {
00193         if (graph->filters[i]->filter->query_formats)
00194             graph->filters[i]->filter->query_formats(graph->filters[i]);
00195         else
00196             avfilter_default_query_formats(graph->filters[i]);
00197     }
00198 
00199     /* go through and merge as many format lists as possible */
00200     for (i = 0; i < graph->filter_count; i++) {
00201         AVFilterContext *filter = graph->filters[i];
00202 
00203         for (j = 0; j < filter->input_count; j++) {
00204             AVFilterLink *link = filter->inputs[j];
00205             if (!link) continue;
00206 
00207             if (!link->in_formats || !link->out_formats)
00208                 return AVERROR(EINVAL);
00209 
00210             if (link->type == AVMEDIA_TYPE_VIDEO &&
00211                 !avfilter_merge_formats(link->in_formats, link->out_formats)) {
00212 
00213                 /* couldn't merge format lists, auto-insert scale filter */
00214                 snprintf(filt_args, sizeof(filt_args), "0:0:%s",
00215                          graph->scale_sws_opts);
00216                 if (ret = insert_conv_filter(graph, link, "scale", filt_args))
00217                     return ret;
00218             }
00219             else if (link->type == AVMEDIA_TYPE_AUDIO) {
00220                 if (!link->in_chlayouts || !link->out_chlayouts ||
00221                     !link->in_packing   || !link->out_packing)
00222                     return AVERROR(EINVAL);
00223 
00224                 if (!avfilter_merge_formats(link->in_formats,   link->out_formats)   ||
00225                     !avfilter_merge_formats(link->in_chlayouts, link->out_chlayouts) ||
00226                     !avfilter_merge_formats(link->in_packing,   link->out_packing))
00227                     if (ret = insert_conv_filter(graph, link, "aconvert", NULL))
00228                        return ret;
00229             }
00230         }
00231     }
00232 
00233     return 0;
00234 }
00235 
00236 static void pick_format(AVFilterLink *link)
00237 {
00238     if (!link || !link->in_formats)
00239         return;
00240 
00241     link->in_formats->format_count = 1;
00242     link->format = link->in_formats->formats[0];
00243     avfilter_formats_unref(&link->in_formats);
00244     avfilter_formats_unref(&link->out_formats);
00245 
00246     if (link->type == AVMEDIA_TYPE_AUDIO) {
00247         link->in_chlayouts->format_count = 1;
00248         link->channel_layout = link->in_chlayouts->formats[0];
00249         avfilter_formats_unref(&link->in_chlayouts);
00250         avfilter_formats_unref(&link->out_chlayouts);
00251 
00252         link->in_packing->format_count = 1;
00253         link->planar = link->in_packing->formats[0] == AVFILTER_PLANAR;
00254         avfilter_formats_unref(&link->in_packing);
00255         avfilter_formats_unref(&link->out_packing);
00256     }
00257 }
00258 
00259 static void pick_formats(AVFilterGraph *graph)
00260 {
00261     int i, j;
00262 
00263     for (i = 0; i < graph->filter_count; i++) {
00264         AVFilterContext *filter = graph->filters[i];
00265 
00266         for (j = 0; j < filter->input_count; j++)
00267             pick_format(filter->inputs[j]);
00268         for (j = 0; j < filter->output_count; j++)
00269             pick_format(filter->outputs[j]);
00270     }
00271 }
00272 
00273 int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
00274 {
00275     int ret;
00276 
00277     /* find supported formats from sub-filters, and merge along links */
00278     if ((ret = query_formats(graph, log_ctx)) < 0)
00279         return ret;
00280 
00281     /* Once everything is merged, it's possible that we'll still have
00282      * multiple valid media format choices. We pick the first one. */
00283     pick_formats(graph);
00284 
00285     return 0;
00286 }
00287 
00288 int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
00289 {
00290     int ret;
00291 
00292     if ((ret = ff_avfilter_graph_check_validity(graphctx, log_ctx)))
00293         return ret;
00294     if ((ret = ff_avfilter_graph_config_formats(graphctx, log_ctx)))
00295         return ret;
00296     if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx)))
00297         return ret;
00298 
00299     return 0;
00300 }
00301 
00302 int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags)
00303 {
00304     int i, r = AVERROR(ENOSYS);
00305 
00306     if(!graph)
00307         return r;
00308 
00309     if((flags & AVFILTER_CMD_FLAG_ONE) && !(flags & AVFILTER_CMD_FLAG_FAST)) {
00310         r=avfilter_graph_send_command(graph, target, cmd, arg, res, res_len, flags | AVFILTER_CMD_FLAG_FAST);
00311         if(r != AVERROR(ENOSYS))
00312             return r;
00313     }
00314 
00315     if(res_len && res)
00316         res[0]= 0;
00317 
00318     for (i = 0; i < graph->filter_count; i++) {
00319         AVFilterContext *filter = graph->filters[i];
00320         if(!strcmp(target, "all") || (filter->name && !strcmp(target, filter->name)) || !strcmp(target, filter->filter->name)){
00321             r = avfilter_process_command(filter, cmd, arg, res, res_len, flags);
00322             if(r != AVERROR(ENOSYS)) {
00323                 if((flags & AVFILTER_CMD_FLAG_ONE) || r<0)
00324                     return r;
00325             }
00326         }
00327     }
00328 
00329     return r;
00330 }
00331 
00332 int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *command, const char *arg, int flags, double ts)
00333 {
00334     int i;
00335 
00336     if(!graph)
00337         return 0;
00338 
00339     for (i = 0; i < graph->filter_count; i++) {
00340         AVFilterContext *filter = graph->filters[i];
00341         if(filter && (!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name))){
00342             AVFilterCommand **que = &filter->command_queue, *next;
00343             while(*que && (*que)->time <= ts)
00344                 que = &(*que)->next;
00345             next= *que;
00346             *que= av_mallocz(sizeof(AVFilterCommand));
00347             (*que)->command = av_strdup(command);
00348             (*que)->arg     = av_strdup(arg);
00349             (*que)->time    = ts;
00350             (*que)->flags   = flags;
00351             (*que)->next    = next;
00352             if(flags & AVFILTER_CMD_FLAG_ONE)
00353                 return 0;
00354         }
00355     }
00356 
00357     return 0;
00358 }