Statistics
| Branch: | Revision:

ffmpeg / libavfilter / avfiltergraph.c @ 45a09319

History | View | Annotate | Download (19.3 KB)

1 eccb6fb7 Vitor Sessak
/*
2 ec8398a3 Vitor Sessak
 * filter graphs
3 eccb6fb7 Vitor Sessak
 * copyright (c) 2007 Bobby Bingham
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "avfilter.h"
23
#include "avfiltergraph.h"
24
25 b9a7a65a Vitor Sessak
typedef struct AVFilterGraph {
26 eccb6fb7 Vitor Sessak
    unsigned filter_count;
27
    AVFilterContext **filters;
28 7f8fb52f Vitor Sessak
29 f3f42a3c Vitor Sessak
    /** fake filters to handle links to internal filters */
30
    AVFilterContext *link_filter_in;
31
    AVFilterContext *link_filter_out;
32 b9a7a65a Vitor Sessak
} GraphContext;
33 eccb6fb7 Vitor Sessak
34 7f8fb52f Vitor Sessak
typedef struct {
35
    AVFilterContext *graph;
36
} GraphLinkContext;
37
38
static int link_init(AVFilterContext *ctx, const char *args, void *opaque)
39
{
40
    GraphLinkContext *linkctx = ctx->priv;
41
    linkctx->graph = opaque;
42
    return !opaque;
43
}
44
45 66d9e9be Vitor Sessak
/**
46
 * Given the link between the dummy filter and an internal filter whose input
47 7f8fb52f Vitor Sessak
 * is being exported outside the graph, this returns the externally visible
48 ec8398a3 Vitor Sessak
 * link.
49 66d9e9be Vitor Sessak
 */
50 7f8fb52f Vitor Sessak
static inline AVFilterLink *get_extern_input_link(AVFilterLink *link)
51
{
52
    GraphLinkContext *lctx = link->src->priv;
53
    return lctx->graph->inputs[link->srcpad];
54
}
55
56
/** request a frame from a filter providing input to the graph */
57 1d2067e2 Vitor Sessak
static int link_in_request_frame(AVFilterLink *link)
58 7f8fb52f Vitor Sessak
{
59
    AVFilterLink *link2 = get_extern_input_link(link);
60
61
    if(!link2)
62 1d2067e2 Vitor Sessak
        return -1;
63
    return avfilter_request_frame(link2);
64 7f8fb52f Vitor Sessak
}
65
66 affadb5b Vitor Sessak
67
static int link_in_poll_frame(AVFilterLink *link)
68
{
69
    AVFilterLink *link2 = get_extern_input_link(link);
70
    if(!link2)
71
        return -1;
72
    return avfilter_poll_frame(link2);
73
}
74
75 7f8fb52f Vitor Sessak
static int link_in_config_props(AVFilterLink *link)
76
{
77
    AVFilterLink *link2 = get_extern_input_link(link);
78
    int (*config_props)(AVFilterLink *);
79
    int ret;
80
81
    if(!link2)
82
        return -1;
83
    if(!(config_props = link2->src->output_pads[link2->srcpad].config_props))
84
        config_props = avfilter_default_config_output_link;
85
    ret = config_props(link2);
86
87
    link->w = link2->w;
88
    link->h = link2->h;
89
90
    return ret;
91
}
92
93 66d9e9be Vitor Sessak
/**
94 de065016 Vitor Sessak
 * Given the link between the dummy filter and an internal filter whose output
95 7f8fb52f Vitor Sessak
 * is being exported outside the graph, this returns the externally visible
96 ec8398a3 Vitor Sessak
 * link.
97 66d9e9be Vitor Sessak
 */
