ffmpeg之采集音频

发布时间 2023-09-07 15:44:02作者: 阿风小子

 

一、打开音频设备

设备可以是多媒体文件和物理设备

#ifndef TESTC_H
#define TESTC_H

#include <stdio.h>
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"  //打开音频设备相关的头文件
#include "libavformat/avformat.h"  //ffmpeg下的所有文件都是以格式来呈现的

#endif

输入设备为同目录下的video_2.mp4

#include "testc.h"


void main(int argc, char **argv)
{
    int ret = 0;
    char errors[1024];
    static AVFormatContext *fmt_ctx = NULL;   //ffmpeg下的“文件描述符”

    char *devicename =  "./video_2.mp4";
    //register audio device
    avdevice_register_all();

    //get format
    AVInputFormat *iformat = av_find_input_format("alsa");

    if( (ret = avformat_open_input(&fmt_ctx, devicename, NULL, NULL)) < 0)
    {
        av_strerror(ret, errors, 1024);
        printf("Failed to open audio device, [%d]%s\n", ret, errors);
        return;
    };

    av_log_set_level(AV_LOG_DEBUG);
    av_log(NULL, AV_LOG_DEBUG, "hello, world\n");

    return;
}

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

 

 

 

内存泄漏注意:创建了必须释放

1. avformat_open_input(&fmt_ctx, devicename, NULL, NULL);
2. avformat_close_input(&fmt_ctx);
1. av_init_packet(&pkt);
2. av_read_frame(fmt_ctx, &pkt)
3. av_packet_unref(&pkt);

所需头文件

#include "libavcodec/avcodec.h"

代码

#include "testc.h"


void main(int argc, char **argv)
{

    int ret = 0;
    char errors[1024] = {0};
    //context
    static AVFormatContext *fmt_ctx = NULL;   //ffmpeg下的“文件描述符”

    //paket
    int count = 0;
    AVPacket pkt;

    char *devicename =  "./video_2.mp4";
    //register audio device
    avdevice_register_all();

    //get format
    AVInputFormat *iformat = av_find_input_format("alsa");

    //open video
    if( (ret = avformat_open_input(&fmt_ctx, devicename, NULL, NULL)) < 0)
    {
        av_strerror(ret, errors, 1024);
        printf("Failed to open audio device, [%d]%s\n", ret, errors);
        return;
    };

    av_init_packet(&pkt);
    //read data form video
    while(ret = (av_read_frame(fmt_ctx, &pkt))== 0&& 
        count++ < 500) {
        av_log(NULL, AV_LOG_INFO, "pkt size is %d(%p), count=%d\n",
        pkt.size,pkt.data, count);
        av_packet_unref(&pkt);//releas pkt
    }

    avformat_close_input(&fmt_ctx);//releas ctx

    av_log_set_level(AV_LOG_DEBUG);
    av_log(NULL, AV_LOG_DEBUG, "finish!\n");

    return;
}

三、录制音频

 

1.创建文件

创建文件来保存采集的音频数据

//create file
char *out = "/home/lee/vido_learn/mytest/audio.pcm";
FILE *outfile = fopen(out,"wb+");

2.写入数据

//write file 
fwrite(pkt.data, pkt.size, 1, outfile);
fflush(outfile);

3.关闭文件

//close file
fclose(outfile);

出于效率考虑fwrite()会先把数据写到缓存区,待缓存区有一定大小的块数据后才把通过文件io操作磁盘将数据写入文件,加入fflush()会立即将数据写入磁盘

四、执行程序

执行程序后会生成audio.pcm文件


 

在命令行使用ffply进行播放

 ffplay -ar 44100 -ac 2 -f f32le audio.pcm 

-ar 44100 采样率44100Hz
-ac 2 通道数
-f f32le 采样大小32位

五、音频重采样

 

 

 

 

 

包含头文件

#include "libswresample/swresample.h"
uint8_t **src_data = NULL;
    int src_linesize = 0;

     uint8_t **dts_data = NULL;
    int dts_linesize = 0;   

    //4096/4=1024/2=512
    //创建输入缓冲区
    av_samples_alloc_array_and_samples(&src_data,       //输出缓冲区地址
                                       &src_linesize,    //缓冲区的大小
                                       2,               //通道个数
                                       512,             //单通道采样个数
                                       AV_SAMPLE_FMT_FLT,//采样格式
                                       0);
    //创建输出缓冲区
    av_samples_alloc_array_and_samples(&dts_data,       //输出缓冲区地址
                                       &dts_linesize,    //缓冲区的大小
                                       2,               //通道个数
                                       512,             //单通道采样个数
                                       AV_SAMPLE_FMT_S16,//采样格式
                                       0);
//重采样
          swr_convert(swr_ctx, 
                    dts_data, 
                    dts_linesize, 
                    (const uint8_t **)src_data, 
                    src_linesize);