[英]Capturing Video to an AVI File with DirectShow
我正在嘗試使用DirectShow編寫C ++應用程序,以將視頻捕獲保存到文件中。 代碼中的步驟是:1.創建捕獲圖生成器2.創建系統設備枚舉器3.創建系統設備枚舉器-為了獲取捕獲過濾器4.為視頻捕獲類別創建一個枚舉器5.創建查詢以捕捉視頻
附加代碼
// gets the device filter
HRESULT getDeviceFilter(REFCLSID clsid, int order, IBaseFilter **pCap)
{
ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;
// Create the System Device Enumerator.
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
reinterpret_cast<void**>(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the video capture category.
hr = pDevEnum->CreateClassEnumerator( clsid, &pEnum, 0);
}
IMoniker *pMoniker = NULL;
if (pEnum->Next(1, &pMoniker, NULL) == S_OK)
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)pCap);
return hr;
}
int main()
{
IGraphBuilder *pGraph = 0;
ICaptureGraphBuilder2 *pBuild = 0;
IBaseFilter *pCap = 0;
HRESULT hr = CoInitialize(NULL);
// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2,
(void**)&pBuild );
ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;
// Create the System Device Enumerator.
hr = CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum,
reinterpret_cast<void**>(&pDevEnum));
IBaseFilter *pMux = 0;
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi, // Specifies AVI for the target file.
L"C:\\Example.avi", // File name.
&pMux, // Receives a pointer to the mux.
NULL); // (Optional) Receives a pointer to the file sink.
// gets the first device, VDM tv card
hr = getDeviceFilter(CLSID_VideoInputDeviceCategory, 0, &pCap);
hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
pMux); // Mux or file sink filter.
// Release the mux filter.
pMux->Release();
IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(1);
pConfigMux->Release();
}
return 0;
}
但是,在調用RenderStream時,出現E_INVALIDARG錯誤
有什么建議么?
謝謝
看一下這個話題 。 看來您錯過了一些步驟。
首先,您不會在任何地方使用pGraph
。 您應該創建一個圖形管理器,然后通過使用SetFilterGraph向其提供指向圖形管理器的指針來初始化圖形構建器。
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// ...
}
其次,您使用的不是由圖形管理器管理的過濾器。 從這里報價:
由pSource,pIntermediate和pSink指定的所有過濾器必須在調用該方法之前添加到圖形中。
您將必須使用AddFilter將過濾器pCap
和pMux
添加到您先前創建的圖形管理器中。 您應該在調用RenderStream之前執行此操作。 之所以如此,是因為RenderStream最終在管理器上調用了連接方法。
如果上述步驟不能解決問題,則可以嘗試其他幾種方法。
設備過濾器 。 您正在使用CLSID_VideoInputDeviceCategory
的第一個設備,但是您確定這是正確的設備嗎? 網絡攝像頭等也包括在此類別中。 確保沒有連接相同類別的其他設備,然后重試。
連接 。 每個設備都是不同的。 可能是您的設備無法直接連接到多路復用器。 在這種情況下,我們將必須找出原因,並確定是否需要連接其他濾波器(例如解碼器)。 GraphEdit是查找這些過濾器的快速方法。
引腳類別/媒體類型 。 以我的經驗,E_INVALIDARG是RenderStream
的前兩個參數引起的時間的90%。 嘗試將引腳類別或媒體類型設置為NULL
。
系統設備枚舉器 :正如您自己描述的那樣,您正在兩次創建系統設備枚舉器。 這對我來說似乎很奇怪,為什么不同時使用這兩個目的呢?
如果您的代碼仍然無法正常工作,則應向我提供更多信息。 使用GraphEdit時是否實現了目標? 您的VDM電視卡過濾器的外觀(引腳,媒體類型)如何?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.