2025-04-27 07:49:33 -04:00

155 lines
4.9 KiB
C++

/*==========================================================================
*
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
*
* File: aconvs.cpp
* Content: This module implements the CAudioConverterSingle class. This
* class relies on the ACM for actual conversions, but manages
* the headaches of mismatched block sizes. It does NOT manage
* multistep conversions.
*
* History:
* Date By Reason
* ==== == ======
* 07/30/99 pnewson Created
*
***************************************************************************/
#include "stdafx.h"
#include "aconvs.h"
#include "acmutils.h"
#include "dndbg.h"
#include "OSInd.h"
CAudioConverterSingle::CAudioConverterSingle(
WAVEFORMATEX *pwfxSrc,
WAVEFORMATEX *pwfxDst )
{
ACMCHECK( acmStreamOpen(&m_has, NULL, pwfxSrc, pwfxDst, NULL, 0, 0, 0) );
// I don't want to count on the fact that realloc is going
// to allocate a new buffer if I pass in a NULL pointer
// for the current buffer. So allocate a small 8 byte buffer
// here. Why 8? Because it is a "nice" sized buffer on all
// machines up to 64 bit processors, but still small enough
// to cause a realloc pretty much right away.
m_dwHoldingBufSize = 8;
m_apbHoldingBuf = std::auto_ptr<BYTE>(new BYTE[m_dwHoldingBufSize]);
if (m_apbHoldingBuf.get() == NULL)
{
//// TODO(pnewson, "memory alloc failure cleanup")
throw exception();
}
m_dwHoldingBufUsed = 0;
// figure out how much slack to add to output buffer estimates
// to account for data that may be in the holding buffer from
// previous calls to Convert. This slack estimate is based on the
// assumption that the ACM will eat up all the input data until
// there is not enough input data to produce another full block of
// output data
DWORD dwSingleBlockOutputSize;
ACMCHECK( acmStreamSize(m_has, pwfxSrc->nBlockAlign, &dwSingleBlockOutputSize,
ACM_STREAMSIZEF_SOURCE) );
// remember the output format's block size
m_dwOutputBlockSize = pwfxDst->nBlockAlign;
m_ash.cbStruct = sizeof(ACMSTREAMHEADER);
m_ash.dwUser = 0;
m_ash.dwSrcUser = 0;
m_ash.dwDstUser = 0;
}
CAudioConverterSingle::~CAudioConverterSingle()
{
ACMCHECK( acmStreamClose(m_has, 0) );
// the auto_ptr takes care of the buffer
}
void CAudioConverterSingle::MaxOutputSize(DWORD dwInputSize, DWORD* pdwOutputSize)
{
// figure out how much the ACM thinks it will output
ACMCHECK( acmStreamSize(m_has, dwInputSize, pdwOutputSize,
ACM_STREAMSIZEF_SOURCE) );
// Add some slack to the output buffer estimates
// to account for data that may be in the holding buffer from
// previous calls to Convert. This slack estimate is based on the
// assumption that the ACM will eat up all the input data until
// there is not enough input data to produce another full block of
// output data. Therefore the slack will not account for more
// than one full block of output data. (Note: the ACM may already
// take this into account when generating it's estimates, by
// rounding up somewhere, but better safe than sorry.)
pdwOutputSize += m_dwOutputBlockSize;
return;
}
void CAudioConverterSingle::Convert(
BYTE* pbInputBuf,
DWORD dwInputSize,
BYTE* pbOutputBuf,
DWORD dwOutputBufSize,
DWORD* pdwActualSize)
{
// copy the input data into the internal buffer
// don't overwrite any data already in that buffer
// that was held over from the previous conversion
if (m_dwHoldingBufUsed + dwInputSize > m_dwHoldingBufSize)
{
// need more space in the input buffer
m_dwHoldingBufSize = m_dwHoldingBufUsed + dwInputSize;
std::auto_ptr<BYTE> apbNewBuf(new BYTE[m_dwHoldingBufSize]);
if (apbNewBuf.get() == NULL)
{
//// TODO(pnewson, "memory alloc failure cleanup")
throw exception();
}
memcpy(apbNewBuf.get(), m_apbHoldingBuf.get(), m_dwHoldingBufUsed);
// note - auto_ptr deletes old buffer here
m_apbHoldingBuf = apbNewBuf;
}
memcpy(m_apbHoldingBuf.get() + m_dwHoldingBufUsed,
pbInputBuf, dwInputSize);
m_ash.fdwStatus = 0;
m_ash.pbSrc = m_apbHoldingBuf.get();
m_ash.cbSrcLength = m_dwHoldingBufUsed;
m_ash.cbSrcLengthUsed = 0;
m_ash.pbDst = pbOutputBuf;
m_ash.cbDstLength = dwOutputBufSize;
m_ash.cbDstLengthUsed = 0;
ACMCHECK( acmStreamPrepareHeader(m_has, &m_ash, 0) );
ACMCHECK( acmStreamConvert(m_has, &m_ash, ACM_STREAMCONVERTF_BLOCKALIGN) );
ACMCHECK( acmStreamUnprepareHeader(m_has, &m_ash, 0) );
// save the unused input data
m_dwHoldingBufUsed = m_ash.cbSrcLength - m_ash.cbSrcLengthUsed;
memmove(m_apbHoldingBuf.get(), m_apbHoldingBuf.get() + m_ash.cbSrcLengthUsed,
m_dwHoldingBufUsed);
// tell the caller how much of the output buffer
// we used, if they care
if (pdwActualSize != NULL)
{
*pdwActualSize = m_ash.cbSrcLengthUsed;
}
return;
};
void CAudioConverterSingle::Flush()
{
m_dwHoldingBufUsed = 0;
}