在音视频应用中,经常需要将音频的采样率做一些转换,比如将16000hz转成441000hz等。 ffmpeg的libresample提供的音频通道数、采样率、位数的转换,下面介绍一下使用流程,示例是将单通道、8khz、16bit转换为单通道、44.1khz、float型pcm
1,初始化context
extern "C"
{
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <libswresample/swresample.h>
}
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swresample.lib")
SwrContext *swr_ctx_ = NULL;
uint8_t **src_data_ = NULL, **dst_data_ = NULL;
int src_nb_samples_, dst_nb_samples_, max_dst_nb_samples_;
int64_t src_ch_layout = AV_CH_LAYOUT_MONO, dst_ch_layout = AV_CH_LAYOUT_MONO;
int src_rate = 8000, dst_rate = 44100;
enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16, dst_sample_fmt = AV_SAMPLE_FMT_FLT;
int ret;
int src_nb_channels = 0, dst_nb_channels = 0;
int src_linesize, dst_linesize;
src_nb_samples_ = 1024;
/* create resampler context */
swr_ctx_ = swr_alloc();
if (!swr_ctx_) {
fprintf(stderr, "Could not allocate resampler context\n");
ret = AVERROR(ENOMEM);
return;
}
/* set options */
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);
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);
/* initialize the resampling context */
if ((ret = swr_init(swr_ctx_)) < 0) {
fprintf(stderr, "Failed to initialize the resampling context\n");
return;
}
/* allocate source and destination samples buffers */
src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
ret = av_samples_alloc_array_and_samples(&src_data_, &src_linesize, src_nb_channels,
src_nb_samples_, src_sample_fmt, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate source samples\n");
return ;
}
/* compute the number of converted samples: buffering is avoided
* ensuring that the output buffer will contain at least all the
* converted input samples */
max_dst_nb_samples_ = dst_nb_samples_ =
av_rescale_rnd(src_nb_samples_, dst_rate, src_rate, AV_ROUND_UP);
/* buffer is going to be directly written to a rawaudio file, no alignment */
dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
ret = av_samples_alloc_array_and_samples(&dst_data_, &dst_linesize, dst_nb_channels,
dst_nb_samples_, dst_sample_fmt, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate destination samples\n");
return;
}
2,对输入的音频数据调用如下代码,其中pBuffer表示pcm数据,dwBufSize表示数据字节数
short *pcmbuf = (short*)src_data_[0];
for (int i = 0; i < dwBufSize; i++)
{
pcmbuf[i] = pBuffer[i];
}
/* convert to destination format */
int ret = swr_convert(swr_ctx_, dst_data_, dst_nb_samples_, (const uint8_t **)src_data_, dwBufSize);
if (ret < 0) {
fprintf(stderr, "Error while converting\n");
return -1;
}
int dst_linesize, dst_nb_channels = 1;
enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_FLT;
int dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
ret, dst_sample_fmt, 1);
if (dst_bufsize < 0) {
fprintf(stderr, "Could not get sample buffer size\n");
return -1;
}
//转换后的数据存在dst_data_[0],字节数为dst_bufsize
//fwrite(dst_data_[0],1,dst_bufsize,fp);
3,销毁对象
if (src_data_)
av_freep(&src_data_[0]);
av_freep(&src_data_);
if (dst_data_)
av_freep(&dst_data_[0]);
av_freep(&dst_data_);
swr_free(&swr_ctx_);