amr_filter.cpp
来自「MONOGRAM AMR Encoder v1.0.0.0」· C++ 代码 · 共 377 行
CPP
377 行
//-----------------------------------------------------------------------------
//
// Monogram AMR Encoder
//
// Base on the 3GPP source codes for AMR
//
// Author : Igor Janos
//
//-----------------------------------------------------------------------------
#include "stdafx.h"
//-----------------------------------------------------------------------------
//
// CAMREncoder
//
//-----------------------------------------------------------------------------
CAMREncoder::CAMREncoder(LPUNKNOWN pUnk, HRESULT *phr) :
CTransformFilter(_T("MONOGRAM AMR Encoder"), pUnk, CLSID_MonogramAMREncoder)
{
// sicko je oukey
if (phr) *phr = NOERROR;
// vyrobime piny
m_pInput = new CTransformInputPin(NAME("Input"), this, phr, L"In");
m_pOutput = new CTransformOutputPin(NAME("Output"), this, phr, L"Out");
encoder = NULL;
dtx = 0;
mode = MR122;
memset(&info, 0, sizeof(info));
// temporary buffer
resampled_samples = (int16*)malloc(8*1024 * sizeof(int16));
resampled_count = 0;
rtStart = 0;
has_start = false;
}
CAMREncoder::~CAMREncoder()
{
if (resampled_samples) { free(resampled_samples); resampled_samples = NULL; }
}
CUnknown *WINAPI CAMREncoder::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
CAMREncoder *enc = new CAMREncoder(pUnk, phr);
if (!enc) {
if (phr) *phr = E_OUTOFMEMORY;
}
return enc;
}
STDMETHODIMP CAMREncoder::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_ISpecifyPropertyPages) {
return GetInterface((ISpecifyPropertyPages*)this, ppv);
} else
if (riid == IID_IMonogramAMREncoder) {
return GetInterface((IMonogramAMREncoder*)this, ppv);
} else
return __super::NonDelegatingQueryInterface(riid, ppv);
}
STDMETHODIMP CAMREncoder::GetPages(CAUUID *pPages)
{
CheckPointer(pPages,E_POINTER);
pPages->cElems = 1;
pPages->pElems = (GUID *) CoTaskMemAlloc(pPages->cElems * sizeof(GUID));
if (pPages->pElems == NULL) {
return E_OUTOFMEMORY;
}
*(pPages->pElems) = CLSID_MonogramAMREncoderPage;
return NOERROR;
} // GetPages
STDMETHODIMP CAMREncoder::GetInfo(AMR_INFO *info)
{
if (info) {
memcpy(info, &this->info, sizeof(AMR_INFO));
}
return NOERROR;
}
STDMETHODIMP CAMREncoder::GetMode(int *mode)
{
if (mode) *mode = this->mode;
return NOERROR;
}
STDMETHODIMP CAMREncoder::SetMode(int mode)
{
this->mode = mode;
return NOERROR;
}
HRESULT CAMREncoder::CheckInputType(const CMediaType *mtIn)
{
// Accept PCM sound
if (mtIn->majortype != MEDIATYPE_Audio) return E_FAIL;
if (mtIn->subtype != MEDIASUBTYPE_PCM) return E_FAIL;
if (mtIn->formattype != FORMAT_WaveFormatEx) return E_FAIL;
return NOERROR;
}
HRESULT CAMREncoder::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
{
HRESULT hr = CheckInputType(mtIn);
if (FAILED(hr)) return hr;
// aj vystup by mal byt slusny
if (mtOut->majortype != MEDIATYPE_Audio) return E_FAIL;
if (mtOut->subtype != MEDIASUBTYPE_AMR) return E_FAIL;
return NOERROR;
}
HRESULT CAMREncoder::GetMediaType(int iPosition, CMediaType *pmt)
{
if (iPosition < 0) return E_INVALIDARG;
if (iPosition > 0) return VFW_S_NO_MORE_ITEMS;
// there is only one type we can produce
pmt->majortype = MEDIATYPE_Audio;
pmt->subtype = MEDIASUBTYPE_AMR;
pmt->formattype = FORMAT_WaveFormatEx;
pmt->lSampleSize = 0;
WAVEFORMATEX *wfx = (WAVEFORMATEX*)pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
memset(wfx, 0, sizeof(*wfx));
wfx->wBitsPerSample = 16;
wfx->nChannels = 1;
wfx->nSamplesPerSec = 8000;
wfx->nBlockAlign = 1;
wfx->nAvgBytesPerSec = 0;
wfx->wFormatTag = 0;
return NOERROR;
}
HRESULT CAMREncoder::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp)
{
// decide the size
pProp->cbBuffer = 2 * 1024; // must be enough for one AMR frame
pProp->cBuffers = 1;
ALLOCATOR_PROPERTIES act;
HRESULT hr = pAlloc->SetProperties(pProp, &act);
if (FAILED(hr)) return hr;
// len tak pre istotu
if (act.cbBuffer < pProp->cbBuffer) return E_FAIL;
return NOERROR;
}
HRESULT CAMREncoder::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt)
{
if (direction == PINDIR_INPUT) {
// check for input type
WAVEFORMATEX *wfx = (WAVEFORMATEX*)pmt->pbFormat;
if (!wfx) return E_FAIL;
// teraz nas zaujima vacero veci:
if (wfx->wBitsPerSample != 16) return E_FAIL;
info.samplerate = wfx->nSamplesPerSec;
info.channels = wfx->nChannels;
if (encoder) {
CloseEncoder();
}
// otvorime novy enkoder
int ret = OpenEncoder();
if (ret < 0) {
CloseEncoder();
return E_FAIL;
}
}
return NOERROR;
}
HRESULT CAMREncoder::BreakConnect(PIN_DIRECTION dir)
{
if (dir == PINDIR_INPUT) {
// tu zrusime instanciu enkodera a odpojime output pin
CloseEncoder();
info.samplerate = 0;
info.channels = 0;
} else
if (dir == PINDIR_OUTPUT) {
}
return __super::BreakConnect(dir);
}
HRESULT CAMREncoder::Receive(IMediaSample *pSample)
{
// not connected ?
if (!m_pOutput->IsConnected()) return E_FAIL;
BYTE *ptr;
HRESULT hr;
long size;
// get data pointers
hr = pSample->GetPointer(&ptr);
size = pSample->GetActualDataLength();
REFERENCE_TIME rtstart, rtstop;
hr = pSample->GetTime(&rtstart, &rtstop);
if (hr == NOERROR) {
if (!has_start) {
rtStart = rtstart;
has_start = true;
}
}
//-------------------------------------------------------------------------
//
// Extract Samples, mix them into one channel and resmple to 8Khz
//
//-------------------------------------------------------------------------
int time_samples = (size / (info.channels * sizeof(int16)));
int chnls;
int acc;
int16 temp_samples[4*1024];
int16 *cur = (int16*)ptr;
int16 *dst = temp_samples;
int16 *in[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
int16 *out[6]= { NULL, NULL, NULL, NULL, NULL, NULL };
static __int64 ins = 0;
static __int64 outs = 0;
chnls = info.channels;
while (time_samples > 0) {
int to_read = min(time_samples, 2*1024);
time_samples -= to_read;
// mixing into one channel
dst = temp_samples;
for (int i=0; i<to_read; i++) {
acc = 0;
for (int ch=0; ch<chnls; ch++) acc += (*cur++);
*dst++ = (int16)(acc / chnls);
}
// resample
out[0] = resampled_samples + resampled_count;
in[0] = temp_samples;
int ret = resample.Process(out, in, to_read);
resampled_count += ret;
// encode these
int16 *r = resampled_samples;
while (resampled_count >= 160) {
hr = Encode(r, 160);
if (FAILED(hr)) {
return hr;
}
r += 160;
resampled_count -= 160;
}
if (resampled_count > 0) memcpy(resampled_samples, r, resampled_count * sizeof(int16));
}
return NOERROR;
}
HRESULT CAMREncoder::Encode(int16 *samples, int count)
{
BYTE buf[1024];
int bytes = Encoder_Interface_Encode(encoder, (Mode)mode, samples, buf, 0);
IMediaSample *sample;
HRESULT hr;
hr = GetDeliveryBuffer(&sample);
if (FAILED(hr)) return hr;
BYTE *ptr;
sample->GetPointer(&ptr);
memcpy(ptr, buf, bytes);
sample->SetActualDataLength(bytes);
if (has_start) {
REFERENCE_TIME rtstart, rtstop;
rtstart = rtStart + (info.frames * 160 * 10000 / 8);
rtstop = rtStart + ((info.frames+1) * 160 * 10000 / 8);
sample->SetTime(&rtstart, &rtstop);
info.frames ++;
}
sample->SetSyncPoint(TRUE);
sample->SetDiscontinuity(FALSE);
hr = m_pOutput->Deliver(sample);
sample->Release();
return hr;
}
HRESULT CAMREncoder::GetDeliveryBuffer(IMediaSample **sample)
{
IMediaSample *pOutSample;
HRESULT hr = m_pOutput->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0);
*sample = pOutSample;
if (FAILED(hr)) {
return hr;
}
// has the type changed ?
AM_MEDIA_TYPE *mt;
if (pOutSample->GetMediaType(&mt) == NOERROR) {
CMediaType _mt(*mt);
SetMediaType(PINDIR_OUTPUT, &_mt);
DeleteMediaType(mt);
}
return NOERROR;
}
HRESULT CAMREncoder::StartStreaming()
{
// zresetujeme veci
resampled_count = 0;
info.frames = 0;
has_start = false;
return __super::StartStreaming();
}
HRESULT CAMREncoder::EndFlush()
{
info.frames = 0;
resampled_count = 0;
has_start = false;
return __super::EndFlush();
}
int CAMREncoder::OpenEncoder()
{
// open a new encoder instance
resampled_count = 0;
encoder = Encoder_Interface_init(dtx);
if (!encoder) return -1;
resample.Open(1, info.samplerate, 8000);
info.frames = 0;
return 0;
}
int CAMREncoder::CloseEncoder()
{
// we close the encoder instance
if (encoder) {
Encoder_Interface_exit(encoder);
encoder = NULL;
}
resample.Close();
resampled_count = 0;
info.frames = 0;
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?