diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index f65faae8ce..91a5f3233f 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -461,6 +461,74 @@ static void swap_channel_layouts(AVFilterGraph *graph) swap_channel_layouts_on_filter(graph->filters[i]); } +static void swap_sample_fmts_on_filter(AVFilterContext *filter) +{ + AVFilterLink *link = NULL; + int format, bps; + int i, j; + + for (i = 0; i < filter->input_count; i++) { + link = filter->inputs[i]; + + if (link->type == AVMEDIA_TYPE_AUDIO && + link->out_formats->format_count == 1) + break; + } + if (i == filter->input_count) + return; + + format = link->out_formats->formats[0]; + bps = av_get_bytes_per_sample(format); + + for (i = 0; i < filter->output_count; i++) { + AVFilterLink *outlink = filter->outputs[i]; + int best_idx, best_score = INT_MIN; + + if (outlink->type != AVMEDIA_TYPE_AUDIO || + outlink->in_formats->format_count < 2) + continue; + + for (j = 0; j < outlink->in_formats->format_count; j++) { + int out_format = outlink->in_formats->formats[j]; + int out_bps = av_get_bytes_per_sample(out_format); + int score; + + if (av_get_packed_sample_fmt(out_format) == format || + av_get_planar_sample_fmt(out_format) == format) { + best_idx = j; + break; + } + + /* for s32 and float prefer double to prevent loss of information */ + if (bps == 4 && out_bps == 8) { + best_idx = j; + break; + } + + /* prefer closest higher or equal bps */ + score = -abs(out_bps - bps); + if (out_bps >= bps) + score += INT_MAX/2; + + if (score > best_score) { + best_score = score; + best_idx = j; + } + } + FFSWAP(int, outlink->in_formats->formats[0], + outlink->in_formats->formats[best_idx]); + } +} + +static void swap_sample_fmts(AVFilterGraph *graph) +{ + int i; + + for (i = 0; i < graph->filter_count; i++) + swap_sample_fmts_on_filter(graph->filters[i]); + +} + static int pick_formats(AVFilterGraph *graph) { int i, j, ret; @@ -491,8 +559,9 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) * of format conversion inside filters */ reduce_formats(graph); - /* for audio filters, ensure the best sample rate and channel layout + /* for audio filters, ensure the best format, sample rate and channel layout * is selected */ + swap_sample_fmts(graph); swap_samplerates(graph); swap_channel_layouts(graph);