planar或者packed
PCM音频原始数据的存储排列方式中,有
planar或者packed(Interleaved),
对于双通道的planar,类似于:
LLLL...RRRR...
对于双通道的packed(Interleaved),类似于:
LRLRLRLR...
在ffmpeg的AVCodecID(avcode.h)中定义了编码ID,
其中,未带_PLANAR表示交织方式,反正,为planar方式
AV_CODEC_ID_PCM_S16LE = 0x10000,
AV_CODEC_ID_PCM_S16BE,
AV_CODEC_ID_PCM_S16LE_PLANAR,
AV_CODEC_ID_PCM_S16BE_PLANAR,
AVSampleFormat
样点格式,通常用到的是s16le整型,f32浮点
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_S64, ///< signed 64 bits
AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
其中,S16表示packed(Interleaved)方式;S16P表示planar方式;AVSampleFormat通过AVStream::AVCodecParameters获得。不过可以发现,在AVSampleFormat里面,是看不出来大端还是小端。所以,要看大小端,还是要依靠AVCodecID。
采样精度
S16表示每个样点16bits=2字节;
F32表示每个样点32bits=4字节;
采样精度可以通过ffmpeg函数av_get_bytes_per_sample获得
/**
* Return number of bytes per sample.
*
* @param sample_fmt the sample format
* @return number of bytes per sample or zero if unknown for the given
* sample format
*/
int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt);
大端小端
大端转小端,先比较一下两份16进制:
1. 48k,双通道,s16be的文件
2. 将上述PCM用ffmpeg转换成:48k,双通道,s16le
ffmpeg -f s16be -ac 2 -ar 48000 -i D:\share\s16be.pcm -f s16le -ar 48000 -ac 2 -y D:\share\s16le.pcm
比较大端转换为小端后的16进制,发现是将每个样点16bit的高8位与低8位进行了交换位置。
代码实现:
if (m_bLittleEndian == false)
{
uint16_t *pSample = (uint16_t *)pOneFrame;
int nSampleNum = m_pFifo->GetFrameSize() / m_nBytesPerSample;
for (int i = 0; i < nSampleNum; i++)
{
uint16_t sample = pSample[i];
sample = (sample << 8) | (sample >> 8);
pSample[i] = sample;
}
}