音频格式解析:交错模式 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

(0)

相关推荐