On 3/21/18, Nicolas George <geo...@nsup.org> wrote: > Paul B Mahol (2018-03-20): >> So user can pick which channels to extract. >> >> Signed-off-by: Paul B Mahol <one...@gmail.com> >> --- >> doc/filters.texi | 15 ++++++++++++ >> libavfilter/af_channelsplit.c | 54 >> +++++++++++++++++++++++++++++++++++-------- >> 2 files changed, 60 insertions(+), 9 deletions(-) > > Quick and incomplete review, for the sake of courtesy. > >> >> diff --git a/doc/filters.texi b/doc/filters.texi >> index bd43a7ac6e..81310e1cdf 100644 >> --- a/doc/filters.texi >> +++ b/doc/filters.texi >> @@ -2208,8 +2208,14 @@ It accepts the following parameters: >> @table @option >> @item channel_layout >> The channel layout of the input stream. The default is "stereo". > >> +@item channels >> +The channel layout of the channels for extraction. The default is "all". > > You do not specify what happens if it specifies channels that are not > present in the input.
OK, what happens is that it fails, and reports reason to the user. > >> @end table >> >> +@subsection Examples >> + >> +@itemize >> +@item >> For example, assuming a stereo input MP3 file, >> @example >> ffmpeg -i in.mp3 -filter_complex channelsplit out.mkv >> @@ -2217,6 +2223,7 @@ ffmpeg -i in.mp3 -filter_complex channelsplit >> out.mkv >> will create an output Matroska file with two audio streams, one >> containing only >> the left channel and the other the right channel. >> >> +@item >> Split a 5.1 WAV file into per-channel files: >> @example >> ffmpeg -i in.wav -filter_complex >> @@ -2226,6 +2233,14 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' >> side_left.wav -map '[SR]' >> side_right.wav >> @end example >> >> +@item >> +Extract LFE from a 5.1 WAV file: >> +@example > >> +ffmpeg -i in.wav -filter_complex >> 'channelsplit=channel_layout=5.1:LFE[LFE]' > > "channel_layout=5.1:channels=LFE"; avoid giving examples relying on > the order of options, especially for secondary ones. OK > >> +-map '[LFE]' lfe.wav >> +@end example >> +@end itemize >> + >> @section chorus >> Add a chorus effect to the audio. >> >> diff --git a/libavfilter/af_channelsplit.c >> b/libavfilter/af_channelsplit.c >> index 8c6b00fe4f..d9b9a60420 100644 >> --- a/libavfilter/af_channelsplit.c >> +++ b/libavfilter/af_channelsplit.c >> @@ -38,6 +38,9 @@ typedef struct ChannelSplitContext { >> >> uint64_t channel_layout; >> char *channel_layout_str; >> + char *channels_str; >> + > >> + int map[64]; > > Minor: could be char to save some memory. > >> } ChannelSplitContext; >> >> #define OFFSET(x) offsetof(ChannelSplitContext, x) >> @@ -45,6 +48,7 @@ typedef struct ChannelSplitContext { >> #define F AV_OPT_FLAG_FILTERING_PARAM >> static const AVOption channelsplit_options[] = { >> { "channel_layout", "Input channel layout.", >> OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, { .str = "stereo" }, >> .flags = A|F }, >> + { "channels", "Channels to extract.", OFFSET(channels_str), >> AV_OPT_TYPE_STRING, { .str = "all" }, .flags = A|F }, >> { NULL } >> }; >> >> @@ -64,15 +68,46 @@ static av_cold int init(AVFilterContext *ctx) >> } >> >> nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); >> - for (i = 0; i < nb_channels; i++) { >> - uint64_t channel = >> av_channel_layout_extract_channel(s->channel_layout, i); >> - AVFilterPad pad = { 0 }; >> >> - pad.type = AVMEDIA_TYPE_AUDIO; >> - pad.name = av_get_channel_name(channel); >> + if (!strcmp(s->channels_str, "all")) { >> + for (i = 0; i < nb_channels; i++) { >> + uint64_t channel = >> av_channel_layout_extract_channel(s->channel_layout, i); >> + AVFilterPad pad = { 0 }; >> + >> + pad.type = AVMEDIA_TYPE_AUDIO; >> + pad.name = av_get_channel_name(channel); >> + >> + s->map[i] = i; >> >> - if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { >> + if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { >> + return ret; >> + } >> + } >> + } else { > > >> + uint64_t channel_layout; >> + int nb_extracted_channels; > > Inconsistent variable names. I dont follow. > >> + >> + if ((ret = av_get_extended_channel_layout(s->channels_str, >> &channel_layout, &nb_extracted_channels)) < 0) >> return ret; >> + >> + for (i = 0; i < nb_extracted_channels; i++) { >> + uint64_t channel = >> av_channel_layout_extract_channel(channel_layout, i); >> + AVFilterPad pad = { 0 }; >> + >> + if ((ret = >> av_get_channel_layout_channel_index(s->channel_layout, channel)) < 0) { >> + av_log(ctx, AV_LOG_ERROR, "Channel name '%s' not present >> in channel layout '%s'.\n", >> + av_get_channel_name(channel), >> s->channel_layout_str); >> + return ret; >> + } >> + >> + s->map[i] = ret; >> + >> + pad.type = AVMEDIA_TYPE_AUDIO; >> + pad.name = av_get_channel_name(channel); >> + >> + if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { >> + return ret; >> + } > > Stop using copy-paste! Set extracted_channels to either the parsed value > or the same as s->channel_layout and build the map only once. Where do you see I copy pasted anything? > >> } >> } >> >> @@ -96,7 +131,7 @@ static int query_formats(AVFilterContext *ctx) >> >> for (i = 0; i < ctx->nb_outputs; i++) { >> AVFilterChannelLayouts *out_layouts = NULL; >> - uint64_t channel = >> av_channel_layout_extract_channel(s->channel_layout, i); >> + uint64_t channel = >> av_channel_layout_extract_channel(s->channel_layout, s->map[i]); >> >> if ((ret = ff_add_channel_layout(&out_layouts, channel)) < 0 || >> (ret = ff_channel_layouts_ref(out_layouts, >> &ctx->outputs[i]->in_channel_layouts)) < 0) >> @@ -109,6 +144,7 @@ static int query_formats(AVFilterContext *ctx) >> static int filter_frame(AVFilterLink *inlink, AVFrame *buf) >> { >> AVFilterContext *ctx = inlink->dst; >> + ChannelSplitContext *s = ctx->priv; >> int i, ret = 0; >> >> for (i = 0; i < ctx->nb_outputs; i++) { >> @@ -119,9 +155,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame >> *buf) >> break; >> } >> >> - buf_out->data[0] = buf_out->extended_data[0] = >> buf_out->extended_data[i]; >> + buf_out->data[0] = buf_out->extended_data[0] = >> buf_out->extended_data[s->map[i]]; >> buf_out->channel_layout = >> - av_channel_layout_extract_channel(buf->channel_layout, i); >> + av_channel_layout_extract_channel(buf->channel_layout, >> s->map[i]); >> buf_out->channels = 1; >> >> ret = ff_filter_frame(ctx->outputs[i], buf_out); > > Regards, > > -- > Nicolas George Accepted stuff fixed locally and gonna apply. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel