| @@ -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 | } |