📄 winmm_render.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 + -