音频格式解析:交错模式 vs Plane模式
概述
音频中我们常见格式如下所示,其中我们注意有些音频格式中带了“P”,比如AV_SAMPLE_FMT_S16P则表示带符号的16位Plane模式。本文我们重点讲述“交错模式”与“Plane模式”下,音频文件内各个Channel组织形式。并附带讲述下FFMPEG中frame结构对这两种格式的管理。
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
};
交错模式
我们平常接触到的wav/PCM等原始音频数据,基本都是交错模式。交错模式可以看成是特殊的Plane模式:Single Plane。交错模式下的数据组织形式如下图所示:
上图显示了一个1024帧立体声文件在交错模式下的排布图。
Plane模式
Plane模式则是按通道划分,一般情况下每个Channel独立占用一段内存。笔者猜测,这样可能便于硬件加速,毕竟所有通道数据不再像“交错模式”穿行产生,每个通道都可以并行产生/消费数据。Plane模式下的数据组织形式如下图所示:
Frame数据管理
ffmpeg的frame结构在处理音频时,考虑到了通道数大于8的情况。相关代码如下所示:
static int get_audio_buffer(AVFrame *frame, int align)
{
int channels;
//判断是否是plane模式
int planar = av_sample_fmt_is_planar(frame->format);
int planes;
int ret, i;
if (!frame->channels)
frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);
channels = frame->channels;
//如果是plane模式,内存则根据通道数分段;参考plane章节
planes = planar ? channels : 1;
CHECK_CHANNELS_CONSISTENCY(frame);
//linesize[0]则表示每个plane数据大小。如果是交错模式,则可以理解为单个plane,所有通道数据组织在一个plane里,
//所以此时linesize[0]表示整个文件大小;如果是plane模式,linesize[0]*channel_cnt表示整个文件大小。
if (!frame->linesize[0]) {
ret = av_samples_get_buffer_size(&frame->linesize[0], channels,
frame->nb_samples, frame->format,
align);
if (ret < 0)
return ret;
}
//如果是plane模式,并且通道个数>8,此时要动用extended_buf结构,而data和extended_data默认大小为8,如果大于8,则
//需要扩大extended_data此时extended_data指针个数与channels个数保持一致,0~7channels数据保存在data[8]的指针指向
//内存中,而大于8的数据则保存在extended_buf[?]中,extended_data[x]指针则屏蔽差异,每个指针对应每个plane[x]数据。
if (planes > AV_NUM_DATA_POINTERS) {
frame->extended_data = av_mallocz_array(planes,
sizeof(*frame->extended_data));
frame->extended_buf = av_mallocz_array((planes - AV_NUM_DATA_POINTERS),
sizeof(*frame->extended_buf));
if (!frame->extended_data || !frame->extended_buf) {
av_freep(&frame->extended_data);
av_freep(&frame->extended_buf);
return AVERROR(ENOMEM);
}
frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
} else
frame->extended_data = frame->data;
for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
frame->buf[i] = av_buffer_alloc(frame->linesize[0]);
if (!frame->buf[i]) {
av_frame_unref(frame);
return AVERROR(ENOMEM);
}
frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
}
for (i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) {
frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]);
if (!frame->extended_buf[i]) {
av_frame_unref(frame);
return AVERROR(ENOMEM);
}
frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data;
}
return 0;
}
综上所述:
Channel <= 8时:
c0 - c7:frame->extended_data[x] = frame->data[x].
Channel > 8时:
c0 - c7:frame->extended_data[x] = frame->data[x].
c8 - c?:frame->extended_data[x] = frame->extended_buf[x].
浮点与整型像素格式取值范围
浮点类型样本取值范围:-1.0 ~ 1.0
整数类型样本取值范围:-32767 ~ 32767 (16bit)
原文链接:https://blog.csdn.net/lyy901135/article/details/103061967