98 7f8fb52f Vitor Sessak
static inline AVFilterLink *get_extern_output_link(AVFilterLink *link)
99
{
100
    GraphLinkContext *lctx = link->dst->priv;
101
    return lctx->graph->outputs[link->dstpad];
102
}
103
104
static int link_out_config_props(AVFilterLink *link)
105
{
106
    AVFilterLink *link2 = get_extern_output_link(link);
107
108
    if(!link2)
109
        return 0;
110
111
    link2->w = link->w;
112
    link2->h = link->h;
113
114 095ae1bc Vitor Sessak
    return 0;
115 7f8fb52f Vitor Sessak
}
116
117
static void link_out_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
118
{
119
    AVFilterLink *link2 = get_extern_output_link(link);
120
121
    if(!link2)
122
        avfilter_unref_pic(picref);
123
    else
124
        avfilter_start_frame(link2, picref);
125
}
126
127
static void link_out_end_frame(AVFilterLink *link)
128
{
129
    AVFilterLink *link2 = get_extern_output_link(link);
130
131
    if(link2)
132
        avfilter_end_frame(link2);
133
}
134
135
static AVFilterPicRef *link_out_get_video_buffer(AVFilterLink *link, int perms)
136
{
137
    AVFilterLink *link2 = get_extern_output_link(link);
138
139
    if(!link2)
140
        return NULL;
141
    else
142
        return avfilter_get_video_buffer(link2, perms);
143
}
144
145 5ded633e Vitor Sessak
static void link_out_draw_slice(AVFilterLink *link, int y, int height)
146 7f8fb52f Vitor Sessak
{
147
    AVFilterLink *link2 = get_extern_output_link(link);
148
149
    if(link2)
150 5ded633e Vitor Sessak
        avfilter_draw_slice(link2, y, height);
151 7f8fb52f Vitor Sessak
}
152
153
/** dummy filter used to help export filters pads outside the graph */
154
static AVFilter vf_graph_dummy =
155
{
156
    .name      = "graph_dummy",
157
158
    .priv_size = sizeof(GraphLinkContext),
159
160
    .init      = link_init,
161
162
    .inputs    = (AVFilterPad[]) {{ .name = NULL, }},
163
    .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
164
};
165
166
static AVFilterLink *get_intern_input_link(AVFilterLink *link)
167
{
168
    GraphContext *graph = link->dst->priv;
169 f3f42a3c Vitor Sessak
    return graph->link_filter_in->outputs[link->dstpad];
170 7f8fb52f Vitor Sessak
}
171
172
static void graph_in_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
173
{
174
    AVFilterLink *link2 = get_intern_input_link(link);
175
    if(link2)
176
        avfilter_start_frame(link2, picref);
177
}
178
179
static void graph_in_end_frame(AVFilterLink *link)
180
{
181
    AVFilterLink *link2 = get_intern_input_link(link);
182
    if(link2)
183
        avfilter_end_frame(link2);
184
}
185
186
static AVFilterPicRef *graph_in_get_video_buffer(AVFilterLink *link, int perms)
187
{
188
    AVFilterLink *link2 = get_intern_input_link(link);
189
    if(link2)
190
        return avfilter_get_video_buffer(link2, perms);
191
    return NULL;
192
}
193
194 5ded633e Vitor Sessak
static void graph_in_draw_slice(AVFilterLink *link, int y, int height)
195 7f8fb52f Vitor Sessak
{
196
    AVFilterLink *link2 = get_intern_input_link(link);
197
    if(link2)
198 5ded633e Vitor Sessak
        avfilter_draw_slice(link2, y, height);
199 7f8fb52f Vitor Sessak
}
200
201
static int graph_in_config_props(AVFilterLink *link)
202
{
203
    AVFilterLink *link2 = get_intern_input_link(link);
204
    int (*config_props)(AVFilterLink *);
205 095ae1bc Vitor Sessak
    int ret;
206 7f8fb52f Vitor Sessak
207
    if(!link2)
208
        return -1;
209
210
    /* copy link properties over to the dummy internal link */
211
    link2->w = link->w;
212
    link2->h = link->h;
213 81c25293 Vitor Sessak
    link2->format = link->format;
214 7f8fb52f Vitor Sessak
215
    if(!(config_props = link2->dst->input_pads[link2->dstpad].config_props))
216
        return 0;   /* FIXME? */
217
        //config_props = avfilter_default_config_input_link;
218 095ae1bc Vitor Sessak
    if(!(ret = config_props(link2)))
219
        link2->init_state = AVLINK_INIT;
220
    else
221
        link2->init_state = AVLINK_STARTINIT;
222
223
    return ret;
224 7f8fb52f Vitor Sessak
}
225
226
static AVFilterLink *get_intern_output_link(AVFilterLink *link)
227
{
228
    GraphContext *graph = link->src->priv;
229 f3f42a3c Vitor Sessak
    return graph->link_filter_out->inputs[link->srcpad];
230 7f8fb52f Vitor Sessak
}
231
232 1d2067e2 Vitor Sessak
static int graph_out_request_frame(AVFilterLink *link)
233 7f8fb52f Vitor Sessak
{
234
    AVFilterLink *link2 = get_intern_output_link(link);
235
236
    if(link2)
237 1d2067e2 Vitor Sessak
        return avfilter_request_frame(link2);
238
    return -1;
239 7f8fb52f Vitor Sessak
}
240
241 affadb5b Vitor Sessak
static int graph_out_poll_frame(AVFilterLink *link)
242
{
243
    AVFilterLink *link2 = get_intern_output_link(link);
244
245
    if(!link2)
246
        return -1;
247
248
    return avfilter_poll_frame(link2);
249
}
250
251 7f8fb52f Vitor Sessak
static int graph_out_config_props(AVFilterLink *link)
252
{
253 095ae1bc Vitor Sessak
    GraphContext *graph = link->src->priv;
254
    AVFilterLink *link2 = graph->link_filter_out->inputs[link->srcpad];
255 7f8fb52f Vitor Sessak
    int ret;
256
257 095ae1bc Vitor Sessak
    if((ret = avfilter_config_links(graph->link_filter_out)))
258
        return ret;
259
260 7f8fb52f Vitor Sessak
    if(!link2)
261
        return 0;
262
263
    link->w = link2->w;
264
    link->h = link2->h;
265
    link->format = link2->format;
266
267 095ae1bc Vitor Sessak
    return 0;
268 7f8fb52f Vitor Sessak
}
269
270
static int add_graph_input(AVFilterContext *gctx, AVFilterContext *filt, unsigned idx,
271
                           char *name)
