You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
7.4 KiB
318 lines
7.4 KiB
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "quakedef.h"
|
|
#include "iframeencoder.h"
|
|
#include "interface.h"
|
|
#include "milesbase.h"
|
|
#include "tier0/dbg.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
void Con_Printf( const char *pMsg, ... )
|
|
{
|
|
}
|
|
|
|
|
|
class FrameEncoder_Miles : public IFrameEncoder
|
|
{
|
|
protected:
|
|
virtual ~FrameEncoder_Miles();
|
|
|
|
public:
|
|
FrameEncoder_Miles();
|
|
|
|
virtual bool Init(int quality, int &rawFrameSize, int &encodedFrameSize);
|
|
virtual void Release();
|
|
virtual void EncodeFrame(const char *pUncompressed, char *pCompressed);
|
|
virtual void DecodeFrame(const char *pCompressed, char *pDecompressed);
|
|
virtual bool ResetState();
|
|
|
|
|
|
public:
|
|
|
|
void Shutdown();
|
|
|
|
static S32 AILCALLBACK EncodeStreamCB(
|
|
UINTa user, // User value passed to ASI_open_stream()
|
|
void *dest, // Location to which stream data should be copied by app
|
|
S32 bytes_requested, // # of bytes requested by ASI codec
|
|
S32 offset // If not -1, application should seek to this point in stream
|
|
);
|
|
|
|
static S32 AILCALLBACK DecodeStreamCB(
|
|
UINTa user, // User value passed to ASI_open_stream()
|
|
void *dest, // Location to which stream data should be copied by app
|
|
S32 bytes_requested, // # of bytes requested by ASI codec
|
|
S32 offset // If not -1, application should seek to this point in stream
|
|
);
|
|
|
|
void FigureOutFrameSizes();
|
|
|
|
|
|
private:
|
|
|
|
// Encoder stuff.
|
|
ASISTRUCT m_Encoder;
|
|
|
|
// Decoder stuff.
|
|
ASISTRUCT m_Decoder;
|
|
|
|
// Destination for encoding and decoding.
|
|
const char *m_pSrc;
|
|
int m_SrcLen;
|
|
int m_CurSrcPos;
|
|
|
|
// Frame sizes..
|
|
int m_nRawBytes;
|
|
int m_nEncodedBytes;
|
|
};
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------ //
|
|
// Helper functions.
|
|
// ------------------------------------------------------------------------ //
|
|
void Convert16UnsignedToSigned(short *pDest, int nSamples)
|
|
{
|
|
for(int i=0; i < nSamples; i++)
|
|
{
|
|
int val = *((unsigned short*)&pDest[i]) - (1 << 15);
|
|
pDest[i] = (short)val;
|
|
}
|
|
}
|
|
|
|
|
|
void Convert16SignedToUnsigned(short *pDest, int nSamples)
|
|
{
|
|
for(int i=0; i < nSamples; i++)
|
|
{
|
|
int val = *((short*)&pDest[i]) + (1 << 15);
|
|
*((unsigned short*)&pDest[i]) = (unsigned short)val;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------ //
|
|
// FrameEncoder_Miles functions.
|
|
// ------------------------------------------------------------------------ //
|
|
FrameEncoder_Miles::FrameEncoder_Miles()
|
|
{
|
|
}
|
|
|
|
|
|
FrameEncoder_Miles::~FrameEncoder_Miles()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
bool FrameEncoder_Miles::Init(int quality, int &rawFrameSize, int &encodedFrameSize)
|
|
{
|
|
Shutdown();
|
|
|
|
|
|
// This tells what protocol we're using.
|
|
C8 suffix[128] = ".v12"; // (.v12, .v24, .v29, or .raw)
|
|
|
|
// encoder converts from RAW to v12
|
|
if ( !m_Encoder.Init( (void *)this, ".RAW", suffix, &FrameEncoder_Miles::EncodeStreamCB ) )
|
|
{
|
|
Con_Printf("(FrameEncoder_Miles): Can't initialize ASI encoder.\n");
|
|
Shutdown();
|
|
return false;
|
|
}
|
|
|
|
// decoder converts from v12 to RAW
|
|
if ( !m_Decoder.Init( (void *)this, suffix, ".RAW", &FrameEncoder_Miles::DecodeStreamCB ) )
|
|
{
|
|
Con_Printf("(FrameEncoder_Miles): Can't initialize ASI decoder.\n");
|
|
Shutdown();
|
|
return false;
|
|
}
|
|
|
|
|
|
FigureOutFrameSizes();
|
|
|
|
|
|
// Output..
|
|
rawFrameSize = m_nRawBytes * 2; // They'll be using 16-bit samples and we're quantizing to 8-bit.
|
|
encodedFrameSize = m_nEncodedBytes;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void FrameEncoder_Miles::Release()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
|
|
void FrameEncoder_Miles::EncodeFrame(const char *pUncompressedBytes, char *pCompressed)
|
|
{
|
|
char samples[1024];
|
|
|
|
if(!m_Encoder.IsActive() || m_nRawBytes > sizeof(samples))
|
|
return;
|
|
|
|
const short *pUncompressed = (const short*)pUncompressedBytes;
|
|
for(int i=0; i < m_nRawBytes; i++)
|
|
samples[i] = (char)(pUncompressed[i] >> 8);
|
|
|
|
m_pSrc = samples;
|
|
m_SrcLen = m_nRawBytes;
|
|
m_CurSrcPos = 0;
|
|
|
|
U32 len = m_Encoder.Process( pCompressed, m_nEncodedBytes );
|
|
if ( len != (U32)m_nEncodedBytes )
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
|
|
void FrameEncoder_Miles::DecodeFrame(const char *pCompressed, char *pDecompressed)
|
|
{
|
|
if(!m_Decoder.IsActive())
|
|
return;
|
|
|
|
m_pSrc = pCompressed;
|
|
m_SrcLen = m_nEncodedBytes;
|
|
m_CurSrcPos = 0;
|
|
|
|
U32 outputSize = m_nRawBytes*2;
|
|
U32 len = m_Decoder.Process( pDecompressed, outputSize );
|
|
|
|
if (len != outputSize)
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
|
|
void FrameEncoder_Miles::Shutdown()
|
|
{
|
|
m_Decoder.Shutdown();
|
|
m_Encoder.Shutdown();
|
|
}
|
|
|
|
|
|
bool FrameEncoder_Miles::ResetState()
|
|
{
|
|
if(!m_Decoder.IsActive() || !m_Encoder.IsActive())
|
|
return true;
|
|
|
|
for(int i=0; i < 2; i++)
|
|
{
|
|
char data[2048], compressed[2048];
|
|
memset(data, 0, sizeof(data));
|
|
m_pSrc = data;
|
|
m_SrcLen = m_nRawBytes;
|
|
m_CurSrcPos = 0;
|
|
|
|
U32 len = m_Encoder.Process( compressed, m_nEncodedBytes );
|
|
if ( len != (U32)m_nEncodedBytes )
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
m_pSrc = compressed;
|
|
m_SrcLen = m_nEncodedBytes;
|
|
m_CurSrcPos = 0;
|
|
|
|
m_Decoder.Process( data, m_nRawBytes * 2 );
|
|
}
|
|
|
|
// Encode and decode a couple frames of zeros.
|
|
return true;
|
|
}
|
|
|
|
|
|
S32 AILCALLBACK FrameEncoder_Miles::EncodeStreamCB(
|
|
UINTa user, // User value passed to ASI_open_stream()
|
|
void *dest, // Location to which stream data should be copied by app
|
|
S32 bytes_requested, // # of bytes requested by ASI codec
|
|
S32 offset // If not -1, application should seek to this point in stream
|
|
)
|
|
{
|
|
FrameEncoder_Miles *pThis = (FrameEncoder_Miles*)user;
|
|
Assert(pThis && offset == -1);
|
|
|
|
// Figure out how many samples we can safely give it.
|
|
int maxSamples = pThis->m_SrcLen - pThis->m_CurSrcPos;
|
|
int samplesToGive = MIN(maxSamples, bytes_requested/2);
|
|
|
|
// Convert to 16-bit signed mono.
|
|
short *pOut = (short*)dest;
|
|
for(int i=0; i < samplesToGive; i++)
|
|
{
|
|
pOut[i] = pThis->m_pSrc[pThis->m_CurSrcPos+i] << 8;
|
|
}
|
|
|
|
pThis->m_CurSrcPos += samplesToGive;
|
|
return samplesToGive * 2;
|
|
}
|
|
|
|
S32 AILCALLBACK FrameEncoder_Miles::DecodeStreamCB(
|
|
UINTa user, // User value passed to ASI_open_stream()
|
|
void *dest, // Location to which stream data should be copied by app
|
|
S32 bytes_requested, // # of bytes requested by ASI codec
|
|
S32 offset // If not -1, application should seek to this point in stream
|
|
)
|
|
{
|
|
FrameEncoder_Miles *pThis = (FrameEncoder_Miles*)user;
|
|
Assert(pThis && offset == -1);
|
|
|
|
int maxBytes = pThis->m_SrcLen - pThis->m_CurSrcPos;
|
|
int bytesToGive = MIN(maxBytes, bytes_requested);
|
|
memcpy(dest, &pThis->m_pSrc[pThis->m_CurSrcPos], bytesToGive);
|
|
|
|
pThis->m_CurSrcPos += bytesToGive;
|
|
return bytesToGive;
|
|
}
|
|
|
|
|
|
void FrameEncoder_Miles::FigureOutFrameSizes()
|
|
{
|
|
// Figure out the frame sizes. It is probably not prudent in general to assume fixed frame sizes with Miles codecs
|
|
// but it works with the voxware codec right now and simplifies things a lot.
|
|
m_nRawBytes = (int)m_Encoder.GetProperty( m_Encoder.INPUT_BLOCK_SIZE );
|
|
|
|
char uncompressed[1024];
|
|
char compressed[1024];
|
|
|
|
Assert(m_nRawBytes <= sizeof(uncompressed));
|
|
|
|
m_pSrc = uncompressed;
|
|
m_SrcLen = m_nRawBytes;
|
|
m_CurSrcPos = 0;
|
|
|
|
m_nEncodedBytes = (int)m_Encoder.Process( compressed, sizeof(compressed) );
|
|
}
|
|
|
|
|
|
|
|
class IVoiceCodec;
|
|
extern IVoiceCodec* CreateVoiceCodec_Frame(IFrameEncoder *pEncoder);
|
|
void* CreateVoiceCodec_Miles()
|
|
{
|
|
IFrameEncoder *pEncoder = new FrameEncoder_Miles;
|
|
if(!pEncoder)
|
|
return NULL;
|
|
|
|
return CreateVoiceCodec_Frame(pEncoder);
|
|
}
|
|
|
|
EXPOSE_INTERFACE_FN(CreateVoiceCodec_Miles, IVoiceCodec, "vaudio_miles")
|
|
|
|
|