annotate ffmpeg/libavfilter/graphparser.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
yading@10 1 /*
yading@10 2 * filter graph parser
yading@10 3 * Copyright (c) 2008 Vitor Sessak
yading@10 4 * Copyright (c) 2007 Bobby Bingham
yading@10 5 *
yading@10 6 * This file is part of FFmpeg.
yading@10 7 *
yading@10 8 * FFmpeg is free software; you can redistribute it and/or
yading@10 9 * modify it under the terms of the GNU Lesser General Public
yading@10 10 * License as published by the Free Software Foundation; either
yading@10 11 * version 2.1 of the License, or (at your option) any later version.
yading@10 12 *
yading@10 13 * FFmpeg is distributed in the hope that it will be useful,
yading@10 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 16 * Lesser General Public License for more details.
yading@10 17 *
yading@10 18 * You should have received a copy of the GNU Lesser General Public
yading@10 19 * License along with FFmpeg; if not, write to the Free Software
yading@10 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 21 */
yading@10 22
yading@10 23 #include <string.h>
yading@10 24 #include <stdio.h>
yading@10 25
yading@10 26 #include "libavutil/avstring.h"
yading@10 27 #include "libavutil/mem.h"
yading@10 28 #include "avfilter.h"
yading@10 29
yading@10 30 #define WHITESPACES " \n\t"
yading@10 31
yading@10 32 /**
yading@10 33 * Link two filters together.
yading@10 34 *
yading@10 35 * @see avfilter_link()
yading@10 36 */
yading@10 37 static int link_filter(AVFilterContext *src, int srcpad,
yading@10 38 AVFilterContext *dst, int dstpad,
yading@10 39 void *log_ctx)
yading@10 40 {
yading@10 41 int ret;
yading@10 42 if ((ret = avfilter_link(src, srcpad, dst, dstpad))) {
yading@10 43 av_log(log_ctx, AV_LOG_ERROR,
yading@10 44 "Cannot create the link %s:%d -> %s:%d\n",
yading@10 45 src->filter->name, srcpad, dst->filter->name, dstpad);
yading@10 46 return ret;
yading@10 47 }
yading@10 48
yading@10 49 return 0;
yading@10 50 }
yading@10 51
yading@10 52 /**
yading@10 53 * Parse the name of a link, which has the format "[linkname]".
yading@10 54 *
yading@10 55 * @return a pointer (that need to be freed after use) to the name
yading@10 56 * between parenthesis
yading@10 57 */
yading@10 58 static char *parse_link_name(const char **buf, void *log_ctx)
yading@10 59 {
yading@10 60 const char *start = *buf;
yading@10 61 char *name;
yading@10 62 (*buf)++;
yading@10 63
yading@10 64 name = av_get_token(buf, "]");
yading@10 65
yading@10 66 if (!name[0]) {
yading@10 67 av_log(log_ctx, AV_LOG_ERROR,
yading@10 68 "Bad (empty?) label found in the following: \"%s\".\n", start);
yading@10 69 goto fail;
yading@10 70 }
yading@10 71
yading@10 72 if (*(*buf)++ != ']') {
yading@10 73 av_log(log_ctx, AV_LOG_ERROR,
yading@10 74 "Mismatched '[' found in the following: \"%s\".\n", start);
yading@10 75 fail:
yading@10 76 av_freep(&name);
yading@10 77 }
yading@10 78
yading@10 79 return name;
yading@10 80 }
yading@10 81
yading@10 82 /**
yading@10 83 * Create an instance of a filter, initialize and insert it in the
yading@10 84 * filtergraph in *ctx.
yading@10 85 *
yading@10 86 * @param filt_ctx put here a filter context in case of successful creation and configuration, NULL otherwise.
yading@10 87 * @param ctx the filtergraph context
yading@10 88 * @param index an index which is supposed to be unique for each filter instance added to the filtergraph
yading@10 89 * @param filt_name the name of the filter to create
yading@10 90 * @param args the arguments provided to the filter during its initialization
yading@10 91 * @param log_ctx the log context to use
yading@10 92 * @return 0 in case of success, a negative AVERROR code otherwise
yading@10 93 */
yading@10 94 static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int index,
yading@10 95 const char *filt_name, const char *args, void *log_ctx)
yading@10 96 {
yading@10 97 AVFilter *filt;
yading@10 98 char inst_name[30];
yading@10 99 char tmp_args[256];
yading@10 100 int ret;
yading@10 101
yading@10 102 snprintf(inst_name, sizeof(inst_name), "Parsed_%s_%d", filt_name, index);
yading@10 103
yading@10 104 filt = avfilter_get_by_name(filt_name);
yading@10 105
yading@10 106 if (!filt) {
yading@10 107 av_log(log_ctx, AV_LOG_ERROR,
yading@10 108 "No such filter: '%s'\n", filt_name);
yading@10 109 return AVERROR(EINVAL);
yading@10 110 }
yading@10 111
yading@10 112 *filt_ctx = avfilter_graph_alloc_filter(ctx, filt, inst_name);
yading@10 113 if (!*filt_ctx) {
yading@10 114 av_log(log_ctx, AV_LOG_ERROR,
yading@10 115 "Error creating filter '%s'\n", filt_name);
yading@10 116 return AVERROR(ENOMEM);
yading@10 117 }
yading@10 118
yading@10 119 if (!strcmp(filt_name, "scale") && args && !strstr(args, "flags") &&
yading@10 120 ctx->scale_sws_opts) {
yading@10 121 snprintf(tmp_args, sizeof(tmp_args), "%s:%s",
yading@10 122 args, ctx->scale_sws_opts);
yading@10 123 args = tmp_args;
yading@10 124 }
yading@10 125
yading@10 126 ret = avfilter_init_str(*filt_ctx, args);
yading@10 127 if (ret < 0) {
yading@10 128 av_log(log_ctx, AV_LOG_ERROR,
yading@10 129 "Error initializing filter '%s' with args '%s'\n", filt_name, args);
yading@10 130 return ret;
yading@10 131 }
yading@10 132
yading@10 133 return 0;
yading@10 134 }
yading@10 135
yading@10 136 /**
yading@10 137 * Parse a string of the form FILTER_NAME[=PARAMS], and create a
yading@10 138 * corresponding filter instance which is added to graph with
yading@10 139 * create_filter().
yading@10 140 *
yading@10 141 * @param filt_ctx Pointer that is set to the created and configured filter
yading@10 142 * context on success, set to NULL on failure.
yading@10 143 * @param filt_ctx put here a pointer to the created filter context on
yading@10 144 * success, NULL otherwise
yading@10 145 * @param buf pointer to the buffer to parse, *buf will be updated to
yading@10 146 * point to the char next after the parsed string
yading@10 147 * @param index an index which is assigned to the created filter
yading@10 148 * instance, and which is supposed to be unique for each filter
yading@10 149 * instance added to the filtergraph
yading@10 150 * @return 0 in case of success, a negative AVERROR code otherwise
yading@10 151 */
yading@10 152 static int parse_filter(AVFilterContext **filt_ctx, const char **buf, AVFilterGraph *graph,
yading@10 153 int index, void *log_ctx)
yading@10 154 {
yading@10 155 char *opts = NULL;
yading@10 156 char *name = av_get_token(buf, "=,;[\n");
yading@10 157 int ret;
yading@10 158
yading@10 159 if (**buf == '=') {
yading@10 160 (*buf)++;
yading@10 161 opts = av_get_token(buf, "[],;\n");
yading@10 162 }
yading@10 163
yading@10 164 ret = create_filter(filt_ctx, graph, index, name, opts, log_ctx);
yading@10 165 av_free(name);
yading@10 166 av_free(opts);
yading@10 167 return ret;
yading@10 168 }
yading@10 169
yading@10 170 AVFilterInOut *avfilter_inout_alloc(void)
yading@10 171 {
yading@10 172 return av_mallocz(sizeof(AVFilterInOut));
yading@10 173 }
yading@10 174
yading@10 175 void avfilter_inout_free(AVFilterInOut **inout)
yading@10 176 {
yading@10 177 while (*inout) {
yading@10 178 AVFilterInOut *next = (*inout)->next;
yading@10 179 av_freep(&(*inout)->name);
yading@10 180 av_freep(inout);
yading@10 181 *inout = next;
yading@10 182 }
yading@10 183 }
yading@10 184
yading@10 185 static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
yading@10 186 {
yading@10 187 AVFilterInOut *ret;
yading@10 188
yading@10 189 while (*links && (!(*links)->name || strcmp((*links)->name, label)))
yading@10 190 links = &((*links)->next);
yading@10 191
yading@10 192 ret = *links;
yading@10 193
yading@10 194 if (ret) {
yading@10 195 *links = ret->next;
yading@10 196 ret->next = NULL;
yading@10 197 }
yading@10 198
yading@10 199 return ret;
yading@10 200 }
yading@10 201
yading@10 202 static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
yading@10 203 {
yading@10 204 element->next = *inouts;
yading@10 205 *inouts = element;
yading@10 206 }
yading@10 207
yading@10 208 static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
yading@10 209 {
yading@10 210 while (*inouts && (*inouts)->next)
yading@10 211 inouts = &((*inouts)->next);
yading@10 212
yading@10 213 if (!*inouts)
yading@10 214 *inouts = *element;
yading@10 215 else
yading@10 216 (*inouts)->next = *element;
yading@10 217 *element = NULL;
yading@10 218 }
yading@10 219
yading@10 220 static int link_filter_inouts(AVFilterContext *filt_ctx,
yading@10 221 AVFilterInOut **curr_inputs,
yading@10 222 AVFilterInOut **open_inputs, void *log_ctx)
yading@10 223 {
yading@10 224 int pad, ret;
yading@10 225
yading@10 226 for (pad = 0; pad < filt_ctx->nb_inputs; pad++) {
yading@10 227 AVFilterInOut *p = *curr_inputs;
yading@10 228
yading@10 229 if (p) {
yading@10 230 *curr_inputs = (*curr_inputs)->next;
yading@10 231 p->next = NULL;
yading@10 232 } else if (!(p = av_mallocz(sizeof(*p))))
yading@10 233 return AVERROR(ENOMEM);
yading@10 234
yading@10 235 if (p->filter_ctx) {
yading@10 236 ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx);
yading@10 237 av_free(p->name);
yading@10 238 av_free(p);
yading@10 239 if (ret < 0)
yading@10 240 return ret;
yading@10 241 } else {
yading@10 242 p->filter_ctx = filt_ctx;
yading@10 243 p->pad_idx = pad;
yading@10 244 append_inout(open_inputs, &p);
yading@10 245 }
yading@10 246 }
yading@10 247
yading@10 248 if (*curr_inputs) {
yading@10 249 av_log(log_ctx, AV_LOG_ERROR,
yading@10 250 "Too many inputs specified for the \"%s\" filter.\n",
yading@10 251 filt_ctx->filter->name);
yading@10 252 return AVERROR(EINVAL);
yading@10 253 }
yading@10 254
yading@10 255 pad = filt_ctx->nb_outputs;
yading@10 256 while (pad--) {
yading@10 257 AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut));
yading@10 258 if (!currlinkn)
yading@10 259 return AVERROR(ENOMEM);
yading@10 260 currlinkn->filter_ctx = filt_ctx;
yading@10 261 currlinkn->pad_idx = pad;
yading@10 262 insert_inout(curr_inputs, currlinkn);
yading@10 263 }
yading@10 264
yading@10 265 return 0;
yading@10 266 }
yading@10 267
yading@10 268 static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs,
yading@10 269 AVFilterInOut **open_outputs, void *log_ctx)
yading@10 270 {
yading@10 271 AVFilterInOut *parsed_inputs = NULL;
yading@10 272 int pad = 0;
yading@10 273
yading@10 274 while (**buf == '[') {
yading@10 275 char *name = parse_link_name(buf, log_ctx);
yading@10 276 AVFilterInOut *match;
yading@10 277
yading@10 278 if (!name)
yading@10 279 return AVERROR(EINVAL);
yading@10 280
yading@10 281 /* First check if the label is not in the open_outputs list */
yading@10 282 match = extract_inout(name, open_outputs);
yading@10 283
yading@10 284 if (match) {
yading@10 285 av_free(name);
yading@10 286 } else {
yading@10 287 /* Not in the list, so add it as an input */
yading@10 288 if (!(match = av_mallocz(sizeof(AVFilterInOut)))) {
yading@10 289 av_free(name);
yading@10 290 return AVERROR(ENOMEM);
yading@10 291 }
yading@10 292 match->name = name;
yading@10 293 match->pad_idx = pad;
yading@10 294 }
yading@10 295
yading@10 296 append_inout(&parsed_inputs, &match);
yading@10 297
yading@10 298 *buf += strspn(*buf, WHITESPACES);
yading@10 299 pad++;
yading@10 300 }
yading@10 301
yading@10 302 append_inout(&parsed_inputs, curr_inputs);
yading@10 303 *curr_inputs = parsed_inputs;
yading@10 304
yading@10 305 return pad;
yading@10 306 }
yading@10 307
yading@10 308 static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
yading@10 309 AVFilterInOut **open_inputs,
yading@10 310 AVFilterInOut **open_outputs, void *log_ctx)
yading@10 311 {
yading@10 312 int ret, pad = 0;
yading@10 313
yading@10 314 while (**buf == '[') {
yading@10 315 char *name = parse_link_name(buf, log_ctx);
yading@10 316 AVFilterInOut *match;
yading@10 317
yading@10 318 AVFilterInOut *input = *curr_inputs;
yading@10 319
yading@10 320 if (!name)
yading@10 321 return AVERROR(EINVAL);
yading@10 322
yading@10 323 if (!input) {
yading@10 324 av_log(log_ctx, AV_LOG_ERROR,
yading@10 325 "No output pad can be associated to link label '%s'.\n", name);
yading@10 326 av_free(name);
yading@10 327 return AVERROR(EINVAL);
yading@10 328 }
yading@10 329 *curr_inputs = (*curr_inputs)->next;
yading@10 330
yading@10 331 /* First check if the label is not in the open_inputs list */
yading@10 332 match = extract_inout(name, open_inputs);
yading@10 333
yading@10 334 if (match) {
yading@10 335 if ((ret = link_filter(input->filter_ctx, input->pad_idx,
yading@10 336 match->filter_ctx, match->pad_idx, log_ctx)) < 0) {
yading@10 337 av_free(name);
yading@10 338 return ret;
yading@10 339 }
yading@10 340 av_free(match->name);
yading@10 341 av_free(name);
yading@10 342 av_free(match);
yading@10 343 av_free(input);
yading@10 344 } else {
yading@10 345 /* Not in the list, so add the first input as a open_output */
yading@10 346 input->name = name;
yading@10 347 insert_inout(open_outputs, input);
yading@10 348 }
yading@10 349 *buf += strspn(*buf, WHITESPACES);
yading@10 350 pad++;
yading@10 351 }
yading@10 352
yading@10 353 return pad;
yading@10 354 }
yading@10 355
yading@10 356 static int parse_sws_flags(const char **buf, AVFilterGraph *graph)
yading@10 357 {
yading@10 358 char *p = strchr(*buf, ';');
yading@10 359
yading@10 360 if (strncmp(*buf, "sws_flags=", 10))
yading@10 361 return 0;
yading@10 362
yading@10 363 if (!p) {
yading@10 364 av_log(graph, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n");
yading@10 365 return AVERROR(EINVAL);
yading@10 366 }
yading@10 367
yading@10 368 *buf += 4; // keep the 'flags=' part
yading@10 369
yading@10 370 av_freep(&graph->scale_sws_opts);
yading@10 371 if (!(graph->scale_sws_opts = av_mallocz(p - *buf + 1)))
yading@10 372 return AVERROR(ENOMEM);
yading@10 373 av_strlcpy(graph->scale_sws_opts, *buf, p - *buf + 1);
yading@10 374
yading@10 375 *buf = p + 1;
yading@10 376 return 0;
yading@10 377 }
yading@10 378
yading@10 379 int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
yading@10 380 AVFilterInOut **inputs,
yading@10 381 AVFilterInOut **outputs)
yading@10 382 {
yading@10 383 int index = 0, ret = 0;
yading@10 384 char chr = 0;
yading@10 385
yading@10 386 AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL;
yading@10 387
yading@10 388 filters += strspn(filters, WHITESPACES);
yading@10 389
yading@10 390 if ((ret = parse_sws_flags(&filters, graph)) < 0)
yading@10 391 goto fail;
yading@10 392
yading@10 393 do {
yading@10 394 AVFilterContext *filter;
yading@10 395 filters += strspn(filters, WHITESPACES);
yading@10 396
yading@10 397 if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, graph)) < 0)
yading@10 398 goto end;
yading@10 399 if ((ret = parse_filter(&filter, &filters, graph, index, graph)) < 0)
yading@10 400 goto end;
yading@10 401
yading@10 402
yading@10 403 if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, graph)) < 0)
yading@10 404 goto end;
yading@10 405
yading@10 406 if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
yading@10 407 graph)) < 0)
yading@10 408 goto end;
yading@10 409
yading@10 410 filters += strspn(filters, WHITESPACES);
yading@10 411 chr = *filters++;
yading@10 412
yading@10 413 if (chr == ';' && curr_inputs)
yading@10 414 append_inout(&open_outputs, &curr_inputs);
yading@10 415 index++;
yading@10 416 } while (chr == ',' || chr == ';');
yading@10 417
yading@10 418 if (chr) {
yading@10 419 av_log(graph, AV_LOG_ERROR,
yading@10 420 "Unable to parse graph description substring: \"%s\"\n",
yading@10 421 filters - 1);
yading@10 422 ret = AVERROR(EINVAL);
yading@10 423 goto end;
yading@10 424 }
yading@10 425
yading@10 426 append_inout(&open_outputs, &curr_inputs);
yading@10 427
yading@10 428
yading@10 429 *inputs = open_inputs;
yading@10 430 *outputs = open_outputs;
yading@10 431 return 0;
yading@10 432
yading@10 433 fail:end:
yading@10 434 while (graph->nb_filters)
yading@10 435 avfilter_free(graph->filters[0]);
yading@10 436 av_freep(&graph->filters);
yading@10 437 avfilter_inout_free(&open_inputs);
yading@10 438 avfilter_inout_free(&open_outputs);
yading@10 439 avfilter_inout_free(&curr_inputs);
yading@10 440
yading@10 441 *inputs = NULL;
yading@10 442 *outputs = NULL;
yading@10 443
yading@10 444 return ret;
yading@10 445 }
yading@10 446
yading@10 447 int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
yading@10 448 AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr,
yading@10 449 void *log_ctx)
yading@10 450 {
yading@10 451 #if 0
yading@10 452 int ret;
yading@10 453 AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
yading@10 454 AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
yading@10 455 AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL;
yading@10 456
yading@10 457 if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0)
yading@10 458 goto fail;
yading@10 459
yading@10 460 /* First input can be omitted if it is "[in]" */
yading@10 461 if (inputs && !inputs->name)
yading@10 462 inputs->name = av_strdup("in");
yading@10 463 for (cur = inputs; cur; cur = cur->next) {
yading@10 464 if (!cur->name) {
yading@10 465 av_log(log_ctx, AV_LOG_ERROR,
yading@10 466 "Not enough inputs specified for the \"%s\" filter.\n",
yading@10 467 cur->filter_ctx->filter->name);
yading@10 468 ret = AVERROR(EINVAL);
yading@10 469 goto fail;
yading@10 470 }
yading@10 471 if (!(match = extract_inout(cur->name, &open_outputs)))
yading@10 472 continue;
yading@10 473 ret = avfilter_link(match->filter_ctx, match->pad_idx,
yading@10 474 cur->filter_ctx, cur->pad_idx);
yading@10 475 avfilter_inout_free(&match);
yading@10 476 if (ret < 0)
yading@10 477 goto fail;
yading@10 478 }
yading@10 479
yading@10 480 /* Last output can be omitted if it is "[out]" */
yading@10 481 if (outputs && !outputs->name)
yading@10 482 outputs->name = av_strdup("out");
yading@10 483 for (cur = outputs; cur; cur = cur->next) {
yading@10 484 if (!cur->name) {
yading@10 485 av_log(log_ctx, AV_LOG_ERROR,
yading@10 486 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
yading@10 487 filters);
yading@10 488 ret = AVERROR(EINVAL);
yading@10 489 goto fail;
yading@10 490 }
yading@10 491 if (!(match = extract_inout(cur->name, &open_inputs)))
yading@10 492 continue;
yading@10 493 ret = avfilter_link(cur->filter_ctx, cur->pad_idx,
yading@10 494 match->filter_ctx, match->pad_idx);
yading@10 495 avfilter_inout_free(&match);
yading@10 496 if (ret < 0)
yading@10 497 goto fail;
yading@10 498 }
yading@10 499
yading@10 500 fail:
yading@10 501 if (ret < 0) {
yading@10 502 while (graph->nb_filters)
yading@10 503 avfilter_free(graph->filters[0]);
yading@10 504 av_freep(&graph->filters);
yading@10 505 }
yading@10 506 avfilter_inout_free(&inputs);
yading@10 507 avfilter_inout_free(&outputs);
yading@10 508 /* clear open_in/outputs only if not passed as parameters */
yading@10 509 if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
yading@10 510 else avfilter_inout_free(&open_inputs);
yading@10 511 if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
yading@10 512 else avfilter_inout_free(&open_outputs);
yading@10 513 return ret;
yading@10 514 }
yading@10 515 #else
yading@10 516 int index = 0, ret = 0;
yading@10 517 char chr = 0;
yading@10 518
yading@10 519 AVFilterInOut *curr_inputs = NULL;
yading@10 520 AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
yading@10 521 AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
yading@10 522
yading@10 523 if ((ret = parse_sws_flags(&filters, graph)) < 0)
yading@10 524 goto end;
yading@10 525
yading@10 526 do {
yading@10 527 AVFilterContext *filter;
yading@10 528 const char *filterchain = filters;
yading@10 529 filters += strspn(filters, WHITESPACES);
yading@10 530
yading@10 531 if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0)
yading@10 532 goto end;
yading@10 533
yading@10 534 if ((ret = parse_filter(&filter, &filters, graph, index, log_ctx)) < 0)
yading@10 535 goto end;
yading@10 536
yading@10 537 if (filter->input_count == 1 && !curr_inputs && !index) {
yading@10 538 /* First input pad, assume it is "[in]" if not specified */
yading@10 539 const char *tmp = "[in]";
yading@10 540 if ((ret = parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx)) < 0)
yading@10 541 goto end;
yading@10 542 }
yading@10 543
yading@10 544 if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx)) < 0)
yading@10 545 goto end;
yading@10 546
yading@10 547 if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
yading@10 548 log_ctx)) < 0)
yading@10 549 goto end;
yading@10 550
yading@10 551 filters += strspn(filters, WHITESPACES);
yading@10 552 chr = *filters++;
yading@10 553
yading@10 554 if (chr == ';' && curr_inputs) {
yading@10 555 av_log(log_ctx, AV_LOG_ERROR,
yading@10 556 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
yading@10 557 filterchain);
yading@10 558 ret = AVERROR(EINVAL);
yading@10 559 goto end;
yading@10 560 }
yading@10 561 index++;
yading@10 562 } while (chr == ',' || chr == ';');
yading@10 563
yading@10 564 if (chr) {
yading@10 565 av_log(log_ctx, AV_LOG_ERROR,
yading@10 566 "Unable to parse graph description substring: \"%s\"\n",
yading@10 567 filters - 1);
yading@10 568 ret = AVERROR(EINVAL);
yading@10 569 goto end;
yading@10 570 }
yading@10 571
yading@10 572 if (curr_inputs) {
yading@10 573 /* Last output pad, assume it is "[out]" if not specified */
yading@10 574 const char *tmp = "[out]";
yading@10 575 if ((ret = parse_outputs(&tmp, &curr_inputs, &open_inputs, &open_outputs,
yading@10 576 log_ctx)) < 0)
yading@10 577 goto end;
yading@10 578 }
yading@10 579
yading@10 580 end:
yading@10 581 /* clear open_in/outputs only if not passed as parameters */
yading@10 582 if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
yading@10 583 else avfilter_inout_free(&open_inputs);
yading@10 584 if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
yading@10 585 else avfilter_inout_free(&open_outputs);
yading@10 586 avfilter_inout_free(&curr_inputs);
yading@10 587
yading@10 588 if (ret < 0) {
yading@10 589 while (graph->nb_filters)
yading@10 590 avfilter_free(graph->filters[0]);
yading@10 591 av_freep(&graph->filters);
yading@10 592 }
yading@10 593 return ret;
yading@10 594 }
yading@10 595
yading@10 596 #endif