Revision d2027baa

View differences:

libavfilter/avfiltergraph.c
26 26
#include "avfilter.h"
27 27
#include "avfiltergraph.h"
28 28

  
29
/**
30
 * For use in av_log
31
 */
32
static const char *log_name(void *p)
33
{
34
    return "Filter parser";
35
}
36

  
37
static const AVClass filter_parser_class = {
38
    "Filter parser",
39
    log_name
40
};
41

  
42
static const AVClass *log_ctx = &filter_parser_class;
43

  
44 29
void avfilter_destroy_graph(AVFilterGraph *graph)
45 30
{
46 31
    for(; graph->filter_count > 0; graph->filter_count --)
......
48 33
    av_freep(&graph->filters);
49 34
}
50 35

  
51
/* TODO: insert in sorted order */
36
/**
37
 * @todo insert in sorted order
38
 */
52 39
void avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
53 40
{
54 41
    graph->filters = av_realloc(graph->filters,
......
56 43
    graph->filters[graph->filter_count - 1] = filter;
57 44
}
58 45

  
59
/* search intelligently, once we insert in order */
46
/*
47
 * @todo search intelligently, once we insert in order
48
 */
60 49
AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
61 50
{
62 51
    int i;
......
160 149
    return 0;
161 150
}
162 151

  
163
static int create_filter(AVFilterGraph *ctx, int index, char *name,
164
                         char *args)
165
{
166
    AVFilterContext *filt;
167

  
168
    AVFilter *filterdef;
169
    char tmp[20];
170

  
171
    snprintf(tmp, 20, "%d", index);
172
    if(!(filterdef = avfilter_get_by_name(name)) ||
173
       !(filt = avfilter_open(filterdef, tmp))) {
174
        av_log(&log_ctx, AV_LOG_ERROR,
175
               "error creating filter '%s'\n", name);
176
        return -1;
177
    }
178
    avfilter_graph_add_filter(ctx, filt);
179
    if(avfilter_init_filter(filt, args, NULL)) {
180
        av_log(&log_ctx, AV_LOG_ERROR,
181
               "error initializing filter '%s'\n", name);
182
        return -1;
183
    }
184

  
185
    return 0;
186
}
187

  
188
static int link_filter(AVFilterGraph *ctx, int src, int srcpad,
189
                       int dst, int dstpad)
190
{
191
    AVFilterContext *filt, *filtb;
192

  
193
    char tmp[20];
194

  
195
    snprintf(tmp, 20, "%d", src);
196
    if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
197
        av_log(&log_ctx, AV_LOG_ERROR, "link source does not exist in graph\n");
198
        return -1;
199
    }
200
    snprintf(tmp, 20, "%d", dst);
201
    if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) {
202
        av_log(&log_ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
203
        return -1;
204
    }
205
    if(avfilter_link(filt, srcpad, filtb, dstpad)) {
206
        av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
207
        return -1;
208
    }
209

  
210
    return 0;
211
}
212

  
213
static void consume_whitespace(const char **buf)
214
{
215
    *buf += strspn(*buf, " \n\t");
216
}
217

  
218
/**
219
 * Copy the first size bytes of input string to a null-terminated string,
220
 * removing any control character. Ex: "aaa'bb'c\'c\\" -> "aaabbc'c\"
221
 */
222
static void copy_unquoted(char *out, const char *in, int size)
223
{
224
    int i;
225
    for (i=0; i < size; i++) {
226
        if (in[i] == '\'')
227
            continue;
228
        else if (in[i] == '\\') {
229
            if (i+1 == size) {
230
                *out = 0;
231
                return;
232
            }
233
            i++;
234
        }
235
        *out++ = in[i];
236
    }
237
    *out=0;
238
}
239

  
240
/**
241
 * Consumes a string from *buf.
242
 * @return a copy of the consumed string, which should be free'd after use
243
 */
