* qatar/master: vsrc_buffer: fix check from 7ae7c41. libxvid: Reorder functions to avoid forward declarations; make functions static. libxvid: drop some pointless dead code wmal: vertical alignment cosmetics wmal: Warn about missing bitstream splicing feature and ask for sample. wmal: Skip seekable_frame_in_packet. wmal: Drop unused variable num_possible_block_size. avfiltergraph: make the AVFilterInOut alloc/free API public graphparser: allow specifying sws flags in the graph description. graphparser: fix the order of connecting unlabeled links. graphparser: add avfilter_graph_parse2(). vsrc_buffer: allow using a NULL buffer to signal EOF. swscale: handle last pixel if lines have an odd width. qdm2: fix a dubious pointer cast WMAL: Do not try to read rawpcm coefficients if bits is invalid mov: Fix detecting there is no sync sample. tiffdec: K&R cosmetics avf: has_duration does not check the global one dsputil: fix optimized emu_edge function on Win64. Conflicts: doc/APIchanges libavcodec/libxvid_rc.c libavcodec/libxvidff.c libavcodec/tiff.c libavcodec/wmalosslessdec.c libavfilter/avfiltergraph.h libavfilter/graphparser.c libavfilter/version.h libavfilter/vsrc_buffer.c libswscale/output.c
Showing the changes to libavfilter/graphparser.c (1 of 18 files). Show all
Unified · Split
| @@ -189,13 +189,15 @@ static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links) · 188 unmodified lines | |||
| 189 | { | 189 | { |
| 190 | AVFilterInOut *ret; | 190 | AVFilterInOut *ret; |
| 191 | 191 | ||
| 192 | while (*links && strcmp((*links)->name, label)) | 192 | while (*links && (!(*links)->name || strcmp((*links)->name, label))) |
| 193 | links = &((*links)->next); | 193 | links = &((*links)->next); |
| 194 | 194 | ||
| 195 | ret = *links; | 195 | ret = *links; |
| 196 | 196 | ||
| 197 | if (ret) | 197 | if (ret) { |
| 198 | *links = ret->next; | 198 | *links = ret->next; |
| 199 | ret->next = NULL; | ||
| 200 | } | ||
| 199 | 201 | ||
| 200 | return ret; | 202 | return ret; |
| 201 | } | 203 | } |
| @@ -206,22 +208,31 @@ static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element) · 4 unmodified lines | |||
| 206 | *inouts = element; | 208 | *inouts = element; |
| 207 | } | 209 | } |
| 208 | 210 | ||
| 211 | static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element) | ||
| 212 | { | ||
| 213 | while (*inouts && (*inouts)->next) | ||
| 214 | inouts = &((*inouts)->next); | ||
| 215 | |||
| 216 | if (!*inouts) | ||
| 217 | *inouts = *element; | ||
| 218 | else | ||
| 219 | (*inouts)->next = *element; | ||
| 220 | *element = NULL; | ||
| 221 | } | ||
| 222 | |||
| 209 | static int link_filter_inouts(AVFilterContext *filt_ctx, | 223 | static int link_filter_inouts(AVFilterContext *filt_ctx, |
| 210 | AVFilterInOut **curr_inputs, | 224 | AVFilterInOut **curr_inputs, |
| 211 | AVFilterInOut **open_inputs, void *log_ctx) | 225 | AVFilterInOut **open_inputs, void *log_ctx) |
| 212 | { | 226 | { |
| 213 | int pad = filt_ctx->input_count, ret; | 227 | int pad, ret; |
| 214 | 228 | ||
| 215 | while (pad--) { | 229 | for (pad = 0; pad < filt_ctx->input_count; pad++) { |
| 216 | AVFilterInOut *p = *curr_inputs; | 230 | AVFilterInOut *p = *curr_inputs; |
| 217 | if (!p) { | ||
| 218 | av_log(log_ctx, AV_LOG_ERROR, | ||
| 219 | "Not enough inputs specified for the \"%s\" filter.\n", | ||
| 220 | filt_ctx->filter->name); | ||
| 221 | return AVERROR(EINVAL); | ||
| 222 | } | ||
| 223 | 231 | ||
| 224 | *curr_inputs = (*curr_inputs)->next; | 232 | if (p) |
| 233 | *curr_inputs = (*curr_inputs)->next; | ||
| 234 | else if (!(p = av_mallocz(sizeof(*p)))) | ||
| 235 | return AVERROR(ENOMEM); | ||
| 225 | 236 | ||
| 226 | if (p->filter_ctx) { | 237 | if (p->filter_ctx) { |
| 227 | if ((ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx)) < 0) | 238 | if ((ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx)) < 0) |
| @@ -258,6 +269,7 @@ static int link_filter_inouts(AVFilterContext *filt_ctx, · 30 unmodified lines | |||
| 258 | static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs, | 269 | static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs, |
| 259 | AVFilterInOut **open_outputs, void *log_ctx) | 270 | AVFilterInOut **open_outputs, void *log_ctx) |
| 260 | { | 271 | { |
| 272 | AVFilterInOut *parsed_inputs = NULL; | ||
| 261 | int pad = 0; | 273 | int pad = 0; |
| 262 | 274 | ||
| 263 | while (**buf == '[') { | 275 | while (**buf == '[') { |
| @@ -280,12 +292,15 @@ static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs, · 16 unmodified lines | |||
| 280 | match->pad_idx = pad; | 292 | match->pad_idx = pad; |
| 281 | } | 293 | } |
| 282 | 294 | ||
| 283 | insert_inout(curr_inputs, match); | 295 | append_inout(&parsed_inputs, &match); |
| 284 | 296 | ||
| 285 | *buf += strspn(*buf, WHITESPACES); | 297 | *buf += strspn(*buf, WHITESPACES); |
| 286 | pad++; | 298 | pad++; |
| 287 | } | 299 | } |
| 288 | 300 | ||
| 301 | append_inout(&parsed_inputs, curr_inputs); | ||
| 302 | *curr_inputs = parsed_inputs; | ||
| 303 | |||
| 289 | return pad; | 304 | return pad; |
| 290 | } | 305 | } |
| 291 | 306 | ||
| @@ -334,10 +349,173 @@ static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs, · 42 unmodified lines | |||
| 334 | return pad; | 349 | return pad; |
| 335 | } | 350 | } |
| 336 | 351 | ||
| 352 | #if FF_API_GRAPH_AVCLASS | ||
| 353 | #define log_ctx graph | ||
| 354 | #else | ||
| 355 | #define log_ctx NULL | ||
| 356 | #endif | ||
| 357 | |||
| 358 | static int parse_sws_flags(const char **buf, AVFilterGraph *graph) | ||
| 359 | { | ||
| 360 | char *p = strchr(*buf, ';'); | ||
| 361 | |||
| 362 | if (strncmp(*buf, "sws_flags=", 10)) | ||
| 363 | return 0; | ||
| 364 | |||
| 365 | if (!p) { | ||
| 366 | av_log(log_ctx, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n"); | ||
| 367 | return AVERROR(EINVAL); | ||
| 368 | } | ||
| 369 | |||
| 370 | *buf += 4; // keep the 'flags=' part | ||
| 371 | |||
| 372 | av_freep(&graph->scale_sws_opts); | ||
| 373 | if (!(graph->scale_sws_opts = av_mallocz(p - *buf + 1))) | ||
| 374 | return AVERROR(ENOMEM); | ||
| 375 | av_strlcpy(graph->scale_sws_opts, *buf, p - *buf + 1); | ||
| 376 | |||
| 377 | *buf = p + 1; | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, | ||
| 382 | AVFilterInOut **inputs, | ||
| 383 | AVFilterInOut **outputs) | ||
| 384 | { | ||
| 385 | int index = 0, ret = 0; | ||
| 386 | char chr = 0; | ||
| 387 | |||
| 388 | AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL; | ||
| 389 | |||
| 390 | filters += strspn(filters, WHITESPACES); | ||
| 391 | |||
| 392 | if ((ret = parse_sws_flags(&filters, graph)) < 0) | ||
| 393 | goto fail; | ||
| 394 | |||
| 395 | do { | ||
| 396 | AVFilterContext *filter; | ||
| 397 | filters += strspn(filters, WHITESPACES); | ||
| 398 | |||
| 399 | if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0) | ||
| 400 | goto end; | ||
| 401 | |||
| 402 | if ((ret = parse_filter(&filter, &filters, graph, index, log_ctx)) < 0) | ||
| 403 | goto end; | ||
| 404 | |||
| 405 | if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx)) < 0) | ||
| 406 | goto end; | ||
| 407 | |||
| 408 | if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs, | ||
| 409 | log_ctx)) < 0) | ||
| 410 | goto end; | ||
| 411 | |||
| 412 | filters += strspn(filters, WHITESPACES); | ||
| 413 | chr = *filters++; | ||
| 414 | |||
| 415 | if (chr == ';' && curr_inputs) | ||
| 416 | append_inout(&open_outputs, &curr_inputs); | ||
| 417 | index++; | ||
| 418 | } while (chr == ',' || chr == ';'); | ||
| 419 | |||
| 420 | if (chr) { | ||
| 421 | av_log(log_ctx, AV_LOG_ERROR, | ||
| 422 | "Unable to parse graph description substring: \"%s\"\n", | ||
| 423 | filters - 1); | ||
| 424 | ret = AVERROR(EINVAL); | ||
| 425 | goto end; | ||
| 426 | } | ||
| 427 | |||
| 428 | append_inout(&open_outputs, &curr_inputs); | ||
| 429 | |||
| 430 | |||
| 431 | *inputs = open_inputs; | ||
| 432 | *outputs = open_outputs; | ||
| 433 | return 0; | ||
| 434 | |||
| 435 | fail:end: | ||
| 436 | for (; graph->filter_count > 0; graph->filter_count--) | ||
| 437 | avfilter_free(graph->filters[graph->filter_count - 1]); | ||
| 438 | av_freep(&graph->filters); | ||
| 439 | avfilter_inout_free(&open_inputs); | ||
| 440 | avfilter_inout_free(&open_outputs); | ||
| 441 | avfilter_inout_free(&curr_inputs); | ||
| 442 | |||
| 443 | *inputs = NULL; | ||
| 444 | *outputs = NULL; | ||
| 445 | |||
| 446 | return ret; | ||
| 447 | } | ||
| 448 | #undef log_ctx | ||
| 449 | |||
| 337 | int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, | 450 | int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, |
| 338 | AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr, | 451 | AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr, |
| 339 | void *log_ctx) | 452 | void *log_ctx) |
| 340 | { | 453 | { |
| 454 | #if 0 | ||
| 455 | int ret; | ||
| 456 | AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL; | ||
| 457 | AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL; | ||
| 458 | AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL; | ||
| 459 | |||
| 460 | if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0) | ||
| 461 | goto fail; | ||
| 462 | |||
| 463 | /* First input can be omitted if it is "[in]" */ | ||
| 464 | if (inputs && !inputs->name) | ||
| 465 | inputs->name = av_strdup("in"); | ||
| 466 | for (cur = inputs; cur; cur = cur->next) { | ||
| 467 | if (!cur->name) { | ||
| 468 | av_log(log_ctx, AV_LOG_ERROR, | ||
| 469 | "Not enough inputs specified for the \"%s\" filter.\n", | ||
| 470 | cur->filter_ctx->filter->name); | ||
| 471 | ret = AVERROR(EINVAL); | ||
| 472 | goto fail; | ||
| 473 | } | ||
| 474 | if (!(match = extract_inout(cur->name, &open_outputs))) | ||
| 475 | continue; | ||
| 476 | ret = avfilter_link(match->filter_ctx, match->pad_idx, | ||
| 477 | cur->filter_ctx, cur->pad_idx); | ||
| 478 | avfilter_inout_free(&match); | ||
| 479 | if (ret < 0) | ||
| 480 | goto fail; | ||
| 481 | } | ||
| 482 | |||
| 483 | /* Last output can be omitted if it is "[out]" */ | ||
| 484 | if (outputs && !outputs->name) | ||
| 485 | outputs->name = av_strdup("out"); | ||
| 486 | for (cur = outputs; cur; cur = cur->next) { | ||
| 487 | if (!cur->name) { | ||
| 488 | av_log(log_ctx, AV_LOG_ERROR, | ||
| 489 | "Invalid filterchain containing an unlabelled output pad: \"%s\"\n", | ||
| 490 | filters); | ||
| 491 | ret = AVERROR(EINVAL); | ||
| 492 | goto fail; | ||
| 493 | } | ||
| 494 | if (!(match = extract_inout(cur->name, &open_inputs))) | ||
| 495 | continue; | ||
| 496 | ret = avfilter_link(cur->filter_ctx, cur->pad_idx, | ||
| 497 | match->filter_ctx, match->pad_idx); | ||
| 498 | avfilter_inout_free(&match); | ||
| 499 | if (ret < 0) | ||
| 500 | goto fail; | ||
| 501 | } | ||
| 502 | |||
| 503 | fail: | ||
| 504 | if (ret < 0) { | ||
| 505 | for (; graph->filter_count > 0; graph->filter_count--) | ||
| 506 | avfilter_free(graph->filters[graph->filter_count - 1]); | ||
| 507 | av_freep(&graph->filters); | ||
| 508 | } | ||
| 509 | avfilter_inout_free(&inputs); | ||
| 510 | avfilter_inout_free(&outputs); | ||
| 511 | /* clear open_in/outputs only if not passed as parameters */ | ||
| 512 | if (open_inputs_ptr) *open_inputs_ptr = open_inputs; | ||
| 513 | else avfilter_inout_free(&open_inputs); | ||
| 514 | if (open_outputs_ptr) *open_outputs_ptr = open_outputs; | ||
| 515 | else avfilter_inout_free(&open_outputs); | ||
| 516 | return ret; | ||
| 517 | } | ||
| 518 | #else | ||
| 341 | int index = 0, ret = 0; | 519 | int index = 0, ret = 0; |
| 342 | char chr = 0; | 520 | char chr = 0; |
| 343 | 521 | ||
| @@ -414,3 +592,5 @@ end: · 70 unmodified lines | |||
| 414 | } | 592 | } |
| 415 | return ret; | 593 | return ret; |
| 416 | } | 594 | } |
| 595 | |||
| 596 | #endif | ||