#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 是自動調用的