diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/voice_codecs/frame_encoder | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'engine/voice_codecs/frame_encoder')
| -rw-r--r-- | engine/voice_codecs/frame_encoder/iframeencoder.h | 39 | ||||
| -rw-r--r-- | engine/voice_codecs/frame_encoder/voice_codec_frame.cpp | 155 |
2 files changed, 194 insertions, 0 deletions
diff --git a/engine/voice_codecs/frame_encoder/iframeencoder.h b/engine/voice_codecs/frame_encoder/iframeencoder.h new file mode 100644 index 0000000..8bf5594 --- /dev/null +++ b/engine/voice_codecs/frame_encoder/iframeencoder.h @@ -0,0 +1,39 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IFRAMEENCODER_H +#define IFRAMEENCODER_H +#pragma once + + +// A frame encoder is a codec that encodes and decodes data in fixed-size frames. +// VoiceCodec_Frame handles queuing of data and the IVoiceCodec interface. +abstract_class IFrameEncoder +{ +public: + virtual ~IFrameEncoder() {} + + // This is called by VoiceCodec_Frame to see if it can initialize.. + // Fills in the uncompressed and encoded frame size (both are in BYTES). + virtual bool Init(int quality, int &rawFrameSize, int &encodedFrameSize) = 0; + + virtual void Release() = 0; + + // pUncompressed is 8-bit signed mono sound data with 'rawFrameSize' bytes. + // pCompressed is the size of encodedFrameSize. + virtual void EncodeFrame(const char *pUncompressed, char *pCompressed) = 0; + + // pCompressed is encodedFrameSize. + // pDecompressed is where the 8-bit signed mono samples are stored and has space for 'rawFrameSize' bytes. + virtual void DecodeFrame(const char *pCompressed, char *pDecompressed) = 0; + + // Some codecs maintain state between Compress and Decompress calls. This should clear that state. + virtual bool ResetState() = 0; +}; + + +#endif // IFRAMEENCODER_H diff --git a/engine/voice_codecs/frame_encoder/voice_codec_frame.cpp b/engine/voice_codecs/frame_encoder/voice_codec_frame.cpp new file mode 100644 index 0000000..6de3dcd --- /dev/null +++ b/engine/voice_codecs/frame_encoder/voice_codec_frame.cpp @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "audio/public/ivoicecodec.h" +#include <string.h> +#include "tier0/dbg.h" +#include "iframeencoder.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#ifndef min + #define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + + + + + +// VoiceCodec_Frame can be used to wrap a frame encoder for the engine. As it gets sound data, it will queue it +// until it has enough for a frame, then it will compress it. Same thing for decompression. +class VoiceCodec_Frame : public IVoiceCodec +{ +public: + enum {MAX_FRAMEBUFFER_SAMPLES=1024}; + + VoiceCodec_Frame(IFrameEncoder *pEncoder) + { + m_nEncodeBufferSamples = 0; + m_nRawBytes = m_nRawSamples = m_nEncodedBytes = 0; + m_pFrameEncoder = pEncoder; + } + + virtual ~VoiceCodec_Frame() + { + if(m_pFrameEncoder) + m_pFrameEncoder->Release(); + } + + virtual bool Init( int quality ) + { + if(m_pFrameEncoder && m_pFrameEncoder->Init(quality, m_nRawBytes, m_nEncodedBytes)) + { + m_nRawSamples = m_nRawBytes >> 1; + Assert(m_nRawBytes <= MAX_FRAMEBUFFER_SAMPLES && m_nEncodedBytes <= MAX_FRAMEBUFFER_SAMPLES); + return true; + } + else + { + if(m_pFrameEncoder) + m_pFrameEncoder->Release(); + + m_pFrameEncoder = NULL; + return false; + } + } + + virtual void Release() + { + delete this; + } + + virtual int Compress(const char *pUncompressedBytes, int nSamples, char *pCompressed, int maxCompressedBytes, bool bFinal) + { + if(!m_pFrameEncoder) + return 0; + + const short *pUncompressed = (const short*)pUncompressedBytes; + + int nCompressedBytes = 0; + while((nSamples + m_nEncodeBufferSamples) >= m_nRawSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) + { + // Get the data block out. + short samples[MAX_FRAMEBUFFER_SAMPLES]; + memcpy(samples, m_EncodeBuffer, m_nEncodeBufferSamples*BYTES_PER_SAMPLE); + memcpy(&samples[m_nEncodeBufferSamples], pUncompressed, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); + nSamples -= m_nRawSamples - m_nEncodeBufferSamples; + pUncompressed += m_nRawSamples - m_nEncodeBufferSamples; + m_nEncodeBufferSamples = 0; + + // Compress it. + m_pFrameEncoder->EncodeFrame((const char*)samples, &pCompressed[nCompressedBytes]); + nCompressedBytes += m_nEncodedBytes; + } + + // Store the remaining samples. + int nNewSamples = min(nSamples, min(m_nRawSamples-m_nEncodeBufferSamples, m_nRawSamples)); + if(nNewSamples) + { + memcpy(&m_EncodeBuffer[m_nEncodeBufferSamples], &pUncompressed[nSamples - nNewSamples], nNewSamples*BYTES_PER_SAMPLE); + m_nEncodeBufferSamples += nNewSamples; + } + + // If it must get the last data, just pad with zeros.. + if(bFinal && m_nEncodeBufferSamples && (maxCompressedBytes - nCompressedBytes) >= m_nEncodedBytes) + { + memset(&m_EncodeBuffer[m_nEncodeBufferSamples], 0, (m_nRawSamples - m_nEncodeBufferSamples) * BYTES_PER_SAMPLE); + m_pFrameEncoder->EncodeFrame((const char*)m_EncodeBuffer, &pCompressed[nCompressedBytes]); + nCompressedBytes += m_nEncodedBytes; + m_nEncodeBufferSamples = 0; + } + + return nCompressedBytes; + } + + virtual int Decompress(const char *pCompressed, int compressedBytes, char *pUncompressed, int maxUncompressedBytes) + { + if(!m_pFrameEncoder) + return 0; + + Assert((compressedBytes % m_nEncodedBytes) == 0); + int nDecompressedBytes = 0; + int curCompressedByte = 0; + while((compressedBytes - curCompressedByte) >= m_nEncodedBytes && (maxUncompressedBytes - nDecompressedBytes) >= m_nRawBytes) + { + m_pFrameEncoder->DecodeFrame( pCompressed ? &pCompressed[curCompressedByte] : NULL, &pUncompressed[nDecompressedBytes]); + curCompressedByte += m_nEncodedBytes; + nDecompressedBytes += m_nRawBytes; + } + + return nDecompressedBytes / BYTES_PER_SAMPLE; + } + + virtual bool ResetState() + { + if(m_pFrameEncoder) + return m_pFrameEncoder->ResetState(); + else + return false; + } + + +public: + // The codec encodes and decodes samples in fixed-size blocks, so we queue up uncompressed and decompressed data + // until we have blocks large enough to give to the codec. + short m_EncodeBuffer[MAX_FRAMEBUFFER_SAMPLES]; + int m_nEncodeBufferSamples; + + IFrameEncoder *m_pFrameEncoder; + int m_nRawBytes, m_nRawSamples; + int m_nEncodedBytes; +}; + + +IVoiceCodec* CreateVoiceCodec_Frame(IFrameEncoder *pEncoder) +{ + return new VoiceCodec_Frame(pEncoder); +} + |