Search code examples
ffmpeg

ignore "channel_layout" when working with multichannel audio in ffmpeg


I'm working with multichannel audio files (higher-order ambisonics), that typically have at least 16 channels.

Sometimes I'm only interested in a subset of the audiochannels (e.g. the first 25 channels of a file that contains even more channels).

For this I have a script like the following, that takes a multichannel input file, an output file and the number of channels I want to extract:

#!/bin/sh
infile=$1
outfile=$2
channels=$3

channelmap=$(seq -s"|" 0 $((channels-1)))

ffmpeg -y -hide_banner \
  -i "${infile}" \
  -filter_complex "[0:a]channelmap=${channelmap}" \
  -c:a  libopus -mapping_family 255 -b:a 160k -sample_fmt s16 -vn -f webm -dash 1 \
  "${outfile}"

The actual channel extraction is done via the channelmap filter, that is invoked with something like -filter:complex "[0:a]channelmap=0|1|2|3"

This works great with 1,2,4 or 16 channels.

However, it fails with 9 channels, and 25 and 17 (and generally anything with >>16 channels).

The error I get is:

$ ffmpeg -y -hide_banner -i input.wav  -filter_complex "[0:a]channelmap=0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16" -c:a libopus -mapping_family 255 -b:a 160k  -sample_fmt s16 -vn -f webm -dash 1 output.webm
Input #0, wav, from 'input.wav':
  Duration: 00:00:09.99, bitrate: 17649 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 25 channels, s16, 17640 kb/s
[Parsed_channelmap_0 @ 0x5568874ffbc0] Output channel layout is not set and cannot be guessed from the maps.
[AVFilterGraph @ 0x5568874fff40] Error initializing filter 'channelmap' with args '0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16'
Error initializing complex filters.
Invalid argument

So ffmpeg cannot guess the channel layout for a 17 channel file. ffmpeg -layouts only lists channel layouts with 1,2,3,4,5,6,7,8 & 16.

However, I really don't care about the channel layout. The entire concept of "channel layout" is centered around the idea, that each audio channel should go to a different speaker. But my audio channels are not speaker feeds at all.

So I tried providing explicit channel layouts, with something like -filter_complex "[0:a]channelmap=map=0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16:channel_layout=unknown", but this results in an error when parsing the channel layout:

$ ffmpeg -y -hide_banner -i input.wav  -filter_complex "[0:a]channelmap=map=0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16:channel_layout=unknown" -c:a  libopus -mapping_family 255 -b:a 160k  -sample_fmt s16 -vn -f webm -dash 1 output.webm
Input #0, wav, from 'input.wav':
  Duration: 00:00:09.99, bitrate: 17649 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 25 channels, s16, 17640 kb/s
[Parsed_channelmap_0 @ 0x55b60492bf80] Error parsing channel layout: 'unknown'.
[AVFilterGraph @ 0x55b604916d00] Error initializing filter 'channelmap' with args 'map=0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16:channel_layout=unknown'
Error initializing complex filters.
Invalid argument

I also tried values like any, all, none, 0x0 and 0xFF with the same result. I tried using mono (as the channels are kind-of independent), but ffmpeg is trying to be clever and tells me that a mono layout must not have 17 channels.

I know that ffmpeg can handle multi-channel files without a layout. E.g. converting a 25-channel file without the -filter_complex "..." works without problems, and ffprobe gives me an unknown channel layout.

So: how do I tell ffmpeg to just not care about the channel_layout when creating an output file that only contains a subset of the input channels?


Solution

  • Based on Audio Channel Manipulation you could try splitting into n separate streams the amerge them back together:

    -filter_complex "\
    [0:a]pan=mono|c0=c0[a0];\
    [0:a]pan=mono|c0=c1[a1];\
    [0:a]pan=mono|c0=c2[a2];\
    [0:a]pan=mono|c0=c3[a3];\
    [0:a]pan=mono|c0=c4[a4];\
    [0:a]pan=mono|c0=c5[a5];\
    [0:a]pan=mono|c0=c6[a6];\
    [0:a]pan=mono|c0=c7[a7];\
    [0:a]pan=mono|c0=c8[a8];\
    [0:a]pan=mono|c0=c9[a9];\
    [0:a]pan=mono|c0=c10[a10];\
    [0:a]pan=mono|c0=c11[a11];\
    [0:a]pan=mono|c0=c12[a12];\
    [0:a]pan=mono|c0=c13[a13];\
    [0:a]pan=mono|c0=c14[a14];\
    [0:a]pan=mono|c0=c15[a15];\
    [0:a]pan=mono|c0=c16[a16];\
    [a0][a1][a2][a3][a4][a5][a6][a7][a8][a9][a10][a11][a12][a13][a14][a15][a16]amerge=inputs=17"