272
{
273
    GraphContext *graph = gctx->priv;
274
275
    AVFilterPad graph_inpad =
276
    {
277
        .name             = name,
278 2b052439 Vitor Sessak
        .type             = CODEC_TYPE_VIDEO,
279 7f8fb52f Vitor Sessak
        .start_frame      = graph_in_start_frame,
280
        .end_frame        = graph_in_end_frame,
281
        .get_video_buffer = graph_in_get_video_buffer,
282
        .draw_slice       = graph_in_draw_slice,
283
        .config_props     = graph_in_config_props,
284
        /* XXX */
285
    };
286
    AVFilterPad dummy_outpad =
287
    {
288
        .name          = NULL,          /* FIXME? */
289 2b052439 Vitor Sessak
        .type          = CODEC_TYPE_VIDEO,
290 7f8fb52f Vitor Sessak
        .request_frame = link_in_request_frame,
291 affadb5b Vitor Sessak
        .poll_frame    = link_in_poll_frame,
292 7f8fb52f Vitor Sessak
        .config_props  = link_in_config_props,
293
    };
294
295
    avfilter_insert_inpad (gctx, gctx->input_count, &graph_inpad);
296 f3f42a3c Vitor Sessak
    avfilter_insert_outpad(graph->link_filter_in, graph->link_filter_in->output_count,
297 7f8fb52f Vitor Sessak
                           &dummy_outpad);
298 f3f42a3c Vitor Sessak
    return avfilter_link(graph->link_filter_in,
299
                         graph->link_filter_in->output_count-1, filt, idx);
300 7f8fb52f Vitor Sessak
}
301
302
static int add_graph_output(AVFilterContext *gctx, AVFilterContext *filt, unsigned idx,
303
                            char *name)
