| 導購 | 订阅 | 在线投稿
分享
 
 
 

利用Directshow開發源Filter

來源:互聯網網民  2006-12-17 07:32:09  評論

利用Directshow開發源Filter

利用Directshow開發源Filter 摘要:

我們一般不推薦自己開發音頻或者視頻捕捉過濾器,因爲diectshow對于音視頻的捕捉設備以經提供了支持。所以,這篇文檔,對于某些用戶需要從特定設備捕捉一些數據提供一些幫助。這篇文檔主要包括以下內容。

1捕捉filter 對pin的要求

2如何完成一個預覽pin

3如何産生源數據 1 對pin的要求Pin Requirements for Capture Filters

Pin的名字

你可以給你的filter起任何名字,如果你的pin的名字以~符號開頭,那麽當應用程序調用IGraphBuilder::RenderFile方法時,filter圖表管理器不會自動render這個pin的。例如,如果一個filter具有一個捕捉pin和預覽pin,相應的你給他們命名爲”~Capture”和“Preview”。如果一個應用程序在graph中render這個filter ,那麽預覽pin就會自動和它缺省的render相連接,但是,capture pin上卻不連接任何東西,這是一個合理的缺省行爲。這個也可以應用到那些傳輸不准備被rendered數據的pin,也可以應用到需要屬性設置的pin上。

注:名字中含有~符號的pin是可以手動連接的。

Pin的種類

一個捕捉filter通常用一個捕捉pin,也許還有一個預覽pin。一些捕捉filter除了這兩種pin之外還有其他的pin,用來傳遞其他的數據,例如控制信息。每一個輸出pin都必須暴露IKsPropertySet接口,應用程序通過這些接口來判斷pin的種類,pin一般都會返回PIN_CATEGORY_CAPTURE or PIN_CATEGORY_PREVIEW。下面的例子演示了一個捕捉pin如何通過IKsPropertySet來返回pin的種類

// Set: Cannot set any properties.

HRESULT CMyCapturePin::Set(REFGUID guidPropSet, DWORD dwID,

void *pInstanceData, DWORD cbInstanceData, void *pPropData,

DWORD cbPropData)

{

return E_NOTIMPL;

}

// Get: Return the pin category (our only property).

HRESULT CMyCapturePin::Get(

REFGUID guidPropSet, // Which property set.

DWORD dwPropID, // Which property in that set.

void *pInstanceData, // Instance data (ignore).

DWORD cbInstanceData, // Size of the instance data (ignore).

void *pPropData, // Buffer to receive the property data.

DWORD cbPropData, // Size of the buffer.

DWORD *pcbReturned // Return the size of the property.

)

{

if (guidPropSet != AMPROPSETID_Pin)

return E_PROP_SET_UNSUPPORTED;

if (dwPropID != AMPROPERTY_PIN_CATEGORY)

return E_PROP_ID_UNSUPPORTED;

if (pPropData == NULL && pcbReturned == NULL)

return E_POINTER;

if (pcbReturned)

*pcbReturned = sizeof(GUID);

if (pPropData == NULL) // Caller just wants to know the size.

return S_OK;

if (cbPropData < sizeof(GUID)) // The buffer is too small.

return E_UNEXPECTED;

*(GUID *)pPropData = PIN_CATEGORY_CAPTURE;

return S_OK;

}

// QuerySupported: Query whether the pin supports the specified property.

HRESULT CMyCapturePin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID,

DWORD *pTypeSupport)

{

if (guidPropSet != AMPROPSETID_Pin)

return E_PROP_SET_UNSUPPORTED;

if (dwPropID != AMPROPERTY_PIN_CATEGORY)

return E_PROP_ID_UNSUPPORTED;

if (pTypeSupport)

// We support getting this property, but not setting it.

*pTypeSupport = KSPROPERTY_SUPPORT_GET;

return S_OK;

}

2如何完成一個預覽pin Implementing a Preview Pin (Optional)

如果你的filter有一個預覽pin,預覽pin發送的數據是捕捉pin傳遞的數據的拷貝。預覽pin發送的數據不會降低捕捉pin的桢率,捕捉pin比預覽pin有優先權。

