⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winmm_render.cpp

📁 audio-video-codecs.rar语音编解码器
💻 CPP
字号:
/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//       Copyright(c) 2003-2007 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_WINMM_AUDIO_RENDER)

#include "winmm_render.h"

void CALLBACK waveOutProc(HWAVEOUT /*m_hWO*/,
                          UINT uMsg,
                          DWORD_PTR dwInstance,
                          DWORD_PTR /*dwParam1*/,
                          Ipp32u) /*dwParam2*/
{
  UMC::WinMMAudioRender* pRender = (UMC::WinMMAudioRender*) dwInstance;

  switch(uMsg)
  {
   case WOM_OPEN:
       break;
   case WOM_DONE:
       pRender->Release();
       break;
   case WOM_CLOSE:
       break;
   default:
       break;
  }
}

UMC::WinMMAudioRender::BufArray::BufArray():
  m_uiBufSize(0),
  m_uiHdrNum(WINMM_BUF_NUM_MAX)
{
  memset(m_pArray, 0, sizeof(WAVEHDR) * m_uiHdrNum);
}

UMC::WinMMAudioRender::BufArray::~BufArray()
{
  for (Ipp32u i = 0; i < m_uiHdrNum; i++) {
    if (m_pArray[i].lpData) {
      delete[](m_pArray[i].lpData);
    }
    m_pArray[i].lpData = NULL;
  }
}

UMC::Status UMC::WinMMAudioRender::BufArray::Init(Ipp32u uiBufSize)
{
  Status umcRes = UMC_OK;
  m_uiBufSize = uiBufSize;

  for (Ipp32u i = 0; UMC_OK == umcRes && i < m_uiHdrNum; i++) {
    if (m_pArray[i].lpData) {
      delete[](m_pArray[i].lpData);
    }
    memset(&m_pArray[i], 0, sizeof(WAVEHDR));
    m_pArray[i].lpData = new char[WINMM_BUF_SIZE];
    if (NULL == m_pArray[i].lpData) {
      umcRes = UMC_ERR_ALLOC;
    }
    m_pArray[i].dwBufferLength = m_uiBufSize;
    memset(m_pArray[i].lpData, 0, m_uiBufSize);
  }
  return umcRes;
}

void UMC::WinMMAudioRender::BufArray::ZeroBuffers()
{
  for (Ipp32u i = 0; i < m_uiHdrNum; i++) {
    if (m_pArray[i].lpData) {
      memset(m_pArray[i].lpData, 0, m_uiBufSize);
    }
  }
}

UMC::WinMMAudioRender::WinMMAudioRender():
    m_hWO(NULL),
    m_sm_free_buffers(0),
    m_dfStartPTS(-1.0),
    m_dfSampleNorm(1.0),
    m_DataSize(0)
{}

UMC::Status UMC::WinMMAudioRender::Reset()
{
  Status umcRes = UMC_OK;
  MMRESULT mmres;

  if (m_hWO) {
    m_bStop = 1;
    vm_time_sleep(10);
    mmres = waveOutClose(m_hWO);
    if (mmres == WAVERR_STILLPLAYING) {  // need to reset buffers
      mmres = waveOutReset(m_hWO);
      mmres = waveOutClose(m_hWO);
    }
    m_hWO = NULL;
  }

  if (m_sm_free_buffers) {
    m_sm_free_buffers = NULL;
    CloseHandle(m_sm_free_buffers);
  }

  // all buffers free
  if (UMC_OK == umcRes) {
    VM_ASSERT(NULL == m_sm_free_buffers);
    m_sm_free_buffers = CreateSemaphore(NULL, WINMM_BUF_NUM_MAX,
                                        WINMM_BUF_NUM_MAX, NULL);
    if (NULL == m_sm_free_buffers) {
      umcRes = UMC_ERR_FAILED;
    }
  }

  m_Hdrs.ZeroBuffers();

  if (UMC_OK == umcRes &&
      MMSYSERR_NOERROR != waveOutOpen(&m_hWO,
                                      WAVE_MAPPER,
                                      &m_WaveFmtX,
                                      (DWORD_PTR) waveOutProc,
                                      (DWORD_PTR) this,
                                      CALLBACK_FUNCTION)) {
    umcRes = UMC_ERR_FAILED;
  }

  if (UMC_OK == umcRes) {
    Ipp32u wdVolume = m_dwVolume | (m_dwVolume << 16);
    if (MMSYSERR_NOERROR != waveOutSetVolume(m_hWO, wdVolume)) {
      umcRes = UMC_ERR_FAILED;
    }

    m_dfStartPTS = -1.0;
    m_iFreeBuf = WINMM_BUF_NUM_MAX - 1;
    m_iDoneBuf = 0;
    m_iOffset = -1;
  }

  if (UMC_OK == umcRes) {
    m_DataBuffer.Reset();
    //umcRes = BasicAudioRender::Reset();
  }

  m_bStop = 0;
  return umcRes;
}

