[FFmpeg-devel] [PATCH] lavfi: support unknown channel layouts.
Stefano Sabatini
stefasab at gmail.com
Thu Jan 3 13:05:31 CET 2013
On date Wednesday 2013-01-02 17:28:33 +0100, Nicolas George encoded:
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> libavfilter/audio.c | 2 +-
> libavfilter/avcodec.c | 3 --
> libavfilter/avfiltergraph.c | 78 ++++++++++++++++++++++++++++++++++++++----
> libavfilter/formats.c | 79 ++++++++++++++++++++++++++++++++++++++-----
> libavfilter/formats.h | 31 +++++++++++++++++
> 5 files changed, 174 insertions(+), 19 deletions(-)
>
>
> Updated according to Stefano's comments.
> The next patches are unchanged apart from a macro rename.
>
>
> diff --git a/libavfilter/audio.c b/libavfilter/audio.c
> index 72dcd14..c72979d 100644
> --- a/libavfilter/audio.c
> +++ b/libavfilter/audio.c
> @@ -44,7 +44,7 @@ AVFilterBufferRef *ff_default_get_audio_buffer(AVFilterLink *link, int perms,
> AVFilterBufferRef *samplesref = NULL;
> uint8_t **data;
> int planar = av_sample_fmt_is_planar(link->format);
> - int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
> + int nb_channels = link->channels;
> int planes = planar ? nb_channels : 1;
> int linesize;
> int full_perms = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE |
> diff --git a/libavfilter/avcodec.c b/libavfilter/avcodec.c
> index 0c1f02a..2343d19 100644
> --- a/libavfilter/avcodec.c
> +++ b/libavfilter/avcodec.c
> @@ -96,9 +96,6 @@ AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_frame(const AVFrame *frame
> int channels = av_frame_get_channels(frame);
> int64_t layout = av_frame_get_channel_layout(frame);
>
> - if(av_frame_get_channels(frame) > 8) // libavfilter does not suport more than 8 channels FIXME, remove once libavfilter is fixed
> - return NULL;
> -
> if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) {
> av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
> return NULL;
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index 10f9b7e..cfee00d 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_LAYOUT2CHANS(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,40 @@ 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) {
> + 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 +718,18 @@ 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_LAYOUT2CHANS(in_chlayout) || FF_LAYOUT2CHANS(out_chlayout)) {
> + if (FF_LAYOUT2CHANS(in_chlayout))
> + in_channels = FF_LAYOUT2CHANS(in_chlayout);
> + if (FF_LAYOUT2CHANS(out_chlayout))
> + out_channels = FF_LAYOUT2CHANS(out_chlayout);
> + score -= 10000 + FFABS(out_channels - in_channels) +
> + (in_channels > out_channels ? 10000 : 0);
> + /* let the remaining computation run and get 0 */
confusing: what's the point of computing score if you already knows it
is 0?
> + in_chlayout = out_chlayout = 0;
> + }
this could be commented. Also the heuristics seems somehow arbitrary
(and I'd prefer the score to be computed in a separated function, but
this is unrelated).
[...]
> int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
> {
> ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts);
> + (*l)->all_layouts = (*l)->all_counts = 0;
> + return 0;
> }
given the logic, naming this as "set_channel_layout()" maybe more
clear, but feel free to keep the current name for consistency with the
other misnamed functions.
>
> AVFilterFormats *ff_all_formats(enum AVMediaType type)
> @@ -309,6 +369,7 @@ AVFilterFormats *ff_all_samplerates(void)
> AVFilterChannelLayouts *ff_all_channel_layouts(void)
> {
> AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
> + ret->all_layouts = 1;
> return ret;
> }
>
> diff --git a/libavfilter/formats.h b/libavfilter/formats.h
> index c5a4e3d..b1eaa0c 100644
> --- a/libavfilter/formats.h
> +++ b/libavfilter/formats.h
> @@ -69,15 +69,46 @@ struct AVFilterFormats {
> struct AVFilterFormats ***refs; ///< references to this list
> };
>
> +/**
> + * A list of supported channel layouts.
> + *
> + * The list works the same as AVFilterFormats, except for the following
> + * differences:
> + * - A list with all_layouts = 1 means all channel layouts with a known
> + * disposition; nb_channel_layouts must then be 0.
> + * - A list with all_counts = 1 means all channel counts, with a known or
> + * unknown disposition ; nb_channel_layouts must then be 0 and all_layouts 1.
> + * - The list must not contain a layout with a known disposition and a
> + * channel count with unknown disposition with the same number of channels
> + * (e.g. AV_CH_LAYOUT_STEREO and FF_CHANS2LAYOUT(2).
> + */
> typedef struct AVFilterChannelLayouts {
> uint64_t *channel_layouts; ///< list of channel layouts
> int nb_channel_layouts; ///< number of channel layouts
> + char all_layouts; ///< accept any known channel layout
> + char all_counts; ///< accept any channel layout or count
>
> unsigned refcount; ///< number of references to this list
> struct AVFilterChannelLayouts ***refs; ///< references to this list
> } AVFilterChannelLayouts;
>
> /**
> + * Encode a channel count as a channel layout.
alternatively this could be named COUNT2LAYOUT
> + * FF_CHANS2LAYOUT(c) means any channel layout with c channels, with a known
> + * or unknown disposition.
> + * The result is only valid inside AVFilterChannelLayouts and immediately
> + * related functions.
> + */
> +#define FF_CHANS2LAYOUT(c) (0x8000000000000000ULL | (c))
> +
> +/**
> + * Decode a channel count encoded as a channel layout.
> + * Return 0 is the channel layout was a real one.
is -> if?
also:
Return 0 is the channel layout was a real one, otherwise the number of
channels | channels count.
> + */
> +#define FF_LAYOUT2CHANS(l) (((l) & 0x8000000000000000ULL) ? \
> + (int)((l) & 0x7FFFFFFF) : 0)
> +
ditto, this could be LAYOUT2COUNT
> +/**
> * Return a channel layouts/samplerates list which contains the intersection of
> * the layouts/samplerates of a and b. Also, all the references of a, all the
> * references of b, and a and b themselves will be deallocated.
> --
> 1.7.10.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
--
FFmpeg = Foolish and Fanciful Most Plastic Evil Geek
More information about the ffmpeg-devel
mailing list