之前一直在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;
}

本程序大部分是雷神实现的代码,只不过针对特定环境做了改动,在此致敬雷神!!!!!!!!

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