244
static char *consume_string(const char **buf)
245
{
246
    const char *start;
247
    char *ret;
248
    int size;
249

  
250
    consume_whitespace(buf);
251

  
252
    if (!(**buf))
253
        return av_mallocz(1);
254

  
255
    start = *buf;
256

  
257
    while(1) {
258
        *buf += strcspn(*buf, " ()=,'\\");
259
        if (**buf == '\\')
260
            *buf+=2;
261
        else
262
            break;
263
    }
264

  
265
    if (**buf == '\'') {
266
        const char *p = *buf;
267
        do {
268
            p++;
269
            p = strchr(p, '\'');
270
        } while (p && p[-1] == '\\');
271
        if (p)
272
            *buf = p + 1;
273
        else
274
            *buf += strlen(*buf); // Move the pointer to the null end byte
275
    }
276

  
277
    size = *buf - start + 1;
278
    ret = av_malloc(size);
279
    copy_unquoted(ret, start, size-1);
280

  
281
    return ret;
282
}
283

  
284
/**
285
 * Parse "(linkname)"
286
 * @arg name a pointer (that need to be free'd after use) to the name between
287
 *           parenthesis
288
 */
289
static void parse_link_name(const char **buf, char **name)
290
{
291
    (*buf)++;
292

  
293
    *name = consume_string(buf);
294

  
295
    if (!*name[0])
296
        goto fail;
297

  
298
    if (*(*buf)++ != ')')
299
        goto fail;
300

  
301
    return;
302
 fail:
303
    av_freep(name);
304
    av_log(&log_ctx, AV_LOG_ERROR, "Could not parse link name!\n");
305
}
306

  
307
/**
308
 * Parse "filter=params"
309
 * @arg name a pointer (that need to be free'd after use) to the name of the
310
 *           filter
311
 * @arg ars  a pointer (that need to be free'd after use) to the args of the
312
 *           filter
313
 */
314
static int parse_filter(const char **buf, AVFilterGraph *graph, int index)
315
{
316
    char *name, *opts;
317
    name = consume_string(buf);
318

  
319
    if (**buf == '=') {
320
        (*buf)++;
321
        opts = consume_string(buf);
322
    } else {
323
        opts = NULL;
324
    }
325

  
326
    return create_filter(graph, index, name, opts);
327
}
328

  
329
enum LinkType {
330
    LinkTypeIn,
331
    LinkTypeOut,
332
};
333

  
334
/**
335
 * A linked-list of the inputs/outputs of the filter chain.
336
 */
337
typedef struct AVFilterInOut {
338
    enum LinkType type;
339
    char *name;
340
    int instance;
341
    int pad_idx;
342

  
343
    struct AVFilterInOut *next;
344
} AVFilterInOut;
345

  
346
static void free_inout(AVFilterInOut *head)
347
{
348
    while (head) {
349
        AVFilterInOut *next;
350
        next = head->next;
351
        av_free(head);
352
        head = next;
353
    }
354
}
355

  
356
/**
357
 * Parse "(a1)(link2) ... (etc)"
358
 */
359
static int parse_inouts(const char **buf, AVFilterInOut **inout, int firstpad,
360
                        enum LinkType type, int instance)
361
{
362
    int pad = firstpad;
363
    while (**buf == '(') {
364
        AVFilterInOut *inoutn = av_malloc(sizeof(AVFilterInOut));
365
        parse_link_name(buf, &inoutn->name);
366
        inoutn->type = type;
367
        inoutn->instance = instance;
368
        inoutn->pad_idx = pad++;
369
        inoutn->next = *inout;
370
        *inout = inoutn;
371
    }
372
    return pad;
373
}
374

  
375
/**
376
 * Parse a string describing a filter graph.
377
 */
