本文讲解如何在linux下面采集音频数据,分成3部分讲解。
使用ffmpeg来采集音频数据,主要需要2个软硬件环境:
使用ffmpeg来采集音频,我们首先需要知道,如何访问麦克风,这个其实我们可以像访问文件一样,访问麦克风。文件的话,我们一般给出一个文件路径,就可以访问了,比如“/home/test/a.mp4”,同理,我们的麦克风的地址是“hw:0”,我只知道是这个地址,不知道为什么是这个地址,假如大家有知道为什么的,欢迎留言交流。
其次,我们需要知道,麦克风这个文件格式是什么?对于麦克风这种硬件设备,与其说是格式,我更觉得这是驱动程序。在linux上,通用的音频驱动程序,就是alsa。
这样的话,我们很容易形成了下面这样的命令:
ffmpeg -f alsa -i hw:0 out.wav
这里, -f 指定格式(驱动程序)为alsa, -i 指出文件路径,这里是麦克风地址“hw:0”,最后一个是输出文件路径,这里为当前路径下,保存为 out.wav文件。
我们在终端运行这条命令之后,然后对着麦克风讲话“123456”,然后按q结束录音,就可以看到当前路径下面,生成了 out.wav。然后我们使用
ffplay out.wav
播放这段录音,就可以听到刚刚我们喊的“123456”。
使用ffmpeg代码来采集音频,其实也就和上面命令行一样,需要注意上面个两个内容:
然后我们像正常的打开文件一样,采用avformat_open_input 函数,打开文件(这里是麦克风),设置好文件格式(这里是alsa驱动程序)。打开这个文件之后,我们使用av_read_frame从这个文件(麦克风)中读取数据,最后把读取到的数据,保存在文件中。下面分3个部分讲解这些内容:
由于我们这里,打开了麦克风设备,在这之前,需要先注册所有的设备,通过调用avdevice_register_all() 来注册。然后就是像正常打开文件一样,调用avformat_open_input打开文件。文件路径为“hw:0”,文件格式为通过av_find_input_format找到的alsa的AVInputFormat,这样,就会构造出我们想要的fmt_ctx。
AVFormatContext *fmt_ctx = NULL;
char *devicename = "hw:0";
avdevice_register_all();
AVInputFormat *iformat = av_find_input_format("alsa");
avformat_open_input(&fmt_ctx, devicename, iformat, NULL)
avformat_close_input(&fmt_ctx);
读取麦克风数据,就通过av_read_frame,把前面的fmt_ctx对应的数据,读取出来就行。读取完的数据,保存在AVPacket pkt的 data里面,长度为pkt.size。
int ret = 0;
AVPacket pkt;
av_init_packet(&pkt);
while(ret = (av_read_frame(fmt_ctx, &pkt))== 0) {
av_log(NULL, AV_LOG_INFO, "pkt size is %d(%p)\n",
pkt.size,pkt.data);
av_packet_unref(&pkt);
}
保存文件,就比较简单了,把pkt.data,通过fwrite写到文件中去即可。
char *out = "./audio.pcm";
FILE *outfile = fopen(out,"wb+");
fwrite(pkt.data, 1, pkt.size, outfile);
fclose(outfile);
下面贴上所有代码。保存为record_audio.c 文件。
#include
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h" //打开音频设备相关的头文件
#include "libavformat/avformat.h" //ffmpeg下的所有文件都是以格式来呈现的
void main(int argc, char **argv)
{
int ret = 0;
char errors[1024] = {0};
//context
AVFormatContext *fmt_ctx = NULL; //ffmpeg下的“文件描述符”
//paket
int count = 0;
AVPacket pkt;
//create file
char *out = "./audio.pcm";
FILE *outfile = fopen(out,"wb+");
char *devicename = "hw:0";
//register audio device
avdevice_register_all();
//get format
AVInputFormat *iformat = av_find_input_format("alsa");
//open audio
if( (ret = avformat_open_input(&fmt_ctx, devicename, iformat, 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 audio
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);
fwrite(pkt.data, 1, pkt.size, outfile);
fflush(outfile);
av_packet_unref(&pkt);//release pkt
}
fclose(outfile);
avformat_close_input(&fmt_ctx);//releas ctx
return;
}
然后通过命令 gcc record_audio.c -lavformat -lavutil -lavdevice -lavcodec -o record_audio 生成可执行文件。
然后执行 ./record_audio, 并录音。录音结果保存在audio.pcm文件中。
然后通过命令
ffplay -ar 44100 -ac 2 -f s16le audio.pcm
播放此音频,发现结果正常。
上面命令解析
-ar 表示 audio sampling rate,即音频采样率,为44100 Hz。
-ac表示 audio channels,即音频通道数,一般为2,左声道和右声道。
-f s16le,表示采样大小为 有符号的 16位 小端字节序。 signed 16 bit little endian。