linux下的音频采集那些事儿
之前一直在windows下作多媒体,谁知道跑到linux下不灵了,在网上查了些资料,总算是有点思路了,主要是两大家族oss和alsa,选择了alsa来进行开发,编译alsa-lib和alsa-utils编译alsa-lib 是这样的,../configure --host= aarch64-linux-gnu --prefix=/usr/local/ --enable-shared --disab
·
之前一直在windows下作多媒体,谁知道跑到linux下不灵了,在网上查了些资料,总算是有点思路了,主要是两大家族oss和alsa,选择了alsa来进行开发,编译alsa-lib和alsa-utils
编译alsa-lib 是这样的,../configure --host= aarch64-linux-gnu --prefix=/usr/local/ --enable-shared --disable-python
接下来就是make make install
完成就是写了音频采集的线程,如下:
class AudioCapture : public QObject
{
Q_OBJECT
public:
explicit AudioCapture(QObject *parent = nullptr);
void init(int buffer_frames,int sample_rate,
QString dev_name);
void device_list();
void pcm_list();
void setRunFlag(bool flag){_bRunFlag = flag;}
signals:
void sig_capture_data(QByteArray data);
public slots:
void doCapture();
private:
int _buffer_frames;
int _sample_rate;
QString _dev_name;
bool _bRunFlag;
};
#include "audiocapture.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <QDebug>
AudioCapture::AudioCapture(QObject *parent) : QObject(parent)
{
}
void AudioCapture::init(int buffer_frames, int sample_rate, QString dev_name)
{
_sample_rate = sample_rate;
_buffer_frames = buffer_frames;
_dev_name = dev_name;
_bRunFlag = false;
}
void AudioCapture::doCapture()
{
snd_pcm_t *capture_handle;
snd_pcm_hw_params_t *hw_params;
snd_pcm_format_t format = SND_PCM_FORMAT_S16;
int err;
char *buffer = nullptr;
if((err = snd_pcm_open(&capture_handle,_dev_name.toStdString().c_str(),
SND_PCM_STREAM_CAPTURE,0))<0)
{
return;
}
if(err = snd_pcm_hw_params_malloc(&hw_params) < 0)
{
return;
}
if(err = snd_pcm_hw_params_any(capture_handle,hw_params) < 0)
{
return;
}
if(err = snd_pcm_hw_params_set_access(capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
{
return;
}
if(err = snd_pcm_hw_params_set_format(capture_handle,hw_params,format) < 0)
{
return;
}
if(err = snd_pcm_hw_params_set_rate_near(capture_handle,hw_params,(uint *)&_sample_rate,0) < 0)
{
return;
}
if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,1)) < 0)
{
return;
}
if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0)
{
return;
}
snd_pcm_hw_params_free(hw_params);
if((err=snd_pcm_prepare(capture_handle))<0)
{
return;
}
buffer=(char *)malloc(128*snd_pcm_format_width(format)/8*2);
while(true)
{
if((err=snd_pcm_readi(capture_handle,buffer,_buffer_frames))!=_buffer_frames)
{
return;
}
emit sig_capture_data(QByteArray(buffer,_buffer_frames));
if(_bRunFlag)
{
break;
}
}
free(buffer);
snd_pcm_close(capture_handle);
}
完成直接调用,就可以将采集的数据抓出来。
AudioCapture _capture;
_capture.init(128,44100,"hw:2,0");
_capture.doCapture();
采集完成之后,将采集的程序转化为aac,下面是方法
int AACEncode::encodeAAC(const QString &fileInput, const QString &fileOutput)
{
AVFormatContext* pFormatCtx;
AVOutputFormat* fmt;
AVStream* audio_st;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;
uint8_t* frame_buf;
AVFrame* pFrame;
AVPacket pkt;
SwrContext *swr;
int got_frame=0;
int ret=0;
int size=0;
FILE *in_file=NULL; //Raw PCM data
int framenum=1000; //Audio frame number
const char* out_file = fileOutput.toUtf8().data(); //Output URL
int i;
in_file= fopen(fileInput.toUtf8().data(), "rb");
av_register_all();
//Method 1.
pFormatCtx = avformat_alloc_context();
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;
//Method 2.
//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
//fmt = pFormatCtx->oformat;
//Open output URL
if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
printf("Failed to open output file!\n");
return -1;
}
audio_st = avformat_new_stream(pFormatCtx, 0);
if (audio_st==NULL){
return -1;
}
pCodec = avcodec_find_encoder(fmt->audio_codec);
if (!pCodec){
printf("Can not find encoder!\n");
return -1;
}
pCodecCtx = audio_st->codec;
pCodecCtx->codec_id = fmt->audio_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
pCodecCtx->sample_fmt = pCodec->sample_fmts[0];
pCodecCtx->sample_rate= 44100;
pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
pCodecCtx->bit_rate = 64000;
pCodecCtx->profile=FF_PROFILE_AAC_MAIN ;
pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
//Show some information
av_dump_format(pFormatCtx, 0, out_file, 1);
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 44100, 0);
av_opt_set_int(swr, "out_sample_rate", 44100, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
swr_init(swr);
uint8_t *outs[2];
int len = 4096;
outs[0]=(uint8_t *)malloc(len);//len 为4096
outs[1]=(uint8_t *)malloc(len);
if ((ret = avcodec_open2(pCodecCtx, pCodec,NULL)) < 0){
printf("Failed to open encoder!\n");
return -1;
}
pFrame = av_frame_alloc();
pFrame->nb_samples= pCodecCtx->frame_size;
pFrame->format= pCodec->sample_fmts[0];
size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
frame_buf = (uint8_t *)av_malloc(size);
avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
//Write Header
avformat_write_header(pFormatCtx,NULL);
av_new_packet(&pkt,size);
for (i=0; i<framenum; i++){
//Read PCM
if (fread(frame_buf, 1, size, in_file) <= 0){
printf("Failed to read raw data! \n");
return -1;
}else if(feof(in_file)){
break;
}
int count=swr_convert(swr, outs,len*4,(const uint8_t **)&frame_buf,len/4);//len 为4096
pFrame->data[0] =(uint8_t*)outs[0];//audioFrame 是VFrame
pFrame->data[1] =(uint8_t*)outs[1];
//pFrame->data[0] = frame_buf; //PCM Data
pFrame->pts=i*100;
got_frame=0;
//Encode
ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);
if(ret < 0){
printf("Failed to encode!\n");
return -1;
}
if (got_frame==1){
printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size);
pkt.stream_index = audio_st->index;
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
//Flush Encoder
ret = flush_encoder(pFormatCtx,0);
if (ret < 0) {
printf("Flushing encoder failed\n");
return -1;
}
//Write Trailer
av_write_trailer(pFormatCtx);
//Clean
if (audio_st){
avcodec_close(audio_st->codec);
av_free(pFrame);
av_free(frame_buf);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
fclose(in_file);
return 0;
}
本程序大部分是雷神实现的代码,只不过针对特定环境做了改动,在此致敬雷神!!!!!!!!
更多推荐
已为社区贡献1条内容
所有评论(0)