- 使用命令的方式
ffmpeg -f s16le -ac 2 -ar 48000 -i 48000_2_s16le.pcm -f s16le
-ac 2 -ar 44100 44100_2_s16l.pcm
上面的命令可以将样点格式为AV_SAMPLE_S16,采样率48000Hz的双通道PCM数据,转换为样点格式为AV_SAMPLE_S16,采样率44100Hz的双通道PCM数据,参数可根据实际情况进行调整。
- 使用代码
void pcmResample()
{
const QString src_FileName;
const QString dst_FileName;
int src_rate = 48000;
int dst_rate = 44100;
int src_ch_layout = AV_CH_LAYOUT_STEREO;
int dst_ch_layout = AV_CH_LAYOUT_STEREO;
AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16;
AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16;
int src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);;
int dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);;
int src_bytesPerSample = src_nb_channels * av_get_bytes_per_sample(src_sample_fmt);
int dst_bytesPerSmaple = dst_nb_channels * av_get_bytes_per_sample(dst_sample_fmt);
uint8_t** src_data = nullptr;
uint8_t** dst_data = nullptr;
SwrContext* swr_ctx = nullptr; //转换上下文
swr_ctx = swr_alloc_set_opts(NULL,
dst_ch_layout,dst_sample_fmt,dst_rate,
src_ch_layout,src_sample_fmt,src_rate,
0,NULL);
//初始化上下文
swr_init(swr_ctx);
int src_nb_samples= 1024; //输入缓冲区样本数量
//输入缓冲区大小
int src_lineSize =0;
//创建输入缓冲区
int ret = av_samples_alloc_array_and_samples(&src_data,&src_lineSize,src_nb_channels,src_nb_samples,src_sample_fmt,0);
//输出缓冲区样本数量
int dst_nb_samples = av_rescale_rnd(src_nb_samples,dst_rate,src_rate,AVRounding::AV_ROUND_UP);
//创建输出缓冲区
ret = av_samples_alloc_array_and_samples(&dst_data,0,dst_nb_channels,dst_nb_samples,dst_sample_fmt,0);
QFile src_file("D:/CODE/useFfmpeg/48000_2_s16le.pcm");//(src_FileName);
QFile dst_file("D:/CODE/useFfmpeg/44100_2_s16le.pcm");//(dst_FileName);
src_file.open(QIODevice::ReadOnly);
dst_file.open(QIODevice::WriteOnly);
while (true) {
//读取数据,填入输入缓冲区
int readLen = src_file.read((char*)src_data[0],src_lineSize);
if(readLen <=0 )
{
break;
}
//实际读取的样本数量
int readSample = readLen/src_bytesPerSample;
//重采样转换
ret = swr_convert(swr_ctx,dst_data,dst_nb_samples,(const uint8_t**)src_data,readSample);
//从输出缓冲区获取数据
if(ret <0)
{
break;
}
dst_file.write((char*)dst_data[0],ret*dst_bytesPerSmaple);
}
//取出缓存的数据
ret = swr_convert(swr_ctx,dst_data,dst_nb_samples,0,0);
dst_file.write((char*)dst_data[0],ret*dst_bytesPerSmaple);
src_file.close();
dst_file.close();
av_freep(&src_data[0]);
av_freep(&src_data);
av_freep(&dst_data[0]);
av_freep(&dst_data);
swr_free(&swr_ctx);
}
引用的头文件如下
extern "C"
{
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
}
使用两种方式转换出来的PCM文件大小应该一致,否则应该检查代码是否有误