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
Unified · Split
| @@ -26,49 +26,6 @@ · 25 unmodified lines | ||
| 26 | 26 | #include "avfilter.h" |
| 27 | 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 | 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 | 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 | 213 | static void consume_whitespace(const char **buf) |
| 315 | 214 | { |
| 316 | 215 | *buf += strspn(*buf, " \n\t"); |
| @@ -415,17 +314,19 @@ static void parse_link_name(const char **buf, char **name) · 98 unmodified lines | ||
| 415 | 314 | * @arg ars a pointer (that need to be free'd after use) to the args of the |
| 416 | 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 | 322 | if (**buf == '=') { |
| 423 | 323 | consume_char(buf); |
| 424 | − *opts = consume_string(buf); | |
| 324 | + opts = consume_string(buf); | |
| 425 | 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 | 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) | |
| 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) | |
| 381 | +int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) | |
| 512 | 382 | { |
| 513 | − AVFilterGraphDesc *ret; | |
| 514 | − AVFilterGraphDescFilter **filterp, *filtern; | |
| 515 | − AVFilterGraphDescLink **linkp, *linkn; | |
| 516 | 383 | AVFilterInOut *inout=NULL; |
| 517 | − AVFilterInOut *head; | |
| 384 | + AVFilterInOut *head=NULL; | |
| 518 | 385 | |
| 519 | 386 | int index = 0; |
| 520 | 387 | char chr = 0; |
| 521 | 388 | int pad = 0; |
| 522 | 389 | int has_out = 0; |
| 523 | 390 | |
| 391 | + char tmp[20]; | |
| 392 | + AVFilterContext *filt; | |
| 393 | + | |
| 524 | 394 | consume_whitespace(&filters); |
| 525 | 395 | |
| 526 | − if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc)))) | |
| 527 | − return NULL; | |
| 396 | + do { | |
| 397 | + int oldpad = pad; | |
| 528 | 398 | |
| 529 | − filterp = &ret->filters; | |
| 530 | − linkp = &ret->links; | |
| 399 | + pad = parse_inouts(&filters, &inout, chr == ',', LinkTypeIn, index); | |
| 531 | 400 | |
| 532 | − do { | |
| 533 | − if(chr == ',') { | |
| 534 | − linkn = av_mallocz(sizeof(AVFilterGraphDescLink)); | |
| 535 | − linkn->src = index-1; | |
| 536 | − linkn->srcpad = pad; | |
| 537 | − linkn->dst = index; | |
| 538 | − linkn->dstpad = 0; | |
| 539 | − | |
| 540 | − *linkp = linkn; | |
| 541 | − linkp = &linkn->next; | |
| 401 | + if (parse_filter(&filters, graph, index) < 0) | |
| 402 | + goto fail; | |
| 403 | + | |
| 404 | + // If the first filter has an input and none was given, it is | |
| 405 | + // implicitly the input of the whole graph. | |
| 406 | + if (pad == 0 && graph->filters[graph->filter_count-1]->input_count == 1) { | |
| 407 | + snprintf(tmp, 20, "%d", index); | |
| 408 | + if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | |
| 409 | + av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | |
| 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)); | |
| 547 | − filtern->index = index; | |
| 548 | − parse_filter(&filters, &filtern->filter, &filtern->args); | |
| 549 | − *filterp = filtern; | |
| 550 | − filterp = &filtern->next; | |
| 418 | + if(chr == ',') { | |
| 419 | + if (link_filter(graph, index-1, oldpad, index, 0) < 0) | |
| 420 | + goto fail; | |
| 551 | 421 | |
| 552 | − pad = parse_inouts(&filters, &inout, 0, | |
| 553 | − LinkTypeOut, index); | |
| 422 | + } | |
| 423 | + pad = parse_inouts(&filters, &inout, 0, LinkTypeOut, index); | |
| 554 | 424 | chr = consume_char(&filters); |
| 555 | 425 | index++; |
| 556 | 426 | } while (chr == ',' || chr == ';'); |
| @@ -561,16 +431,28 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 4 unmodified lines | ||
| 561 | 431 | continue; // Already processed |
| 562 | 432 | |
| 563 | 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 | 441 | goto fail; |
| 566 | − ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | |
| 567 | − ret->inputs->filter = inout->instance; | |
| 568 | − ret->inputs->pad = inout->pad_idx; | |
| 442 | + } | |
| 569 | 443 | } else if (!strcmp(inout->name, "out")) { |
| 570 | 444 | has_out = 1; |
| 571 | − ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | |
| 572 | − ret->outputs->filter = inout->instance; | |
| 573 | − ret->outputs->pad = inout->pad_idx; | |
| 445 | + snprintf(tmp, 20, "%d", inout->instance); | |
| 446 | + if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | |
| 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 | 456 | } else { |
| 575 | 457 | AVFilterInOut *p, *src, *dst; |
| 576 | 458 | for (p = inout->next; |
| @@ -593,15 +475,9 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 16 unmodified lines | ||
| 593 | 475 | inout->name); |
| 594 | 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; | |
| 604 | − linkp = &linkn->next; | |
| 479 | + if (link_filter(graph, src->instance, src->pad_idx, dst->instance, dst->pad_idx) < 0) | |
| 480 | + goto fail; | |
| 605 | 481 | |
| 606 | 482 | src->instance = -1; |
| 607 | 483 | dst->instance = -1; |
| @@ -610,44 +486,24 @@ static AVFilterGraphDesc *parse_chain(const char *filters, int has_in) · 2 unmodified lines | ||
| 610 | 486 | |
| 611 | 487 | free_inout(head); |
| 612 | 488 | |
| 613 | − if (!has_in) { | |
| 614 | − ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | |
| 615 | − ret->inputs->filter = 0; | |
| 616 | − } | |
| 617 | 489 | if (!has_out) { |
| 618 | − ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport)); | |
| 619 | − ret->outputs->filter = index-1; | |
| 620 | − } | |
| 621 | − | |
| 622 | − return ret; | |
| 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; | |
| 490 | + snprintf(tmp, 20, "%d", index-1); | |
| 491 | + if(!(filt = avfilter_graph_get_filter(graph, tmp))) { | |
| 492 | + av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | |
| 493 | + goto fail; | |
| 494 | + } | |
| 637 | 495 | |
| 638 | − /* Try first to parse supposing there is no (in) element */ | |
| 639 | − if (!(desc = parse_chain(filters, 0))) { | |
| 640 | − /* If it didn't work, parse supposing there is an (in) element */ | |
| 641 | − desc = parse_chain(filters, 1); | |
| 642 | − } | |
| 643 | − if (!desc) | |
| 644 | − return -1; | |
| 496 | + if(avfilter_link(filt, pad, out, outpad)) { | |
| 497 | + av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | |
| 498 | + goto fail; | |
| 499 | + } | |
| 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 | 503 | return 0; |
| 504 | + | |
| 505 | + fail: | |
| 506 | + free_inout(head); | |
| 507 | + avfilter_destroy_graph(graph); | |
| 508 | + return -1; | |
| 653 | 509 | } |