From b6afb2dde1aa92ff8fac020f34fc436fede388b0 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Wed, 2 Jan 2013 15:11:30 +0100 Subject: lavfi: support unknown channel layouts. --- libavfilter/avfiltergraph.c | 85 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) (limited to 'libavfilter/avfiltergraph.c') diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index c05bbb7fe6..4b7d194275 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -185,9 +185,24 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name) return NULL; } +static void sanitize_channel_layouts(void *log, AVFilterChannelLayouts *l) +{ + if (!l) + return; + if (l->nb_channel_layouts) { + if (l->all_layouts || l->all_counts) + av_log(log, AV_LOG_WARNING, "All layouts set on non-empty list\n"); + l->all_layouts = l->all_counts = 0; + } else { + if (l->all_counts && !l->all_layouts) + av_log(log, AV_LOG_WARNING, "All counts without all layouts\n"); + l->all_layouts = 1; + } +} + static int filter_query_formats(AVFilterContext *ctx) { - int ret; + int ret, i; AVFilterFormats *formats; AVFilterChannelLayouts *chlayouts; AVFilterFormats *samplerates; @@ -201,6 +216,11 @@ static int filter_query_formats(AVFilterContext *ctx) return ret; } + for (i = 0; i < ctx->nb_inputs; i++) + sanitize_channel_layouts(ctx, ctx->inputs[i]->out_channel_layouts); + for (i = 0; i < ctx->nb_outputs; i++) + sanitize_channel_layouts(ctx, ctx->outputs[i]->in_channel_layouts); + formats = ff_all_formats(type); if (!formats) return AVERROR(ENOMEM); @@ -470,7 +490,7 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) link->in_samplerates->format_count = 1; link->sample_rate = link->in_samplerates->formats[0]; - if (!link->in_channel_layouts->nb_channel_layouts) { + if (link->in_channel_layouts->all_layouts) { av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" "the link between filters %s and %s.\n", link->src->name, link->dst->name); @@ -478,7 +498,10 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) } link->in_channel_layouts->nb_channel_layouts = 1; link->channel_layout = link->in_channel_layouts->channel_layouts[0]; - link->channels = av_get_channel_layout_nb_channels(link->channel_layout); + if ((link->channels = FF_LAYOUT2COUNT(link->channel_layout))) + link->channel_layout = 0; + else + link->channels = av_get_channel_layout_nb_channels(link->channel_layout); } ff_formats_unref(&link->in_formats); @@ -534,8 +557,42 @@ static int reduce_formats_on_filter(AVFilterContext *filter) format_count, ff_add_format); REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, format_count, ff_add_format); - REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, - channel_layouts, nb_channel_layouts, ff_add_channel_layout); + + /* reduce channel layouts */ + for (i = 0; i < filter->nb_inputs; i++) { + AVFilterLink *inlink = filter->inputs[i]; + uint64_t fmt; + + if (!inlink->out_channel_layouts || + inlink->out_channel_layouts->nb_channel_layouts != 1) + continue; + fmt = inlink->out_channel_layouts->channel_layouts[0]; + + for (j = 0; j < filter->nb_outputs; j++) { + AVFilterLink *outlink = filter->outputs[j]; + AVFilterChannelLayouts *fmts; + + fmts = outlink->in_channel_layouts; + if (inlink->type != outlink->type || fmts->nb_channel_layouts == 1) + continue; + + if (fmts->all_layouts) { + /* Turn the infinite list into a singleton */ + fmts->all_layouts = fmts->all_counts = 0; + ff_add_channel_layout(&outlink->in_channel_layouts, fmt); + break; + } + + for (k = 0; k < outlink->in_channel_layouts->nb_channel_layouts; k++) { + if (fmts->channel_layouts[k] == fmt) { + fmts->channel_layouts[0] = fmt; + fmts->nb_channel_layouts = 1; + ret = 1; + break; + } + } + } + } return ret; } @@ -663,7 +720,23 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) int out_channels = av_get_channel_layout_nb_channels(out_chlayout); int count_diff = out_channels - in_channels; int matched_channels, extra_channels; - int score = 0; + int score = 100000; + + if (FF_LAYOUT2COUNT(in_chlayout) || FF_LAYOUT2COUNT(out_chlayout)) { + /* Compute score in case the input or output layout encodes + a channel count; in this case the score is not altered by + the computation afterwards, as in_chlayout and + out_chlayout have both been set to 0 */ + if (FF_LAYOUT2COUNT(in_chlayout)) + in_channels = FF_LAYOUT2COUNT(in_chlayout); + if (FF_LAYOUT2COUNT(out_chlayout)) + out_channels = FF_LAYOUT2COUNT(out_chlayout); + score -= 10000 + FFABS(out_channels - in_channels) + + (in_channels > out_channels ? 10000 : 0); + in_chlayout = out_chlayout = 0; + /* Let the remaining computation run, even if the score + value is not altered */ + } /* channel substitution */ for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) { -- cgit v1.2.3