#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L)
#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80000003L)
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
2147746321
#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80040211L)
#define VFW_E_SIZENOTSET ((HRESULT)0x80040212L)
#define S_FALSE ((HRESULT)0x00000001L)
在line 4841
【HRESULT
CBaseAllocator::Alloc(void)
{
/* Error if he hasn't set the size yet */
if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
return VFW_E_SIZENOTSET;
}】
CBaseOutputPin::GetDeliveryBuffer 的时候怎么会出现这错误 CO_E_FAILEDTOGETWINDIR
//
// MessageId: CO_E_FAILEDTOGETWINDIR
//
// MessageText:
//
// Unable to obtain the Windows directory
//
这是由什么引起的啊
#define VFW_E_NOT_COMMITTED ((HRESULT)0x80040211L)
刚开始我被CO_E_FAILEDTOGETWINDIR 这个错误迷惑了 但后来我读了GetDeliveryBuffer函数涉及到的源码我终于发现了
其实这个错误是在CBaseAllocator::GetBuffer()中由于
if (!m_bCommitted) {
return VFW_E_NOT_COMMITTED;
注意: #define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80040211L)
和上面的错误值相同 而且在代码里根本没有返回 CO_E_FAILEDTOGETWINDIR 的地方
后来我又跟踪m_bCommitted 为什么没有被置为1(true)
这里说明一下 如果你的输出Pin 是基于CBaseOutPin 的话 那么
填充sample 必须遵循如下步骤
1 首先调用CBaseAllocator::SetProperties 方法来指定内存的要求,包括内存的数量和大小
2 调用CBaseAllocator::Commit 类分配内存 在这个函数中调用 Alloc()将m_bCommitted 置为1
3 通过CBaseAllocator::GetBuffer 得到media samples,这个方法一直阻塞直到另一块sample
可用,
4 当你使用完sample 以后,记得调用sample 上的IUnknown::Release 来减少sample 的引用计
数,当一个sample 的引用计数到了0 时,sample 并不是被删除,而是返回到allocator 内存池
中,供其他的客户使用。
5 当你使用完allocator 以后,记得要调用CBaseAllocator::Decommit 来释放内存。
后来我发现由于CBaseAllocator::Commit调用CBaseAllocator::Alloc()
进行检查
CBaseAllocator::Alloc(void)
{
/* Error if he hasn't set the size yet */
if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
return VFW_E_SIZENOTSET;
而这些值是在
CBaseAllocator::SetProperties()被赋值的
如下:
pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
pActual->cBuffers = m_lCount = pRequest->cBuffers;
pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
而我在
CRecvOutPutPin::DecideBufferSize内部调用 SetProperties()pRequest->cbBuffer
赋值为0 所以造成了如上错误
但是我也弄明白了 填充sample的流程。
CRecvOutPutPin::DecideBufferSize 这个函数是在Pin连接时自动调用。
HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer,
REFERENCE_TIME *pStartTime,
REFERENCE_TIME *pEndTime,
DWORD dwFlags
)
{
UNREFERENCED_PARAMETER(pStartTime);
UNREFERENCED_PARAMETER(pEndTime);
UNREFERENCED_PARAMETER(dwFlags);
CMediaSample *pSample;
*ppBuffer = NULL;
for (;;)
{
{ // scope for lock
CAutoLock cObjectLock(this);
/* Check we are committed */
if (!m_bCommitted) {
return VFW_E_NOT_COMMITTED;
}
pSample = (CMediaSample *) m_lFree.RemoveHead();
if (pSample == NULL) {
SetWaiting();
}
}
/* If we didn't get a sample then wait for the list to signal */
if (pSample) {
break;
}
if (dwFlags & AM_GBF_NOWAIT) {
return VFW_E_TIMEOUT;
}
ASSERT(m_hSem != NULL);
WaitForSingleObject(m_hSem, INFINITE);
}
/* Addref the buffer up to one. On release
back to zero instead of being deleted, it will requeue itself by
calling the ReleaseBuffer member function. NOTE the owner of a
media sample must always be derived from CBaseAllocator */
ASSERT(pSample->m_cRef == 0);
pSample->m_cRef = 1;
*ppBuffer = pSample;
return NOERROR;
}
///当filter 出于stop 状态时
STDMETHODIMP
CNetworkReceiverFilter::Stop (
)
{
LockFilter () ;
// synchronous call to stop the receiver (leaves the multicast group
// and terminates the thread)
m_pNetReceiver -> Stop () ;
// if we have an output pin (we should) stop it
if (m_pOutput) {
//重载CBasePin::Inactive() 调用IMemAllocator::Decommit method decommit the memory allocator
m_pOutput -> Inactive () ;
}
m_State = State_Stopped ;
UnlockFilter () ;
return S_OK ;
}
//filter 处于 pause 状态
STDMETHODIMP
CNetworkReceiverFilter::Pause (
)
{
HRESULT hr ;
LockFilter ();
if (m_ulIP == UNDEFINED ||
m_ulNIC == UNDEFINED)
{
hr = E_FAIL ;
}
else if (m_State == State_Stopped)
{
// --------------------------------------------------------------------
// stopped -> pause transition; get the filter up and running
// activate the receiver; joins the multicast group and starts the
// thread
//重载 the CBasePin::Active method. 调用 IMemAllocator::Commit method on the allocator, to allocate memory for buffers.
hr = m_pNetReceiver -> Activate (m_ulIP, m_usPort, m_ulNIC) ;//
if (SUCCEEDED (hr))
{
m_State = State_Paused ;
if (m_pOutput &&
m_pOutput -> IsConnected ())
{
m_pOutput -> Active ();
}
}
}
else
{
// --------------------------------------------------------------------
// run -> pause transition; do nothing but set the state
m_State = State_Paused ;
hr = S_OK ;
}
UnlockFilter () ;
return hr ;
}
InitAllocator 是自动调用的