QT学习篇(三):QT音频采集QAudioInput

    对于音频采集有很多的方式,在windows下存在API可以使用,例如wave;但是QT中有一个强大的音频处理的库,可以实现音频采集,设置采集的参数等。       这里便来记录下对这个库的使用-------QAudioInput。
    首先在使用这个库之前,需要先想.pro文件中添加     QT              +=   multimedia    ,否则程序会报错。
    既然是采集音频,那么首先需要进行一步参数配置,告诉计算机应该以什么样的方式进行数据采集,像是采样率、声道数量、编码方式等;
  1. QAudioFormat format;
  2.     format.setSampleRate(16000);
  3.     format.setChannelCount(2);   //设定声道数目,mono(平声道)的声道数目是1;stero(立体声)的声道数目是2
  4.     format.setSampleSize(16);
  5.     format.setCodec("audio/pcm");   //编码器
  6.     format.setByteOrder(QAudioFormat::LittleEndian);   //设定高低位,LittleEndian(低位优先)/LargeEndian(高位优先)
  7.     format.setSampleType(QAudioFormat::SignedInt);
这样计算机便知道如何去采集数据了,当然参数是可调的,具体配置不同参数可产生什么不同的效果,可以参考QT本身提供的示例程序Audio Recorder Example,在这个程序里可以通过界面来修改个参数值进行采样。
       但是只是让计算机知道如何采样还是不够的,还需要让她知道采集何处的数据,计算机上存在这么多的器件,我们需要通过音频输入设备进行采集,则需要告诉计算机一个音频输入设备的序号(这个序号存在与计算机系统数据中),我们需要来获取到这个设备的序号才行啊。
  1. //获取默认的音频输入设备,判断是否支持指定的格式,如果不支持则使用一个邻近的格式
  2.     QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
  3.     if (!info.isFormatSupported(format))
  4.     {
  5.         format = info.nearestFormat(format);
  6.     }
      现在已经知道从哪采集数据以及采集方式了,那么便可以使用QAudioInput进行数据采集了。
  1. QTimer::singleShot(10000, this, SLOT(stopRecording()));
  2.     QAudioInput* audioInput;
  3.     audioInput = new QAudioInput(format, NULL);
  4.     audioInput->start(&file);
     QTimer应该知道是干什么用的吧,这样便实现录制10s,然后进入stopRecording函数,在stopRecording中来结束录制。
      而audioInput->start(),便实现了开始录音并将音频数据写入到文件中;
  1. QFile file;
  2.     file.setFileName("test.raw");
  3.     file.open( QIODevice::WriteOnly | QIODevice::Truncate );
     这样便实现了10s的录音并保存为文件。
      但是更多的时候我们采集到音频并不是为了保存到文件,而是想进行编码再通过网络进行发送,那应该怎么做呢?
      前面的我们不需要进行任何更改,那些对于我们怎么处理得到的数据并没有影响,我们要做的应该在start函数,不是进行写入文件,而是通过其他方式得到音频数据流;可能有人会说采用先写到文件,再从文件读的方式,那么这就回涉及到文件的读取冲突问题,就是可行那么速度也是很大的问题啊。
      这时QT给我们提供了一个重载函数start(),当然她没有任何的参数,在QT手册中是这样给我们介绍的
  1. Returns a pointer to the internal QIODevice being used to transfer data from the system's audio input. The device will already be open and read() can read data directly from it.
     简单说就是这个函数返回指向内部QIODevice的指针,那么我们就可以通过她来进行数据的读取了吧。
  1. QIODevice* streamIn;
  2. streamIn = audioInput->start();
当然streamIn要作为全局来使用,这样我们就得到了指向存放音频数据的内存的指针。
      接下来便是判断streamIn指向的内存中是否存在数据,有那就执行获取数据到准备好的数组中。
      网上提供了readyRead()信号,但是我尝试之后并不能使用,具体原因可以看 Qt学习篇(三):readyRead误使用  。
      这里我使用的方式比较暴力,既然我们已经在进行音频采集了,那么就说明在streamIn中会逐渐积累数据,我是直接延时一段时间,然后就去进行数据转存,嗯   这个方法还是可以用的。
在数据转存中我的不知道出现了什么错误,还在进行修改(保存出的文件完全就是杂音,但是仍然可以微弱的听到原声音),贴上我的代码吧,虽然有错但是可借鉴。
  1. void getAudio::slogReadData()   //现转存时出现错误,导致杂音
  2. {
  3.     short srcAudio[L_FRAME]={0};
  4.     FILE* fp = fopen("E:/Proj/Em_Lab/AnyMSG_Driect_Table/Transmit/video.qt/test.raw", "a+");

  5.     if (!audioInput)
  6.     {
  7.         qDebug("AudioInput Error");
  8.         return;
  9.     }

  10.     QByteArray dataBuffer(BUFFER_SIZE, 0);
  11.     qint64 len1 = audioInput->bytesReady();

  12.     if (len1 > BUFFER_SIZE)
  13.     {
  14.         qDebug("BUFFER_SIZE too small");
  15.         return;
  16.     }
  17.     qint64 len2 = streamIn->read(dataBuffer.data(), len1);

  18.     tempBuffer.append(dataBuffer.data(), len2);  //tempBuffer存放一帧的音频数据,用于编码

  19.     for(int i = 0; i < tempBuffer.length()/(L_FRAME * 2); i++)
  20.     {
  21.         memcpy(srcAudio, tempBuffer.data() + i * L_FRAME * 2, L_FRAME*2);

  22.         fwrite(srcAudio, 1, sizeof(srcAudio), fp);
  23.     }
  24.     fclose(fp);
  25.     tempBuffer.clear();
  26. }
复制代码
其中宏定义如下:
  1. #define BUFFER_SIZE         35280
  2. #define  L_FRAME            80
复制代码
    此次记录到此结束,最终无损音频文件还没得到呢。

你可能感兴趣的:(Qt)