FFMPEG error when finding stream information with custom AVIOContext - c++

I am writing software that takes in a file as a stream and decodes it. I have the following custom AVIO code for stream input:
/* Allocate a 4kb buffer for copying. */
std::uint32_t bufSize = 4096;
struct vidBuf
{
std::byte* ptr;
int size;
};
vidBuf tmpVidBuf = { const_cast<std::byte*>(videoBuffer.data()),
static_cast<int>(videoBuffer.size()) };
AVIOContext *avioContext =
avio_alloc_context(reinterpret_cast<std::uint8_t*>(av_malloc(bufSize)),
bufSize, 0,
reinterpret_cast<void*>(&tmpVidBuf),
[](void *opaque, std::uint8_t *buf, int bufSize) -> int
{
auto &me = *reinterpret_cast<vidBuf*>(opaque);
bufSize = std::min(bufSize, me.size);
std::copy_n(me.ptr, bufSize, reinterpret_cast<std::byte*>(buf));
me.ptr += bufSize;
me.size -= bufSize;
return bufSize;
}, nullptr, nullptr);
auto avFormatPtr = avformat_alloc_context();
avFormatPtr->pb = avioContext;
avFormatPtr->flags |= AVFMT_FLAG_CUSTOM_IO;
//avFormatPtr->probesize = tmpVidBuf.size;
//avFormatPtr->max_analyze_duration = 5000000;
avformat_open_input(&avFormatPtr, nullptr, nullptr, nullptr);
if(auto ret = avformat_find_stream_info(avFormatPtr, nullptr);
ret < 0)
logerror << "Could not open the video file: " << makeAVError(ret) << '\n';
However, when I run this code I get the error:
[mov,mp4,m4a,3gp,3g2,mj2 # 0x55d10736d580] stream 0, offset 0x30: partial file
[mov,mp4,m4a,3gp,3g2,mj2 # 0x55d10736d580] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none(tv, bt709), 540x360, 649 kb/s): unspecified pixel format
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.76.100
Duration: 00:04:08.41, start: 0.000000, bitrate: N/A
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none(tv, bt709), 540x360, 649 kb/s, SAR 1:1 DAR 3:2, 29.97 fps, 29.97 tbr, 30k tbn, 60k tbc (default)
Metadata:
handler_name : ISO Media file produced by Google Inc. Created on: 01/10/2021.
vendor_id : [0][0][0][0]
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 69 kb/s (default)
Metadata:
handler_name : ISO Media file produced by Google Inc. Created on: 01/10/2021.
vendor_id : [0][0][0][0]
Assertion desc failed at libswscale/swscale_internal.h:677
Note the absence of the YUV420p part in the video stream data.
This is strange since if I run my program with a different mp4 file it works perfectly fine, this error only occurs with a specific mp4 file. I know that the mp4 file is valid since mpv can play it, and ffprobe is able to get its metadata:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'heard.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.76.100
Duration: 00:04:08.41, start: 0.000000, bitrate: 724 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 540x360 [SAR 1:1 DAR 3:2], 649 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
Metadata:
handler_name : ISO Media file produced by Google Inc. Created on: 01/10/2021.
vendor_id : [0][0][0][0]
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 69 kb/s (default)
Metadata:
handler_name : ISO Media file produced by Google Inc. Created on: 01/10/2021.
vendor_id : [0][0][0][0]
As you can see by my code I also tried setting analyzeduration and probesize, but this did not fix the issue.
I also know that this error is because of my custom io because when I have avformat_open_input open the file directly, it is able to be decoded just fine. I am new to ffmpeg, so I might have missed something simple.

As SuRGeoNix pointed out, I had not implemented a seek function for the AVIO context; I think this messed up FFMPEG since it could not figure out the size of the buffer. This is my now working code:
std::uint32_t bufSize = 4096;
struct vidBuf
{
std::byte* ptr;
std::byte* origPtr;
int size;
int fullSize;
};
vidBuf tmpVidBuf = { const_cast<std::byte*>(videoBuffer.data()),
const_cast<std::byte*>(videoBuffer.data()),
static_cast<int>(videoBuffer.size()),
static_cast<int>(videoBuffer.size()), };
AVIOContext *avioContext =
avio_alloc_context(reinterpret_cast<std::uint8_t*>(av_malloc(bufSize)),
bufSize, 0,
reinterpret_cast<void*>(&tmpVidBuf),
[](void *opaque, std::uint8_t *buf, int bufSize) -> int
{
auto &me = *reinterpret_cast<vidBuf*>(opaque);
bufSize = std::min(bufSize, me.size);
std::copy_n(me.ptr, bufSize, reinterpret_cast<std::byte*>(buf));
me.ptr += bufSize;
me.size -= bufSize;
return bufSize;
},
nullptr,
[](void *opaque, std::int64_t where, int whence) -> std::int64_t
{
auto me = reinterpret_cast<vidBuf*>(opaque);
switch(whence)
{
case AVSEEK_SIZE:
/* Maybe size left? */
return me->fullSize;
break;
case SEEK_SET:
if(me->fullSize > where)
{
me->ptr = me->origPtr + where;
me->size = me->fullSize - where;
}
else
return EOF;
break;
case SEEK_CUR:
if(me->size > where)
{
me->ptr += where;
me->size -= where;
}
else
return EOF;
break;
case SEEK_END:
if(me->fullSize > where)
{
me->ptr = (me->origPtr + me->fullSize) - where;
int curPos = me->ptr - me->origPtr;
me->size = me->fullSize - curPos;
}
else
return EOF;
break;
default:
/* On error, do nothing, return current position of file. */
logerror << "Could not process buffer seek: "
<< whence << ".\n";
break;
}
return me->ptr - me->origPtr;
});

Related

FFMPEG library- transcode raw image to h264 stream, and the output file does not contains pts and dts info

I am trying using ffmpeg c++ library to convert several raw yuyv image to h264 stream, the image come from memory and passed as string about 24fps, i do the convention as the following steps:
init AVFormatContext,AVCodec,AVCodecContext and create new AVStream. this step i mainly refer to ffmpeg-libav-tutorial, and AVFormatContext use customize write_buffer() function(refer to simplest_ffmpeg_mem_handler)
receive raw frame data, set width and height(1920x1080), and set pts and dts. here i manually set the output fps to 24, and use a global counter to count num of frames, and the pts is calculated by this counter, code snippet(video_avs is AVStream,output_fps is 24 and time_base is 1/24):
input_frame->width = w; // 1920
input_frame->height = h; // 1080
input_frame->pkt_dts = input_frame->pts = global_pts;
global_pts += video_avs->time_base.den/video_avs->time_base.num / output_fps.num * output_fps.den;
convert it from yuyv to yuv422(because h264 does not support yuyv) and resize it from 1920x1080 to 640x480(because i need this resolution output), use sws_scale()
use avcodec_send_frame() and avcodec_receive_packet() to get the output packet. set output_packet duration and stream_index, then use av_write_frame() to write frame data.
AVPacket *output_packet = av_packet_alloc();
int response = avcodec_send_frame(encoder->video_avcc, frame);
while (response >= 0) {
response = avcodec_receive_packet(encoder->video_avcc, output_packet); // !! here output_packet.size is calculated
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
}
else if (response < 0) {
printf("Error while sending packet to decoder"); // ??av_err2str(response)会报错
return response;
}
// duration = next_pts - this_pts = timescale / fps = 1 / timebase / fps
output_packet->duration = (encoder->video_avs->time_base.den / encoder->video_avs->time_base.num) / (output_fps.num / output_fps.den);
output_packet->stream_index = 0;
int response = av_write_frame(encoder->avfc, output_packet); // packet order are not ensure
if (response != 0) { printf("Error %d while receiving packet from decoder", response); return -1;}
}
av_packet_unref(output_packet);
av_packet_free(&output_packet);
in write_buffer() function, video stream output is stored to string variable, and then i write this string to file with ostream, and suffix mp4.
after all the above steps, the output.mp4 cannot be played, the ffprobe output.mp4 -show_frames output is
(image):
Input #0, h264, from '/Users/ming/code/dev/haomo/output.mp4':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High 4:2:2), yuv422p(progressive), 640x480, 24.92 fps, 24 tbr, 1200k tbn, 48 tbc
[FRAME]
media_type=video
stream_index=0
key_frame=1
pkt_pts=N/A
pkt_pts_time=N/A
pkt_dts=N/A
pkt_dts_time=N/A
best_effort_timestamp=N/A
best_effort_timestamp_time=N/A
Note that before and after calling av_write_frame() in step 4, the passed argument output_packet contains correct pts and dts info, i cannot figure out why the output stream lost these info.
I figure it out, the output stream is a raw h264 stream, and I directly store this stream into a file with a suffix of ".mp4", so it is actually not a correct mp4 file.
Then it store the stream into output.h264 file, and use ffmpeg to convert it to mp4 file: ffmpeg -framerate 24 -i output.h264 -c copy output.mp4, finally this output.mp4 contains right pts data and can be played.

Why do i get avc1.000000? (FFMPEG, H.264 Video Encoding, C++)

I have a bunch of bitmaps, and need to make them encoded in h.264 in fragmented .mp4.
I'm using C++.
What could cause that my AVC Profile is set to 0, SPS[], PPS[] and codec string to avc1.000000?
Output from the mp4info:
File:
minor version: 200
compatible brand: iso6
compatible brand: mp41
fast start: yes
Movie:
duration: 0 ms
time scale: 1000
fragments: yes
Found 1 Tracks
Track 1:
flags: 3 ENABLED IN-MOVIE
id: 1
type: Video
duration: 0 ms
language: und
media:
sample count: 0
timescale: 90000
duration: 0 (media timescale units)
duration: 0 (ms)
bitrate (computed): 412.672 Kbps
sample count with fragments: 35
duration with fragments: 540000
duration with fragments: 6000 (ms)
display width: 1280.000000
display height: 720.000000
Sample Description 0
Coding: avc1 (H.264)
Width:n 1280
Height: 720
Depth: 24
AVC Profile: 0
AVC Profile Compat: 0
AVC Level: 0
AVC NALU Length Size: 0
AVC SPS: []
AVC PPS: []
Codecs String: avc1.000000
I'm using things like
if (stream->codecpar->codec_id == AVCodecID.AV_CODEC_ID_H264)
{
err = ffmpeg.av_opt_set(cctx->priv_data, "preset", "ultrafast", 0);
err = ffmpeg.av_opt_set(cctx->priv_data, "tune", "zerolatency", 0);
err = ffmpeg.av_opt_set(cctx->priv_data, "profile", "high", 0);
}
...
AVDictionary* opts = null;
ffmpeg.av_dict_set(&opts, "movflags", "default_base_moof+frag_keyframe+empty_moov", 0);
...
AVPacket* pPacket = ffmpeg.av_packet_alloc();
try
{
int error;
do
{
ffmpeg.avcodec_send_frame(cctx, &convertedFrame).ThrowExceptionIfError();
error = ffmpeg.avcodec_receive_packet(cctx, pPacket);
} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));
error.ThrowExceptionIfError();
}
finally
{
ffmpeg.av_packet_rescale_ts(pPacket, cctx->time_base, stream->time_base);
pPacket->stream_index = stream->index;
ffmpeg.av_interleaved_write_frame(ofctx, pPacket);
ffmpeg.av_packet_unref(pPacket);
}
What am I missing? I'm using examples from internet. Thought that if AVFrame is encoded (send_frame) with H264 with profiles and presets and received as AVPacket. It should be done automatically.
This is my first post, please be nice. Thanks in advance for helping.

