Commited in SoC by Vitor Sessak on 2008-03-29 15:12:47 Originally committed as revision 12743 to svn://svn.ffmpeg.org/ffmpeg/trunk
Showing the changes to libavfilter/avfiltergraph.c (1 of 1 file). Show all
Unified · Split
| @@ -26,49 +26,6 @@ · 25 unmodified lines | |||
| 26 | #include "avfilter.h" | 26 | #include "avfilter.h" |
| 27 | #include "avfiltergraph.h" | 27 | #include "avfiltergraph.h" |
| 28 | 28 | ||
| 29 | |||
| 30 | /** Linked-list of filters to create for an AVFilterGraphDesc */ | ||
| 31 | typedef struct AVFilterGraphDescFilter | ||
| 32 | { | ||
| 33 | int index; ///< filter instance index | ||
| 34 | char *filter; ///< name of filter type | ||
| 35 | char *args; ///< filter parameters | ||
| 36 | struct AVFilterGraphDescFilter *next; | ||
| 37 | } AVFilterGraphDescFilter; | ||
| 38 | |||
| 39 | /** Linked-list of links between filters */ | ||
| 40 | typedef struct AVFilterGraphDescLink | ||
| 41 | { | ||
| 42 | /* TODO: allow referencing pads by name, not just by index */ | ||
| 43 | int src; ///< index of the source filter | ||
| 44 | unsigned srcpad; ///< index of the output pad on the source filter | ||
| 45 | |||
| 46 | int dst; ///< index of the dest filter | ||
| 47 | unsigned dstpad; ///< index of the input pad on the dest filter | ||
| 48 | |||
| 49 | struct AVFilterGraphDescLink *next; | ||
| 50 | } AVFilterGraphDescLink; | ||
| 51 | |||
| 52 | /** Linked-list of filter pads to be exported from the graph */ | ||
| 53 | typedef struct AVFilterGraphDescExport | ||
| 54 | { | ||
| 55 | /* TODO: allow referencing pads by name, not just by index */ | ||
| 56 | char *name; ///< name of the exported pad | ||
| 57 | int filter; ///< index of the filter | ||
| 58 | unsigned pad; ///< index of the pad to be exported | ||
| 59 | |||
| 60 | struct AVFilterGraphDescExport *next; | ||
| 61 | } AVFilterGraphDescExport; | ||
| 62 | |||
| 63 | /** Description of a graph to be loaded from a file, etc */ | ||
| 64 | typedef struct | ||
| 65 | { | ||
| 66 | AVFilterGraphDescFilter *filters; ///< filters in the graph | ||
| 67 | AVFilterGraphDescLink *links; ///< links between the filters | ||
| 68 | AVFilterGraphDescExport *inputs; ///< inputs to export | ||
| 69 | AVFilterGraphDescExport *outputs; ///< outputs to export | ||
| 70 | } AVFilterGraphDesc; | ||
| 71 | |||
| 72 | /** | 29 | /** |
| 73 | * For use in av_log | 30 | * For use in av_log |
| 74 | */ | 31 | */ |
| @@ -253,64 +210,6 @@ static int link_filter(AVFilterGraph *ctx, int src, int srcpad, · 178 unmodified lines | |||
| 253 | return 0; | 210 | return 0; |
| 254 | } | 211 | } |
| 255 | 212 | ||
| 256 | static int load_from_desc(AVFilterGraph *graph, AVFilterGraphDesc *desc, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) | ||
| 257 | { | ||
| 258 | AVFilterGraphDescExport *curpad; | ||
| 259 | char tmp[20]; | ||
| 260 | AVFilterContext *filt; | ||
| 261 | AVFilterGraphDescFilter *curfilt; | ||
| 262 | AVFilterGraphDescLink *curlink; | ||
| 263 | |||
| 264 | |||
| 265 | /* create all filters */ | ||
| 266 | for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) { | ||
| 267 | if (create_filter(graph, curfilt->index, curfilt->filter, | ||
| 268 | curfilt->args) < 0) | ||
| 269 | goto fail; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* create all links */ | ||
| 273 | for(curlink = desc->links; curlink; curlink = curlink->next) { | ||
| 274 | if (link_filter(graph, curlink->src, curlink->srcpad, | ||
| 275 | curlink->dst, curlink->dstpad) < 0) | ||
| 276 | goto fail; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* export all input pads */ | ||
| 280 | for(curpad = desc->inputs; curpad; curpad = curpad->next) { | ||
| 281 | snprintf(tmp, 20, "%d", curpad->filter); | ||
| 282 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | ||
| 283 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | ||
| 284 | goto fail; | ||
| 285 | } | ||
| 286 | if(avfilter_link(in, inpad, filt, curpad->pad)) { | ||
| 287 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | ||
| 288 | goto fail; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | /* export all output pads */ | ||
| 293 | for(curpad = desc->outputs; curpad; curpad = curpad->next) { | ||
| 294 | snprintf(tmp, 20, "%d", curpad->filter); | ||
| 295 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | ||
| 296 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | ||
| 297 | goto fail; | ||
| 298 | } | ||
| 299 | |||
| 300 | if(avfilter_link(filt, curpad->pad, out, outpad)) { | ||
| 301 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | ||
| 302 | goto fail; | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | return 0; | ||
| 307 | |||
| 308 | fail: | ||
| 309 | avfilter_destroy_graph(graph); | ||
| 310 | return -1; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | static void consume_whitespace(const char **buf) | 213 | static void consume_whitespace(const char **buf) |
| 315 | { | 214 | { |
| 316 | *buf += strspn(*buf, " \n\t"); | 215 | *buf += strspn(*buf, " \n\t"); |
| @@ -415,17 +314,19 @@ static void parse_link_name(const char **buf, char **name) · 98 unmodified lines | |||
| 415 | * @arg ars a pointer (that need to be free'd after use) to the args of the | 314 | * @arg ars a pointer (that need to be free'd after use) to the args of the |
| 416 | * filter | 315 | * filter |
| 417 | */ | 316 | */ |
| 418 | static void parse_filter(const char **buf, char **name, char **opts) | 317 | static int parse_filter(const char **buf, AVFilterGraph *graph, int index) |
| 419 | { | 318 | { |
| 420 | *name = consume_string(buf); | 319 | char *name, *opts; |
| 320 | name = consume_string(buf); | ||
| 421 | 321 | ||
| 422 | if (**buf == '=') { | 322 | if (**buf == '=') { |
| 423 | consume_char(buf); | 323 | consume_char(buf); |
| 424 | *opts = consume_string(buf); | 324 | opts = consume_string(buf); |
| 425 | } else { | 325 | } else { |
| 426 | *opts = NULL; | 326 | opts = NULL; |
| 427 | } | 327 | } |
| 428 | 328 | ||
| 329 | return create_filter(graph, index, name, opts); | ||
| 429 | } | 330 | } |
| 430 | 331 | ||
| 431 | enum LinkType { | 332 | enum LinkType { |
| @@ -475,82 +376,51 @@ static int parse_inouts(const char **buf, AVFilterInOut **inout, int firstpad, · 43 unmodified lines | |||
| 475 | } | 376 | } |
| 476 | 377 | ||
| 477 | /** | 378 | /** |
| 478 | * Free a graph description. | 379 | * Parse a string describing a filter graph. |
| 479 | */ | 380 | */ |
| 480 | static void free_desc(AVFilterGraphDesc *desc) | 381 | int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) |
| 481 | { | ||
| 482 | void *next; | ||
| 483 | |||
| 484 | while(desc->filters) { | ||
| 485 | next = desc->filters->next; | ||
| 486 | av_free(desc->filters->filter); | ||
| 487 | av_free(desc->filters->args); | ||
| 488 | av_free(desc->filters); | ||
| 489 | desc->filters = next; | ||
| 490 | } | ||
| 491 | |||
| 492 | while(desc->links) { | ||
| 493 | next = desc->links->next; | ||
| 494 | av_free(desc->links); | ||
| 495 | desc->links = next; | ||
| 496 | } | ||
| 497 | |||
| 498 | while(desc->inputs) { | ||
| 499 | next = desc->inputs->next; | ||
| 500 | av_free(desc->inputs); | ||
| 501 | desc->inputs = next; | ||
| 502 | } | ||
| 503 | |||
| 504 | while(desc->outputs) { | ||
| 505 | next = desc->outputs->next; | ||
| 506 | av_free(desc->outputs); | ||
| 507 | desc->outputs = next; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) | ||
| 512 | { | 382 | { |
| 513 | AVFilterGraphDesc *ret; | ||
| 514 | AVFilterGraphDescFilter **filterp, *filtern; | ||
| 515 | AVFilterGraphDescLink **linkp, *linkn; | ||
| 516 | AVFilterInOut *inout=NULL; | 383 | AVFilterInOut *inout=NULL; |
| 517 | AVFilterInOut *head; | 384 | AVFilterInOut *head=NULL; |
| 518 | 385 | ||
| 519 | int index = 0; | 386 | int index = 0; |
| 520 | char chr = 0; | 387 | char chr = 0; |
| 521 | int pad = 0; | 388 | int pad = 0; |
| 522 | int has_out = 0; | 389 | int has_out = 0; |
| 523 | 390 | ||
| 391 | char tmp[20]; | ||
| 392 | AVFilterContext *filt; | ||
| 393 | |||
| 524 | consume_whitespace(&filters); | 394 | consume_whitespace(&filters); |
| 525 | 395 | ||
| 526 | if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc)))) | 396 | do { |
| 527 | return NULL; | 397 | int oldpad = pad; |
| 528 | 398 | ||
| 529 | filterp = &ret->filters; | 399 | pad = parse_inouts(&filters, &inout, chr == ',', LinkTypeIn, index); |
| 530 | linkp = &ret->links; | ||
| 531 | 400 | ||
| 532 | do { | 401 | if (parse_filter(&filters, graph, index) < 0) |
| 533 | if(chr == ',') { | 402 | goto fail; |
| 534 | linkn = av_mallocz(sizeof(AVFilterGraphDescLink)); | 403 | |
| 535 | linkn->src = index-1; | 404 | // If the first filter has an input and none was given, it is |
| 536 | linkn->srcpad = pad; | 405 | // implicitly the input of the whole graph. |
| 537 | linkn->dst = index; | 406 | if (pad == 0 && graph->filters[graph->filter_count-1]->input_count == 1) { |
| 538 | linkn->dstpad = 0; | 407 | snprintf(tmp, 20, "%d", index); |
| 539 | 408 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | |
| 540 | *linkp = linkn; | 409 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); |
| 541 | linkp = &linkn->next; | 410 | goto fail; |
| 411 | } | ||
| 412 | if(avfilter_link(in, inpad, filt, 0)) { | ||
| 413 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | ||
| 414 | goto fail; | ||
| 415 | } | ||
| 542 | } | 416 | } |
| 543 | pad = parse_inouts(&filters, &inout, chr == ',' || (!has_in), | ||
| 544 | LinkTypeIn, index); | ||
| 545 | 417 | ||
| 546 | filtern = av_mallocz(sizeof(AVFilterGraphDescFilter)); | 418 | if(chr == ',') { |
| 547 | filtern->index = index; | 419 | if (link_filter(graph, index-1, oldpad, index, 0) < 0) |
| 548 | parse_filter(&filters, &filtern->filter, &filtern->args); | 420 | goto fail; |
| 549 | *filterp = filtern; | ||
| 550 | filterp = &filtern->next; | ||
| 551 | 421 | ||
| 552 | pad = parse_inouts(&filters, &inout, 0, | 422 | } |
| 553 | LinkTypeOut, index); | 423 | pad = parse_inouts(&filters, &inout, 0, LinkTypeOut, index); |
| 554 | chr = consume_char(&filters); | 424 | chr = consume_char(&filters); |
| 555 | index++; | 425 | index++; |
| 556 | } while (chr == ',' || chr == ';'); | 426 | } while (chr == ',' || chr == ';'); |
| @@ -561,16 +431,28 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 4 unmodified lines | |||
| 561 | continue; // Already processed | 431 | continue; // Already processed |
| 562 | 432 | ||
| 563 | if (!strcmp(inout->name, "in")) { | 433 | if (!strcmp(inout->name, "in")) { |
| 564 | if (!has_in) | 434 | snprintf(tmp, 20, "%d", inout->instance); |
| 435 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | ||
| 436 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | ||
| 437 | goto fail; | ||
| 438 | } | ||
| 439 | if(avfilter_link(in, inpad, filt, inout->pad_idx)) { | ||
| 440 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | ||
| 565 | goto fail; | 441 | goto fail; |
| 566 | ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | 442 | } |
| 567 | ret->inputs->filter = inout->instance; | ||
| 568 | ret->inputs->pad = inout->pad_idx; | ||
| 569 | } else if (!strcmp(inout->name, "out")) { | 443 | } else if (!strcmp(inout->name, "out")) { |
| 570 | has_out = 1; | 444 | has_out = 1; |
| 571 | ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | 445 | snprintf(tmp, 20, "%d", inout->instance); |
| 572 | ret->outputs->filter = inout->instance; | 446 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { |
| 573 | ret->outputs->pad = inout->pad_idx; | 447 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); |
| 448 | goto fail; | ||
| 449 | } | ||
| 450 | |||
| 451 | if(avfilter_link(filt, inout->pad_idx, out, outpad)) { | ||
| 452 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | ||
| 453 | goto fail; | ||
| 454 | } | ||
| 455 | |||
| 574 | } else { | 456 | } else { |
| 575 | AVFilterInOut *p, *src, *dst; | 457 | AVFilterInOut *p, *src, *dst; |
| 576 | for (p = inout->next; | 458 | for (p = inout->next; |
| @@ -593,15 +475,9 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 16 unmodified lines | |||
| 593 | inout->name); | 475 | inout->name); |
| 594 | goto fail; | 476 | goto fail; |
| 595 | } | 477 | } |
| 596 | linkn = av_mallocz(sizeof(AVFilterGraphDescLink)); | ||
| 597 | |||
| 598 | linkn->src = src->instance; | ||
| 599 | linkn->srcpad = src->pad_idx; | ||
| 600 | linkn->dst = dst->instance; | ||
| 601 | linkn->dstpad = dst->pad_idx; | ||
| 602 | 478 | ||
| 603 | *linkp = linkn; | 479 | if (link_filter(graph, src->instance, src->pad_idx, dst->instance, dst->pad_idx) < 0) |
| 604 | linkp = &linkn->next; | 480 | goto fail; |
| 605 | 481 | ||
| 606 | src->instance = -1; | 482 | src->instance = -1; |
| 607 | dst->instance = -1; | 483 | dst->instance = -1; |
| @@ -610,44 +486,24 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 2 unmodified lines | |||
| 610 | 486 | ||
| 611 | free_inout(head); | 487 | free_inout(head); |
| 612 | 488 | ||
| 613 | if (!has_in) { | ||
| 614 | ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | ||
| 615 | ret->inputs->filter = 0; | ||
| 616 | } | ||
| 617 | if (!has_out) { | 489 | if (!has_out) { |
| 618 | ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | 490 | snprintf(tmp, 20, "%d", index-1); |
| 619 | ret->outputs->filter = index-1; | 491 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { |
| 620 | } | 492 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); |
| 621 | 493 | goto fail; | |
| 622 | return ret; | 494 | } |
| 623 | |||
| 624 | fail: | ||
| 625 | free_inout(head); | ||
| 626 | |||
| 627 | free_desc(ret); | ||
| 628 | return NULL; | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * Parse a string describing a filter graph. | ||
| 633 | */ | ||
| 634 | int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) | ||
| 635 | { | ||
| 636 | AVFilterGraphDesc *desc; | ||
| 637 | 495 | ||
| 638 | /* Try first to parse supposing there is no (in) element */ | 496 | if(avfilter_link(filt, pad, out, outpad)) { |
| 639 | if (!(desc = parse_chain(filters, 0))) { | 497 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); |
| 640 | /* If it didn't work, parse supposing there is an (in) element */ | 498 | goto fail; |
| 641 | desc = parse_chain(filters, 1); | 499 | } |
| 642 | } | ||
| 643 | if (!desc) | ||
| 644 | return -1; | ||
| 645 | 500 | ||
| 646 | if (load_from_desc(graph, desc, in, inpad, out, outpad) < 0) { | ||
| 647 | free_desc(desc); | ||
| 648 | return -1; | ||
| 649 | } | 501 | } |
| 650 | 502 | ||
| 651 | free_desc(desc); | ||
| 652 | return 0; | 503 | return 0; |
| 504 | |||
| 505 | fail: | ||
| 506 | free_inout(head); | ||
| 507 | avfilter_destroy_graph(graph); | ||
| 508 | return -1; | ||
| 653 | } | 509 | } |