378
int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad)
379
{
380
    AVFilterInOut *inout=NULL;
381
    AVFilterInOut  *head=NULL;
382

  
383
    int index = 0;
384
    char chr = 0;
385
    int pad = 0;
386
    int has_out = 0;
387

  
388
    char tmp[20];
389
    AVFilterContext *filt;
390

  
391
    consume_whitespace(&filters);
392

  
393
    do {
394
        int oldpad = pad;
395

  
396
        pad = parse_inouts(&filters, &inout, chr == ',', LinkTypeIn, index);
397

  
398
        if (parse_filter(&filters, graph, index) < 0)
399
            goto fail;
400

  
401
        // If the first filter has an input and none was given, it is
402
        // implicitly the input of the whole graph.
403
        if (pad == 0 && graph->filters[graph->filter_count-1]->input_count == 1) {
404
            snprintf(tmp, 20, "%d", index);
405
            if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
406
                av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
407
                goto fail;
408
            }
409
            if(avfilter_link(in, inpad, filt, 0)) {
410
                av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
411
                goto fail;
412
            }
413
        }
414

  
415
        if(chr == ',') {
416
            if (link_filter(graph, index-1, oldpad, index, 0) < 0)
417
                goto fail;
418

  
419
        }
420
        pad = parse_inouts(&filters, &inout, 0, LinkTypeOut, index);
421
        chr = *filters++;
422
        index++;
423
    } while (chr == ',' || chr == ';');
424

  
425
    head = inout;
426
    for (; inout != NULL; inout = inout->next) {
427
        if (inout->instance == -1)
428
            continue; // Already processed
429

  
430
        if (!strcmp(inout->name, "in")) {
431
            snprintf(tmp, 20, "%d", inout->instance);
432
            if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
433
                av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
434
                goto fail;
435
            }
436
            if(avfilter_link(in, inpad, filt, inout->pad_idx)) {
437
                av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
438
                goto fail;
439
            }
440
        } else if (!strcmp(inout->name, "out")) {
441
            has_out = 1;
442
            snprintf(tmp, 20, "%d", inout->instance);
443
            if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
444
                av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
445
                goto fail;
446
            }
447

  
448
            if(avfilter_link(filt, inout->pad_idx, out, outpad)) {
449
                av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
450
                goto fail;
451
        }
452

  
453
        } else {
454
            AVFilterInOut *p, *src, *dst;
455
            for (p = inout->next;
456
                 p && strcmp(p->name,inout->name); p = p->next);
457

  
458
            if (!p) {
459
                av_log(&log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
460
                       inout->name);
461
                goto fail;
462
            }
463

  
464
            if (p->type == LinkTypeIn && inout->type == LinkTypeOut) {
465
                src = inout;
466
                dst = p;
467
            } else if (p->type == LinkTypeOut && inout->type == LinkTypeIn) {
468
                src = p;
469
                dst = inout;
470
            } else {
471
                av_log(&log_ctx, AV_LOG_ERROR, "Two links named '%s' are either both input or both output\n",
472
                       inout->name);
473
                goto fail;
474
            }
475

  
476
            if (link_filter(graph, src->instance, src->pad_idx, dst->instance, dst->pad_idx) < 0)
477
                goto fail;
478

  
479
            src->instance = -1;
480
            dst->instance = -1;
481
        }
482
    }
483

  
484
    free_inout(head);
485

  
486
    if (!has_out) {
487
        snprintf(tmp, 20, "%d", index-1);
488
        if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
489
            av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
490
            goto fail;
491
        }
492

  
493
        if(avfilter_link(filt, pad, out, outpad)) {
494
            av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
495
            goto fail;
496
        }
497

  
498
    }
499

  
500
    return 0;
501

  
502
 fail:
503
    free_inout(head);
504
    avfilter_destroy_graph(graph);
505
    return -1;
506
}
libavfilter/avfiltergraph.h
30 30
} AVFilterGraph;
31 31

  
32 32
/**
33
 * Add to a graph a graph described by a string.
34
 * @param graph   the filter graph where to link the parsed graph context
35
 * @param filters string to be parsed
36
 * @param in      input to the graph to be parsed (TODO: allow several)
37
 * @param inpad   pad index of the input
38
 * @param in      output to the graph to be parsed (TODO: allow several)
39
 * @param inpad   pad index of the output
40
 * @return        zero on success, -1 on error
33
 * Get a pointer to a graph by instance name
41 34
 */
42
int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad);
35
AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name);
43 36

  
44 37
/**
45 38
 * Add an existing filter instance to a filter graph.

Also available in: Unified diff