zoukankan      html  css  js  c++  java
  • EasyPlayerPro Windows播放器进行本地对讲喊话音频采集功能实现

    需求

    在安防行业应用中,除了在本地看到摄像机的视频和进行音频监听外,还有一个重要的功能,那就是对讲. EasyPlayerPro-win为了减轻二次开发者的工作量,将本地音频采集也进行了集成;

    功能特点

    • 支持获取本地所有音频输入设备列表;
    • 可任意选择任一音频输入设备;
    • 可设置采样率和采样精度及位率;
    • 可设置编码格式(当前支持G711A,G711U,AAC);

    EasyPlayerPro播放器

    实现流程

    1. 采用DirectSound8进行本地音频采集;
    2. 将采集到的音频数据写入编码队列;
    3. 在编码线程中获取源始音频数据,进行音频编码;
    4. 编码完成后,将编码数据回调给上层应用;
        //获取声音采集设备列表
        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 -1;
        if (NULL == pSoundCaptureThread->pSupportWaveFormatEx)      return -1;
    
        if (waveFormatExIndex< 0 || waveFormatExIndex>=pSoundCaptureThread->supportWaveFormatExCount)   return -2;
    
        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( 1024, _wfxInput->nAvgBytesPerSec / 8 );
        pSoundCaptureThread->dwNotifySize -= pSoundCaptureThread->dwNotifySize % _wfxInput->nBlockAlign;
        pSoundCaptureThread->dwCaptureBufferSize = pSoundCaptureThread->dwNotifySize * 16;
    
        dscbd.dwSize        = sizeof(DSCBUFFERDESC);
        dscbd.dwBufferBytes = pSoundCaptureThread->dwCaptureBufferSize;
        dscbd.lpwfxFormat   = _wfxInput;
        hr = pSoundCaptureThread->lpDirectSoundCapture8->CreateCaptureBuffer( &dscbd, &pSoundCaptureThread->lpDSBCapture, NULL);
    
        if (FAILED(hr))                                 return -3;
        if (NULL == pSoundCaptureThread->lpDSBCapture)  return -4;
    
        pSoundCaptureThread->dwNextCaptureOffset = 0;
    
        hr = pSoundCaptureThread->lpDSBCapture->QueryInterface( IID_IDirectSoundNotify, (PVOID*)&pSoundCaptureThread->lpDSNotify );
        for( INT i = 0; i < 16; i++ ) 
        {
            pSoundCaptureThread->DSBPosNotify[i].dwOffset     = (pSoundCaptureThread->dwNotifySize * i) + pSoundCaptureThread->dwNotifySize - 1;
            pSoundCaptureThread->DSBPosNotify[i].hEventNotify = pSoundCaptureThread->hCaptureNotifyEvent;
        }
        hr = pSoundCaptureThread->lpDSNotify->SetNotificationPositions( 16, pSoundCaptureThread->DSBPosNotify);
    
        hr = pSoundCaptureThread->lpDSBCapture->Start( DSCBSTART_LOOPING );
        //m_fIsCapture = TRUE;
    
        if (SUCCEEDED(hr))
        {
            if (NULL == pSoundCaptureThread->hCaptureNotifyThread)
            {
                pSoundCaptureThread->flag = 0x01;
                pSoundCaptureThread->userPtr = this;
                pSoundCaptureThread->captureCallback = callback;
                pSoundCaptureThread->callbackUserPtr = userptr;
                pSoundCaptureThread->hCaptureNotifyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_lpDirectSoundCaptureThread, 
                    pSoundCaptureThread, 0, NULL);
                while (pSoundCaptureThread->flag!=0x02 && pSoundCaptureThread->flag!=0x00)  {Sleep(100);}
            }
        }
    
        return hr;
        }
    
    
        //获取源始音频数据
        int DirectSoundCapturer::ProcessCaptureData()
        {
        HRESULT hrRet = 0;
        LONG    lLockSize;
    
        if (NULL == pSoundCaptureThread)            return -1;
        if (pSoundCaptureThread->flag == 0x03)      return -1;
        if (NULL == pSoundCaptureThread->lpDSBCapture)  return -1;
    
        do {
    
            DWORD   dwCapturePos, dwReadPos;
            hrRet = pSoundCaptureThread->lpDSBCapture->GetCurrentPosition( &dwCapturePos, &dwReadPos );
    
            lLockSize = dwReadPos - pSoundCaptureThread->dwNextCaptureOffset;
            if( lLockSize < 0 ) lLockSize += pSoundCaptureThread->dwCaptureBufferSize;
    
            // Block align lock size so that we are always write on a boundary
            lLockSize -= (lLockSize % pSoundCaptureThread->dwNotifySize);
            if( lLockSize == 0 ) {
                hrRet = -1;
                break;
            }
    
            PVOID   pCapturedData[2]   = {NULL, NULL};
            DWORD   dwCaptureLength[2] = {0, 0};
    
            // Lock the capture buffer down
            hrRet = pSoundCaptureThread->lpDSBCapture->Lock( pSoundCaptureThread->dwNextCaptureOffset,
                                         lLockSize, 
                                         &pCapturedData[0],
                                         &dwCaptureLength[0],
                                         &pCapturedData[1],
                                         &dwCaptureLength[1], 0L );
            if( FAILED( hrRet ) ) {
                hrRet = -2;
                break;
            }
    
            if (NULL != pSoundCaptureThread->captureCallback)
            {
                pSoundCaptureThread->captureCallback(&pSoundCaptureThread->inWaveFormatEx, pSoundCaptureThread->callbackUserPtr,
                    (unsigned char *)pCapturedData[0], (int)dwCaptureLength[0], (unsigned char *)pCapturedData[1], (int)dwCaptureLength[1]);
            }
    
            pSoundCaptureThread->dwNextCaptureOffset += dwCaptureLength[0];
            pSoundCaptureThread->dwNextCaptureOffset %= pSoundCaptureThread->dwCaptureBufferSize;       // Circular buffer
    
            if( pCapturedData[1] != NULL ) {
                pSoundCaptureThread->dwNextCaptureOffset += dwCaptureLength[1];
                pSoundCaptureThread->dwNextCaptureOffset %= pSoundCaptureThread->dwCaptureBufferSize; // Circular buffer
            }
    
            pSoundCaptureThread->lpDSBCapture->Unlock( pCapturedData[0], dwCaptureLength[0],
                                   pCapturedData[1], dwCaptureLength[1] );
        } while(0);
    
        return hrRet;
        }

    关于EasyPlayerPro播放器

    EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP、RTMP、HTTP、HLS、UDP、RTP、File等多种流媒体协议播放、支持本地文件播放,支持本地抓拍、本地录像、播放旋转、多屏播放、倍数播放等多种功能特性,核心基于ffmpeg,稳定、高效、可靠、可控,支持Windows、Android、iOS三个平台,目前在多家教育、安防、行业型公司,都得到的应用,广受好评!

    EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro

    点击链接加入群【EasyPlayer & EasyPlayerPro】:544917793

    技术支持

    获取更多信息

    EasyDarwin开源流媒体服务器:www.EasyDarwin.org

    EasyDSS商用流媒体解决方案:www.EasyDSS.com

    EasyNVR无插件直播方案:www.EasyNVR.com

    Copyright © EasyDarwin Team 2012-2017

    EasyDarwin

  • 相关阅读:
    OpenGL搭建环境-VS2012【OpenGL】
    IOS内存约定-【ios】
    bootstrap下jQuery自动完成的样式调整-【jQuery】
    如何访问https的网站?-【httpclient】
    twitter typeahead控件使用经历
    grails服务端口冲突解决办法-【grails】
    jQuery中live函数的替代-【jQuery】
    如何自动设置网页中meta节点keywords属性-【SEO】
    如何在grails2.3.x中的fork模式下进行调试?-【grails】
    树的简介及Java实现
  • 原文地址:https://www.cnblogs.com/babosa/p/9217699.html
Copyright © 2011-2022 走看看