UMC::Status UMC::WinMMAudioRender::Close()
{
  MMRESULT mmres;

  BasicAudioRender::Close();
  if (m_hWO) {
    vm_time_sleep(10);
    mmres = waveOutClose(m_hWO);
    if (mmres == WAVERR_STILLPLAYING) {  // need to reset buffers
      mmres = waveOutReset(m_hWO);
      mmres = waveOutClose(m_hWO);
    }
    m_hWO = NULL;
  }

  if (m_sm_free_buffers) {
    CloseHandle(m_sm_free_buffers);
  }

  m_sm_free_buffers = NULL;
  return UMC::UMC_OK;
}

UMC::WinMMAudioRender::~WinMMAudioRender()
{
  Close();
}

UMC::Status UMC::WinMMAudioRender::Init(MediaReceiverParams* pInit)
{
  Status umcRes = UMC_OK;
  AudioRenderParams* pParams =
      DynamicCast<AudioRenderParams, MediaReceiverParams>(pInit);

  if (NULL == pParams) {
    umcRes = UMC_ERR_NULL_PTR;
  }

  sAudioStreamInfo *pASInfo = NULL;

  if (UMC_OK == umcRes) {
    pASInfo = &pParams->info;
    Close();
    umcRes = m_Hdrs.Init(WINMM_BUF_SIZE);
  }

  if (UMC_OK == umcRes) {
    // prepare waveout
    m_WaveFmtX.wFormatTag      = (Ipp16u)WAVE_FORMAT_PCM;
    m_WaveFmtX.nChannels       = (Ipp16u)pASInfo->channels;
    m_WaveFmtX.nSamplesPerSec  = pASInfo->sample_frequency;
    m_WaveFmtX.wBitsPerSample  = (Ipp16u)pASInfo->bitPerSample;
    m_WaveFmtX.nBlockAlign     = (Ipp16u)((m_WaveFmtX.wBitsPerSample *
                                           m_WaveFmtX.nChannels) >> 3);
    m_WaveFmtX.nAvgBytesPerSec = pASInfo->sample_frequency * m_WaveFmtX.nBlockAlign;
    m_WaveFmtX.cbSize          = 0;
    m_dfStartPTS               = -1.0;
    m_dwVolume                 = 0xffffffff;
    m_dfSampleNorm             = 1.0 / pASInfo->sample_frequency;

    umcRes = Reset();
  }

  if (UMC_OK == umcRes) {
    umcRes = BasicAudioRender::Init(pInit);
  }

  return umcRes;
}

void UMC::WinMMAudioRender::Release()
{
  if (m_hWO && m_sm_free_buffers) {
    if (!m_bStop) {
      waveOutUnprepareHeader(m_hWO, &m_Hdrs.m_pArray[m_iDoneBuf], sizeof(WAVEHDR));
    }
    ReleaseSemaphore(m_sm_free_buffers, 1, NULL);

    if (WINMM_BUF_NUM_MAX == ++m_iDoneBuf) {
      m_iDoneBuf = 0;
    }
  }
}

UMC::Status UMC::WinMMAudioRender::UnLockInputBuffer(MediaData *in,
                                                     Status StreamStatus)
{
  Status umcRes = BasicAudioRender::UnLockInputBuffer(in,StreamStatus);

  if (UMC_OK == umcRes && m_dfStartPTS == -1.0) { // first frame
    m_dfStartPTS = in->GetTime();
    if (m_dfStartPTS < 0) {
      m_dfStartPTS = 0.0;
    }
  }

  return umcRes;
}

