From patchwork Wed Mar 21 23:02:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 8079 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.1.70 with SMTP id c67csp146778jad; Wed, 21 Mar 2018 16:08:29 -0700 (PDT) X-Google-Smtp-Source: AG47ELvo+fvnnIWeCW0ErH68NB5jVEVLJoL0HOdWMvaAYGFZ3z2pOtgJzkB3O+ykKsBinB84TSV3 X-Received: by 10.28.212.141 with SMTP id l135mr3560443wmg.122.1521673709693; Wed, 21 Mar 2018 16:08:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521673709; cv=none; d=google.com; s=arc-20160816; b=xMZGcx1hsvzx6JHGZi3AE3eHOOh7stWAXKu6Dp7bJD5nVdFX8QKyFemW1YgSST0oXF O3Ov9YyrlKUADZaxR6VeXiG2AAyrHvWNYP9AwafAp0xaed/P5cNq8FriLXp+wrZIjc7u pLxasisxeALN8+W1i5SSJgQwUu13UFyDgmoQ2wQHEoP9bCCvLnKooBxVWbCT73ishMk6 SqqUIqTTWUM/raU4vB7bAfA77Gm7JdaZ49M7TEhllxay3lnOEcm/5WQUjYIAUCgdHz8B Wip9RApiBdJY18apH3larWnDiqSfQNVh8tqdnWNLMeBL80eXtT8P5Cyost5V9yxuQy5/ 10PQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=GqpYHGVbWVqfrN2RxVQ3sdJcq0/QlWZoBPyTiniKl6o=; b=dObA6icmcWPO5wi/fAL2HaD1yQL4mizOQNCkKXo+hzT+Y67pMK3sXjMnZif0xMx9rb WklNLSvMZVCbhs+ujASqhMcsu8ham8slnykSkqDe/zUpCDyL0Lu6hBx7wxyf7RmfjOST 5ttFuDx+32tlN4p1bHnOWMXucjkyVBrBYzKsa4R1NuYlviyh96+uLpN9bAwBq9YDMpjy lMvhu2JGjFE2pR3AUbB6d96LLCErGgU1+gZuqwIVdjRW7gSeukJeO5XMT0GsE/dIF0jQ JP6s5XXFTtb3gDlrL6yo6RKPeb4RQfOAbRDpHRGeFzCH7edmz2KIVI4xjwQjt9f5EVXW svvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ZektNZpf; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id m8si77644wrg.460.2018.03.21.16.08.29; Wed, 21 Mar 2018 16:08:29 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=ZektNZpf; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CEC86689A8B; Thu, 22 Mar 2018 01:08:11 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f50.google.com (mail-wm0-f50.google.com [74.125.82.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BBDBB689950 for ; Thu, 22 Mar 2018 01:08:04 +0200 (EET) Received: by mail-wm0-f50.google.com with SMTP id e194so12575550wmd.3 for ; Wed, 21 Mar 2018 16:08:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=UNbyoOWodmJiMJYLmAPu7Al2a2I0N3RFUHLPpc3lko8=; b=ZektNZpfejcK9iIxcY8vMD1xcD5b4d9TOndhIrvNUijvqYLaWq4yN34IwqZJtg+7Dw K8VK8V2RaDVLzM0Ys772GnZAC29n5ZgoGpEjJ7J+uYM65SVXra8q7TrVk5hAcQIuA6KG Kmn9NEf9zu8NN8ruVj48JsWyJ11UQbHpATYXqrPRo7c+98wRuDJaE7Kv7CwVnpAUlhh2 nX9EuvUAWlTjXnz+UKLqH72rOqkkZG7Kcq3kdb46AVesVA34ByON8c4jvUPcL+YJx6Th 3EemG0DBayPy9PCJI2fmJfq1XOwQLcK855J9I7IF91U5dBnQA1wa17gzN33EvpmuY1HY ZZwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=UNbyoOWodmJiMJYLmAPu7Al2a2I0N3RFUHLPpc3lko8=; b=p8wUG25BkYDOjxsNLg47HUKbQurNKg4vyhhcYUff9Eu21n/kZQSl3FpEq6pv0NzW80 Y7bM3i9e5qbsfbR3GzgJEqmdKqeolzMs3e56ZX0L1A0/US+uyLYPC7Dm4EVbIuvUa6HY 2BwMAgSNcnV0+UhWkyIIvNGzsKAET6OWAp1vYeBlfIDFplDee+jrlv7uZevjVT4p7xs1 uPMLP4+N63j2cImANOm8ciR8KYVU2OS62swfkybgYLcFtXcXEUNBOSw8henE3NQtxv2I BY4JIegND+5MRHSq7zyR3MaX+s78oHZ7EdtuteRxEKAWGuV59ZKEWNThuCY0g6qVWGaZ laOw== X-Gm-Message-State: AElRT7HthENzst0KIB734sXULg8+cTXPmVGpNggOvocSJaKBVZZAhD12 HoLl07M0x/0FHc3qwVy8HhH5FQ== X-Received: by 10.28.74.22 with SMTP id x22mr112834wma.23.1521673383346; Wed, 21 Mar 2018 16:03:03 -0700 (PDT) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id s49sm7223789wrc.95.2018.03.21.16.03.02 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 16:03:02 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Thu, 22 Mar 2018 00:02:20 +0100 Message-Id: <20180321230220.13585-1-onemda@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180320181108.26163-1-onemda@gmail.com> References: <20180320181108.26163-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH] avfilter/af_channelsplit: add channels option X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" So user can pick which channels to extract. Signed-off-by: Paul B Mahol --- doc/filters.texi | 18 ++++++++++++++++++ libavfilter/af_channelsplit.c | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index aa7d4fc2d9..14e3b74a83 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2208,8 +2208,17 @@ It accepts the following parameters: @table @option @item channel_layout The channel layout of the input stream. The default is "stereo". +@item channels +A channel layout describing the channels to be extracted as separate output streams +or "all" to extract each input channel as a separate stream. The default is "all". + +Choosing channels not present in channel layout in the input will result in an error. @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 +2226,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 +2236,14 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]' side_right.wav @end example +@item +Extract only LFE from a 5.1 WAV file: +@example +ffmpeg -i in.wav -filter_complex 'channelsplit=channel_layout=5.1:channels=LFE[LFE]' +-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..821bb73801 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]; } 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 } }; @@ -53,8 +57,9 @@ AVFILTER_DEFINE_CLASS(channelsplit); static av_cold int init(AVFilterContext *ctx) { ChannelSplitContext *s = ctx->priv; + uint64_t channel_layout; int nb_channels; - int ret = 0, i; + int all = 0, ret = 0, 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", @@ -63,14 +68,35 @@ static av_cold int init(AVFilterContext *ctx) goto fail; } - nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); + + if (!strcmp(s->channels_str, "all")) { + nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); + channel_layout = s->channel_layout; + all = 1; + } else { + if ((ret = av_get_extended_channel_layout(s->channels_str, &channel_layout, &nb_channels)) < 0) + return ret; + } + for (i = 0; i < nb_channels; i++) { - uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, i); + uint64_t channel = av_channel_layout_extract_channel(channel_layout, i); AVFilterPad pad = { 0 }; pad.type = AVMEDIA_TYPE_AUDIO; pad.name = av_get_channel_name(channel); + if (all) { + s->map[i] = i; + } else { + 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; + } + if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { return ret; } @@ -96,7 +122,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 +135,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 +146,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);