can't configure hardware parameters on ALSA raspberry pi c appliction

I trying to write ALSA application for recording audio, and when I try to set some parameters and then print them to the screen I getting some default numbers that i cant change
#include <alsa/asoundlib.h>
using namespace std;
typedef struct {
int audio;
int recording;
void *cons;
snd_pcm_t *inhandle;
snd_pcm_t *outhandle;
unsigned long sampleIndex;
unsigned long inlen;
unsigned long sampleRate;
} audio_t;
static audio_t aud;
void aboutAlsa(snd_pcm_t *handle,snd_pcm_hw_params_t *params) {
unsigned int val, val2;
snd_pcm_format_t val3;
int dir;
snd_pcm_uframes_t frames;
printf("ALSA library version: %s\n",SND_LIB_VERSION_STR);
printf("PCM handle name = '%s'\n",snd_pcm_name(handle));
printf("PCM state = %s\n",snd_pcm_state_name(snd_pcm_state(handle)));
snd_pcm_hw_params_get_access(params,(snd_pcm_access_t *) &val);
printf("access type = %s\n",snd_pcm_access_name((snd_pcm_access_t)val));
snd_pcm_hw_params_get_format(params, &val3);
printf("format = '%s' (%s)\n",snd_pcm_format_name(val3),
snd_pcm_format_description(val3));
snd_pcm_hw_params_get_subformat(params,(snd_pcm_subformat_t *)&val);
printf("subformat = '%s' (%s)\n",snd_pcm_subformat_name((snd_pcm_subformat_t)val),
snd_pcm_subformat_description((snd_pcm_subformat_t)val));
snd_pcm_hw_params_get_channels(params, &val);
printf("channels = %d\n", val);
snd_pcm_hw_params_get_rate(params, &val, &dir);
printf("rate = %d bps\n", val);
snd_pcm_hw_params_get_period_time(params,&val, &dir);
printf("period time = %d us\n", val);
snd_pcm_hw_params_get_period_size(params,&frames, &dir);
printf("period size = %d frames\n", (int)frames);
snd_pcm_hw_params_get_buffer_time(params,&val, &dir);
printf("buffer time = %d us\n", val);
snd_pcm_hw_params_get_buffer_size(params,(snd_pcm_uframes_t *) &val);
printf("buffer size = %d frames\n", val);
snd_pcm_hw_params_get_periods(params, &val, &dir);
printf("periods per buffer = %d frames\n", val);
snd_pcm_hw_params_get_rate_numden(params,&val, &val2);
printf("exact rate = %d/%d bps\n", val, val2);
val = snd_pcm_hw_params_get_sbits(params);
printf("significant bits = %d\n", val);
return;
}
static int openKnownAudio(int record) {
int rc;
int SAMPLERATE = 16000;
unsigned int val;
int dir=0;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params=NULL;
snd_pcm_uframes_t frames;
size_t esz = 256;
char err[esz];
/* Open PCM device for recording (capture). */
if (record) {
if ((rc=snd_pcm_open(&aud.inhandle, "default",SND_PCM_STREAM_CAPTURE, 0))<0) {
snprintf(err, esz, "unable to open pcm device for recording: %s\n",snd_strerror(rc));
}
handle=aud.inhandle;
} else {
if ((rc=snd_pcm_open(&aud.outhandle, "default",SND_PCM_STREAM_PLAYBACK, 0))<0) {
snprintf(err, esz, "unable to open pcm device for playback: %s\n",snd_strerror(rc));
}
handle=aud.outhandle;
}
/* Configure hardware parameters */
if((rc=snd_pcm_hw_params_malloc(&hw_params)) < 0) {
snprintf(err, esz, "unable to malloc hw_params: %s\n",snd_strerror(rc));
}
if((rc=snd_pcm_hw_params_any(handle, hw_params))<0) {
snprintf(err, esz, "unable to setup hw_params: %s\n",snd_strerror(rc));
}
if((rc=snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED))<0) {
snprintf(err, esz, "unable to set access mode: %s\n",snd_strerror(rc));
}
if((rc=snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE))<0) {
snprintf(err, esz, "unable to set format: %s\n",snd_strerror(rc));
}
if((rc=snd_pcm_hw_params_set_channels(handle, hw_params, 1))<0) {
snprintf(err, esz, "unable to set channels: %s\n",snd_strerror(rc));
}
val = SAMPLERATE;
dir = 0;
if((rc=snd_pcm_hw_params_set_rate(handle, hw_params, SAMPLERATE,0))<0) {
snprintf(err, esz, "unable to set samplerate: %s\n",snd_strerror(rc));
}
if (val!=SAMPLERATE) {
snprintf(err, esz, "unable to set requested samplerate: requested=%i got=%i\n",SAMPLERATE,val);
}
frames = 64;
if ((rc=snd_pcm_hw_params_set_period_size_near(handle,hw_params, &frames, &dir))<0) {
snprintf(err, esz, "unable to set period size: %s\n",snd_strerror(rc));
}
frames = 4096;
if ((rc=snd_pcm_hw_params_set_buffer_size_near(handle,hw_params, &frames))<0) {
snprintf(err, esz, "unable to set buffer size: %s\n",snd_strerror(rc));
}
if ((rc = snd_pcm_hw_params(handle, hw_params))<0) {
snprintf(err, esz, "unable to set hw parameters: %s\n",snd_strerror(rc));
}
aboutAlsa(handle,hw_params);
snd_pcm_hw_params_free(hw_params);
aud.recording = (record)? 1:0;
aud.audio=1;
return 1;
}
This what I get on raspberry pi when I run it:
ALSA library version: 1.0.28
PCM handle name = 'default'
PCM state = PREPARED
access type = RW_INTERLEAVED
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 1
rate = 16000 bps
period time = 21333 us
period size = 341 frames
buffer time = 256000 us
buffer size = 4096 frames
periods per buffer = 4096 frames
exact rate = 16000/1 bps
significant bits = 16
And this is what I get when I run it on desktop pc:
ALSA library version: 1.0.28
PCM handle name = 'default'
PCM state = PREPARED
access type = RW_INTERLEAVED
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 1
rate = 16000 bps
period time = 4000 us
period size = 64 frames
buffer time = 256000 us
buffer size = 4096 frames
periods per buffer = 64 frames
exact rate = 16000/1 bps
significant bits = 16
As you can see I'm trying to set the period size to 64 and getting back 341, this value only changes when I change the rate, lets say I set the rate to 44100 and this what I getting back:
rate = 44100 bps
period time = 21333 us
period size = 940 frames
buffer time = 85328 us
buffer size = 3763 frames
periods per buffer = 3763 frames
On desktop pc this doesn't happens I tried to trace down this functions in alsa-lib but I getting lost there also tried different sound cards and still getting same result .
In case of PulseAudio you did set the PulseAudio device , not the real device.
The real HW can have the limitation, you must correctly react to.
If you'd like to see min/max boundary of some parameter, you can do the next:
using snd_pcm_hw_params_dump function
snd_pcm_hw_params_t *params;
snd_pcm_t *pcm_handle;
int pcm;
/* Open the PCM device in playback mode */
pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0);
if (pcm < 0) {
printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm));
goto error_handling;
}
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(&params);
pcm = snd_pcm_hw_params_any(pcm_handle, params);
if (pcm < 0) {
printf("Broken configuration for this PCM: no configurations available\n");
goto error_handling;
}
printf("hw boundary params ***********************\n");
snd_pcm_hw_params_dump(params, log);
printf("*******************************************\n");
The same using min/max functions
snd_pcm_t* pcm;
snd_pcm_hw_params_t* hw_parameters;
int parameter;
//... open device and allocate hw params here
/*Fill params with a full configuration space for a PCM.
The configuration space will be filled with all possible
ranges for the PCM device.*/
snd_pcm_hw_params_any(pcm,hw_parameters);
/* please substitute <parameter name> with real parameter name
for example buffer_size, buffer_time, rate, etc*/
snd_pcm_hw_params_get_<parameter name>_min(hw_parameters,&parameter);
printf("<parameter name> min : %d/n", parameter);
snd_pcm_hw_params_get_<parameter name>_max(hw_parameters,&parameter);
printf("<parameter name> max : %d/n", parameter);
I faced with the same issue, when tried to set the period size.
There are my boundary (two different pcm devices):
log #1
hw boundary params ***********************
ACCESS: RW_INTERLEAVED
FORMAT: U8 S16_LE S16_BE S24_LE S24_BE S32_LE S32_BE FLOAT_LE FLOAT_BE MU_LAW A_LAW S24_3LE S24_3BE
SUBFORMAT: STD
SAMPLE_BITS: [8 32]
FRAME_BITS: [8 1024]
CHANNELS: [1 32]
RATE: [1 192000]
PERIOD_TIME: (5 4294967295)
PERIOD_SIZE: [1 1398102)
PERIOD_BYTES: [128 1398102)
PERIODS: [3 1024]
BUFFER_TIME: (15 4294967295]
BUFFER_SIZE: [3 4194304]
BUFFER_BYTES: [384 4194304]
TICK_TIME: ALL
*******************************************
log#2
**********************************DEBUG
period time min : 21333
period time max : 21334
buffer time min : 1
buffer time max : -1
channels min : 1
channels max : 10000
rate min : 4000
rate max : -1
period size min : 85
period size max : 91628833
buffer size min : 170
buffer size max : 274877906
**********************************DEBUG_END
Here we can't change the period size due to period time limitation.