UMC::Status UMC::WinMMAudioRender::SendFrame(MediaData* pInData)
{
  Status    umcRes = UMC_OK;
  Ipp32u    uiBufSize = WINMM_BUF_SIZE;
  MMRESULT  res;
  Ipp32u    uiBytes = 0;
  Ipp8u*    pbBuffer = NULL;

  if (NULL == pInData) {
    umcRes = UMC_ERR_NULL_PTR;
  }

  if (UMC_OK == umcRes) {
    uiBytes = pInData->GetDataSize();
    pbBuffer = (Ipp8u*)pInData->GetDataPointer();
  }

  while (UMC_OK == umcRes && 0 < uiBytes) {
    vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("uiBytes = %i\n"), uiBytes);
    if (-1 == m_iOffset) {
        WaitForSingleObject(m_sm_free_buffers, INFINITE);
        if (m_bStop) {
          break;
        }

        if (++m_iFreeBuf == WINMM_BUF_NUM_MAX) {
          m_iFreeBuf = 0;
        }
        m_iOffset = 0;
    }

    vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("m_iFreeBuf = %i\n"), m_iFreeBuf);
    WAVEHDR *pHdr = &m_Hdrs.m_pArray[m_iFreeBuf];

    if (uiBufSize - m_iOffset > uiBytes) {
      memcpy(pHdr->lpData + m_iOffset, pbBuffer, uiBytes);
      m_iOffset += uiBytes;
      m_DataSize += uiBytes;
      uiBytes = 0;
    } else {
      memcpy(pHdr->lpData + m_iOffset, pbBuffer, uiBufSize - m_iOffset);
      uiBytes -= uiBufSize - m_iOffset;
      pbBuffer += (uiBufSize - m_iOffset);
      m_DataSize += (uiBufSize - m_iOffset);
      m_iOffset = -1;
    }

    vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("all %i bytes are copied!!!\n"), m_DataSize);
    if ((-1 == m_iOffset) && (!m_bStop)) {
      vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("buffer %i is full and ready for playback\n"), m_iFreeBuf);
      res = waveOutPrepareHeader(m_hWO, pHdr, sizeof(WAVEHDR));
      if (MMSYSERR_NOERROR == res) {
        res = waveOutWrite(m_hWO, pHdr, sizeof(WAVEHDR));
      }
      if (MMSYSERR_NOERROR != res) {
        vm_debug_trace(VM_DEBUG_ALL, VM_STRING("Failed to write WaveOut!!!\n"));
        umcRes = UMC_ERR_FAILED;
      }
    }
  }
  return umcRes;
}

UMC::Status UMC::WinMMAudioRender::DrainBuffer()
{
  Status    umcRes = UMC_OK;
  MMRESULT  res;

  WAVEHDR *pHdr = &m_Hdrs.m_pArray[m_iFreeBuf];
  vm_debug_trace(VM_DEBUG_ALL, VM_STRING("Draining internal buffer ...\n"));
  vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("%i bytes are copied!!!\n"), m_DataSize);

  if (m_iOffset != -1) {  // some data is not written
    res = waveOutPrepareHeader(m_hWO, pHdr, sizeof(WAVEHDR));
    if (MMSYSERR_NOERROR == res) {
      res = waveOutWrite(m_hWO, pHdr, sizeof(WAVEHDR));
      vm_debug_trace1(VM_DEBUG_ALL, VM_STRING("Written %i buffer\n"), m_iFreeBuf);
      if (MMSYSERR_NOERROR != res) {
        vm_debug_trace(VM_DEBUG_ALL, VM_STRING("finish: Failed to write WaveOut!!!\n"));
        umcRes = UMC_ERR_FAILED;
      }
    }
  }

  MMTIME wotime;
  wotime.wType = TIME_BYTES;
  wotime.u.cb = 0;

  /*** wait till the buffer is done ***/
  while (!(pHdr->dwFlags & WHDR_DONE)) {
    vm_time_sleep(100);
  }

  return umcRes;
}


UMC::Status UMC::WinMMAudioRender::Pause(bool bPause)
{
  MMRESULT mmRes = MMSYSERR_NOERROR;

  if (m_hWO ) {
    if (bPause) {
      mmRes = waveOutPause(m_hWO);
    } else {
      mmRes = waveOutRestart(m_hWO);
    }
  }
  return (MMSYSERR_NOERROR == mmRes) ? UMC_OK : UMC_ERR_FAILED;
}

Ipp64f UMC::WinMMAudioRender::GetTimeTick()
{
  if (m_hWO || -1.0 != m_dfStartPTS) {
    MMTIME wotime;
    wotime.wType    = TIME_SAMPLES;
    wotime.u.sample = 0;
    if (MMSYSERR_NOERROR == waveOutGetPosition(m_hWO, &wotime, sizeof(wotime))) {
      if (wotime.wType == TIME_SAMPLES) { // format is supported
        return m_dfStartPTS + wotime.u.sample * m_dfSampleNorm;
      }
    }
  }
  return 0;
}

#endif  // UMC_ENABLE_WINMM_AUDIO_RENDER

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -