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. > @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. > +-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. > + > + 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. > } > } > > @@ -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
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel