最近一直在DM365平台上进行音视频录制的开发工作, 由于系统为wince6.0,所以采用了directshow实现。视频编码模块封装成单独的filter, 由于硬编码器的输入缓冲区要求物理地址连续(TI提供了一个叫CMEM的模块),这就需要重新实现directshow的内存管理机制。
一、实现自己的内存分配器
1. 内存管理的几个相关接口及类有:
1).IMemAllocator
2).CBaseAllocator
3).CMemAllocator
2. 实际的内存分配相关函数是在CMemAllocator中实现,涉及3个函数:
1).HRESULT CMemAllocator::Alloc(void), 此函数进行内存分配,代码如下:
HRESULT CMemAllocator::Alloc(void) { ... m_pBuffer = (PBYTE)VirtualAlloc(NULL, m_lCount * lAlignedSize, MEM_COMMIT, PAGE_READWRITE); .... for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { pSample = new CMediaSample( NAME("Default memory media sample"), this, &hr, pNext + m_lPrefix, // GetPointer() value m_lSize); // not including prefix ASSERT(SUCCEEDED(hr)); if (pSample == NULL) { return E_OUTOFMEMORY; } // This CANNOT fail m_lFree.Add(pSample); ... }
2).void CMemAllocator::Free(void),此致函数体为空,有一个注释如下
// in our case, we keep the memory until we are deleted, so
// we do nothing here. The memory is deleted in the destructor by
// calling ReallyFree()
3).void CMemAllocator::ReallyFree(void),这才是真正的内存释放函
3. 要实现自己的MemAllocator,只需要对CMemAllocator中的,Alloc、RellyFree函数中内存分配与释放进行修改。由于RellyFree不是虚函数,不能继承CmemAllocator。我们可以从CBaseAllocator继承一个类,其实现参考CMemAllocator。
二、自定义内存分配器的调用
1.directshow中内存分配器的调用流程
1.在amfilter.cpp中,定义了一个全局的函数 STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator) { return CoCreateInstance(CLSID_MemoryAllocator, 0, CLSCTX_INPROC_SERVER, IID_IMemAllocator, (void **)ppAllocator); } 2.可以发现在CBaseInputPin::GetAllocator函数中调用了该函数 STDMETHODIMP CBaseInputPin::GetAllocator( IMemAllocator **ppAllocator) { CheckPointer(ppAllocator,E_POINTER); ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); CAutoLock cObjectLock(m_pLock); if (m_pAllocator == NULL) { HRESULT hr = CreateMemoryAllocator(&m_pAllocator); if (FAILED(hr)) { return hr; } } ASSERT(m_pAllocator != NULL); *ppAllocator = m_pAllocator; m_pAllocator->AddRef(); return NOERROR; } HRESULT CBaseInputPin::BreakConnect() { /* We don't need our allocator any more */ if (m_pAllocator) { // Always decommit the allocator because a downstream filter may or // may not decommit the connection's allocator. A memory leak could // occur if the allocator is not decommited when a pin is disconnected. HRESULT hr = m_pAllocator->Decommit(); if( FAILED( hr ) ) { return hr; } m_pAllocator->Release(); m_pAllocator = NULL; } return S_OK; }
2. 从上述调用过程可以发现,我们只需要重新实现CBaseInputPin::GetAllocator即可,我的实现如下:
HRESULT CAviInputPin::GetAllocator( IMemAllocator ** ppAllocator ) { CheckPointer(ppAllocator,E_POINTER); ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); CAutoLock cObjectLock(m_pLock); if (m_pAllocator == NULL) { HRESULT hr = NOERROR; m_pAllocator = new CCemeMemAllocator(L"CCemeMemAllocator", NULL, &hr); if (FAILED(hr)) { return hr; } } ASSERT(m_pAllocator != NULL); *ppAllocator = m_pAllocator; m_pAllocator->AddRef(); //此条语句不可缺少 return NOERROR; }