summaryrefslogtreecommitdiff
path: root/libavfilter/af_join.c
diff options
context:
space:
mode:
authorJames Almer <jamrial@gmail.com>2021-08-31 11:03:14 -0300
committerJames Almer <jamrial@gmail.com>2022-03-15 09:42:46 -0300
commit1f96db959c1235bb7079d354e09914a0a2608f62 (patch)
tree21ac480d5b148c0524761853e6badb3a90a7ca3f /libavfilter/af_join.c
parent8a5896ec1f635ccf0d726f7ba7a06649ebeebf25 (diff)
downloadffmpeg-1f96db959c1235bb7079d354e09914a0a2608f62.tar.gz
avfilter: convert to new channel layout API
Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavfilter/af_join.c')
-rw-r--r--libavfilter/af_join.c270
1 files changed, 177 insertions, 93 deletions
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index 6cc21f465c..3e272d9161 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -24,6 +24,7 @@
* a single output
*/
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
@@ -36,10 +37,10 @@
#include "internal.h"
typedef struct ChannelMap {
- int input; ///< input stream index
- int in_channel_idx; ///< index of in_channel in the input stream data
- uint64_t in_channel; ///< layout describing the input channel
- uint64_t out_channel; ///< layout describing the output channel
+ int input; ///< input stream index
+ int in_channel_idx; ///< index of in_channel in the input stream data
+ enum AVChannel in_channel;
+ enum AVChannel out_channel;
} ChannelMap;
typedef struct JoinContext {
@@ -48,11 +49,10 @@ typedef struct JoinContext {
int inputs;
char *map;
char *channel_layout_str;
- uint64_t channel_layout;
+ AVChannelLayout ch_layout;
int64_t eof_pts;
- int nb_channels;
ChannelMap *channels;
/**
@@ -79,20 +79,21 @@ static const AVOption join_options[] = {
{ NULL }
};
+#define MAP_SEPARATOR '|'
+
AVFILTER_DEFINE_CLASS(join);
static int parse_maps(AVFilterContext *ctx)
{
JoinContext *s = ctx->priv;
- char separator = '|';
char *cur = s->map;
while (cur && *cur) {
+ ChannelMap *map;
char *sep, *next, *p;
- uint64_t in_channel = 0, out_channel = 0;
- int input_idx, out_ch_idx, in_ch_idx;
+ int input_idx, out_ch_idx;
- next = strchr(cur, separator);
+ next = strchr(cur, MAP_SEPARATOR);
if (next)
*next++ = 0;
@@ -104,28 +105,16 @@ static int parse_maps(AVFilterContext *ctx)
}
*sep++ = 0;
-#define PARSE_CHANNEL(str, var, inout) \
- if (!(var = av_get_channel_layout(str))) { \
- av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
- return AVERROR(EINVAL); \
- } \
- if (av_get_channel_layout_nb_channels(var) != 1) { \
- av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
- inout " channel.\n"); \
- return AVERROR(EINVAL); \
- }
-
/* parse output channel */
- PARSE_CHANNEL(sep, out_channel, "output");
- if (!(out_channel & s->channel_layout)) {
- av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
- "requested channel layout.\n", sep);
+ out_ch_idx = av_channel_layout_index_from_string(&s->ch_layout, sep);
+ if (out_ch_idx < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid output channel: %s.\n", sep);
return AVERROR(EINVAL);
}
- out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
- out_channel);
- if (s->channels[out_ch_idx].input >= 0) {
+ map = &s->channels[out_ch_idx];
+
+ if (map->input >= 0) {
av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
"'%s'.\n", sep);
return AVERROR(EINVAL);
@@ -142,19 +131,21 @@ static int parse_maps(AVFilterContext *ctx)
if (*cur)
cur++;
- in_ch_idx = strtol(cur, &p, 0);
+ map->input = input_idx;
+ map->in_channel = AV_CHAN_NONE;
+ map->in_channel_idx = strtol(cur, &p, 0);
if (p == cur) {
- /* channel specifier is not a number,
- * try to parse as channel name */
- PARSE_CHANNEL(cur, in_channel, "input");
+ /* channel specifier is not a number, handle as channel name */
+ map->in_channel = av_channel_from_string(cur);
+ if (map->in_channel < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid input channel: %s.\n", cur);
+ return AVERROR(EINVAL);
+ }
+ } else if (map->in_channel_idx < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid input channel index: %d\n", map->in_channel_idx);
+ return AVERROR(EINVAL);
}
- s->channels[out_ch_idx].input = input_idx;
- if (in_channel)
- s->channels[out_ch_idx].in_channel = in_channel;
- else
- s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
-
cur = next;
}
return 0;
@@ -165,22 +156,37 @@ static av_cold int join_init(AVFilterContext *ctx)
JoinContext *s = ctx->priv;
int ret, i;
- if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
- av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
+ ret = av_channel_layout_from_string(&s->ch_layout, s->channel_layout_str);
+ if (ret < 0) {
+#if FF_API_OLD_CHANNEL_LAYOUT
+ uint64_t mask;
+FF_DISABLE_DEPRECATION_WARNINGS
+ mask = av_get_channel_layout(s->channel_layout_str);
+ if (!mask) {
+#endif
+ av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
+ s->channel_layout_str);
+ return AVERROR(EINVAL);
+#if FF_API_OLD_CHANNEL_LAYOUT
+ }
+FF_ENABLE_DEPRECATION_WARNINGS
+ av_log(ctx, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n",
s->channel_layout_str);
- return AVERROR(EINVAL);
+ av_channel_layout_from_mask(&s->ch_layout, mask);
+#endif
}
- s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
- s->channels = av_calloc(s->nb_channels, sizeof(*s->channels));
- s->buffers = av_calloc(s->nb_channels, sizeof(*s->buffers));
+ s->channels = av_calloc(s->ch_layout.nb_channels, sizeof(*s->channels));
+ s->buffers = av_calloc(s->ch_layout.nb_channels, sizeof(*s->buffers));
s->input_frames = av_calloc(s->inputs, sizeof(*s->input_frames));
if (!s->channels || !s->buffers|| !s->input_frames)
return AVERROR(ENOMEM);
- for (i = 0; i < s->nb_channels; i++) {
- s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
- s->channels[i].input = -1;
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
+ s->channels[i].out_channel = av_channel_layout_channel_from_index(&s->ch_layout, i);
+ s->channels[i].input = -1;
+ s->channels[i].in_channel_idx = -1;
+ s->channels[i].in_channel = AV_CHAN_NONE;
}
if ((ret = parse_maps(ctx)) < 0)
@@ -221,7 +227,7 @@ static int join_query_formats(AVFilterContext *ctx)
AVFilterChannelLayouts *layouts = NULL;
int i, ret;
- if ((ret = ff_add_channel_layout(&layouts, s->channel_layout)) < 0 ||
+ if ((ret = ff_add_channel_layout(&layouts, &s->ch_layout)) < 0 ||
(ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0)
return ret;
@@ -238,38 +244,55 @@ static int join_query_formats(AVFilterContext *ctx)
return 0;
}
+typedef struct ChannelList {
+ enum AVChannel *ch;
+ int nb_ch;
+} ChannelList;
+
+static enum AVChannel channel_list_pop(ChannelList *chl, int idx)
+{
+ enum AVChannel ret = chl->ch[idx];
+ memcpy(chl->ch + idx, chl->ch + idx + 1,
+ (chl->nb_ch - idx - 1) * sizeof(*chl->ch));
+ chl->nb_ch--;
+ return ret;
+}
+
+/*
+ * If ch is present in chl, remove it from the list and return it.
+ * Otherwise return AV_CHAN_NONE.
+ */
+static enum AVChannel channel_list_pop_ch(ChannelList *chl, enum AVChannel ch)
+{
+ for (int i = 0; i < chl->nb_ch; i++)
+ if (chl->ch[i] == ch)
+ return channel_list_pop(chl, i);
+ return AV_CHAN_NONE;
+}
+
static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
- uint64_t *inputs)
+ ChannelList *inputs)
{
int i;
for (i = 0; i < ctx->nb_inputs; i++) {
- AVFilterLink *link = ctx->inputs[i];
-
- if (ch->out_channel & link->channel_layout &&
- !(ch->out_channel & inputs[i])) {
+ if (channel_list_pop_ch(&inputs[i], ch->out_channel) != AV_CHAN_NONE) {
ch->input = i;
ch->in_channel = ch->out_channel;
- inputs[i] |= ch->out_channel;
return;
}
}
}
static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
- uint64_t *inputs)
+ ChannelList *inputs)
{
int i;
for (i = 0; i < ctx->nb_inputs; i++) {
- AVFilterLink *link = ctx->inputs[i];
-
- if ((inputs[i] & link->channel_layout) != link->channel_layout) {
- uint64_t unused = link->channel_layout & ~inputs[i];
-
+ if (inputs[i].nb_ch) {
ch->input = i;
- ch->in_channel = av_channel_layout_extract_channel(unused, 0);
- inputs[i] |= ch->in_channel;
+ ch->in_channel = channel_list_pop(&inputs[i], 0);
return;
}
}
@@ -279,81 +302,136 @@ static int join_config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
JoinContext *s = ctx->priv;
- uint64_t *inputs; // nth element tracks which channels are used from nth input
+ // unused channels from each input
+ ChannelList *inputs_unused;
+ char inbuf[64], outbuf[64];
int i, ret = 0;
- /* initialize inputs to user-specified mappings */
- if (!(inputs = av_calloc(ctx->nb_inputs, sizeof(*inputs))))
+ /* initialize unused channel list for each input */
+ inputs_unused = av_calloc(ctx->nb_inputs, sizeof(*inputs_unused));
+ if (!inputs_unused)
return AVERROR(ENOMEM);
- for (i = 0; i < s->nb_channels; i++) {
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ AVFilterLink *inlink = ctx->inputs[i];
+ AVChannelLayout *chl = &inlink->ch_layout;
+ ChannelList *iu = &inputs_unused[i];
+
+ iu->nb_ch = chl->nb_channels;
+ iu->ch = av_malloc_array(iu->nb_ch, sizeof(*iu->ch));
+ if (!iu->ch) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for (int ch_idx = 0; ch_idx < iu->nb_ch; ch_idx++) {
+ iu->ch[ch_idx] = av_channel_layout_channel_from_index(chl, ch_idx);
+ if (iu->ch[ch_idx] < 0) {
+ /* no channel ordering information in this input,
+ * so don't auto-map from it */
+ iu->nb_ch = 0;
+ break;
+ }
+ }
+ }
+
+ /* process user-specified maps */
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
AVFilterLink *inlink;
+ AVChannelLayout *ichl;
+ ChannelList *iu;
if (ch->input < 0)
continue;
inlink = ctx->inputs[ch->input];
+ ichl = &inlink->ch_layout;
+ iu = &inputs_unused[ch->input];
+
+ /* get the index for the channels defined by name */
+ if (ch->in_channel != AV_CHAN_NONE) {
+ ch->in_channel_idx = av_channel_layout_index_from_channel(ichl, ch->in_channel);
+ if (ch->in_channel_idx < 0) {
+ av_channel_name(inbuf, sizeof(inbuf), ch->in_channel);
+ av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
+ "input stream #%d.\n", inbuf,
+ ch->input);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
- if (!ch->in_channel)
- ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
- ch->in_channel_idx);
-
- if (!(ch->in_channel & inlink->channel_layout)) {
- av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
- "input stream #%d.\n", av_get_channel_name(ch->in_channel),
- ch->input);
+ /* make sure channels specified by index actually exist */
+ if (ch->in_channel_idx >= ichl->nb_channels) {
+ av_log(ctx, AV_LOG_ERROR, "Requested channel with index %d is not "
+ "present in input stream #%d.\n", ch->in_channel_idx, ch->input);
ret = AVERROR(EINVAL);
goto fail;
}
- inputs[ch->input] |= ch->in_channel;
+ channel_list_pop_ch(iu, av_channel_layout_channel_from_index(ichl, ch->in_channel_idx));
}
/* guess channel maps when not explicitly defined */
/* first try unused matching channels */
- for (i = 0; i < s->nb_channels; i++) {
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
if (ch->input < 0)
- guess_map_matching(ctx, ch, inputs);
+ guess_map_matching(ctx, ch, inputs_unused);
}
/* if the above failed, try to find _any_ unused input channel */
- for (i = 0; i < s->nb_channels; i++) {
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
if (ch->input < 0)
- guess_map_any(ctx, ch, inputs);
+ guess_map_any(ctx, ch, inputs_unused);
if (ch->input < 0) {
+ av_channel_name(outbuf, sizeof(outbuf), ch->out_channel);
av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
"output channel '%s'.\n",
- av_get_channel_name(ch->out_channel));
+ outbuf);
+ ret = AVERROR(EINVAL);
goto fail;
}
- ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
- ch->in_channel);
+ if (ch->in_channel != AV_CHAN_NONE) {
+ ch->in_channel_idx = av_channel_layout_index_from_channel(
+ &ctx->inputs[ch->input]->ch_layout, ch->in_channel);
+ }
+
+ av_assert0(ch->in_channel_idx >= 0);
}
/* print mappings */
av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
- for (i = 0; i < s->nb_channels; i++) {
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
- av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
- av_get_channel_name(ch->in_channel),
- av_get_channel_name(ch->out_channel));
+ AVFilterLink *inlink = ctx->inputs[ch->input];
+ AVChannelLayout *ichl = &inlink->ch_layout;
+ enum AVChannel in_ch = av_channel_layout_channel_from_index(
+ ichl, ch->in_channel_idx);
+
+ av_channel_name(inbuf, sizeof(inbuf), in_ch);
+ av_channel_name(outbuf, sizeof(outbuf), ch->out_channel);
+ av_log(ctx, AV_LOG_VERBOSE, "%d.%s(%d) => %s(%d) ", ch->input,
+ inbuf, ch->in_channel_idx,
+ outbuf, i);
}
av_log(ctx, AV_LOG_VERBOSE, "\n");
for (i = 0; i < ctx->nb_inputs; i++) {
- if (!inputs[i])
+ if (inputs_unused[i].nb_ch == ctx->inputs[i]->ch_layout.nb_channels)
av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
"stream %d.\n", i);
}
fail:
- av_freep(&inputs);
+ for (i = 0; i < ctx->nb_inputs; i++)
+ av_freep(&inputs_unused[i].ch);
+ av_freep(&inputs_unused);
return ret;
}
@@ -382,8 +460,8 @@ static int try_push_frame(AVFilterContext *ctx)
frame = av_frame_alloc();
if (!frame)
return AVERROR(ENOMEM);
- if (s->nb_channels > FF_ARRAY_ELEMS(frame->data)) {
- frame->extended_data = av_calloc(s->nb_channels,
+ if (s->ch_layout.nb_channels > FF_ARRAY_ELEMS(frame->data)) {
+ frame->extended_data = av_calloc(s->ch_layout.nb_channels,
sizeof(*frame->extended_data));
if (!frame->extended_data) {
ret = AVERROR(ENOMEM);
@@ -392,7 +470,7 @@ static int try_push_frame(AVFilterContext *ctx)
}
/* copy the data pointers */
- for (i = 0; i < s->nb_channels; i++) {
+ for (i = 0; i < s->ch_layout.nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
AVFrame *cur = s->input_frames[ch->input];
AVBufferRef *buf;
@@ -442,15 +520,21 @@ static int try_push_frame(AVFilterContext *ctx)
}
frame->nb_samples = nb_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
frame->channel_layout = outlink->channel_layout;
- frame->channels = outlink->channels;
+ frame->channels = outlink->ch_layout.nb_channels;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ if ((ret = av_channel_layout_copy(&frame->ch_layout, &outlink->ch_layout)) < 0)
+ return ret;
frame->sample_rate = outlink->sample_rate;
frame->format = outlink->format;
frame->pts = s->input_frames[0]->pts;
frame->linesize[0] = linesize;
if (frame->data != frame->extended_data) {
memcpy(frame->data, frame->extended_data, sizeof(*frame->data) *
- FFMIN(FF_ARRAY_ELEMS(frame->data), s->nb_channels));
+ FFMIN(FF_ARRAY_ELEMS(frame->data), s->ch_layout.nb_channels));
}
s->eof_pts = frame->pts + av_rescale_q(frame->nb_samples,