304
{
305
    GraphContext *graph = gctx->priv;
306
307
    AVFilterPad graph_outpad =
308
    {
309
        .name             = name,
310 2b052439 Vitor Sessak
        .type             = CODEC_TYPE_VIDEO,
311 7f8fb52f Vitor Sessak
        .request_frame    = graph_out_request_frame,
312 affadb5b Vitor Sessak
        .poll_frame       = graph_out_poll_frame,
313 7f8fb52f Vitor Sessak
        .config_props     = graph_out_config_props,
314
    };
315
    AVFilterPad dummy_inpad =
316
    {
317
        .name             = NULL,          /* FIXME? */
318 2b052439 Vitor Sessak
        .type             = CODEC_TYPE_VIDEO,
319 7f8fb52f Vitor Sessak
        .start_frame      = link_out_start_frame,
320
        .end_frame        = link_out_end_frame,
321
        .draw_slice       = link_out_draw_slice,
322
        .get_video_buffer = link_out_get_video_buffer,
323
        .config_props     = link_out_config_props,
324
    };
325
326
    avfilter_insert_outpad(gctx, gctx->output_count, &graph_outpad);
327 f3f42a3c Vitor Sessak
    avfilter_insert_inpad (graph->link_filter_out, graph->link_filter_out->input_count,
328 7f8fb52f Vitor Sessak
                           &dummy_inpad);
329 f3f42a3c Vitor Sessak
    return avfilter_link(filt, idx, graph->link_filter_out,
330
                         graph->link_filter_out->input_count-1);
331 7f8fb52f Vitor Sessak
}
332
333 b9a7a65a Vitor Sessak
static void uninit(AVFilterContext *ctx)
334 eccb6fb7 Vitor Sessak
{
335 b9a7a65a Vitor Sessak
    GraphContext *graph = ctx->priv;
336 eccb6fb7 Vitor Sessak
337 f3f42a3c Vitor Sessak
    if(graph->link_filter_in) {
338
        avfilter_destroy(graph->link_filter_in);
339
        graph->link_filter_in = NULL;
340
    }
341
    if(graph->link_filter_out) {
342
        avfilter_destroy(graph->link_filter_out);
343
        graph->link_filter_out = NULL;
344 7f8fb52f Vitor Sessak
    }
345 65a4bd9c Vitor Sessak
    for(; graph->filter_count > 0; graph->filter_count --)
346
        avfilter_destroy(graph->filters[graph->filter_count - 1]);
347 ffcaef34 Vitor Sessak
    av_freep(&graph->filters);
348
}
349
350 57d4a157 Vitor Sessak
/* TODO: insert in sorted order */
351 b9a7a65a Vitor Sessak
void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter)
352 ffcaef34 Vitor Sessak
{
353 b9a7a65a Vitor Sessak
    GraphContext *graph = graphctx->priv;
354 eccb6fb7 Vitor Sessak
355
    graph->filters = av_realloc(graph->filters,
356
                                sizeof(AVFilterContext*) * ++graph->filter_count);
357
    graph->filters[graph->filter_count - 1] = filter;
358
}
359
360 57d4a157 Vitor Sessak
/* search intelligently, once we insert in order */
361
AVFilterContext *avfilter_graph_get_filter(AVFilterContext *ctx, char *name)
362
{
363
    GraphContext *graph = ctx->priv;
364
    int i;
365
366
    if(!name)
367
        return NULL;
368
369
    for(i = 0; i < graph->filter_count; i ++)
370
        if(graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
371
            return graph->filters[i];
372
373
    return NULL;
374
}
375
376 7b470878 Vitor Sessak
static int query_formats(AVFilterContext *graphctx)
377
{
378
    GraphContext *graph = graphctx->priv;
379 f3f42a3c Vitor Sessak
    AVFilterContext *linkfiltin  = graph->link_filter_in;
380
    AVFilterContext *linkfiltout = graph->link_filter_out;
381 7b470878 Vitor Sessak
    int i, j;
382
383
    /* ask all the sub-filters for their supported colorspaces */
384
    for(i = 0; i < graph->filter_count; i ++) {
385
        if(graph->filters[i]->filter->query_formats)
386
            graph->filters[i]->filter->query_formats(graph->filters[i]);
387
        else
388
            avfilter_default_query_formats(graph->filters[i]);
389
    }
390
391
    /* use these formats on our exported links */
392 f3f42a3c Vitor Sessak
    for(i = 0; i < linkfiltout->input_count; i ++) {
393
        avfilter_formats_ref( linkfiltout->inputs[i]->in_formats,
394
                             &linkfiltout->inputs[i]->out_formats);
395 7b470878 Vitor Sessak
396
        if(graphctx->outputs[i])
397 f3f42a3c Vitor Sessak
            avfilter_formats_ref(linkfiltout->inputs[i]->in_formats,
398 7b470878 Vitor Sessak
                                 &graphctx->outputs[i]->in_formats);
399
    }
400 f3f42a3c Vitor Sessak
    for(i = 0; i < linkfiltin->output_count; i ++) {
401
        avfilter_formats_ref( linkfiltin->outputs[i]->out_formats,
402
                             &linkfiltin->outputs[i]->in_formats);
403 7b470878 Vitor Sessak
404
        if(graphctx->inputs[i])
405 f3f42a3c Vitor Sessak
            avfilter_formats_ref(linkfiltin->outputs[i]->out_formats,
406 7b470878 Vitor Sessak
                                 &graphctx-> inputs[i]->out_formats);
407
    }
408
409
    /* go through and merge as many format lists as possible */
410
    for(i = 0; i < graph->filter_count; i ++) {
411
        AVFilterContext *filter = graph->filters[i];
412
413
        for(j = 0; j < filter->input_count; j ++) {
414
            AVFilterLink *link;
415
            if(!(link = filter->inputs[j]))
416
                continue;
417
            if(link->in_formats != link->out_formats) {
418
                if(!avfilter_merge_formats(link->in_formats,
419
                                           link->out_formats)) {
420
                    /* couldn't merge format lists. auto-insert scale filter */
421
                    AVFilterContext *scale;
422
423 3ec394ea Vitor Sessak
                    if(!(scale =
424
                         avfilter_open(avfilter_get_by_name("scale"), NULL)))
425 7b470878 Vitor Sessak
                        return -1;
426
                    if(scale->filter->init(scale, NULL, NULL) ||
427
                       avfilter_insert_filter(link, scale, 0, 0)) {
428
                        avfilter_destroy(scale);
429
                        return -1;
430
                    }
431
432
                    avfilter_graph_add_filter(graphctx, scale);
433
                    scale->filter->query_formats(scale);
434 de5985b6 Vitor Sessak
                    if(!avfilter_merge_formats(scale-> inputs[0]->in_formats,
435 7b470878 Vitor Sessak
                                              scale-> inputs[0]->out_formats) ||
436 de5985b6 Vitor Sessak
                       !avfilter_merge_formats(scale->outputs[0]->in_formats,
437 7b470878 Vitor Sessak
                                              scale->outputs[0]->out_formats))
438
                        return -1;
439
                }
440
            }
441
        }
442
    }
443
444
    return 0;
445
}
446
447
static void pick_format(AVFilterLink *link)
448
{
449
    if(!link || !link->in_formats)
450
        return;
451
452
    link->in_formats->format_count = 1;
453
    link->format = link->in_formats->formats[0];
454
455
    avfilter_formats_unref(&link->in_formats);
456
    avfilter_formats_unref(&link->out_formats);
457
}
458
459
static void pick_formats(GraphContext *graph)
460
{
461
    int i, j;
462
463
    for(i = 0; i < graph->filter_count; i ++) {
464
        AVFilterContext *filter = graph->filters[i];
465
466 789210fa Vitor Sessak
        if(filter->filter == &avfilter_vf_graph)
467 7b470878 Vitor Sessak
            pick_formats(filter->priv);
468
469
        for(j = 0; j < filter->input_count; j ++)
470
            pick_format(filter->inputs[j]);
471
        for(j = 0; j < filter->output_count; j ++)
472
            pick_format(filter->outputs[j]);
473
    }
474
}
475
476
int avfilter_graph_config_formats(AVFilterContext *graphctx)
477
{
478
    GraphContext *graph = graphctx->priv;
479
480 ec8398a3 Vitor Sessak
    /* find supported formats from sub-filters, and merge along links */
481 7b470878 Vitor Sessak
    if(query_formats(graphctx))
482
        return -1;
483
484
    /* Once everything is merged, it's possible that we'll still have
485 177ff260 Vitor Sessak
     * multiple valid colorspace choices. We pick the first one. */
486 7b470878 Vitor Sessak
    pick_formats(graph);
487
488
    return 0;
489
}
490
491 45a09319 Vitor Sessak
static int graph_load_from_desc2(AVFilterContext *ctx, AVFilterGraphDesc *desc)
492 57d4a157 Vitor Sessak
{
493
    AVFilterGraphDescFilter *curfilt;
494
    AVFilterGraphDescLink   *curlink;
495
    AVFilterContext *filt, *filtb;
496
497 d1633ac6 Vitor Sessak
    AVFilter *filterdef;
498 789210fa Vitor Sessak
    char tmp[20];
499 d1633ac6 Vitor Sessak
500 57d4a157 Vitor Sessak
    /* create all filters */
501
    for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) {
502 789210fa Vitor Sessak
        snprintf(tmp, 20, "%d", curfilt->index);
503 d1633ac6 Vitor Sessak
        if(!(filterdef = avfilter_get_by_name(curfilt->filter)) ||
504 789210fa Vitor Sessak
           !(filt = avfilter_open(filterdef, tmp))) {
505 affadb5b Vitor Sessak
            av_log(ctx, AV_LOG_ERROR,
506 789210fa Vitor Sessak
               "error creating filter '%s'\n", curfilt->filter);
507 57d4a157 Vitor Sessak
            goto fail;
508
        }
509
        avfilter_graph_add_filter(ctx, filt);
510
        if(avfilter_init_filter(filt, curfilt->args, NULL)) {
511 affadb5b Vitor Sessak
            av_log(ctx, AV_LOG_ERROR,
512 789210fa Vitor Sessak
                "error initializing filter '%s'\n", curfilt->filter);
513 57d4a157 Vitor Sessak
            goto fail;
514
        }
515
    }
516
517
    /* create all links */
518
    for(curlink = desc->links; curlink; curlink = curlink->next) {
519 789210fa Vitor Sessak
        snprintf(tmp, 20, "%d", curlink->src);
520
        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
521 57d4a157 Vitor Sessak
            av_log(ctx, AV_LOG_ERROR, "link source does not exist in graph\n");
522
            goto fail;
523
        }
524 789210fa Vitor Sessak
        snprintf(tmp, 20, "%d", curlink->dst);
525
        if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) {
526 57d4a157 Vitor Sessak
            av_log(ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
527
            goto fail;
528
        }
529
        if(avfilter_link(filt, curlink->srcpad, filtb, curlink->dstpad)) {
530
            av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
531
            goto fail;
532
        }
533
    }
