00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00026 #include "libavutil/audioconvert.h"
00027 #include "libavutil/internal.h"
00028 #include "libavutil/opt.h"
00029
00030 #include "audio.h"
00031 #include "avfilter.h"
00032 #include "formats.h"
00033 #include "internal.h"
00034
00035 typedef struct ChannelSplitContext {
00036 const AVClass *class;
00037
00038 uint64_t channel_layout;
00039 char *channel_layout_str;
00040 } ChannelSplitContext;
00041
00042 #define OFFSET(x) offsetof(ChannelSplitContext, x)
00043 #define A AV_OPT_FLAG_AUDIO_PARAM
00044 #define F AV_OPT_FLAG_FILTERING_PARAM
00045 static const AVOption channelsplit_options[] = {
00046 { "channel_layout", "Input channel layout.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, { .str = "stereo" }, .flags = A|F },
00047 { NULL },
00048 };
00049
00050 AVFILTER_DEFINE_CLASS(channelsplit);
00051
00052 static int init(AVFilterContext *ctx, const char *arg)
00053 {
00054 ChannelSplitContext *s = ctx->priv;
00055 int nb_channels;
00056 int ret = 0, i;
00057
00058 s->class = &channelsplit_class;
00059 av_opt_set_defaults(s);
00060 if ((ret = av_set_options_string(s, arg, "=", ":")) < 0)
00061 return ret;
00062 if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
00063 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
00064 s->channel_layout_str);
00065 ret = AVERROR(EINVAL);
00066 goto fail;
00067 }
00068
00069 nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
00070 for (i = 0; i < nb_channels; i++) {
00071 uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, i);
00072 AVFilterPad pad = { 0 };
00073
00074 pad.type = AVMEDIA_TYPE_AUDIO;
00075 pad.name = av_get_channel_name(channel);
00076
00077 ff_insert_outpad(ctx, i, &pad);
00078 }
00079
00080 fail:
00081 av_opt_free(s);
00082 return ret;
00083 }
00084
00085 static int query_formats(AVFilterContext *ctx)
00086 {
00087 ChannelSplitContext *s = ctx->priv;
00088 AVFilterChannelLayouts *in_layouts = NULL;
00089 int i;
00090
00091 ff_set_common_formats (ctx, ff_planar_sample_fmts());
00092 ff_set_common_samplerates(ctx, ff_all_samplerates());
00093
00094 ff_add_channel_layout(&in_layouts, s->channel_layout);
00095 ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->out_channel_layouts);
00096
00097 for (i = 0; i < ctx->nb_outputs; i++) {
00098 AVFilterChannelLayouts *out_layouts = NULL;
00099 uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, i);
00100
00101 ff_add_channel_layout(&out_layouts, channel);
00102 ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->in_channel_layouts);
00103 }
00104
00105 return 0;
00106 }
00107
00108 static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
00109 {
00110 AVFilterContext *ctx = inlink->dst;
00111 int i, ret = 0;
00112
00113 for (i = 0; i < ctx->nb_outputs; i++) {
00114 AVFilterBufferRef *buf_out = avfilter_ref_buffer(buf, ~AV_PERM_WRITE);
00115
00116 if (!buf_out) {
00117 ret = AVERROR(ENOMEM);
00118 break;
00119 }
00120
00121 buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i];
00122 buf_out->audio->channel_layout =
00123 av_channel_layout_extract_channel(buf->audio->channel_layout, i);
00124
00125 ret = ff_filter_samples(ctx->outputs[i], buf_out);
00126 if (ret < 0)
00127 break;
00128 }
00129 avfilter_unref_buffer(buf);
00130 return ret;
00131 }
00132
00133 AVFilter avfilter_af_channelsplit = {
00134 .name = "channelsplit",
00135 .description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams"),
00136 .priv_size = sizeof(ChannelSplitContext),
00137
00138 .init = init,
00139 .query_formats = query_formats,
00140
00141 .inputs = (const AVFilterPad[]){{ .name = "default",
00142 .type = AVMEDIA_TYPE_AUDIO,
00143 .filter_samples = filter_samples, },
00144 { NULL }},
00145 .outputs = NULL,
00146 .priv_class = &channelsplit_class,
00147 };