Showing the changes to libavfilter/avfiltergraph.c (1 of 4 files). Show all
Unified · Split
| @@ -25,8 +25,10 @@ · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | #include "avfilter.h" | 26 | #include "avfilter.h" |
| 27 | #include "avfiltergraph.h" | 27 | #include "avfiltergraph.h" |
| 28 | #include "formats.h" | ||
| 28 | #include "internal.h" | 29 | #include "internal.h" |
| 29 | 30 | ||
| 31 | #include "libavutil/audioconvert.h" | ||
| 30 | #include "libavutil/log.h" | 32 | #include "libavutil/log.h" |
| 31 | 33 | ||
| 32 | static const AVClass filtergraph_class = { | 34 | static const AVClass filtergraph_class = { |
| @@ -168,9 +170,27 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) · 135 unmodified lines | |||
| 168 | 170 | ||
| 169 | for (j = 0; j < filter->input_count; j++) { | 171 | for (j = 0; j < filter->input_count; j++) { |
| 170 | AVFilterLink *link = filter->inputs[j]; | 172 | AVFilterLink *link = filter->inputs[j]; |
| 171 | if (link && link->in_formats != link->out_formats) { | 173 | int convert_needed = 0; |
| 172 | if (!avfilter_merge_formats(link->in_formats, | 174 | |
| 173 | link->out_formats)) { | 175 | if (!link) |
| 176 | continue; | ||
| 177 | |||
| 178 | if (link->in_formats != link->out_formats && | ||
| 179 | !avfilter_merge_formats(link->in_formats, | ||
| 180 | link->out_formats)) | ||
| 181 | convert_needed = 1; | ||
| 182 | if (link->type == AVMEDIA_TYPE_AUDIO) { | ||
| 183 | if (link->in_channel_layouts != link->out_channel_layouts && | ||
| 184 | !ff_merge_channel_layouts(link->in_channel_layouts, | ||
| 185 | link->out_channel_layouts)) | ||
| 186 | convert_needed = 1; | ||
| 187 | if (link->in_samplerates != link->out_samplerates && | ||
| 188 | !ff_merge_samplerates(link->in_samplerates, | ||
| 189 | link->out_samplerates)) | ||
| 190 | convert_needed = 1; | ||
| 191 | } | ||
| 192 | |||
| 193 | if (convert_needed) { | ||
| 174 | AVFilterContext *convert; | 194 | AVFilterContext *convert; |
| 175 | AVFilter *filter; | 195 | AVFilter *filter; |
| 176 | AVFilterLink *inlink, *outlink; | 196 | AVFilterLink *inlink, *outlink; |
| @@ -214,13 +234,27 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) · 37 unmodified lines | |||
| 214 | inlink = convert->inputs[0]; | 234 | inlink = convert->inputs[0]; |
| 215 | outlink = convert->outputs[0]; | 235 | outlink = convert->outputs[0]; |
| 216 | if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || | 236 | if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || |
| 217 | !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) { | 237 | !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) |
| 238 | ret |= AVERROR(ENOSYS); | ||
| 239 | if (inlink->type == AVMEDIA_TYPE_AUDIO && | ||
| 240 | (!ff_merge_samplerates(inlink->in_samplerates, | ||
| 241 | inlink->out_samplerates) || | ||
| 242 | !ff_merge_channel_layouts(inlink->in_channel_layouts, | ||
| 243 | inlink->out_channel_layouts))) | ||
| 244 | ret |= AVERROR(ENOSYS); | ||
| 245 | if (outlink->type == AVMEDIA_TYPE_AUDIO && | ||
| 246 | (!ff_merge_samplerates(outlink->in_samplerates, | ||
| 247 | outlink->out_samplerates) || | ||
| 248 | !ff_merge_channel_layouts(outlink->in_channel_layouts, | ||
| 249 | outlink->out_channel_layouts))) | ||
| 250 | ret |= AVERROR(ENOSYS); | ||
| 251 | |||
| 252 | if (ret < 0) { | ||
| 218 | av_log(log_ctx, AV_LOG_ERROR, | 253 | av_log(log_ctx, AV_LOG_ERROR, |
| 219 | "Impossible to convert between the formats supported by the filter " | 254 | "Impossible to convert between the formats supported by the filter " |
| 220 | "'%s' and the filter '%s'\n", link->src->name, link->dst->name); | 255 | "'%s' and the filter '%s'\n", link->src->name, link->dst->name); |
| 221 | return AVERROR(EINVAL); | 256 | return ret; |
| 222 | } | 257 | } |
| 223 | } | ||
| 224 | } | 258 | } |
| 225 | } | 259 | } |
| 226 | } | 260 | } |
| @@ -228,46 +262,90 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) · 1 unmodified line | |||
| 228 | return 0; | 262 | return 0; |
| 229 | } | 263 | } |
| 230 | 264 | ||
| 231 | static void pick_format(AVFilterLink *link) | 265 | static int pick_format(AVFilterLink *link) |
| 232 | { | 266 | { |
| 233 | if (!link || !link->in_formats) | 267 | if (!link || !link->in_formats) |
| 234 | return; | 268 | return 0; |
| 235 | 269 | ||
| 236 | link->in_formats->format_count = 1; | 270 | link->in_formats->format_count = 1; |
| 237 | link->format = link->in_formats->formats[0]; | 271 | link->format = link->in_formats->formats[0]; |
| 238 | 272 | ||
| 273 | if (link->type == AVMEDIA_TYPE_AUDIO) { | ||
| 274 | if (!link->in_samplerates->format_count) { | ||
| 275 | av_log(link->src, AV_LOG_ERROR, "Cannot select sample rate for" | ||
| 276 | " the link between filters %s and %s.\n", link->src->name, | ||
| 277 | link->dst->name); | ||
| 278 | return AVERROR(EINVAL); | ||
| 279 | } | ||
| 280 | link->in_samplerates->format_count = 1; | ||
| 281 | link->sample_rate = link->in_samplerates->formats[0]; | ||
| 282 | |||
| 283 | if (!link->in_channel_layouts->nb_channel_layouts) { | ||
| 284 | av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" | ||
| 285 | "the link between filters %s and %s.\n", link->src->name, | ||
| 286 | link->dst->name); | ||
| 287 | return AVERROR(EINVAL); | ||
| 288 | } | ||
| 289 | link->in_channel_layouts->nb_channel_layouts = 1; | ||
| 290 | link->channel_layout = link->in_channel_layouts->channel_layouts[0]; | ||
| 291 | } | ||
| 292 | |||
| 239 | avfilter_formats_unref(&link->in_formats); | 293 | avfilter_formats_unref(&link->in_formats); |
| 240 | avfilter_formats_unref(&link->out_formats); | 294 | avfilter_formats_unref(&link->out_formats); |
| 295 | avfilter_formats_unref(&link->in_samplerates); | ||
| 296 | avfilter_formats_unref(&link->out_samplerates); | ||
| 297 | ff_channel_layouts_unref(&link->in_channel_layouts); | ||
| 298 | ff_channel_layouts_unref(&link->out_channel_layouts); | ||
| 299 | |||
| 300 | return 0; | ||
| 241 | } | 301 | } |
| 242 | 302 | ||
| 303 | #define REDUCE_FORMATS(fmt_type, list_type, list, var, nb, add_format) \ | ||
| 304 | do { \ | ||
| 305 | for (i = 0; i < filter->input_count; i++) { \ | ||
| 306 | AVFilterLink *link = filter->inputs[i]; \ | ||
| 307 | fmt_type fmt; \ | ||
| 308 | \ | ||
| 309 | if (!link->out_ ## list || link->out_ ## list->nb != 1) \ | ||
| 310 | continue; \ | ||
| 311 | fmt = link->out_ ## list->var[0]; \ | ||
| 312 | \ | ||
| 313 | for (j = 0; j < filter->output_count; j++) { \ | ||
| 314 | AVFilterLink *out_link = filter->outputs[j]; \ | ||
| 315 | list_type *fmts; \ | ||
| 316 | \ | ||
| 317 | if (link->type != out_link->type || \ | ||
| 318 | out_link->in_ ## list->nb == 1) \ | ||
| 319 | continue; \ | ||
| 320 | fmts = out_link->in_ ## list; \ | ||
| 321 | \ | ||
| 322 | if (!out_link->in_ ## list->nb) { \ | ||
| 323 | add_format(&out_link->in_ ##list, fmt); \ | ||
| 324 | break; \ | ||
| 325 | } \ | ||
| 326 | \ | ||
| 327 | for (k = 0; k < out_link->in_ ## list->nb; k++) \ | ||
| 328 | if (fmts->var[k] == fmt) { \ | ||
| 329 | fmts->var[0] = fmt; \ | ||
| 330 | fmts->nb = 1; \ | ||
| 331 | ret = 1; \ | ||
| 332 | break; \ | ||
| 333 | } \ | ||
| 334 | } \ | ||
| 335 | } \ | ||
| 336 | } while (0) | ||
| 337 | |||
| 243 | static int reduce_formats_on_filter(AVFilterContext *filter) | 338 | static int reduce_formats_on_filter(AVFilterContext *filter) |
| 244 | { | 339 | { |
| 245 | int i, j, k, ret = 0; | 340 | int i, j, k, ret = 0; |
| 246 | 341 | ||
| 247 | for (i = 0; i < filter->input_count; i++) { | 342 | REDUCE_FORMATS(int, AVFilterFormats, formats, formats, |
| 248 | AVFilterLink *link = filter->inputs[i]; | 343 | format_count, avfilter_add_format); |
| 249 | int format = link->out_formats->formats[0]; | 344 | REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, |
| 250 | 345 | format_count, avfilter_add_format); | |
| 251 | if (link->out_formats->format_count != 1) | 346 | REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, |
| 252 | continue; | 347 | channel_layouts, nb_channel_layouts, ff_add_channel_layout); |
| 253 | |||
| 254 | for (j = 0; j < filter->output_count; j++) { | ||
| 255 | AVFilterLink *out_link = filter->outputs[j]; | ||
| 256 | AVFilterFormats *fmts = out_link->in_formats; | ||
| 257 | 348 | ||
| 258 | if (link->type != out_link->type || | ||
| 259 | out_link->in_formats->format_count == 1) | ||
| 260 | continue; | ||
| 261 | |||
| 262 | for (k = 0; k < out_link->in_formats->format_count; k++) | ||
| 263 | if (fmts->formats[k] == format) { | ||
| 264 | fmts->formats[0] = format; | ||
| 265 | fmts->format_count = 1; | ||
| 266 | ret = 1; | ||
| 267 | break; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | return ret; | 349 | return ret; |
| 272 | } | 350 | } |
| 273 | 351 | ||
| @@ -283,18 +361,121 @@ static void reduce_formats(AVFilterGraph *graph) · 9 unmodified lines | |||
| 283 | } while (reduced); | 361 | } while (reduced); |
| 284 | } | 362 | } |
| 285 | 363 | ||
| 286 | static void pick_formats(AVFilterGraph *graph) | 364 | static void swap_samplerates_on_filter(AVFilterContext *filter) |
| 365 | { | ||
| 366 | AVFilterLink *link = NULL; | ||
| 367 | int sample_rate; | ||
| 368 | int i, j; | ||
| 369 | |||
| 370 | for (i = 0; i < filter->input_count; i++) { | ||
| 371 | link = filter->inputs[i]; | ||
| 372 | |||
| 373 | if (link->type == AVMEDIA_TYPE_AUDIO && | ||
| 374 | link->out_samplerates->format_count == 1) | ||
| 375 | break; | ||
| 376 | } | ||
| 377 | if (i == filter->input_count) | ||
| 378 | return; | ||
| 379 | |||
| 380 | sample_rate = link->out_samplerates->formats[0]; | ||
| 381 | |||
| 382 | for (i = 0; i < filter->output_count; i++) { | ||
| 383 | AVFilterLink *outlink = filter->outputs[i]; | ||
| 384 | int best_idx, best_diff = INT_MAX; | ||
| 385 | |||
| 386 | if (outlink->type != AVMEDIA_TYPE_AUDIO || | ||
| 387 | outlink->in_samplerates->format_count < 2) | ||
| 388 | continue; | ||
| 389 | |||
| 390 | for (j = 0; j < outlink->in_samplerates->format_count; j++) { | ||
| 391 | int diff = abs(sample_rate - outlink->in_samplerates->formats[j]); | ||
| 392 | |||
| 393 | if (diff < best_diff) { | ||
| 394 | best_diff = diff; | ||
| 395 | best_idx = j; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | FFSWAP(int, outlink->in_samplerates->formats[0], | ||
| 399 | outlink->in_samplerates->formats[best_idx]); | ||
| 400 | } | ||
| 401 | } | ||
| 402 | |||
| 403 | static void swap_samplerates(AVFilterGraph *graph) | ||
| 404 | { | ||
| 405 | int i; | ||
| 406 | |||
| 407 | for (i = 0; i < graph->filter_count; i++) | ||
| 408 | swap_samplerates_on_filter(graph->filters[i]); | ||
| 409 | } | ||
| 410 | |||
| 411 | static void swap_channel_layouts_on_filter(AVFilterContext *filter) | ||
| 287 | { | 412 | { |
| 413 | AVFilterLink *link = NULL; | ||
| 414 | uint64_t chlayout; | ||
| 288 | int i, j; | 415 | int i, j; |
| 289 | 416 | ||
| 417 | for (i = 0; i < filter->input_count; i++) { | ||
| 418 | link = filter->inputs[i]; | ||
| 419 | |||
| 420 | if (link->type == AVMEDIA_TYPE_AUDIO && | ||
| 421 | link->out_channel_layouts->nb_channel_layouts == 1) | ||
| 422 | break; | ||
| 423 | } | ||
| 424 | if (i == filter->input_count) | ||
| 425 | return; | ||
| 426 | |||
| 427 | chlayout = link->out_channel_layouts->channel_layouts[0]; | ||
| 428 | |||
| 429 | for (i = 0; i < filter->output_count; i++) { | ||
| 430 | AVFilterLink *outlink = filter->outputs[i]; | ||
| 431 | int best_idx, best_score = INT_MIN; | ||
| 432 | |||
| 433 | if (outlink->type != AVMEDIA_TYPE_AUDIO || | ||
| 434 | outlink->in_channel_layouts->nb_channel_layouts < 2) | ||
| 435 | continue; | ||
| 436 | |||
| 437 | for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { | ||
| 438 | uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; | ||
| 439 | int matched_channels = av_get_channel_layout_nb_channels(chlayout & | ||
| 440 | out_chlayout); | ||
| 441 | int extra_channels = av_get_channel_layout_nb_channels(out_chlayout & | ||
| 442 | (~chlayout)); | ||
| 443 | int score = matched_channels - extra_channels; | ||
| 444 | |||
| 445 | if (score > best_score) { | ||
| 446 | best_score = score; | ||
| 447 | best_idx = j; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], | ||
| 451 | outlink->in_channel_layouts->channel_layouts[best_idx]); | ||
| 452 | } | ||
| 453 | |||
| 454 | } | ||
| 455 | |||
| 456 | static void swap_channel_layouts(AVFilterGraph *graph) | ||
| 457 | { | ||
| 458 | int i; | ||
| 459 | |||
| 460 | for (i = 0; i < graph->filter_count; i++) | ||
| 461 | swap_channel_layouts_on_filter(graph->filters[i]); | ||
| 462 | } | ||
| 463 | |||
| 464 | static int pick_formats(AVFilterGraph *graph) | ||
| 465 | { | ||
| 466 | int i, j, ret; | ||
| 467 | |||
| 290 | for (i = 0; i < graph->filter_count; i++) { | 468 | for (i = 0; i < graph->filter_count; i++) { |
| 291 | AVFilterContext *filter = graph->filters[i]; | 469 | AVFilterContext *filter = graph->filters[i]; |
| 292 | 470 | ||
| 293 | for (j = 0; j < filter->input_count; j++) | 471 | for (j = 0; j < filter->input_count; j++) |
| 294 | pick_format(filter->inputs[j]); | 472 | if ((ret = pick_format(filter->inputs[j])) < 0) |
| 473 | return ret; | ||
| 295 | for (j = 0; j < filter->output_count; j++) | 474 | for (j = 0; j < filter->output_count; j++) |
| 296 | pick_format(filter->outputs[j]); | 475 | if ((ret = pick_format(filter->outputs[j])) < 0) |
| 476 | return ret; | ||
| 297 | } | 477 | } |
| 478 | return 0; | ||
| 298 | } | 479 | } |
| 299 | 480 | ||
| 300 | int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) | 481 | int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) |
| @@ -310,7 +491,13 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) · 9 unmodified lines | |||
| 310 | * of format conversion inside filters */ | 491 | * of format conversion inside filters */ |
| 311 | reduce_formats(graph); | 492 | reduce_formats(graph); |
| 312 | 493 | ||
| 313 | pick_formats(graph); | 494 | /* for audio filters, ensure the best sample rate and channel layout |
| 495 | * is selected */ | ||
| 496 | swap_samplerates(graph); | ||
| 497 | swap_channel_layouts(graph); | ||
| 498 | |||
| 499 | if ((ret = pick_formats(graph)) < 0) | ||
| 500 | return ret; | ||
| 314 | 501 | ||
| 315 | return 0; | 502 | return 0; |
| 316 | } | 503 | } |