音频格式解析:交错模式 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模式,内存则根据通道数分段;参考palne章节。
    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;
    }

	//如果是Planes模式,并且通道个数>8,此时要动用到extended_buf结构,
	//而date和extended_data默认大小为8,如果大于8,则需扩大extended_data 
	//此时extended_data指针个数与Channel个数保持一致,0-7channel数据保存
	//在data[8]的指针指向内存中,而大于8的数据则保存在extended_buf[?]中,
	//extended_data[x]指针则屏蔽差异,每个指针对应每个palne[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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值