您的位置:首页 > 其它

samplefmt.c阅读笔记

2014-03-09 23:27 323 查看
知识点一:

* For planar sample formats, each audio channel is in a separate data plane,

* and linesize is the buffer size, in bytes, for a single plane. All data

* planes must be the same size. For packed sample formats, only the first data

* plane is used, and samples for each channel are interleaved. In this case,

* linesize is the buffer size, in bytes, for the 1 plane.

这解释了音频smaple_fmt中什么是planar,什么是packed。

知识点二:

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_NB ///< Number of sample formats. DO NOT USE if linking dynamically

};

此枚举的AV_SAMPLE_FMT_NB定义得很巧妙。从-1开始,那么最后一个枚举的值就是这个枚举内可枚举的情况的总数。

typedef struct SampleFmtInfo {

char name[8];

int bits;

int planar;

enum AVSampleFormat altform; ///< planar<->packed alternative form

} SampleFmtInfo;

/** this table gives more information about formats */

static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = {

[AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P },

[AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P },

[AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P },

[AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP },

[AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP },

[AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 },

[AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 },

[AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 },

[AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT },

[AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL },

};

结构体SampleFmtInfo的定义及全局变量sample_fmt_info的定义也很巧妙,如果没有这样的定义,那么对不同sample format的属性的获取就得通过

大量的if else了。

av_get_sample_fmt_name

av_get_sample_fmt

等函数的实现证明了这点。

知识点三:

int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,

enum AVSampleFormat sample_fmt, int align)

{

int line_size;

int sample_size = av_get_bytes_per_sample(sample_fmt);

int planar = av_sample_fmt_is_planar(sample_fmt);

/* validate parameter ranges */

if (!sample_size || nb_samples <= 0 || nb_channels <= 0)

return AVERROR(EINVAL);

/* auto-select alignment if not specified */

if (!align) {

align = 1;

nb_samples = FFALIGN(nb_samples, 32);

}

/* check for integer overflow */

if (nb_channels > INT_MAX / align ||

(int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size)

return AVERROR(EINVAL);

line_size = planar ? FFALIGN(nb_samples * sample_size, align) :

FFALIGN(nb_samples * sample_size * nb_channels, align);

if (linesize)

*linesize = line_size;

return planar ? line_size * nb_channels : line_size;

}

1、大小=采样数×每个采样的大小×通道数。如果是planar,则先对齐再×通道数。

2、从此函数的参数有nb_samples及nb_channels及解码后的AVFrame中的采样个数与通道参数可基本推测出采样个数指的都是单通道。

当然:

AVFrame的

/**

* number of audio samples (per channel) described by this frame

*/

int nb_samples;

这个描述更明确了。

3、此函数除了获得函数,还得到linesize。linesize为每个plan数据字节大小

知识点四:

int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,

const uint8_t *buf, int nb_channels, int nb_samples,

enum AVSampleFormat sample_fmt, int align)

{

int ch, planar, buf_size, line_size;

planar = av_sample_fmt_is_planar(sample_fmt);

buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples,

sample_fmt, align);

if (buf_size < 0)

return buf_size;

audio_data[0] = (uint8_t *)buf;

for (ch = 1; planar && ch < nb_channels; ch++)

audio_data[ch] = audio_data[ch-1] + line_size;

if (linesize)

*linesize = line_size;

#if FF_API_SAMPLES_UTILS_RETURN_ZERO

return 0;

#else

return buf_size;

#endif

}

1、将buf中的音频数据转成由audio_data指向。

int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples,

int nb_channels, enum AVSampleFormat sample_fmt)

{

int planar = av_sample_fmt_is_planar(sample_fmt);

int planes = planar ? nb_channels : 1;

int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);

int data_size = nb_samples * block_align;

int fill_char = (sample_fmt == AV_SAMPLE_FMT_U8 ||

sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00;

int i;

offset *= block_align;

for (i = 0; i < planes; i++)

memset(audio_data[i] + offset, fill_char, data_size);

return 0;

}

1、如果为AV_SAMPLE_FMT_U8或AV_SAMPLE_FMT_U8P,则设置成0x80,其它格式则将数据设置为0x00

总结:

AVFrame中的data数组存放着指向音频数据的指针;

如果音频的samplefmt为planar格式,则,每个channel对应一个plannar(平面),每个plannar对应data
,如第一个音频通道数据由data[0]的指针指向,第二个音频通道的数据由data[1]的指针指向。linesize为一个平面的音频数据字节大小。

如果音频的samplefmt为packed格式,则,只有一个平面,对应的数据在data[0]对应的指针中指向。linesize即为音频数据的字节大小。多个通道的音频采样交错排布。如采样1左声道,采样1右声道,采样2左声道,采样2右声道......

AVFrame中的nb_samples字段为每个音频通道所拥有的采样数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: