从音频设备中读取音频数据

从音频设备中读取音频数据

// AVFormatContext *s  上下文
// AVPacket *pkt  音视频包,到底是音频包、还是视频包,跟环境有关系,可以通过AVPacket做判断,到底是音频包、还是视频包
// res非0,读取失败,为0,成功,可以拿个while循环,来判断数据有没有读取完毕
int res = av_read_frame(<#AVFormatContext *s#>, <#AVPacket *pkt#>)

AVPacket参数

  1. data,音视频的具体数据
  2. size,data缓冲区的大小,

AVPacket相关API

//对AVPacket进行一次初始化,就是对除了data和size外,其他的参数进行的初始化
av_init_packet(<#AVPacket *pkt#>)
//释放AVPacket资源,减少一个引用计数,与上面的API,是一对
av_packet_unref(<#AVPacket *pkt#>)

init和unref 是成双出现的
//给AVPacket分配空间,
//做了2件事,1.分配空间  2. 调用av_init_packet
av_packet_alloc();

//做了2件事,1.先调用av_packet_unref ,2. 对av_packet_alloc创建的空间进行释放
av_packet_free(<#AVPacket **pkt#>)

alloc和free 是成双出现的

从设备中读取音频数据

  1. 增加头文件 #include "libavcodec/avcodec.h"
  2. 看下面代码
    //每次重新分配地址
    AVPacket pkt;
    //初始化
    av_init_packet(&pkt);
    //默认为读取500次后退出
    int count = 0;
    while ((av_read_frame(fmt_ctx, &pkt) == 0)&& (count++ <= 500)) {
        
    }

总的代码

这是目前testc.c文件中的代码

void haha()
{
    av_log_set_level(AV_LOG_DEBUG);
    av_log(NULL, AV_LOG_DEBUG, "Hello world\n");
    
    
    //1. 注册所有设备
    avdevice_register_all();
    //2. 获取格式  设置采集方式
    AVInputFormat * iformat = av_find_input_format("avfoundation");
    
    AVFormatContext *fmt_ctx = NULL;
    
    //音频设备  mac上 :0 从第一个音频设备获取声音   可以到ffmpeg官网查看devicename说明
    char * devicename = ":0";
    
    AVDictionary *options = NULL;    
    
    //3.打开设备
    /*
     AVFormatContext **ps  上下文,作用:前面调用的API和后面调用的API都依赖于上下文,对一个多媒体文件进行解码、编码都依赖于上下文,操作那个文件,只需要把这个文件的上下文传过去,就知道是对那个文件操作了 。这个上下文是avformat_open_input这个API返回的指针,我们只要定义这个指针就行 AVFormatContext *fmt_ctx;
     const char *url: 可以是一个网络地址,也可以是本地的文件,
     AVInputFormat *fmt
     AVDictionary **options   打开设备的一些参数,一般解码的时候用到
     */

    // 成功==0,不成功!= 0
    int ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options);
    if (ret < 0) {
        /*
        int    enum         错误码
        char   errbuf       错误信息输出到哪
        size_t errbuf_size
         */
        char errors[1024];
        
        av_strerror(ret, errors, 1024);
        printf(stderr,"Failed to open audio device,[%d]%s\n",ret,errors);
        return;
    }
    //每次重新分配地址
    AVPacket pkt;
    //初始化
    av_init_packet(&pkt);
    //默认为读取500次后退出
    int count = 0;
    while ((av_read_frame(fmt_ctx, &pkt) == 0)&& (count++ <= 500)) {
        
    }
    av_packet_unref(&pkt);
    
    return;
};

优化代码

内存泄露

avformat_open_input
产生了一个上下文,需要关掉,掉下面API
avformat_close_input(<#AVFormatContext **s#>)
av_read_frame
使用完成之后,没有将对应的资源释放掉,随着录制时间越来越长,占用的内存越来越多,产生程序没有内存而崩掉的问题

AVPacket相关的API

av_init_packet
初始化AVPacket,使用默认值
av_packet_unref
释放AVPacket,减一个引用计数,在内部对AVPacket中的buffer(缓冲区的数据)进行释放
av_packet_alloc()
产生一个AVPacket空间,在堆段,
av_packet_free(<#AVPacket **pkt#>)
释放alloc分配的资

一般顺序是先掉av_packet_unref,释放掉AVPacket内部的资源,然后再掉av_packet_free释放掉对应的内存地址

优化后的代码
void record_audio()
{
    av_log_set_level(AV_LOG_DEBUG);
    //1. 注册所有设备
    avdevice_register_all();
    //2. 获取格式  设置采集方式
    AVInputFormat * iformat = av_find_input_format("avfoundation");
    
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;
    //每次重新分配地址
    AVPacket pkt;
    //默认为读取500次后退出
    int count = 0;
    
    //音频设备  mac上 :0 从第一个音频设备获取声音   可以到ffmpeg官网查看devicename说明
    char * devicename = ":0";
     
    
    //3.打开设备
    /*
     AVFormatContext **ps  上下文,作用:前面调用的API和后面调用的API都依赖于上下文,对一个多媒体文件进行解码、编码都依赖于上下文,操作那个文件,只需要把这个文件的上下文传过去,就知道是对那个文件操作了 。这个上下文是avformat_open_input这个API返回的指针,我们只要定义这个指针就行 AVFormatContext *fmt_ctx;
     const char *url: 可以是一个网络地址,也可以是本地的文件,
     AVInputFormat *fmt
     AVDictionary **options   打开设备的一些参数,一般解码的时候用到
     */

    // 成功==0,不成功!= 0
    int ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options);
    if (ret < 0) {
        /*
        int    enum         错误码
        char   errbuf       错误信息输出到哪
        size_t errbuf_size
         */
        char errors[1024];
        
        av_strerror(ret, errors, 1024);
        printf(stderr,"Failed to open audio device,[%d]%s\n",ret,errors);
        return;
    }
    //初始化
    av_init_packet(&pkt);
    while ((av_read_frame(fmt_ctx, &pkt) == 0)&& (count++ <= 500)) {
        //释放掉pkt
        av_packet_unref(&pkt);
    }
    //释放上下文
    avformat_close_input(&fmt_ctx);
    av_log(NULL, AV_LOG_DEBUG, "Finished\n");
    return;
};

你可能感兴趣的:(从音频设备中读取音频数据)