In ffmpeg 6.0 I want to get the channel layout syntax name like: FFmpeg Channel Layout Syntax
Then I could use some filter like aformat :
aformat=sample_fmts=u8|s16:channel_layouts=stereo
I did use AVCodecParameters
get the ch_layout
, but I don't know how to change it to channel layout syntax, like: stereo, or 5.1.
Is there any function we could get it? thanks.
We may use av_channel_layout_describe for getting string describing the channel layout.
int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size)
:
Get a human-readable string describing the channel layout properties.
For getting the description, we have to find the channel layout (AVChannelLayout
structure) of the audio stream first.
Open an input file and find stream information:
avformat_open_input(&avFmtCtx, input_file, nullptr, nullptr)
avformat_find_stream_info(avFmtCtx, nullptr)
Find the index of the relevant audio stream (first audio stream for example), and get codec parameters:
int streamIndex = -1;
for (int si = 0; si < (int)avFmtCtx->nb_streams; si++)
{
if (avFmtCtx->streams[si]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
avCodecParams = avFmtCtx->streams[si]->codecpar;
streamIndex = si;
break;
}
}
Get channel layout description:
char chLayoutDescription[128];
int sts = av_channel_layout_describe(&avCodecParams->ch_layout, chLayoutDescription, sizeof(chLayoutDescription));
Code sample:
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}
#include <stdio.h>
//Create "stereo.mp4" for testing:
//ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -f lavfi -i sine=frequency=100 -f lavfi -i sine=frequency=1000 -map_channel 1.0.0 -map_channel 2.0.0 -acodec aac -ar 44100 -ac 2 -t 10 stereo.mp4
//Create "six_channels.mp4" for testing:
//ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -f lavfi -i sine=frequency=100 -f lavfi -i sine=frequency=500 -f lavfi -i sine=frequency=600 -f lavfi -i sine=frequency=700 -f lavfi -i sine=frequency=800 -f lavfi -i sine=frequency=900 -map_channel 1.0.0 -map_channel 2.0.0 -map_channel 3.0.0 -map_channel 4.0.0 -map_channel 5.0.0 -map_channel 6.0.0 -acodec aac -ar 44100 -ac 6 -t 10 six_channels.mp4
int main()
{
const char *input_file = "stereo.mp4"; //Output: ch_layout_description = stereo
//const char *input_file = "six_channels.mp4"; //Output: ch_layout_description = 5.1
AVFormatContext* avFmtCtx = avformat_alloc_context();
AVStream* avFirstAudioStream = nullptr;
AVCodecParameters* avCodecParams = nullptr;
//https://stackoverflow.com/q/76083629/4926757
if (avformat_open_input(&avFmtCtx, input_file, nullptr, nullptr) != 0)
{
fprintf(stderr, "Couldn't open file with avformat_open_input\n");
return 1;
}
if (avformat_find_stream_info(avFmtCtx, nullptr) < 0)
{
fprintf(stderr, "Couldn't get stream info with avformat_find_stream_info\n");
return 1;
}
//Find the index of the first audio stream, and get codec parameters
int streamIndex = -1;
for (int si = 0; si < (int)avFmtCtx->nb_streams; si++)
{
if (avFmtCtx->streams[si]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
avCodecParams = avFmtCtx->streams[si]->codecpar;
streamIndex = si;
break;
}
}
//Get channel layout description:
////////////////////////////////////////////////////////////////////////////
char chLayoutDescription[128];
int sts = av_channel_layout_describe(&avCodecParams->ch_layout, chLayoutDescription, sizeof(chLayoutDescription));
if (sts < 0)
{
fprintf(stderr, "Error: av_channel_layout_describe returned status %d\n", sts); //Error...
return 1;
}
printf("ch_layout_description = %s\n", chLayoutDescription); //Print channel layout description
////////////////////////////////////////////////////////////////////////////
avformat_free_context(avFmtCtx);
return 0;
}
Reading the channel layout of dshow microphone device:
When reading the channel layout of the microphone, the channel layout description is 2 channels
and not stereo
.
Looking at avCodecParams->ch_layout
of "stereo.mp4"
file, we may see that:
order
= AV_CHANNEL_ORDER_NATIVE
nb_channels
= 2
Looking at avCodecParams->ch_layout
of the microphone (using the debugger), we may see that:
order
= AV_CHANNEL_ORDER_UNSPEC
nb_channels
= 2
We may conclude that the channels order of the microphone is unspecified.
When the channels order is unspecified, FFmpeg reports 2 channels
instead of stereo
.
Looking at my microphone, it looks like the two microphones holds are one very close, and located one above the other (while stereo layout supposed to be left and right with some distance).
I don't know if there are microphone models that reports stereo
layout, but 2 channels
layout seems correct for my microphone.
Getting the default channel layout for the given number of channels:
We may use av_channel_layout_default
for getting the default channel layout for the given number of channels (i.e getting stereo
for 2 channels).
Code sample for getting the default channel layout:
char defaultChLayoutDescription[128];
AVChannelLayout default_ch_layout;
av_channel_layout_default(&default_ch_layout, avCodecParams->ch_layout.nb_channels);
sts = av_channel_layout_describe(&default_ch_layout, defaultChLayoutDescription, sizeof(defaultChLayoutDescription));
Code sample for getting the channel layout of a microphone, and also getting the default layout for 2 channels:
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavutil/avutil.h>
}
#include <stdio.h>
//Create "stereo.mp4" for testing:
//ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -f lavfi -i sine=frequency=100 -f lavfi -i sine=frequency=1000 -map_channel 1.0.0 -map_channel 2.0.0 -acodec aac -ar 44100 -ac 2 -t 10 stereo.mp4
//Create "six_channels.mp4" for testing:
//ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -f lavfi -i sine=frequency=100 -f lavfi -i sine=frequency=500 -f lavfi -i sine=frequency=600 -f lavfi -i sine=frequency=700 -f lavfi -i sine=frequency=800 -f lavfi -i sine=frequency=900 -map_channel 1.0.0 -map_channel 2.0.0 -map_channel 3.0.0 -map_channel 4.0.0 -map_channel 5.0.0 -map_channel 6.0.0 -acodec aac -ar 44100 -ac 6 -t 10 six_channels.mp4
//Listing dshow devices:
//ffmpeg -list_devices true -f dshow -i dummy
int main()
{
//const char *input_file = "stereo.mp4"; //Output: ch_layout_description = stereo
//const char *input_file = "six_channels.mp4"; //Output: ch_layout_description = 5.1
//Capture dshow microphone
////////////////////////////////////////////////////////////////////////////
avdevice_register_all();
const char *input_file = "audio=""@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\\wave_{C7D33711-2FD7-4800-8D99-72ED74527121}"""; //Using Alternative name for my audio device.
const AVInputFormat* ifmt = av_find_input_format("dshow");
////////////////////////////////////////////////////////////////////////////
AVFormatContext* avFmtCtx = avformat_alloc_context();
AVStream* avFirstAudioStream = nullptr;
AVCodecParameters* avCodecParams = nullptr;
//https://stackoverflow.com/q/76083629/4926757
if (avformat_open_input(&avFmtCtx, input_file, ifmt, nullptr) != 0)
{
fprintf(stderr, "Couldn't open file with avformat_open_input\n");
return 1;
}
if (avformat_find_stream_info(avFmtCtx, nullptr) < 0)
{
fprintf(stderr, "Couldn't get stream info with avformat_find_stream_info\n");
return 1;
}
//Find the index of the first audio stream, and get codec parameters
int streamIndex = -1;
for (int si = 0; si < (int)avFmtCtx->nb_streams; si++)
{
if (avFmtCtx->streams[si]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
avCodecParams = avFmtCtx->streams[si]->codecpar;
streamIndex = si;
break;
}
}
//Get channel layout description:
////////////////////////////////////////////////////////////////////////////
char chLayoutDescription[128];
int sts = av_channel_layout_describe(&avCodecParams->ch_layout, chLayoutDescription, sizeof(chLayoutDescription));
if (sts < 0)
{
fprintf(stderr, "Error: av_channel_layout_describe returned status %d\n", sts); //Error...
return 1;
}
////////////////////////////////////////////////////////////////////////////
//Get the default channel layout for the given number of channels:
////////////////////////////////////////////////////////////////////////////
char defaultChLayoutDescription[128];
AVChannelLayout default_ch_layout;
av_channel_layout_default(&default_ch_layout, avCodecParams->ch_layout.nb_channels);
sts = av_channel_layout_describe(&default_ch_layout, defaultChLayoutDescription, sizeof(defaultChLayoutDescription));
if (sts < 0)
{
fprintf(stderr, "Error: av_channel_layout_describe returned status %d\n", sts); //Error...
return 1;
}
////////////////////////////////////////////////////////////////////////////
avformat_close_input(&avFmtCtx);
avformat_free_context(avFmtCtx);
fprintf(stderr, "\nchLayoutDescription = %s\n", chLayoutDescription); //Print channel layout description //2 channels
fprintf(stderr, "\ndefaultChLayoutDescription = %s\n", defaultChLayoutDescription); //Print channel layout description //stereo
return 0;
}
Output:
chLayoutDescription = 2 channels
defaultChLayoutDescription = stereo
Note:
The result is the same for FFmpeg 6.0 and FFmpeg 5.1.2 (while FFmpeg 4.4 excludes the function av_channel_layout_describe
).