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 | 26 | #include "avfilter.h" |
| 27 | 27 | #include "avfiltergraph.h" |
| 28 | +#include "formats.h" | |
| 28 | 29 | #include "internal.h" |
| 29 | 30 | |
| 31 | +#include "libavutil/audioconvert.h" | |
| 30 | 32 | #include "libavutil/log.h" |
| 31 | 33 | |
| 32 | 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 | 171 | for (j = 0; j < filter->input_count; j++) { |
| 170 | 172 | AVFilterLink *link = filter->inputs[j]; |
| 171 | − if (link && link->in_formats != link->out_formats) { | |
| 172 | − if (!avfilter_merge_formats(link->in_formats, | |
| 173 | − link->out_formats)) { | |
| 173 | + int convert_needed = 0; | |
| 174 | + | |
| 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 | 194 | AVFilterContext *convert; |
| 175 | 195 | AVFilter *filter; |
| 176 | 196 | AVFilterLink *inlink, *outlink; |
| @@ -214,13 +234,27 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) · 37 unmodified lines | ||
| 214 | 234 | inlink = convert->inputs[0]; |
| 215 | 235 | outlink = convert->outputs[0]; |
| 216 | 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 | 253 | av_log(log_ctx, AV_LOG_ERROR, |
| 219 | 254 | "Impossible to convert between the formats supported by the filter " |
| 220 | 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 | 262 | return 0; |
| 229 | 263 | } |
| 230 | 264 | |
| 231 | −static void pick_format(AVFilterLink *link) | |
| 265 | +static int pick_format(AVFilterLink *link) | |
| 232 | 266 | { |
| 233 | 267 | if (!link || !link->in_formats) |
| 234 | − return; | |
| 268 | + return 0; | |
| 235 | 269 | |
| 236 | 270 | link->in_formats->format_count = 1; |
| 237 | 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 | 293 | avfilter_formats_unref(&link->in_formats); |
| 240 | 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 | 338 | static int reduce_formats_on_filter(AVFilterContext *filter) |
| 244 | 339 | { |
| 245 | 340 | int i, j, k, ret = 0; |
| 246 | 341 | |
| 247 | − for (i = 0; i < filter->input_count; i++) { | |
| 248 | − AVFilterLink *link = filter->inputs[i]; | |
| 249 | − int format = link->out_formats->formats[0]; | |
| 250 | − | |
| 251 | − if (link->out_formats->format_count != 1) | |
| 252 | − continue; | |
| 253 | − | |
| 254 | − for (j = 0; j < filter->output_count; j++) { | |
| 255 | − AVFilterLink *out_link = filter->outputs[j]; | |
| 256 | − AVFilterFormats *fmts = out_link->in_formats; | |
| 342 | + REDUCE_FORMATS(int, AVFilterFormats, formats, formats, | |
| 343 | + format_count, avfilter_add_format); | |
| 344 | + REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, | |
| 345 | + format_count, avfilter_add_format); | |
| 346 | + REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, | |
| 347 | + channel_layouts, nb_channel_layouts, ff_add_channel_layout); | |
| 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 | 349 | return ret; |
| 272 | 350 | } |
| 273 | 351 | |
| @@ -283,18 +361,121 @@ static void reduce_formats(AVFilterGraph *graph) · 9 unmodified lines | ||
| 283 | 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 | 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 | 468 | for (i = 0; i < graph->filter_count; i++) { |
| 291 | 469 | AVFilterContext *filter = graph->filters[i]; |
| 292 | 470 | |
| 293 | 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 | 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 | 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 | 491 | * of format conversion inside filters */ |
| 311 | 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 | 502 | return 0; |
| 316 | 503 | } |