1.重采样
1.1 为什么要重采样?
1.2 什么是重采样
1.3 可调节的参数
2 对应参数解析
2.1 采样率
2.2 采样格式及量化精度(位宽)
enum AVSampleFormat {AV_SAMPLE_FMT_NONE = -1,AV_SAMPLE_FMT_U8, ///< unsigned 8 bitsAV_SAMPLE_FMT_S16, ///< signed 16 bitsAV_SAMPLE_FMT_S32, ///< signed 32 bitsAV_SAMPLE_FMT_FLT, ///< floatAV_SAMPLE_FMT_DBL, ///< doubleAV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P, ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P, ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP, ///< float, planarAV_SAMPLE_FMT_DBLP, ///< double, planarAV_SAMPLE_FMT_S64, ///< signed 64 bitsAV_SAMPLE_FMT_S64P, ///< signed 64 bits, planarAV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
2.3 平面模式和交错模式 - 分⽚(plane)和打包(packed)
2.4 声道分布(channel_layout)
#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER)
#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)
2.5 ⾳频帧的数据量计算
u8 8
s16 16
s32 32
flt 32
dbl 64
u8p 8
s16p 16
s32p 32
fltp 32
dblp 64
s64 64
s64p 64
2.6 ⾳频播放时间计算
3 FFmpeg重采样API
3.1 分配⾳频重采样的上下⽂
/*** Allocate SwrContext.** If you use this function you will need to set the parameters (manually or* with swr_alloc_set_opts2()) before calling swr_init().** @see swr_alloc_set_opts2(), swr_init(), swr_free()* @return NULL on error, allocated context otherwise*/
struct SwrContext *swr_alloc(void);
3.2 给音频重采样上下文设置参数
/* set options */// 输入参数int64_t src_ch_layout = AV_CH_LAYOUT_STEREO;int src_rate = 48000;enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL;// 设置输入参数av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);// 输出参数int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO;int dst_rate = 44100;enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;// 设置输出参数av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);
3.1.2 上述两步可以直接弄成一步
/*** Allocate SwrContext if needed and set/reset common parameters.** This function does not require *ps to be allocated with swr_alloc(). On the* other hand, swr_alloc() can use swr_alloc_set_opts2() to set the parameters* on the allocated context.** @param ps Pointer to an existing Swr context if available, or to NULL if not.* On success, *ps will be set to the allocated context.* @param out_ch_layout output channel layout (e.g. AV_CHANNEL_LAYOUT_*)* @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*).* @param out_sample_rate output sample rate (frequency in Hz)* @param in_ch_layout input channel layout (e.g. AV_CHANNEL_LAYOUT_*)* @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*).* @param in_sample_rate input sample rate (frequency in Hz)* @param log_offset logging level offset* @param log_ctx parent logging context, can be NULL** @see swr_init(), swr_free()* @return 0 on success, a negative AVERROR code on error.* On error, the Swr context is freed and *ps set to NULL.*/
int swr_alloc_set_opts2(struct SwrContext **ps,const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,const AVChannelLayout *in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,int log_offset, void *log_ctx);
3.3 当设置好相关的参数后,使⽤此函数来初始化SwrContext结构体
* Initialize context after user parameters have been set.* @note The context must be configured using the AVOption API.** @see av_opt_set_int()* @see av_opt_set_dict()** @param[in,out] s Swr context to initialize* @return AVERROR error code in case of failure.*/
int swr_init(struct SwrContext *s);
3.4 这时候理论上是就要通过SwrContext 转化了,那么这里就有一个问题了,转化的数据应该放在哪里呢?--- 因此这一步 是 创建输入缓冲区
如何创建这个输入缓冲区呢?又根据哪些参数创建这个输入缓冲区呢?
很显然,输入缓冲区是要根据 输入的音频的三要素 来创建的。创建出来的缓冲区放在哪里呢?
int av_samples_alloc_array_and_samples(uint8_t ***audio_data,
int *linesize,
int nb_channels,
int nb_samples,
enum AVSampleFormat sample_fmt,
int align);
第一个参数audio_data为:输入缓冲区的首地址,是个三级指针,本质上是对于 一个二级指针的 取地址,out参数
这里要说明一下为什么 audio_data 是个三级指针,首先是一个输出参数,那么意味着,我们传递进来的要改动的就是二级指针,这个二级指针确切来说应该是一个 uint8_t * audiodata[8], 每一个audiodata[i] 都是指向的 每个planar的具体数据。实际上这里就是为了兼容planar才弄了个三级指针。如果不考虑planar 的,二级指针就够了。
第二个参数linesize为:输入缓冲区对齐的音频缓冲区大小,可能为 NULL,out参数
第三个参数nb_channels为:要改动的输入源的 声道数
第四个参数nb_samples为:输入源每个声道的样本数,aac 为1024
第五个参数sample_fmt为:输入源的AVSampleFormat -- 类似AV_SAMPLE_FMT_DBL
第六个参数align为:是否要字节对齐,0为对齐,1为不对齐,一般都要对齐
/*** Allocate a samples buffer for nb_samples samples, and fill data pointers and* linesize accordingly.* The allocated samples buffer can be freed by using av_freep(&audio_data[0])* Allocated data will be initialized to silence.** @see enum AVSampleFormat* The documentation for AVSampleFormat describes the data layout.** @param[out] audio_data array to be filled with the pointer for each channel* @param[out] linesize aligned size for audio buffer(s), may be NULL* @param nb_channels number of audio channels* @param nb_samples number of samples per channel* @param sample_fmt the sample format* @param align buffer size alignment (0 = default, 1 = no alignment)* @return >=0 on success or a negative error code on failure* @todo return the size of the allocated buffer in case of success at the next bump* @see av_samples_fill_arrays()* @see av_samples_alloc_array_and_samples()*/
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,int nb_samples, enum AVSampleFormat sample_fmt, int align);/*** Allocate a data pointers array, samples buffer for nb_samples* samples, and fill data pointers and linesize accordingly.** This is the same as av_samples_alloc(), but also allocates the data* pointers array.** @see av_samples_alloc()*/
int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,int nb_samples, enum AVSampleFormat sample_fmt, int align);