如何捕捉視頻流並保存到文件(Capture video to File)
1 將視頻流保存到AVI文件
AVI Mux filter接收從capture pin過來的視頻流,然後將其打包成AVI流。音頻流也可以連接到AVI Mux Filter上,這樣mux filter就將視頻流和視頻流合成AVI流。File writer將AVI流寫入到文件中。
可以像下面這樣構建graph圖
- IBaseFilter *pMux;
- 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
第一個參數表明文件的類型,這裏表明是AVI,第二個參數是制定文件的名稱。對於AVI文件,SetOutputFileName函數會創建一個AVI mux Filter 和一個 File writer Filter ,並且將兩個filter添加到graph圖中,在這個函數中,通過File Writer Filter 請求IFileSinkFilter接口,然後調用IFileSinkFilter::SetFileName方法,設置文件的名稱。然後將兩個filter連接起來。第三個參數返回一個指向
AVI Mux的指針,同時,它也通過第四個參數返回一個IFileSinkFilter參數,如果你不需要這個參數,你可以將這個參數設置成NULL。
然後,你應該調用下面的函數將capture filter 和AVI Mux連接起來。
- 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();
第5個參數就是使用的上面函數返回的pMux指針。
當捕捉音頻的時候,媒體類型要設置爲MEDIATYPE_Audio,如果你從兩個不同的設備捕捉視頻和音頻,你最好將音頻設置成主流,這樣可以防止兩個數據流間drift,因爲avi mux filter爲同步音頻,會調整視頻的播放速度的。爲了設置master 流,調用IConfigAviMux::SetMasterStream方法,可以採用如下的代碼:
- IConfigAviMux *pConfigMux = NULL;
- hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
- if(SUCCEEDED(hr))
- {
- pConfigMux->SetMasterStream(1);
- pConfigMux->Release();
- }
SetMasterStream的參數指的是數據流的數目,這個是由調用RenderStream的次序決定的。例如,如果你調用RenderStream首先用於視頻流,然後是音頻,那麼視頻流就是0,音頻流就是1。
添加編碼filter
- IBaseFilter *pEncoder;
- //Add it to the filter graph
- pGraph->AddFilter(pEncoder, L"Encode");
- //Render the stream
- hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- pCap, pEncoder, pMux);
- pEncoder->Release();
2 將視頻流保存成wmv格式的文件
爲了將視頻流保存成並編碼成windows media video (WMV)格式的文件,將capture pin連到WM ASF Writer filter。
構建graph圖最簡單的方法就是將在ICaptureGraphBuilder2::SetOutputFileName方法中指定MEDIASUBTYPE_Asf的filter。如下
- IBaseFilter *pASFWriter = 0;
- hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Asf, //Create a windows media file
- L"C:\\VidCap.wmv", //File name
- &pASFWriter, //Receives a pointer to the filter
- NULL); //Receives an IFileSinkFilter interface pointer(optional)
參數MEDIASUBTYPE_Asf 告訴graph builder,要使用wm asf writer作爲文件接收器,於是,pbuild 就創建這個filter,將其添加到graph圖中,然後調用IFileSinkFilter::SetFileName來設置輸出文件的名字。第三個參數用來返回一個ASF writer指針,第四個參數用來返回文件的指針。
在將任何pin連接到WM ASF Writer之前,一定要對WM ASF Writer進行一下設置,你可以同過WM ASF Writer的IConfigAsfWriter接口指針來進行設置。
- IConfigAsfWriter *pConfig = 0;
- hr = pASFWriter->QueryInterface(IID_IConfigAsfWriter, (void**)&pConfig);
- if(SUCCEEDED(hr))
- {
- //Configure the ASF Writer filter
- pConfig->Release();
- }
然後調用ICaptureGraphBuilder2::RenderStream將capture Filter 和 ASF writer連接起來:
- hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, //Capture pin
- &MEDIATYPE_Video, //Video. Use MEDIATYPE_Audio for audio
- pCap, //Pointer to the capture filter
- 0,
- pASFWriter); //Pointer to the sink filter(ASF Filter)
3保存成自定義的文件格式
如果你想將文件保存成自己的格式,你必須有自己的 file writer。看下面的代碼:
- IBaseFilter *pMux = 0;
- IFileSinkFilter *pSink = 0;
- hr = pBuild->SetOutputFileName(&CLSID_MyCustomMuxFilter, //開發自己的Filter
- L"C:\\VidCap.avi", &pMux, &pSink);
4如何將視頻流保存進多個文件
當你將視頻流保存進一個文件後,如果你想開始保存第二個文件,這時,你應該首先將graph停止,然後通過IFileSinkFilter::SetFileName改變 File Writer 的文件名稱。注意,IFileSinkFilter指針你可以在SetOutputFileName時通過第四個參數返回的。
看看保存多個文件的代碼:
- IBaseFilter *pMux = 0;
- IFileSinkFilter *pSink = 0;
- hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,
- L"C:\\YourFileName.avi", &pMux, &pSink);
- if(SUCCEEDED(hr))
- {
- hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
- pCap, NULL, pMux);
- if(SUCCEEDED(hr))
- {
- pControl->Run();
- pControl->Stop();
- //Change the file name and run the graph again
- pSink->SetFileName(L"YourFileName02.avi", 0);
- pControl->Run();
- }
- pMux->Release();
- pSink->Release();
- }