534
535 45a09319 Vitor Sessak
    return 0;
536
537
fail:
538
    uninit(ctx);
539
    return -1;
540
}
541
542
static int graph_load_from_desc(AVFilterContext *ctx, AVFilterGraphDesc *desc)
543
{
544
    AVFilterGraphDescExport *curpad;
545
    char tmp[20];
546
    AVFilterContext *filt;
547
548
    if (graph_load_from_desc2(ctx, desc) < 0)
549
        goto fail;
550
551 57d4a157 Vitor Sessak
    /* export all input pads */
552
    for(curpad = desc->inputs; curpad; curpad = curpad->next) {
553 789210fa Vitor Sessak
        snprintf(tmp, 20, "%d", curpad->filter);
554
        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
555 57d4a157 Vitor Sessak
            av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
556
            goto fail;
557
        }
558
        add_graph_input(ctx, filt, curpad->pad, curpad->name);
559
    }
560
561
    /* export all output pads */
562
    for(curpad = desc->outputs; curpad; curpad = curpad->next) {
563 789210fa Vitor Sessak
        snprintf(tmp, 20, "%d", curpad->filter);
564
        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
565 57d4a157 Vitor Sessak
            av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
566
            goto fail;
567
        }
568
        add_graph_output(ctx, filt, curpad->pad, curpad->name);
