需求
在安防行業應用中,除了在本地看到錄影機的視訊和進行音頻監聽外,還有一個重要的功能,那就是對講. EasyPlayerPro-win為了減輕二次開發者的工作量,将本地音頻采集也進行了內建;
功能特點
- 支援擷取本地所有音頻輸入裝置清單;
- 可任意選擇任一音頻輸入裝置;
- 可設定采樣率和采樣精度及位率;
- 可設定編碼格式(目前支援G711A,G711U,AAC);
實作流程
- 采用DirectSound8進行本地音頻采集;
- 将采集到的音頻資料寫入編碼隊列;
- 在編碼線程中擷取源始音頻資料,進行音頻編碼;
- 編碼完成後,将編碼資料回調給上層應用;
//擷取聲音采集裝置清單
int GetAudioCaptureDeviceList(int *num, SOUND_CAPTURE_DEVICE_INFO **pDeviceInfo);
int OpenAudioCaptureDevice(int captureDeviceIndex);
int GetSupportWaveFormatList(int *num, WAVEFORMATEX **ppWaveFormatEx);
int StartCapture(int waveFormatExIndex, DirectSoundCaptureCallback callback, void *userptr);
int StopCapture();
void CloseAudioCaptureDevice();
static LPTHREAD_START_ROUTINE __stdcall _lpDirectSoundCaptureThread ( LPVOID _pParam );
代碼實作
//開始采集音頻
int DirectSoundCapturer::StartCapture(int waveFormatExIndex, DirectSoundCaptureCallback callback, void *userptr)
{
if (NULL == pSoundCaptureThread) return -;
if (NULL == pSoundCaptureThread->pSupportWaveFormatEx) return -;
if (waveFormatExIndex< || waveFormatExIndex>=pSoundCaptureThread->supportWaveFormatExCount) return -;
HRESULT hr = S_OK;
WAVEFORMATEX *_wfxInput = (WAVEFORMATEX*)&pSoundCaptureThread->pSupportWaveFormatEx[waveFormatExIndex];
memcpy(&pSoundCaptureThread->inWaveFormatEx, _wfxInput, sizeof(WAVEFORMATEX));
DSCBUFFERDESC dscbd;
ZeroMemory( &dscbd, sizeof(DSCBUFFERDESC) );
pSoundCaptureThread->dwNotifySize = max( , _wfxInput->nAvgBytesPerSec / );
pSoundCaptureThread->dwNotifySize -= pSoundCaptureThread->dwNotifySize % _wfxInput->nBlockAlign;
pSoundCaptureThread->dwCaptureBufferSize = pSoundCaptureThread->dwNotifySize * ;
dscbd.dwSize = sizeof(DSCBUFFERDESC);
dscbd.dwBufferBytes = pSoundCaptureThread->dwCaptureBufferSize;
dscbd.lpwfxFormat = _wfxInput;
hr = pSoundCaptureThread->lpDirectSoundCapture8->CreateCaptureBuffer( &dscbd, &pSoundCaptureThread->lpDSBCapture, NULL);
if (FAILED(hr)) return -;
if (NULL == pSoundCaptureThread->lpDSBCapture) return -;
pSoundCaptureThread->dwNextCaptureOffset = ;
hr = pSoundCaptureThread->lpDSBCapture->QueryInterface( IID_IDirectSoundNotify, (PVOID*)&pSoundCaptureThread->lpDSNotify );
for( INT i = ; i < ; i++ )
{
pSoundCaptureThread->DSBPosNotify[i].dwOffset = (pSoundCaptureThread->dwNotifySize * i) + pSoundCaptureThread->dwNotifySize - ;
pSoundCaptureThread->DSBPosNotify[i].hEventNotify = pSoundCaptureThread->hCaptureNotifyEvent;
}
hr = pSoundCaptureThread->lpDSNotify->SetNotificationPositions( , pSoundCaptureThread->DSBPosNotify);
hr = pSoundCaptureThread->lpDSBCapture->Start( DSCBSTART_LOOPING );
//m_fIsCapture = TRUE;
if (SUCCEEDED(hr))
{
if (NULL == pSoundCaptureThread->hCaptureNotifyThread)
{
pSoundCaptureThread->flag = ;
pSoundCaptureThread->userPtr = this;
pSoundCaptureThread->captureCallback = callback;
pSoundCaptureThread->callbackUserPtr = userptr;
pSoundCaptureThread->hCaptureNotifyThread = CreateThread(NULL, , (LPTHREAD_START_ROUTINE)_lpDirectSoundCaptureThread,
pSoundCaptureThread, , NULL);
while (pSoundCaptureThread->flag!= && pSoundCaptureThread->flag!=) {Sleep();}
}
}
return hr;
}
//擷取源始音頻資料
int DirectSoundCapturer::ProcessCaptureData()
{
HRESULT hrRet = ;
LONG lLockSize;
if (NULL == pSoundCaptureThread) return -;
if (pSoundCaptureThread->flag == ) return -;
if (NULL == pSoundCaptureThread->lpDSBCapture) return -;
do {
DWORD dwCapturePos, dwReadPos;
hrRet = pSoundCaptureThread->lpDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos );
lLockSize = dwReadPos - pSoundCaptureThread->dwNextCaptureOffset;
if( lLockSize < ) lLockSize += pSoundCaptureThread->dwCaptureBufferSize;
// Block align lock size so that we are always write on a boundary
lLockSize -= (lLockSize % pSoundCaptureThread->dwNotifySize);
if( lLockSize == ) {
hrRet = -;
break;
}
PVOID pCapturedData[] = {NULL, NULL};
DWORD dwCaptureLength[] = {, };
// Lock the capture buffer down
hrRet = pSoundCaptureThread->lpDSBCapture->Lock( pSoundCaptureThread->dwNextCaptureOffset,
lLockSize,
&pCapturedData[],
&dwCaptureLength[],
&pCapturedData[],
&dwCaptureLength[], L );
if( FAILED( hrRet ) ) {
hrRet = -;
break;
}
if (NULL != pSoundCaptureThread->captureCallback)
{
pSoundCaptureThread->captureCallback(&pSoundCaptureThread->inWaveFormatEx, pSoundCaptureThread->callbackUserPtr,
(unsigned char *)pCapturedData[], (int)dwCaptureLength[], (unsigned char *)pCapturedData[], (int)dwCaptureLength[]);
}
pSoundCaptureThread->dwNextCaptureOffset += dwCaptureLength[];
pSoundCaptureThread->dwNextCaptureOffset %= pSoundCaptureThread->dwCaptureBufferSize; // Circular buffer
if( pCapturedData[] != NULL ) {
pSoundCaptureThread->dwNextCaptureOffset += dwCaptureLength[];
pSoundCaptureThread->dwNextCaptureOffset %= pSoundCaptureThread->dwCaptureBufferSize; // Circular buffer
}
pSoundCaptureThread->lpDSBCapture->Unlock( pCapturedData[], dwCaptureLength[],
pCapturedData[], dwCaptureLength[] );
} while();
return hrRet;
}
關于EasyPlayerPro播放器
EasyPlayerPro是一款全功能的流媒體播放器,支援RTSP、RTMP、HTTP、HLS、UDP、RTP、File等多種流媒體協定播放、支援本地檔案播放,支援本地抓拍、本地錄像、播放旋轉、多屏播放、倍數播放等多種功能特性,核心基于ffmpeg,穩定、高效、可靠、可控,支援Windows、Android、iOS三個平台,目前在多家教育、安防、行業型公司,都得到的應用,廣受好評!
EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro
點選連結加入群【EasyPlayer & EasyPlayerPro】:544917793
技術支援
- 郵件:[email protected]
- QQ交流群:544917793
擷取更多資訊
EasyDarwin開源流媒體伺服器:www.EasyDarwin.org
EasyDSS商用流媒體解決方案:www.EasyDSS.com
EasyNVR無插件直播方案:www.EasyNVR.com
Copyright © EasyDarwin Team 2012-2017