工程在這裏:http://download.csdn.net/detail/aihahaheihei/3835562
目的是寫一個既可以錄音又可以錄視頻的,現在先分開寫錄音的和錄視頻的,接下來就把兩者結合起來啦
這個工程裏面的有些東西沒有描述出來了,下面的文章是轉來的,但工程是我自己寫的,多加了的東東,呵呵,要學會站在巨人的肩膀上創作。
祝自己好運^_^
/*語音採集 - WINDOWS API*/
#define INP_BUFFER_SIZE (8 * 1024) //定義緩衝區大小
bool m_record,m_play; //m_record表示是否正在錄音,m_play表示是否正在回放
WAVEFORMATEX waveform; //WAV文件頭包含音頻格式
DWORD dwDataLength,dwRepetitions; //dwDataLength已有的數據長度,dwRepetitions重複次數
HWAVEIN hWaveIn; //輸入設備句柄
HWAVEOUT hWaveOut; //輸出設備句柄
PBYTE pBuffer1,pBuffer2; //保存輸入數據的兩個緩衝區。
//如果只要一個緩衝區,當緩衝區滿,保存數據時,會無法保存這段時間採集的語音,導致最後獲得的聲音斷斷續續。
//使用兩個緩衝區,當一個緩衝區滿的時候,保存這個已滿的緩衝區數據,而由另一個緩衝區繼續採集語音。
PBYTE pSaveBuffer,pNewBuffer; //保存數據的內存地址。
PWAVEHDR pWaveHdr1,pWaveHdr2; //聲音文件頭
afx_msg LRESULT OnMM_WIM_OPEN(UINT wParam,LONG lParam);
afx_msg LRESULT OnMM_WIM_DATA(UINT wParam,LONG lParam);
afx_msg LRESULT OnMM_WIM_CLOSE(UINT wParam,LONG lParam);
afx_msg LRESULT OnMM_WOM_OPEN(UINT wParam,LONG lParam);
afx_msg LRESULT OnMM_WOM_DONE(UINT wParam,LONG lParam);
afx_msg LRESULT OnMM_WOM_CLOSE(UINT wParam,LONG lParam); //聲明幾個回調函數
pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR))); //給聲音文件頭分配內存空間
pSaveBuffer = reinterpret_cast<PBYTE>(malloc(1)); //給數據內存地址分配空間
//消息綁定
BEGIN_MESSAGE_MAP(/*窗口類*/, /*窗口類的父類*/)
ON_MESSAGE(MM_WIM_OPEN,OnMM_WIM_OPEN)
ON_MESSAGE(MM_WIM_DATA,OnMM_WIM_DATA)
ON_MESSAGE(MM_WIM_CLOSE,OnMM_WIM_CLOSE)
ON_MESSAGE(MM_WOM_OPEN,OnMM_WOM_OPEN)
ON_MESSAGE(MM_WOM_DONE,OnMM_WOM_DONE)
ON_MESSAGE(MM_WOM_CLOSE,OnMM_WOM_CLOSE)
END_MESSAGE_MAP()
void RecordStart() //錄音準備
{
m_record=true;
pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE); //給緩衝區分配空間
if (!pBuffer1||!pBuffer2)
{
if (pBuffer1) free(pBuffer1);
if (pBuffer2) free(pBuffer2);
MessageBeep(MB_ICONEXCLAMATION);
AfxMessageBox(L"Memory error!");
return ;
}
//設置錄音方式
waveform.wFormatTag = WAVE_FORMAT_PCM; //PCM編碼
waveform.nChannels = 1; //單聲道
waveform.nSamplesPerSec = 16000; //採樣頻率,每秒採集次數
waveform.nAvgBytesPerSec= waveform.nSamplesPerSec * sizeof(unsigned short);
waveform.nBlockAlign = waveform.nChannels * waveform.wBitsPerSample / 8;
waveform.wBitsPerSample = 16; //採樣位,模擬信號轉數字信號的精準度
waveform.cbSize = 0; //PCM編碼時,此處爲0
if (waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,(DWORD)this->m_hWnd,NULL,CALLBACK_WINDOW)) { //打開輸入設備
free(pBuffer1);
free(pBuffer2);
MessageBeep(MB_ICONEXCLAMATION);
AfxMessageBox(L"Audio can not be open!");
}
//初始化聲音文件頭
pWaveHdr1->lpData=(LPSTR)pBuffer1; //設置緩衝區
pWaveHdr1->dwBufferLength=INP_BUFFER_SIZE; //緩衝區大小
pWaveHdr1->dwBytesRecorded=0;
pWaveHdr1->dwUser=0;
pWaveHdr1->dwFlags=0;
pWaveHdr1->dwLoops=1;
pWaveHdr1->lpNext=NULL;
pWaveHdr1->reserved=0;
waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR)); //將緩衝區信息和輸入設備關聯
waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ; //將緩衝區地址添加到輸入設備中
pWaveHdr2->lpData=(LPSTR)pBuffer2;
pWaveHdr2->dwBufferLength=INP_BUFFER_SIZE;
pWaveHdr2->dwBytesRecorded=0;
pWaveHdr2->dwUser=0;
pWaveHdr2->dwFlags=0;
pWaveHdr2->dwLoops=1;
pWaveHdr2->lpNext=NULL;
pWaveHdr2->reserved=0;
waveInPrepareHeader(hWaveIn,pWaveHdr2,sizeof(WAVEHDR));
waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ; //同上
pSaveBuffer = (PBYTE)realloc (pSaveBuffer, 1) ;
dwDataLength = 0 ;
waveInStart (hWaveIn) ; //打開輸入設備,開始錄音
}
void RecordStop()
{
m_record=false;
waveInReset(hWaveIn); //停止錄音,關閉輸入設備
}
void PlayStart()
{
if (waveOutOpen(&hWaveOut,WAVE_MAPPER,&waveform,(DWORD)this->m_hWnd,NULL,CALLBACK_WINDOW)) //打開輸出設備,開始回放
{
MessageBeep(MB_ICONEXCLAMATION);
AfxMessageBox(L"Audio output error");
}
m_play=true;
}
void PlayStop()
{
waveOutReset(hWaveOut); //停止回放,關閉輸出設備
m_play = false;
}
LRESULT OnMM_WIM_OPEN(UINT wParam, LONG lParam) //開始錄音
{
// TODO: Add your message handler code here and/or call default
m_record=TRUE;
TRACE(L"MM_WIM_OPEN\n");
return 0;
}
LRESULT ChelloWMDlg::OnMM_WIM_DATA(UINT wParam, LONG lParam) //緩衝區滿的時候,對應的聲音文件頭如pWaveHdr1作爲lParam傳遞進來
{
// TODO: Add your message handler code here and/or call default
// Reallocate save buffer memory
pNewBuffer = (PBYTE)realloc (pSaveBuffer, dwDataLength +
((PWAVEHDR) lParam)->dwBytesRecorded) ;
if (pNewBuffer == NULL)
{
waveInClose (hWaveIn) ;
MessageBeep (MB_ICONEXCLAMATION) ;
AfxMessageBox(L"error memory");
return 0;
}
pSaveBuffer = pNewBuffer ; //在pSaveBuffer尾部繼續申請空間(上面的realloc 函數)
//////////////////////////////////////////////////////////////////////////
CopyMemory(pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,
((PWAVEHDR) lParam)->dwBytesRecorded) ; //將緩衝區數據((PWAVEHDR) lParam)->lpData複製到pSaveBuffer的尾部剛申請的空間中
dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;//加長pSaveBuffer的實際數據長度
if (m_record==false)
{
waveInClose (hWaveIn) ;//停止錄音,關閉輸入設備
return 0;
}
//將音頻寫入到文件中
FILE* fp=fopen("ecord.pcm","ab+");
if(fp==NULL)
{
printf("fopen error,%d",__LINE__);
}
fwrite(((PWAVEHDR) lParam)->lpData,((PWAVEHDR) lParam)->dwBytesRecorded,1,fp);
fclose(fp);
// Send out a new buffer
waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;//將緩衝區添加回到設備中
//假如現在是pWaveHdr1滿了,lParam就是pWaveHdr1,在我們保存pWaveHdr1的數據時,pWaveHdr2正在錄音,保存完pWaveHdr1,再把pWaveHdr1添加回到設備中,這樣達到兩個緩衝區交替使用。
TRACE(L"done input data\n");
return 0;
}
LRESULT ChelloWMDlg::OnMM_WIM_CLOSE(UINT wParam, LONG lParam) //停止錄音時
{
// TODO: Add your message handler code here and/or call default
TRACE(L"MM_WIM_CLOSE\n");
if (0==dwDataLength) { //沒有數據,長度爲0
return 0;
}
waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;//取消輸入設備和pWaveHdr1的關聯
waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
m_record = FALSE ;
free (pBuffer1) ;
free (pBuffer2) ;
if (dwDataLength > 0)
{
//enable play
}
return 0;
}
LRESULT ChelloWMDlg::OnMM_WOM_OPEN(UINT wParam, LONG lParam)//開始回放
{
TRACE(L"open MM_WOM_OPEN\n");
// Set up header
pWaveHdr1->lpData = (LPSTR)pSaveBuffer ;
pWaveHdr1->dwBufferLength = dwDataLength ;
pWaveHdr1->dwBytesRecorded = 0 ;
pWaveHdr1->dwUser = 0 ;
pWaveHdr1->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
pWaveHdr1->dwLoops = dwRepetitions ;
pWaveHdr1->lpNext = NULL ;
pWaveHdr1->reserved = 0 ;
// Prepare and write
waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
m_play = TRUE ;
return 0;
}
LRESULT ChelloWMDlg::OnMM_WOM_DONE(UINT wParam, LONG lParam){ //回放完畢
TRACE(L"open MM_WOM_DONE\n");
waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
waveOutClose (hWaveOut) ;
dwRepetitions = 1 ;
m_play = FALSE ;
return 0;
}
LRESULT ChelloWMDlg::OnMM_WOM_CLOSE(UINT wParam, LONG lParam){ //關閉回放
TRACE(L"open MM_WOM_CLOSE\n");
dwRepetitions = 1 ;
m_play = FALSE ;
return 0;
}