569
    }
570
571
    return 0;
572
573
fail:
574
    uninit(ctx);
575
    return -1;
576
}
577
578 45a09319 Vitor Sessak
int graph_load_from_desc3(AVFilterContext *ctx, AVFilterGraphDesc *desc, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad)
579
{
580
    AVFilterGraphDescExport *curpad;
581
    char tmp[20];
582
    AVFilterContext *filt;
583
584
    if (graph_load_from_desc2(ctx, desc) < 0)
585
        goto fail;
586
587
    /* export all input pads */
588
    for(curpad = desc->inputs; curpad; curpad = curpad->next) {
589
        snprintf(tmp, 20, "%d", curpad->filter);
590
        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
591
            av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
592
            goto fail;
593
        }
594
        if(avfilter_link(in, inpad, filt, curpad->pad)) {
595
            av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
596
            goto fail;
597
        }
598
    }
599
600
    /* export all output pads */
601
    for(curpad = desc->outputs; curpad; curpad = curpad->next) {
602
        snprintf(tmp, 20, "%d", curpad->filter);
603
        if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
604
            av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
605
            goto fail;
606
        }
607
608
        if(avfilter_link(filt, curpad->pad, out, outpad)) {
609
            av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
610
            goto fail;
611
        }
612
    }
613
614
    return 0;
