今天是2024年1月1日,新年的第一缕阳光已经普照大地,祝愿看到这篇文章的所有程序员或程序爱好者都能在新的一年里持之以恒,事业有成。

今天也是我加入CSDN的第4100天,但回过头看一看,这么长的时间也没有在CSDN写下几篇文章,真是一种遗憾。为了弥补这个遗憾,我会继续坚持把这套教程写完。目前的教程总体而言写的还比较粗略,很多细节没有展开写,后面找时间再继续优化,现在主要是梳理一下整体思路,先搞个框架出来。

1.捕获麦克风数据入队列备用

上节课我们已经用openCV成功打开摄像头并实现了预览功能,这节课我们来看一下如何捕获麦克风数据。要捕获麦克风数据,就要先打开麦克风,打开麦克风的方法与《第3课 使用FFmpeg获取并播放音频流》中打开扬声器的方法差不多:

//打开麦克风
void fmle::openMic(){
	int nIndex = 0;
	inWaveform.wFormatTag = WAVE_FORMAT_PCM;
	inWaveform.nSamplesPerSec = 44100;
	inWaveform.wBitsPerSample = 16;
	inWaveform.nChannels = 2;
	inWaveform.nBlockAlign = (inWaveform.wBitsPerSample * inWaveform.nChannels) / 8;
	inWaveform.nAvgBytesPerSec = inWaveform.nBlockAlign * inWaveform.nSamplesPerSec;
	inWaveform.cbSize = 0;
	waveInOpen(&hWaveIn, nIndex, &inWaveform, (DWORD)micCallback, 0L, CALLBACK_FUNCTION);
	waveHdrArr = new WAVEHDR[audioDataArrNum];
	for (int i = 0; i < audioDataArrNum; i++)
	{
		waveHdrArr[i].lpData = new char[audioDataSize];
		waveHdrArr[i].dwBufferLength = audioDataSize;
		waveHdrArr[i].dwBytesRecorded = 0;
		waveHdrArr[i].dwUser = NULL;
		waveHdrArr[i].dwFlags = 0;
		waveHdrArr[i].dwLoops = 1;
		waveHdrArr[i].lpNext = NULL;
		waveHdrArr[i].reserved = 0;
		waveInPrepareHeader(hWaveIn, &waveHdrArr[i], sizeof(WAVEHDR));
		waveInAddBuffer(hWaveIn, &waveHdrArr[i], sizeof(WAVEHDR));
	}
	waveInStart(hWaveIn);
}

DWORD CALLBACK fmle::micCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{

	switch (uMsg)
	{
	case WIM_OPEN:
		TRACE("WIM_OPEN\n");
		break;

	case WIM_DATA:


	{
					 //TRACE("WIM_DATA\n");
					 LPWAVEHDR pwh = (LPWAVEHDR)dwParam1;
					 if (pwh->dwBytesRecorded > 0){
						 EnterCriticalSection(&pThis->queLock);
						 pThis->tmpAudioQueObj.type = 0;
						 pThis->tmpAudioQueObj.dataArr = pwh->lpData;
						 pThis->tmpAudioQueObj.dataLen = pwh->dwBytesRecorded;
						 pThis->inAudioQue.push(pThis->tmpAudioQueObj);
						 if (pThis->inAudioQue.size() > pThis->audioDataArrNum){
							 pThis->inAudioQue.front().dataLen = 0;
							 pThis->inAudioQue.front().dataArr = NULL;
							 pThis->inAudioQue.front().dataLen = NULL;
							 delete[]pThis->inAudioQue.front().dataArr;
							 pThis->inAudioQue.pop();
						 }
						 LeaveCriticalSection(&pThis->queLock);
					 }
					 waveInAddBuffer(pThis->hWaveIn, pwh, sizeof(WAVEHDR));
					 TRACE("pThis->inAudioQue.size():%d\n", pThis->inAudioQue.size());
	}

		break;

	case WIM_CLOSE:
		TRACE("WIM_CLOSE\n");
		waveInStop(pThis->hWaveIn);
		waveInReset(pThis->hWaveIn);
		waveInClose(pThis->hWaveIn);
		break;
	default:
		break;
	}
	return 0;
}

2.将麦克风数据存成文件检测是否正常

上述方法虽然可以将麦克风数据存入队列备用,但我们如何知道它是否正确捕获了呢?我们可以把捕获的pcm数据先存入文件:

FILE *pcmFile;
fopen_s(&pcmFile, "rec.pcm", "wb");
fwrite(pwh->lpData, 1, pwh->dwBytesRecorded, pcmFile);

想一想,上述代码应该分别加在什么地方呢?

录制pcm文件后可以使用Audacity来导入pcm文件测试录制数据是否正确。

第6课 用window API捕获麦克风数据并加入队列备用-LMLPHP

01-02 13:04