音频重采样

什么是音频重采样?

将音频的三要素 采样大小(位深)、声道数、采样率更换为另一套值

为什么要进行重采样?

  • 从设备采集的音频数据和编码器要求的数据不一致;
  • 扬声器要求的音频数据与播放的音频数据不一致;
  • 更方便运算(例如 回音消除总是将多声道转为单声道)。

如何知道是否需要重采样?

  • 要理解音频设备参数
  • 查看ffmpeg的源码(ffmpeg内置了主流设备的参数)

重采样的步骤:

  • 创建重采样上下文
  • 设置参数
  • 初始化重采样
  • 进行重采样(对每一帧)

重要API

  • swr_alloc_set_opts  分配上下文
  • swr_init 初始化上下文
  • swr_convert 采样率转换
  • swr_free 释放上下文
  • av_samples_alloc_array_and_samples 创建缓冲区

  • av_freep 释放内存

我们对采集的音频数据 采样率为44100hz 通道数1  采样大小AV_SAMPLE_FMT_FLT(float类型 32位)

转化为 采样率48000hz, 通道数2,采样大小AV_SAMPLE_FMT_S16(16位)

上代码

//
//  rec_audio.c
//  yuanGitFFmpeg
//
//  Created by yuanxuzhen on 2021/3/29.
//

#include "rec_audio.h"
//
//  test_c.c
//  MyFFmpegDemo
//
//  Created by yuanxuzhen on 2021/3/26.
//

static int rec_status = 0;

void rec_audio(){
    int ret = 0;
    char error[1024] = {0, };
    AVFormatContext* format_context = NULL ;
    char *devicename=":0";
    AVDictionary *options = NULL;
    AVPacket pkt;
    int count = 0;
    char* url = "/Users/yuanxuzhen/study/mac/yuanGitFFmpeg/yuanGitFFmpeg/out/audio.pcm";
    av_log_set_level(AV_LOG_DEBUG);
    avdevice_register_all();
    AVInputFormat * iformat = av_find_input_format("avfoundation");
    ret = avformat_open_input(&format_context, devicename, iformat, &options);
    av_dump_format(format_context, 0, devicename, 0);
    if(ret < 0){
        av_strerror(ret, error, 1024);
        printf(stderr, "Failed to open audio devices, [%d] %s\n", ret, error);
        return;
    };
    //创建文件
    FILE *outFile = fopen(url, "wb");
    rec_status = 1;
    
    /*我们对采集的音频数据 采样率为44100hz 通道数1  采样大小AV_SAMPLE_FMT_FLT(float类型 32位)
     转化为 采样率48000hz, 通道数2,采样大小AV_SAMPLE_FMT_S16(16位)*/
    
    SwrContext* swr_ctx = swr_alloc_set_opts(NULL, // 已经存在的采样上下文,没有C传NULL
                                             AV_CH_LAYOUT_MONO,//输出通道个数
                                             AV_SAMPLE_FMT_S16,//输出的位深
                                             48000,//输出的采样率
                                             AV_CH_LAYOUT_MONO,//输入的通道个数
                                             AV_SAMPLE_FMT_FLT,//输入的位深
                                             44100,//输入的采样率
                                             0,// logging level offset
                                             NULL// parent logging context, can be NULL
                                             );
    uint8_t  **src_data = NULL;
    int src_linesize = 0;
    uint8_t  **dst_data = NULL;
    int dst_linesize = 0;
    //创建输入缓存区
    av_samples_alloc_array_and_samples(&src_data, //输入缓冲区地址
                                       &src_linesize, //缓冲区的大小
                                       1,//通道个数
                                       512,//单通道采样个数
                                       AV_SAMPLE_FMT_FLT,//采样格式
                                       0);
    
    //创建输出缓存区
    av_samples_alloc_array_and_samples(&dst_data,//输出缓冲区地址
                                       &dst_linesize,//缓冲区的大小
                                       1,//通道个数
                                       512,//单通道采样个数
                                       AV_SAMPLE_FMT_S16,//采样格式
                                       0);
    
    
    //获取音频数据并保存
    while ((ret = av_read_frame(format_context, &pkt)) == 0 || ret == -35) {
        if(!rec_status){
            break;
        }
        if(ret == -35){
            usleep(100);
            continue;
        }
        //进行内存拷贝,按字节拷贝的uint8_t  **src_data srcdata相对于是个数组
        memcpy((void*)src_data[0], (void*)pkt.data, pkt.size);
        
        //重采样
        swr_convert(swr_ctx,                    //重采样的上下文
                    dst_data,                   //输出结果缓冲区
                    512,                        //输出每个通道的采样数
                    (const uint8_t **)src_data, //输入缓冲区
                    512);                       //输入单个通道的采样数
        
        fwrite(dst_data[0], 1, dst_linesize, outFile);
        fflush(outFile);
        printf("creent pkt size %d count %d\n", pkt.size, count);
        av_packet_unref(&pkt);
    }
    //释放输入输出缓冲区
    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);
    
    fclose(outFile);
    avformat_close_input(&format_context);
    printf("creent count %d\n",  count);
    
    format_context = NULL;
    return;
}




void set_status(int status){
    rec_status = status;
}








ffplay 播放命令ffplay -ar 48000 -ac 1 -f s16le audio.pcm

 

源代码地址

https://gitee.com/creat151/ffmpeg.git

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值