1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-28 20:53:54 +02:00

lavfi/af_channelsplit: support arbitrary channel layouts

Not just those containing channel values under 64. Also, remove an
arbitrary limitation on channel count.
This commit is contained in:
Anton Khirnov 2024-09-01 12:23:41 +02:00
parent 7dc81d33c2
commit 18d492ff41

View File

@ -34,15 +34,13 @@
#include "filters.h"
#include "formats.h"
#define MAX_CH 64
typedef struct ChannelSplitContext {
const AVClass *class;
AVChannelLayout channel_layout;
char *channels_str;
int map[64];
int *map;
} ChannelSplitContext;
#define OFFSET(x) offsetof(ChannelSplitContext, x)
@ -71,10 +69,9 @@ static av_cold int init(AVFilterContext *ctx)
goto fail;
}
if (channel_layout.nb_channels > MAX_CH) {
av_log(ctx, AV_LOG_ERROR, "Too many channels\n");
goto fail;
}
s->map = av_calloc(channel_layout.nb_channels, sizeof(*s->map));
if (!s->map)
return AVERROR(ENOMEM);
for (i = 0; i < channel_layout.nb_channels; i++) {
enum AVChannel channel = av_channel_layout_channel_from_index(&channel_layout, i);
@ -118,6 +115,7 @@ static av_cold void uninit(AVFilterContext *ctx)
ChannelSplitContext *s = ctx->priv;
av_channel_layout_uninit(&s->channel_layout);
av_freep(&s->map);
}
static int query_formats(AVFilterContext *ctx)
@ -139,9 +137,27 @@ static int query_formats(AVFilterContext *ctx)
AVFilterChannelLayouts *out_layouts = NULL;
enum AVChannel channel = av_channel_layout_channel_from_index(&s->channel_layout, s->map[i]);
if ((ret = av_channel_layout_from_mask(&channel_layout, 1ULL << channel)) < 0 ||
(ret = ff_add_channel_layout(&out_layouts, &channel_layout)) < 0 ||
(ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->incfg.channel_layouts)) < 0)
channel_layout.u.map = av_mallocz(sizeof(*channel_layout.u.map));
if (!channel_layout.u.map)
return AVERROR(ENOMEM);
channel_layout.u.map[0].id = channel;
channel_layout.nb_channels = 1;
channel_layout.order = AV_CHANNEL_ORDER_CUSTOM;
ret = av_channel_layout_retype(&channel_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
if (ret < 0) {
av_channel_layout_uninit(&channel_layout);
return ret;
}
ret = ff_add_channel_layout(&out_layouts, &channel_layout);
av_channel_layout_uninit(&channel_layout);
if (ret < 0)
return ret;
ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->incfg.channel_layouts);
if (ret < 0)
return ret;
}
@ -154,17 +170,16 @@ static int filter_frame(AVFilterLink *outlink, AVFrame *buf)
AVFilterContext *ctx = outlink->src;
ChannelSplitContext *s = ctx->priv;
const int i = FF_OUTLINK_IDX(outlink);
enum AVChannel channel = av_channel_layout_channel_from_index(&buf->ch_layout, s->map[i]);
int ret;
av_assert1(channel >= 0);
buf_out = av_frame_clone(buf);
if (!buf_out)
return AVERROR(ENOMEM);
buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[s->map[i]];
ret = av_channel_layout_from_mask(&buf_out->ch_layout, 1ULL << channel);
av_channel_layout_uninit(&buf_out->ch_layout);
ret = av_channel_layout_copy(&buf_out->ch_layout, &outlink->ch_layout);
if (ret < 0) {
av_frame_free(&buf_out);
return ret;