615
616
fail:
617
    uninit(ctx);
618
    return -1;
619
}
620
621 d22ebb1b Vitor Sessak
static int init(AVFilterContext *ctx, const char *args, void *opaque)
622
{
623
    GraphContext *gctx = ctx->priv;
624
    AVFilterGraphDesc *desc;
625
    int ret;
626
627 f3f42a3c Vitor Sessak
    if(!(gctx->link_filter_in = avfilter_open(&vf_graph_dummy, NULL)))
628 d22ebb1b Vitor Sessak
        return -1;
629 f3f42a3c Vitor Sessak
    if(avfilter_init_filter(gctx->link_filter_in, NULL, ctx))
630
        goto fail;
631
    if(!(gctx->link_filter_out = avfilter_open(&vf_graph_dummy, NULL)))
632
        goto fail;
633
    if(avfilter_init_filter(gctx->link_filter_out, NULL, ctx))
634 d22ebb1b Vitor Sessak
        goto fail;
635
636
    if(!args)
637
        return 0;
638
639
    if(!(desc = avfilter_graph_parse_chain(args)))
640
        goto fail;
641
642
    ret = graph_load_from_desc(ctx, desc);
643
    avfilter_graph_free_desc(desc);
644
    return ret;
645
646
fail:
647 f3f42a3c Vitor Sessak
    avfilter_destroy(gctx->link_filter_in);
648
    if(gctx->link_filter_out)
649
        avfilter_destroy(gctx->link_filter_out);
650 d22ebb1b Vitor Sessak
    return -1;
651
}
652
653
AVFilter avfilter_vf_graph =
654
{
655
    .name      = "graph",
656
657
    .priv_size = sizeof(GraphContext),
658
659
    .init      = init,
660
    .uninit    = uninit,
661
662
    .query_formats = query_formats,
663
664
    .inputs    = (AVFilterPad[]) {{ .name = NULL, }},
665
    .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
666
};