使用FFMPEG对PCM数据重采样

  • 使用命令的方式
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文件大小应该一致,否则应该检查代码是否有误

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值