捕捉pin和預覽pin必須發送一個相同格式的數據。這樣,他們連接都是通過同一種媒體數據類型,如果捕捉pin先連接,預覽pin應該提供相同的媒體類型,對于其他類型的數據媒體,則拒絕。如果預覽pin先連接,然後,如果捕捉pin以另一種媒體類型和其他pin連接,那麽預覽pin就應該用新的媒體類型重新連接,如果和filter的預覽pin連接的下遊filter拒絕新的數據類型,捕捉pin應該拒絕新的媒體類型。可以通過IPin::QueryAccept方法察看filter的預覽pin連接的下遊filter連接的數據媒體,然後通過IFilterGraph::Reconnect方法重新連接pin。

這條規則也適用于圖表管理器重新連接捕捉pin。

下面的代碼大體上描述了上面的過程

// Override CBasePin::CheckMediaType.

CCapturePin::CheckMediaType(CMediaType *pmt)

{

if (m_pMyPreviewPin->IsConnected())

{

// The preview pin is already connected, so query the pin it is

// connected to. If the other pin rejects it, so do we.

hr = m_pMyPreviewPin->GetConnected()->QueryAccept(pmt);

if (hr != S_OK)

{

// The preview pin cannot reconnect with this media type.

return E_INVALIDARG;

}

// The preview pin will reconnect when SetMediaType is called.

}

// Decide whether the capture pin accepts the format.

BOOL fAcceptThisType = ... // (Not shown.)

return (fAcceptThisType? S_OK : E_FAIL);

}

// Override CBasePin::SetMediaType.

CCapturePin::SetMediaType(CMediaType *pmt);

{

if (m_pMyPreviewPin->IsConnected())

{

// The preview pin is already connected, so it must reconnect.

if (m_pMyPreviewPin->GetConnected()->QueryAccept(pmt) == S_OK)

{

// The downstream pin will accept the new type, so it's safe

// to reconnect.

m_pFilter->m_pGraph->Reconnect(m_pMyPreviewPin);

}

else

{

return VFW_E_INVALIDMEDIATYPE;

}

}

// Now do anything that the capture pin needs to set the type.

hr = MyInternalSetMediaType(pmt);

// And finally, call the base-class method.

return CBasePin::SetMediaType(pmt);

}

CPreviewPin::CheckMediaType(CMediaType *pmt)

{

if (m_pMyCapturePin->IsConnected())

{

// The preview pin must connect with the same type.

CMediaType cmt = m_pMyCapturePin->m_mt;

return (*pmt == cmt ? S_OK : VFW_E_INVALIDMEDIATYPE);

}

// Decide whether the preview pin accepts the format. You can use your

// knowledge of which types the capture pin will accept. Regardless,

// when the capture pin connects, the preview pin will reconnect.

return (fAcceptThisType? S_OK : E_FAIL);

}

3在源filter中産生數據 Producing Data in a Capture Filter

狀態改變

一個捕捉filter在運行時會産生數據流。當filter paused的時候,不要發送數據,並且此時,圖表管理器調用CBaseFilter::GetState方法會返回VFW_S_CANT_CUE,這個返回值告訴圖表管理器,filter 正處于paused狀態,停止發送數據。下面的代碼顯示如何派生GetState方法

CMyVidcapFilter::GetState(DWORD dw, FILTER_STATE *pState)

{

CheckPointer(pState, E_POINTER);

*pState = m_State;

if (m_State == State_Paused)

return VFW_S_CANT_CUE;

else

return S_OK;

}

控制不同的數據流

一個捕捉filter應該支持IAMStreamControl接口,因此應用程序應該分別的打開和關閉每一個pin,例如,一個應用程序可以只預覽而沒有捕捉,然後可以轉換到捕捉模式不用重新構建graph圖表。你可以通過CBaseStreamControl類來實現這個接口

時間戳

當一個filter捕捉了一個sample,將在每一個sample上標上一個當前時間的時間戳。結束時間是開始時間加上持續時間。例如,如果一個filter每秒捕捉十個sample,and the stream time is 200,000,000 units when the filter captures the sample, the time stamps should be 200000000 and 201000000. (There are 10,000,000 units per second.) 可以通過IReferenceClock::GetTime方法獲得當前的參考時間,通過IMediaSample::SetTime給sample設置時間戳。

