Signed-off-by: Vittorio Giovara <vittorio.giov...@gmail.com> --- Moved portions of code to functions as Luca requested. I only left the code from MERGE_FORMATS unchanged because it was too heavily entwined in that function. Vittorio
libavfilter/af_aformat.c | 30 +++++++++--- libavfilter/af_channelmap.c | 2 +- libavfilter/af_channelsplit.c | 6 ++- libavfilter/af_join.c | 2 +- libavfilter/avfiltergraph.c | 109 +++++++++++++++++++++++++++++++----------- libavfilter/buffersrc.c | 2 +- libavfilter/formats.c | 45 +++++++++++++++-- libavfilter/formats.h | 4 +- 8 files changed, 153 insertions(+), 47 deletions(-) diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c index c5aa4f7148..259ece4c0b 100644 --- a/libavfilter/af_aformat.c +++ b/libavfilter/af_aformat.c @@ -94,11 +94,29 @@ static int get_sample_rate(const char *samplerate) return FFMAX(ret, 0); } -static int get_channel_layout(const char *channel_layout) +static int parse_channel_layout_string(AVFilterContext *ctx) { - AVChannelLayout ch_layout = {0}; - av_channel_layout_from_string(&ch_layout, channel_layout); - return ch_layout.u.mask; + AFormatContext *s = ctx->priv; + char *next, *cur = s->channel_layouts_str, sep = '|'; + int ret; + + while (cur) { + AVChannelLayout fmt = {0}; + next = strchr(cur, sep); + if (next) + *next++ = 0; + + ret = av_channel_layout_from_string(&fmt, cur); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur);\ + return ret; + } + ff_add_channel_layout(&s->channel_layouts, &fmt); + + cur = next; + } + + return 0; } static av_cold int init(AVFilterContext *ctx) @@ -109,10 +127,8 @@ static av_cold int init(AVFilterContext *ctx) ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format"); PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format, get_sample_rate, 0, "sample rate"); - PARSE_FORMATS(s->channel_layouts_str, uint64_t, s->channel_layouts, - ff_add_channel_layout, get_channel_layout, 0, "channel layout"); - return 0; + return parse_channel_layout_string(ctx); } static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 939f056d6f..54ff146c5b 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -296,7 +296,7 @@ static int channelmap_query_formats(AVFilterContext *ctx) ChannelMapContext *s = ctx->priv; AVFilterChannelLayouts *channel_layouts = NULL; - ff_add_channel_layout(&channel_layouts, s->ch_layout.u.mask); + ff_add_channel_layout(&channel_layouts, &s->ch_layout); ff_set_common_formats(ctx, ff_planar_sample_fmts()); ff_set_common_samplerates(ctx, ff_all_samplerates()); diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index 41b3051c8c..b13919cdf0 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -85,16 +85,18 @@ static int query_formats(AVFilterContext *ctx) ff_set_common_formats (ctx, ff_planar_sample_fmts()); ff_set_common_samplerates(ctx, ff_all_samplerates()); - ff_add_channel_layout(&in_layouts, s->ch_layout.u.mask); + ff_add_channel_layout(&in_layouts, &s->ch_layout); ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->out_channel_layouts); for (i = 0; i < ctx->nb_outputs; i++) { AVFilterChannelLayouts *out_layouts = NULL; + AVChannelLayout tmp = {0}; int ret = av_channel_layout_get_channel(&s->ch_layout, i); if (ret < 0) return ret; - ff_add_channel_layout(&out_layouts, 1ULL << ret); + av_channel_layout_from_mask(&tmp, 1ULL << ret); + ff_add_channel_layout(&out_layouts, &tmp); ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->in_channel_layouts); } diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index 6c000b9257..70dc2d00d7 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -234,7 +234,7 @@ static int join_query_formats(AVFilterContext *ctx) AVFilterChannelLayouts *layouts = NULL; int i; - ff_add_channel_layout(&layouts, s->ch_layout.u.mask); + ff_add_channel_layout(&layouts, &s->ch_layout); ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts); for (i = 0; i < ctx->nb_inputs; i++) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index c72016d2c8..936a791175 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -374,6 +374,8 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) static int pick_format(AVFilterLink *link) { + int ret; + if (!link || !link->in_formats) return 0; @@ -399,11 +401,15 @@ static int pick_format(AVFilterLink *link) link->in_channel_layouts->nb_channel_layouts = 1; #if FF_API_OLD_CHANNEL_LAYOUT FF_DISABLE_DEPRECATION_WARNINGS - link->channel_layout = link->in_channel_layouts->channel_layouts[0]; + if (link->in_channel_layouts->channel_layouts[0].order == AV_CHANNEL_ORDER_NATIVE || + link->in_channel_layouts->channel_layouts[0].order == AV_CHANNEL_ORDER_UNSPEC) + link->channel_layout = link->in_channel_layouts->channel_layouts[0].u.mask; FF_ENABLE_DEPRECATION_WARNINGS #endif - av_channel_layout_from_mask(&link->ch_layout, - link->in_channel_layouts->channel_layouts[0]); + ret = av_channel_layout_copy(&link->ch_layout, + &link->in_channel_layouts->channel_layouts[0]); + if (ret < 0) + return ret; } ff_formats_unref(&link->in_formats); @@ -451,6 +457,47 @@ do { \ } \ } while (0) +static int reduce_formats_channel_layout(AVFilterContext *filter) +{ + int i, j, k, ret = 0; + + for (i = 0; i < filter->nb_inputs; i++) { + AVFilterLink *link = filter->inputs[i]; + AVChannelLayout *fmt; + + if (!link->out_channel_layouts || link->out_channel_layouts->nb_channel_layouts != 1) + continue; + fmt = &link->out_channel_layouts->channel_layouts[0]; + + for (j = 0; j < filter->nb_outputs; j++) { + AVFilterLink *out_link = filter->outputs[j]; + AVFilterChannelLayouts *fmts; + + if (link->type != out_link->type || + out_link->in_channel_layouts->nb_channel_layouts == 1) + continue; + fmts = out_link->in_channel_layouts; + + if (!out_link->in_channel_layouts->nb_channel_layouts) { + ff_add_channel_layout(&out_link->in_channel_layouts, fmt); + break; + } + + for (k = 0; k < out_link->in_channel_layouts->nb_channel_layouts; k++) + if (!av_channel_layout_compare(&fmts->channel_layouts[k], fmt)) { + ret = av_channel_layout_copy(&fmts->channel_layouts[0], fmt); + if (ret < 0) + return ret; + fmts->nb_channel_layouts = 1; + ret = 1; + break; + } + } + } + + return ret; +} + static int reduce_formats_on_filter(AVFilterContext *filter) { int i, j, k, ret = 0; @@ -459,10 +506,11 @@ static int reduce_formats_on_filter(AVFilterContext *filter) nb_formats, ff_add_format); REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, nb_formats, ff_add_format); - REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, - channel_layouts, nb_channel_layouts, ff_add_channel_layout); - return ret; + if (ret < 0) + return ret; + + return reduce_formats_channel_layout(filter); } static void reduce_formats(AVFilterGraph *graph) @@ -582,20 +630,22 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) continue; for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { - uint64_t in_chlayout = link->out_channel_layouts->channel_layouts[0]; - uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; + AVChannelLayout *in_ch_layout = &link->out_channel_layouts->channel_layouts[0]; + AVChannelLayout *out_ch_layout = &outlink->in_channel_layouts->channel_layouts[j]; + AVChannelLayout in = {0}, out = {0}; int in_channels; int out_channels; + uint64_t in_mask = 0, out_mask = 0; int count_diff; int matched_channels, extra_channels; int score = 0; - AVChannelLayout in_ch_layout = {0}; - AVChannelLayout out_ch_layout = {0}; - av_channel_layout_from_mask( &in_ch_layout, in_chlayout); - av_channel_layout_from_mask(&out_ch_layout, out_chlayout); - in_channels = in_ch_layout.nb_channels; - out_channels = out_ch_layout.nb_channels; + in_channels = in_ch_layout->nb_channels; + out_channels = out_ch_layout->nb_channels; + if ( in_ch_layout->order == AV_CHANNEL_ORDER_NATIVE) + in_mask = in_ch_layout->u.mask; + if (out_ch_layout->order == AV_CHANNEL_ORDER_NATIVE) + out_mask = out_ch_layout->u.mask; count_diff = out_channels - in_channels; /* channel substitution */ @@ -603,10 +653,13 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) uint64_t cmp0 = ch_subst[k][0]; uint64_t cmp1 = ch_subst[k][1]; AVChannelLayout tmp = {0}; - if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) && - (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) { - in_chlayout &= ~cmp0; - out_chlayout &= ~cmp1; + + if ( av_channel_layout_subset( in_ch_layout, cmp0) && + !av_channel_layout_subset(out_ch_layout, cmp0) && + av_channel_layout_subset(out_ch_layout, cmp1) && + !av_channel_layout_subset( in_ch_layout, cmp1)) { + in_mask &= ~cmp0; + out_mask &= ~cmp1; /* add score for channel match, minus a deduction for having to do the substitution */ av_channel_layout_from_mask(&tmp, cmp1); @@ -615,19 +668,17 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) } /* no penalty for LFE channel mismatch */ - if ( (in_chlayout & AV_CH_LOW_FREQUENCY) && - (out_chlayout & AV_CH_LOW_FREQUENCY)) + if (av_channel_layout_subset( in_ch_layout, AV_CH_LOW_FREQUENCY) && + av_channel_layout_subset(out_ch_layout, AV_CH_LOW_FREQUENCY)) score += 10; - in_chlayout &= ~AV_CH_LOW_FREQUENCY; - out_chlayout &= ~AV_CH_LOW_FREQUENCY; + in_mask &= ~AV_CH_LOW_FREQUENCY; + out_mask &= ~AV_CH_LOW_FREQUENCY; - av_channel_layout_uninit( &in_ch_layout); - av_channel_layout_uninit(&out_ch_layout); - av_channel_layout_from_mask( &in_ch_layout, in_chlayout & out_chlayout); - av_channel_layout_from_mask(&out_ch_layout, out_chlayout & (~in_chlayout)); + av_channel_layout_from_mask( &in, in_mask & out_mask); + av_channel_layout_from_mask(&out, out_mask & (~in_mask)); - matched_channels = in_ch_layout.nb_channels; - extra_channels = out_ch_layout.nb_channels; + matched_channels = in.nb_channels; + extra_channels = out.nb_channels; score += 10 * matched_channels - 5 * extra_channels; if (score > best_score || @@ -638,7 +689,7 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) } } av_assert0(best_idx >= 0); - FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], + FFSWAP(AVChannelLayout, outlink->in_channel_layouts->channel_layouts[0], outlink->in_channel_layouts->channel_layouts[best_idx]); } diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 838e3ac08d..9f4e8dbf8a 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -347,7 +347,7 @@ static int query_formats(AVFilterContext *ctx) ff_add_format(&samplerates, c->sample_rate); ff_set_common_samplerates(ctx, samplerates); - ff_add_channel_layout(&channel_layouts, c->ch_layout.u.mask); + ff_add_channel_layout(&channel_layouts, &c->ch_layout); ff_set_common_channel_layouts(ctx, channel_layouts); break; default: diff --git a/libavfilter/formats.c b/libavfilter/formats.c index 7b5a93c325..251df0d721 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -131,8 +131,31 @@ AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a, if (a == b) return a; if (a->nb_channel_layouts && b->nb_channel_layouts) { - MERGE_FORMATS(ret, a, b, channel_layouts, nb_channel_layouts, - AVFilterChannelLayouts, fail); + int i, j, k = 0, count = FFMIN(a->nb_channel_layouts, b->nb_channel_layouts); + + if (!(ret = av_mallocz(sizeof(*ret)))) + goto fail; + + if (count) { + if (!(ret->channel_layouts = av_malloc(sizeof(*ret->channel_layouts) * count))) + goto fail; + for (i = 0; i < a->nb_channel_layouts; i++) + for (j = 0; j < b->nb_channel_layouts; j++) + if (!av_channel_layout_compare(&a->channel_layouts[i], + &b->channel_layouts[j])) + if (av_channel_layout_copy(&ret->channel_layouts[k++], + &a->channel_layouts[i]) < 0) + goto fail; + + ret->nb_channel_layouts = k; + } + /* check that there was at least one common format */ + if (!ret->nb_channel_layouts) + goto fail; + + MERGE_REF(ret, a, channel_layouts, AVFilterChannelLayouts, fail); + MERGE_REF(ret, b, channel_layouts, AVFilterChannelLayouts, fail); + } else if (a->nb_channel_layouts) { MERGE_REF(a, b, channel_layouts, AVFilterChannelLayouts, fail); ret = a; @@ -210,9 +233,23 @@ int ff_add_format(AVFilterFormats **avff, int fmt) ADD_FORMAT(avff, fmt, int, formats, nb_formats); } -int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout) +int ff_add_channel_layout(AVFilterChannelLayouts **f, AVChannelLayout *channel_layout) { - ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts); + AVChannelLayout *fmts; + + if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) + return AVERROR(ENOMEM); + + fmts = av_realloc((*f)->channel_layouts, + sizeof(*(*f)->channel_layouts) * ((*f)->nb_channel_layouts + 1));\ + if (!fmts) { + av_freep(&f); + return AVERROR(ENOMEM); + } + + (*f)->channel_layouts = fmts; + return av_channel_layout_copy(&(*f)->channel_layouts[(*f)->nb_channel_layouts++], + channel_layout); } AVFilterFormats *ff_all_formats(enum AVMediaType type) diff --git a/libavfilter/formats.h b/libavfilter/formats.h index b273f8aa03..157ef757b3 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -70,7 +70,7 @@ struct AVFilterFormats { }; typedef struct AVFilterChannelLayouts { - uint64_t *channel_layouts; ///< list of channel layouts + AVChannelLayout *channel_layouts; ///< list of channel layouts int nb_channel_layouts; ///< number of channel layouts unsigned refcount; ///< number of references to this list @@ -114,7 +114,7 @@ void ff_set_common_samplerates(AVFilterContext *ctx, */ void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats); -int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout); +int ff_add_channel_layout(AVFilterChannelLayouts **l, AVChannelLayout *channel_layout); /** * Add *ref as a new reference to f. -- 2.12.0 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel