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

289 lines
9.1 KiB
C++

/*==========================================================================
*
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
*
* File: acmconv.cpp
* Content: This module contains the implementation of the CACMConverter class
* which is responsible for handling audio conversions with codecs
* through the ACM.
*
* History:
* Date By Reason
* ==== == ======
* 07/16/99 rodtoll Created
* 08/25/99 rodtoll General Cleanup/Modifications to support new
* compression sub-system.
* 09/20/99 rodtoll Added memory alloc failure checks
* 10/05/99 rodtoll Added dpf_modnames
*
***************************************************************************/
#include "stdafx.h"
#include "acmconv.h"
#include "dndbg.h"
#include "OSInd.h"
#undef DPF_MODNAME
#define DPF_MODNAME "CACMConverter::CACMConverter"
CACMConverter::CACMConverter(
WAVEFORMATEX *pwfSrcFormat, DVFULLCOMPRESSIONINFO *lpdvfTargetFormat
): CAudioConverter( pwfSrcFormat,lpdvfTargetFormat ),
m_bDirectConvert(FALSE),
m_pwfInnerFormat(NULL),
m_pbInnerBuffer(NULL),
m_dwInnerBufferSize(0)
{
Initialize( pwfSrcFormat, m_lpdvfInfo->lpwfxFormat, pwfSrcFormat );
}
#undef DPF_MODNAME
#define DPF_MODNAME "CACMConverter::CACMConverter"
CACMConverter::CACMConverter(
DVFULLCOMPRESSIONINFO *lpdvfSrcFormat, WAVEFORMATEX *pwfTargetFormat
): CAudioConverter( lpdvfSrcFormat, pwfTargetFormat ),
m_bDirectConvert(FALSE),
m_pwfInnerFormat(NULL),
m_pbInnerBuffer(NULL),
m_dwInnerBufferSize(0)
{
Initialize( lpdvfSrcFormat->lpwfxFormat, pwfTargetFormat, pwfTargetFormat );
}
#undef DPF_MODNAME
#define DPF_MODNAME "CACMConverter::Initialize"
void CACMConverter::Initialize( WAVEFORMATEX *pwfSrcFormat, WAVEFORMATEX *pwfTargetFormat, WAVEFORMATEX *pwfUnCompressedFormat )
{
HRESULT retValue;
m_pwfInnerFormat = GetInnerFormat();
try
{
// Attempt the conversion directly
retValue = acmStreamOpen( &m_hacmSource, NULL, pwfSrcFormat, pwfTargetFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME );
// If it's not possible, we'll have to do a two step conversion
if( retValue == ACMERR_NOTPOSSIBLE ) {
ACMCHECK( acmStreamOpen( &m_hacmSource, NULL, pwfSrcFormat, m_pwfInnerFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME ) );
ACMCHECK( acmStreamOpen( &m_hacmTarget, NULL, m_pwfInnerFormat, pwfTargetFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME ) );
m_bDirectConvert = FALSE;
}
// Still not possible
else if( retValue != 0 )
{
ACMCHECK( retValue );
}
// Direct conversion was possible
else
{
m_bDirectConvert = TRUE;
}
// If we're not direct converting, create an inner conversion
// buffer
if( !m_bDirectConvert )
{
m_dwInnerBufferSize = CAudioConverter::CalcUnCompressedFrameSize( m_lpdvfInfo, m_pwfInnerFormat );
m_pbInnerBuffer = new BYTE[m_dwInnerBufferSize];
if( m_pbInnerBuffer == NULL )
{
acmStreamClose( m_hacmSource, 0 );
acmStreamClose( m_hacmTarget, 0 );
m_bValid = FALSE;
}
}
else
{
m_pbInnerBuffer = NULL;
m_dwInnerBufferSize = 0;
m_pwfInnerFormat = NULL;
}
}
// Caught an ACM exception. Free everything
// and mark the class as not valid.
catch( ACMException &ae )
{
DPFX(DPFPREP, DVF_ERRORLEVEL, ae.what() );
if( m_hacmSource != NULL )
{
acmStreamClose( m_hacmSource, 0 );
}
if( m_hacmTarget != NULL )
{
acmStreamClose( m_hacmTarget, 0 );
}
delete [] m_pbInnerBuffer;
m_pbInnerBuffer = NULL;
m_bValid = FALSE;
return;
}
m_bValid = TRUE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CACMConverter::~CACMConverter"
// CAudioConverter Destructor
//
// This is called when the class is destroyed. Closes up the ACM connections
// and deallocates all the memory.
//
CACMConverter::~CACMConverter()
{
// If this isn't valid, just return, no shutdown required.
if( !m_bValid )
return;
// Shutdown the ACM object
try
{
ACMCHECK( acmStreamClose( m_hacmSource, 0 ) );
if( !m_bDirectConvert )
{
// Unprepare the header
ACMCHECK( acmStreamClose( m_hacmTarget, 0 ) );
}
}
catch( ACMException &ae )
{
DPFX(DPFPREP, DVF_ERRORLEVEL, ae.what() );
}
delete [] m_pbInnerBuffer;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CACMConverter::Convert"
bool CACMConverter::Convert( BYTE *input, UINT inputSize, BYTE *output, UINT &outputSize, BOOL inputSilence )
{
DWORD tmpLength; // Used for storing tmp length values
// Shortcut for silence
// Fill output buffer with silence, return full length
if( inputSilence )
{
DNASSERT( m_pwfTargetFormat->wFormatTag == WAVE_FORMAT_PCM );
tmpLength = outputSize;
memset( output, (m_pwfTargetFormat->wBitsPerSample == 8) ? 0x80 : 0x00, outputSize );
return true;
}
try
{
if( m_bDirectConvert )
{
// Setup the acm function
memset( &m_ashSource, 0, sizeof( ACMSTREAMHEADER ) );
m_ashSource.cbStruct = sizeof( ACMSTREAMHEADER );
m_ashSource.fdwStatus = 0;
m_ashSource.dwUser = 0;
m_ashSource.cbSrcLength = inputSize;
m_ashSource.pbSrc = input;
m_ashSource.cbSrcLengthUsed = 0;
m_ashSource.dwSrcUser = 0;
m_ashSource.pbDst = output;
m_ashSource.cbDstLength = outputSize;
m_ashSource.cbDstLengthUsed = 0;
m_ashSource.dwDstUser = 0;
// Prepare the header for conversion
ACMCHECK( acmStreamPrepareHeader( m_hacmSource, &m_ashSource , 0) );
// Convert the data
ACMCHECK( acmStreamConvert( m_hacmSource, &m_ashSource, ACM_STREAMCONVERTF_BLOCKALIGN ) );
ACMCHECK( acmStreamUnprepareHeader( m_hacmSource, &m_ashSource, 0 ) );
tmpLength = m_ashSource.cbDstLengthUsed;
}
else
{
// Setup the acm header for conversion fro mthe source to the
// inner format
memset( &m_ashSource, 0, sizeof( ACMSTREAMHEADER ) );
m_ashSource.cbStruct = sizeof( ACMSTREAMHEADER );
m_ashSource.fdwStatus = 0;
m_ashSource.dwUser = 0;
m_ashSource.cbSrcLength = inputSize;
m_ashSource.pbSrc = input;
m_ashSource.cbSrcLengthUsed = 0;
m_ashSource.dwSrcUser = 0;
m_ashSource.pbDst = m_pbInnerBuffer;
m_ashSource.cbDstLength = m_dwInnerBufferSize;
m_ashSource.cbDstLengthUsed = 0;
m_ashSource.dwDstUser = 0;
// Prepare the header for conversion
ACMCHECK( acmStreamPrepareHeader( m_hacmSource, &m_ashSource , 0) );
// Convert the data
ACMCHECK( acmStreamConvert( m_hacmSource, &m_ashSource, ACM_STREAMCONVERTF_BLOCKALIGN ) );
ACMCHECK( acmStreamUnprepareHeader( m_hacmSource, &m_ashSource, 0 ) );
DPFX(DPFPREP, DVF_INFOLEVEL, "CONVERTER: Filling in %d bytes", m_dwInnerBufferSize - m_ashSource.cbDstLengthUsed );
memset( &m_ashTarget, 0, sizeof( ACMSTREAMHEADER ) );
m_ashTarget.cbStruct = sizeof( ACMSTREAMHEADER );
m_ashTarget.fdwStatus = 0;
m_ashTarget.dwUser = 0;
m_ashTarget.cbSrcLength = m_dwInnerBufferSize;
m_ashTarget.pbSrc = m_pbInnerBuffer;
m_ashTarget.cbSrcLengthUsed = 0;
m_ashTarget.dwSrcUser = 0;
m_ashTarget.pbDst = output;
m_ashTarget.cbDstLength = outputSize;
m_ashTarget.cbDstLengthUsed = 0;
m_ashTarget.dwDstUser = 0;
// Prepare the header for conversion
ACMCHECK( acmStreamPrepareHeader( m_hacmTarget, &m_ashTarget , 0) );
// Convert the data
ACMCHECK( acmStreamConvert( m_hacmTarget, &m_ashTarget, ACM_STREAMCONVERTF_BLOCKALIGN ) );
ACMCHECK( acmStreamUnprepareHeader( m_hacmTarget, &m_ashTarget, 0 ) );
tmpLength = m_ashTarget.cbDstLengthUsed;
}
}
catch( ACMException &ae )
{
DPFX(DPFPREP, DVF_ERRORLEVEL, ae.what() );
return false;
}
// Fill in the remaining buffer if the output is not of the exact size
// This is often in the case when upconverting.
{
DWORD offset;
offset = outputSize - tmpLength;
if( offset > 0 )
{
DNASSERT( m_pwfTargetFormat->wFormatTag == WAVE_FORMAT_PCM );
memset( &output[outputSize - offset], (m_pwfTargetFormat->wBitsPerSample == 8) ? 0x80 : 0x00, offset );
}
}
// Always return the right length
return true;
}