相連的sample上的時間戳必須是遞增的,即使filter pauses也是這樣,如果一個filter運行,停止,然後又運行,重新開始後産生的sample上的時間戳必須比停止前的sample上的時間戳要大一些。

預覽pin上的sample沒有時間戳,但是,預覽pin一般比捕捉pin到達render pin稍晚,因此,render filter將預覽pin上的sample視作遲到的sample,爲了趕上其他的時間進度,也許會丟失一些數據。

 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
利用Directshow開發源Filter 利用Directshow開發源Filter 摘要: 我們一般不推薦自己開發音頻或者視頻捕捉過濾器,因爲diectshow對于音視頻的捕捉設備以經提供了支持。所以,這篇文檔,對于某些用戶需要從特定設備捕捉一些數據提供一些幫助。這篇文檔主要包括以下內容。 1捕捉filter 對pin的要求 2如何完成一個預覽pin 3如何産生源數據 1 對pin的要求Pin Requirements for Capture Filters Pin的名字 你可以給你的filter起任何名字,如果你的pin的名字以~符號開頭,那麽當應用程序調用IGraphBuilder::RenderFile方法時,filter圖表管理器不會自動render這個pin的。例如,如果一個filter具有一個捕捉pin和預覽pin,相應的你給他們命名爲”~Capture”和“Preview”。如果一個應用程序在graph中render這個filter ,那麽預覽pin就會自動和它缺省的render相連接,但是,capture pin上卻不連接任何東西,這是一個合理的缺省行爲。這個也可以應用到那些傳輸不准備被rendered數據的pin,也可以應用到需要屬性設置的pin上。 注:名字中含有~符號的pin是可以手動連接的。 Pin的種類 一個捕捉filter通常用一個捕捉pin,也許還有一個預覽pin。一些捕捉filter除了這兩種pin之外還有其他的pin,用來傳遞其他的數據,例如控制信息。每一個輸出pin都必須暴露IKsPropertySet接口,應用程序通過這些接口來判斷pin的種類,pin一般都會返回PIN_CATEGORY_CAPTURE or PIN_CATEGORY_PREVIEW。下面的例子演示了一個捕捉pin如何通過IKsPropertySet來返回pin的種類 // Set: Cannot set any properties. HRESULT CMyCapturePin::Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData) { return E_NOTIMPL; } // Get: Return the pin category (our only property). HRESULT CMyCapturePin::Get( REFGUID guidPropSet, // Which property set. DWORD dwPropID, // Which property in that set. void *pInstanceData, // Instance data (ignore). DWORD cbInstanceData, // Size of the instance data (ignore). void *pPropData, // Buffer to receive the property data. DWORD cbPropData, // Size of the buffer. DWORD *pcbReturned // Return the size of the property. ) { if (guidPropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED; if (dwPropID != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED; if (pPropData == NULL && pcbReturned == NULL) return E_POINTER; if (pcbReturned) *pcbReturned = sizeof(GUID); if (pPropData == NULL) // Caller just wants to know the size. return S_OK; if (cbPropData < sizeof(GUID)) // The buffer is too small. return E_UNEXPECTED; *(GUID *)pPropData = PIN_CATEGORY_CAPTURE; return S_OK; } // QuerySupported: Query whether the pin supports the specified property. HRESULT CMyCapturePin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport) { if (guidPropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED; if (dwPropID != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED; if (pTypeSupport) // We support getting this property, but not setting it. *pTypeSupport = KSPROPERTY_SUPPORT_GET; return S_OK; } 2如何完成一個預覽pin Implementing a Preview Pin (Optional) 如果你的filter有一個預覽pin,預覽pin發送的數據是捕捉pin傳遞的數據的拷貝。預覽pin發送的數據不會降低捕捉pin的桢率,捕捉pin比預覽pin有優先權。 捕捉pin和預覽pin必須發送一個相同格式的數據。這樣,他們連接都是通過同一種媒體數據類型,如果捕捉pin先連接,預覽pin應該提供相同的媒體類型,對于其他類型的數據媒體,則拒絕。如果預覽pin先連接,然後,如果捕捉pin以另一種媒體類型和其他pin連接,那麽預覽pin就應該用新的媒體類型重新連接,如果和filter的預覽pin連接的下遊filter拒絕新的數據類型,捕捉pin應該拒絕新的媒體類型。可以通過IPin::QueryAccept方法察看filter的預覽pin連接的下遊filter連接的數據媒體,然後通過IFilterGraph::Reconnect方法重新連接pin。 這條規則也適用于圖表管理器重新連接捕捉pin。 下面的代碼大體上描述了上面的過程 // Override CBasePin::CheckMediaType. CCapturePin::CheckMediaType(CMediaType *pmt) { if (m_pMyPreviewPin->IsConnected()) { // The preview pin is already connected, so query the pin it is // connected to. If the other pin rejects it, so do we. hr = m_pMyPreviewPin->GetConnected()->QueryAccept(pmt); if (hr != S_OK) { // The preview pin cannot reconnect with this media type. return E_INVALIDARG; } // The preview pin will reconnect when SetMediaType is called. } // Decide whether the capture pin accepts the format. BOOL fAcceptThisType = ... // (Not shown.) return (fAcceptThisType? S_OK : E_FAIL); } // Override CBasePin::SetMediaType. CCapturePin::SetMediaType(CMediaType *pmt); { if (m_pMyPreviewPin->IsConnected()) { // The preview pin is already connected, so it must reconnect. if (m_pMyPreviewPin->GetConnected()->QueryAccept(pmt) == S_OK) { // The downstream pin will accept the new type, so it's safe // to reconnect. m_pFilter->m_pGraph->Reconnect(m_pMyPreviewPin); } else { return VFW_E_INVALIDMEDIATYPE; } } // Now do anything that the capture pin needs to set the type. hr = MyInternalSetMediaType(pmt); // And finally, call the base-class method. return CBasePin::SetMediaType(pmt); } CPreviewPin::CheckMediaType(CMediaType *pmt) { if (m_pMyCapturePin->IsConnected()) { // The preview pin must connect with the same type. CMediaType cmt = m_pMyCapturePin->m_mt; return (*pmt == cmt ? S_OK : VFW_E_INVALIDMEDIATYPE); } // Decide whether the preview pin accepts the format. You can use your // knowledge of which types the capture pin will accept. Regardless, // when the capture pin connects, the preview pin will reconnect. return (fAcceptThisType? S_OK : E_FAIL); } 3在源filter中産生數據 Producing Data in a Capture Filter 狀態改變 一個捕捉filter在運行時會産生數據流。當filter paused的時候,不要發送數據,並且此時,圖表管理器調用CBaseFilter::GetState方法會返回VFW_S_CANT_CUE,這個返回值告訴圖表管理器,filter 正處于paused狀態,停止發送數據。下面的代碼顯示如何派生GetState方法 CMyVidcapFilter::GetState(DWORD dw, FILTER_STATE *pState) { CheckPointer(pState, E_POINTER); *pState = m_State; if (m_State == State_Paused) return VFW_S_CANT_CUE; else return S_OK; } 控制不同的數據流 一個捕捉filter應該支持IAMStreamControl接口,因此應用程序應該分別的打開和關閉每一個pin,例如,一個應用程序可以只預覽而沒有捕捉,然後可以轉換到捕捉模式不用重新構建graph圖表。你可以通過CBaseStreamControl類來實現這個接口 時間戳 當一個filter捕捉了一個sample,將在每一個sample上標上一個當前時間的時間戳。結束時間是開始時間加上持續時間。例如,如果一個filter每秒捕捉十個sample,and the stream time is 200,000,000 units when the filter captures the sample, the time stamps should be 200000000 and 201000000. (There are 10,000,000 units per second.) 可以通過IReferenceClock::GetTime方法獲得當前的參考時間,通過IMediaSample::SetTime給sample設置時間戳。 相連的sample上的時間戳必須是遞增的,即使filter pauses也是這樣,如果一個filter運行,停止,然後又運行,重新開始後産生的sample上的時間戳必須比停止前的sample上的時間戳要大一些。 預覽pin上的sample沒有時間戳,但是,預覽pin一般比捕捉pin到達render pin稍晚,因此,render filter將預覽pin上的sample視作遲到的sample,爲了趕上其他的時間進度,也許會丟失一些數據。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有