how to use self-defined inputSamples for trasforming pcm to aac with facc

I'm trying to transform a live stream with g726 and h264 to mp4. I decode g726 to pcm then use faac to encode pcm to aac. Every g726 audio packet I receive is 320 bytes. After decoding, the pcm size is 1280 bytes, so the sample number is 640. But the inputSamples which faacEncOpen gives me is 1024, and my inputFormat is FAAC_INPUT_16BIT. When I pass 640 to faacEncEncode, the sound is not good at all. Does anyone know how to fix this. Thanks in advance!
// (1) Open FAAC engine
hEncoder = faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes); // nInputSamples the function returns is 1024
if(hEncoder == NULL)
{
printf("[ERROR] Failed to call faacEncOpen()\n");
return -1;
}
nInputSamples = 640;// here overwrites the input samples returned from faacEncOpen
nPCMBufferSize = nInputSamples * nPCMBitSize / 8; // nPCMBitSize is 16
pbPCMBuffer = new BYTE [nPCMBufferSize];
pbAACBuffer = new BYTE [nMaxOutputBytes];
// (2.1) Get current encoding configuration
pConfiguration = faacEncGetCurrentConfiguration(hEncoder);
pConfiguration->inputFormat = FAAC_INPUT_16BIT;
// (2.2) Set encoding configuration
nRet = faacEncSetConfiguration(hEncoder, pConfiguration);
for(int i = 0; 1; i++)
{
nBytesRead = fread(pbPCMBuffer, 1, nPCMBufferSize, fpIn);
nInputSamples = nBytesRead * 8 / nPCMBitSize;
// (3) Encode
nRet = faacEncEncode(
hEncoder, (int*) pbPCMBuffer, nInputSamples, pbAACBuffer, nMaxOutputBytes);
fwrite(pbAACBuffer, 1, nRet, fpOut);
printf("%d: faacEncEncode returns %d\n", i, nRet);
if(nBytesRead <= 0)
{
break;
}
}

AVCodecContext::channel_layout 0 for WAV files

I have been successfully loading compressed audio files using FFmpeg and querying their channel_layouts using some code I've written:
AVFormatContext* fmtCxt = nullptr;
avformat_open_input( &fmtCxt, "###/440_sine.wav", nullptr, nullptr );
avformat_find_stream_info( fmtCxt, nullptr );
av_find_best_stream( fmtCxt, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0 );
AVCodecContext* codecCxt = fmtCxt->streams[ret]->codec;
AVCodec* codec = avcodec_find_decoder( codecCxt->codec_id );
avcodec_open2( codecCxt, codec, nullptr );
std::cout << "Channel Layout: " << codecCxt->channel_layout << std::endl;
av_dump_format( fmtCxt, 0, "###/440_sine.wav", 0 );
I've removed all error checking for brevity. However for Microsoft WAV files (mono or stereo) the AVCodecContext::channel_layout member is always 0 - despite ffprobe and av_dump_format(..) both returning valid information:
Input #0, wav, from '###/440_sine.wav':
Duration: 00:00:00.01, bitrate: 740 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 1 channels, s16, 705 kb/s
Also codecCxt->channels returns the correct value. Using a flac file (with exactly the same audio data generated from the same application), gives a channel_layout of 0x4 (AV_CH_FRONT_CENTER).
Your WAV file uses FFmpeg's pcm_s16le codec, which have no information on channel layout. You can only have the number of channels. A lot of explanations can be found here
You have the correct channel_layout with the flac file because FFmpeg's flac codec fills this field. You can find the correspondence table on libavcodec/flac.c file, the flac_channel_layouts array.
If you need to fill channel_layout manually, you can call:
codecCxt->channel_layout = av_get_default_channel_layout( codecCxt->channels );