




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
的美譽;它還被稱作為“變色龍Filter”,由于該Filter上定義了統一的接口,而接口的實現因簡略的硬件驅動程序而異.在FilterGraph中,KsproxyFilter顯示的名字為硬件的Friendlyname(一般在驅動程序的。inf文件中定義)。我們可以通過GraphEdit,在WDMStreaming開頭的名目中找到本機系統中安裝的WDM硬件。由于KsProxy.ax能夠代表各種WDM的音視頻設備,所以這個包裝Filter的工作流程有點簡潔。這個Filter不會預先知道要代表哪種類型的設備,它必須首先訪問驅動程序的屬性集,然后動態配置Filter上應該實現的接口。當KsproxyFilter上的接口方法被應用程序或其他Filter調用時,它會將調用方法以及參數傳遞給驅動程序,由驅動程序最終完成指定功能。除此以外,WDM硬件還支持內核流(KernelStreaming),即內核模式下的數據傳輸,而無需經過到用戶模式的轉換。由于內核模式與用戶模式之間的相互轉換,需要花費很大的計算量。如果使用內核流,不僅可以避開大量的計算,還避開了內核數據與主機內存之間的拷貝過程。在這種情況下,用戶模式的FilterGraph中,即使pin之間是連接的,也不會有實際的數據流淌。典型的情況,如帶有VideoPortPin的視頻捕獲卡,Preview時顯示的圖像就是在內核模式下直接傳送到顯卡的顯存的.所以,你也休想在VPPin后面截獲數據流。講到這里,我想大家應該對DirectShow對硬件的支持問題有了一個總體的熟識。對于應用程序開發人員來說,這方面的內容不用討論得太透,而只需作為背景知識了解一下就好了。其實,大量繁瑣的工作DirectShow已經幫我們做好了。
//陸其明文章結束
Direcshow中視頻捕獲的Filter
Pin的種類
捕獲Filter一般都有兩個或多個輸出pin,他們輸出的媒體類型都一樣,比如預覽pin和捕獲pin,因此依據媒體類型就不能很好的區分這些pin。此時就要依據pin的功能來區分每個pin了,每個pin都有一個GUID,稱為pin的種類。
如果想仔細的了解pin的種類,請看后面的相關內容WorkingwithPinCategories。對于大多數的應用來說,ICaptureGraphBuilder2供應了一些函數可以自動確定pin的種類。
預覽pin和捕獲pin
視頻捕獲Filter都供應了預覽和捕獲的輸出pin,預覽pin用來將視頻流在屏幕上顯示,捕獲pin用來將視頻流寫入文件。
預覽pin和輸出pin有下面的區分:
1為了保證捕獲pin對視頻楨流量,預覽pin必要的時候可以停止。
2經過捕獲pin的視頻楨都有時間戳,但是預覽pin的視頻流沒有時間戳.
預覽pin的視頻流之所以沒有時間戳的緣由在于filter圖表管理器在視頻流里加一個很小的latency,如果捕獲時間被認為就是render時間的話,視頻renderFilter就認為視頻流有一個小小的延遲,如果此時renderfilter試圖連續播放的時候,就會丟楨.去掉時間戳就保證了視頻楨來了就可以播放,不用等待,也不丟楨。
預覽pin的種類GUID為PIN_CATEGORY_PREVIEW
捕獲pin的種類GUID為PIN_CATEGORY_CAPTURE
VideoPortpin
VideoPort是一個介于視頻設備(TV)和視頻卡之間的硬件設備。同過VideoPort,視頻數據可以直接發送到圖像卡上,通過硬件的掩蓋,視頻可以直接在屏幕顯示出來。VideoPort就是連接兩個設備的。
使用VideoPort的最大好處是,不用CPU的任何工作,視頻流直接寫入內存中。當然它也有下面的缺點drawbacks:
略
如果捕獲設備使用了VideoPort,捕獲Filter就用一個videoportpin代替預覽pin。
videoportpin的種類GUID為PIN_CATEGORY_VIDEOPORT
一個捕獲filter至少有一個Capturepin,另外,它可能有一個預覽pin和一個videoportpin
,或者兩者都沒有,也許filter有很多的capturepin,和預覽pin,每一個pin都代表一種媒體類型,因此一個filter可以有一個視頻capturepin,視頻預覽pin,音頻捕獲pin,音頻預覽pin。
UpstreamWDMFilters
在捕獲Filter之上,WDM設備可能需要額外的filters,下面就是這些filter
TVTunerFilter
TVAudioFilter.
AnalogVideoCrossbarFilter
盡管這些都是一些獨立的filter,但是他們可能代表的是同一個硬件設備,每個filter都掌握設備的不同函數,這些filter通過pin連接起來,但是在pin中沒有數據流淌.因此,這些pin的連接和媒體類型無關。他們使用一個GUID值來定義一個給定設備的minidriver,例如:TVtunerFilter和videocapturefilter都支持同一種medium。
在實際應用中,如果你使用ICaptureGraphBuilder2來創建你的capturegraphs,這些filters就會自動被添加到你的graph中.更多的簡略資料,可以參考WDMClassDriverFilters
2選擇一個視頻捕獲設備(Selectcapturedevice)
如何選擇一個視頻捕獲設備,可以采納系統設備枚舉,簡略資料參見UsingtheSystemDeviceEnumerator。enumerator可以依據filter的種類返回一個設備的monikers.Moniker是一個com對象,可以參見IMoniker的SDK。
對于捕獲設備,下面兩種類是相關的.
CLSID_AudioInputDeviceCategory音頻設備
CLSID_VideoInputDeviceCategory視頻設備
下面的代碼演示了如何枚舉一個視頻捕獲設備ICreateDevEnum*pDevEnum=NULL;
IEnumMoniker*pEnum=NULL;//CreatetheSystemDeviceEnumerator.
HRESULThr=CoCreateInstance(CLSID_SystemDeviceEnum,NULL,
CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,
reinterpret_cast〈void**>(&pDevEnum));
if(SUCCEEDED(hr))
{
//創建一個枚舉器,枚舉視頻設備
hr=pDevEnum-〉CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
&pEnum,0);
}
IEnumMoniker接口pEnum返回一個IMoniker接口的列表,代表一系列的moniker,你可以顯示全部的設備,然后讓用戶選擇一個.
采納IMoniker::BindToStorage方法,返回一個IPropertyBag接口指針。然后調用IPropertyBag::Read讀取moniker的屬性.下面看看都包含什么屬性
1FriendlyName是設備的名字
2Description屬性僅僅適用于DV和D-VHS/MPEG攝象機,如果這個屬性可用,這個屬性更簡略的描述了設備的資料
3DevicePath這個屬性是不行讀的,但是每個設備都有一個獨一無二的。你可以用這個屬性來區分同一個設備的不同實例
下面的代碼演示了如何顯示遍歷設備的名稱,接上面的代碼HWNDhList;//Handletothelistbox。
IMoniker*pMoniker=NULL;
while(pEnum—>Next(1,&pMoniker,NULL)==S_OK)
{
IPropertyBag*pPropBag;
hr=pMoniker-〉BindToStorage(0,0,IID_IPropertyBag,
(void**)(&pPropBag));
if(FAILED(hr))
{
pMoniker—〉Release();
continue;//Skipthisone,maybethenextonewillwork.
}
//Findthedescriptionorfriendlyname.
VARIANTvarName;
VariantInit(&varName);
hr=pPropBag-〉Read(L”Description”,&varName,0);
if(FAILED(hr))
{
hr=pPropBag->Read(L”FriendlyName",&varName,0);
}
if(SUCCEEDED(hr))
{
//Addittotheapplication’slistbox.
USES_CONVERSION;
(long)SendMessage(hList,LB_ADDSTRING,0,
(LPARAM)OLE2T(varName。bstrVal));
VariantClear(&varName);
}
pPropBag->Release();
pMoniker->Release();
}
如果用戶選中了一個設備調用IMoniker::BindToObject為設備生成filter,然后將filter加入到graph中。IBaseFilter*pCap=NULL;
hr=pMoniker—〉BindToObject(0,0,IID_IBaseFilter,(void**)&pCap);
if(SUCCEEDED(hr))
{
hr=m_pGraph—>AddFilter(pCap,L”CaptureFilter");
}3預覽視頻(PreviewingVideo)
為了創建可以預覽視頻的graph,可以調用下面的代碼ICaptureGraphBuilder2*pBuild;//CaptureGraphBuilder
//InitializepBuild(notshown).IBaseFilter*pCap;//Videocapturefilter.
/*InitializepCapandaddittothefiltergraph(notshown).*/hr=pBuild—>RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pCap,NULL,NULL);
4如何捕獲視頻流并保存到文件(CapturevideotoFile)
1將視頻流保存到AVI文件
下面的圖表顯示了graph圖
圖2
AVIMuxfilter接收從capturepin過來的視頻流,然后將其打包成AVI流。音頻流也可以連接到AVIMuxFilter上,這樣muxfilter就將視頻流和視頻流合成AVI流。Filewriter將AVI流寫入到文件中.
可以像下面這樣構建graph圖IBaseFilter*pMux;
hr=pBuild—〉SetOutputFileName(
&MEDIASUBTYPE_Avi,//SpecifiesAVIforthetargetfile.
L”C:\\Example.avi”,//Filename.
&pMux,//Receivesapointertothemux。
NULL);//(Optional)Receivesapointertothefilesink。
第一個參數表明文件的類型,這里表明是AVI,其次個參數是制定文件的名稱.對于AVI文件,SetOutputFileName函數會創建一個AVImuxFilter和一個FilewriterFilter,并且將兩個filter添加到graph圖中,在這個函數中,通過FileWriterFilter懇求IFileSinkFilter接口,然后調用IFileSinkFilter::SetFileName方法,設置文件的名稱。然后將兩個filter連接起來.第三個參數返回一個指向AVIMux的指針,同時,它也通過第四個參數返回一個IFileSinkFilter參數,如果你不需要這個參數,你可以將這個參數設置成NULL。
然后,你應該調用下面的函數將capturefilter和AVIMux連接起來。hr=pBuild-〉RenderStream(
&PIN_CATEGORY_CAPTURE,//Pincategory.
&MEDIATYPE_Video,//Mediatype。
pCap,//Capturefilter.
NULL,//Intermediatefilter(optional)。
pMux);//Muxorfilesinkfilter。
//Releasethemuxfilter。
pMux—〉Release();
第5個參數就是使用的上面函數返回的pMux指針。
當捕獲音頻的時候,媒體類型要設置為MEDIATYPE_Audio,如果你從兩個不同的設備捕獲視頻和音頻,你最好將音頻設置成主流,這樣可以防止兩個數據流間drift,由于avimuxfilter為同步音頻,會調整視頻的播放速度的。為了設置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.
添加編碼filterIBaseFilter*pEncoder;
/*Createtheencoderfilter(notshown).*/
//Addittothefiltergraph.
pGraph-〉AddFilter(pEncoder,L"Encoder);/*CallSetOutputFileNameasshownpreviously。*///Renderthestream.
hr=pBuild—>RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,
pCap,pEncoder,pMux);
pEncoder—>Release();
2將視頻流保存成wmv格式的文件
為了將視頻流保存成并編碼成windowsmediavideo(WMV)格式的文件,將capturepin連到WMASFWriterfilter。
圖3
構建graph圖最簡潔的方法就是將在ICaptureGraphBuilder2::SetOutputFileName方法中指定MEDIASUBTYPE_Asf的filter。如下IBaseFilter*pASFWriter=0;
hr=pBuild—>SetOutputFileName(
&MEDIASUBTYPE_Asf,//CreateaWindowsMediafile。
L"C:\\VidCap.wmv”,//Filename。
&pASFWriter,//Receivesapointertothefilter。
NULL);//ReceivesanIFileSinkFilterinterfacepointer(optional)。
參數MEDIASUBTYPE_Asf告知graphbuilder,要使用wmasfwriter作為文件接收器,于是,pbuild就創建這個filter,將其添加到graph圖中,然后調用IFileSinkFilter::SetFileName來設置輸出文件的名字。第三個參數用來返回一個ASFwriter指針,第四個參數用來返回文件的指針。
在將任何pin連接到WMASFWriter之前,肯定要對WMASFWriter進行一下設置,你可以同過WMASFWriter的IConfigAsfWriter接口指針來進行設置.IConfigAsfWriter*pConfig=0;
hr=pASFWriter—〉QueryInterface(IID_IConfigAsfWriter,(void**)&pConfig);
if(SUCCEEDED(hr))
{
//ConfiguretheASFWriterfilter。
pConfig—〉Release();
}
然后調用ICaptureGraphBuilder2::RenderStream將captureFilter和ASFwriter連接起來。hr=pBuild-〉RenderStream(
&PIN_CATEGORY_CAPTURE,//Capturepin。
&MEDIATYPE_Video,//Video。UseMEDIATYPE_Audioforaudio。
pCap,//Pointertothecapturefilter。
0,
pASFWriter);//Pointertothesinkfilter(ASFWriter).
3保存成自定義的文件格式
如果你想將文件保存成自己的格式,你必須有自己的filewriter。看下面的代碼IBaseFilter*pMux=0;
IFileSinkFilter*pSink=0;
hr=pBuild—〉SetOutputFileName(
&CLSID_MyCustomMuxFilter,//自己開發的Filter
L”C:\\VidCap.avi",&pMux,&pSink);
4如何將視頻流保存進多個文件
當你將視頻流保存進一個文件后,如果你想開頭保存其次個文件,這時,你應該首先將graph停止,然后通過IFileSinkFilter::SetFileName轉變FileWriter的文件名稱。注意,IFileSinkFilter指針你可以在SetOutputFileName時通過第四個參數返回的。
看看保存多個文件的代碼吧IBaseFilter*pMux;
IFileSinkFilter*pSink
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();
/*Waitawhile,thenstopthegraph。*/
pControl—〉Stop();
//Changethefilenameandrunthegraphagain.
pSink->SetFileName(L"YourFileName02。avi",0);
pControl-〉Run();
}
pMux-〉Release();
pSink—>Release();
}
5組合視頻的捕獲和預覽
如果想組建一個既可以預覽視頻,又可以將視頻保存成文件的graph,只需要兩次調用ICaptureGraphBuilder2::RenderStream即可。代碼如下://Renderthepreviewstreamtothevideorenderer。
hr=pBuild-〉RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pCap,NULL,NULL);//Renderthecapturestreamtothemux.
hr=pBuild—〉RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pCap,NULL,pMux);
在上面的代碼中,graphbuilder其實隱藏了下面的細節。
1如果captureFilter既有previewpin也有captruepin,那么RenderStream僅僅將兩個pin和renderfilter接起來。如下圖
圖4
2如果caprtureFilter只有一個capturepin,那么CaptureGraphBuilder就采納一個SmartTeeFilter將視頻流分流,graph圖如下
圖5
5如何掌握CaptureGraph(ControllingCaptureGraph)
Filter圖表管理器可以通過IMediaControl接口掌握整個graph的運行,停止和暫停。但是當一個graph有捕獲和預覽兩個數據流的時候,如果我們想單獨的掌握其中的一個數據流話,我們可以通過ICaptureGraphBuilder2::ControlStream。
下面講一下如何來單獨掌握捕獲和預覽數據流。
1掌握捕獲視頻流
下面的代碼,讓捕獲數據流在graph開頭運行1秒后開頭,允運行4秒后結束.//Controlthevideocapturestream.
REFERENCE_TIMErtStart=10000000,rtStop=50000000;
constWORDwStartCookie=1,wStopCookie=2;//Arbitraryvalues.
hr=pBuild->ControlStream(
&PIN_CATEGORY_CAPTURE,//Pincategory。
&MEDIATYPE_Video,//Mediatype。
pCap,//Capturefilter.
&rtStart,&rtStop,//Startandstoptimes。
wStartCookie,wStopCookie//Valuesforthestartandstopevents.
);
pControl-〉Run();
第一個參數表明需要掌握的數據流,一般采納的是pin種類GUID,
其次個參數表明白媒體類型。
第三個參數指明白捕獲的filter。如果想要掌握graph圖中的全部捕獲filter,其次個和第三個參數都要設置成NULL.
第四和第五個參數表明白流開頭和結束的時間,這是一個相對于graph開頭的時間。
只有你調用IMediaControl::Run以后,這個函數才有作用。如果graph正在運行,這個設置立即生效.
最后的兩個參數用來設置當數據流停止,開頭能夠得到的大事通知。對于任何一個運用此方法的數據流,graph當流開頭的時候,會發送EC_STREAM_CONTROL_STARTED通知,在流結束的時候,要發送EC_STREAM_CONTROL_STOPPED通知。wStartCookie和wStopCookie是作為其次個參數的.
看看大事通知處理過程吧while(hr=pEvent—〉GetEvent(&evCode,¶m1,&param2,0),SUCCEEDED(hr))
{
switch(evCode)
{
caseEC_STREAM_CONTROL_STARTED:
//param2==wStartCookie
break;caseEC_STREAM_CONTROL_STOPPED:
//param2==wStopCookie
break;
}
pEvent->FreeEventParams(evCode,param1,param2);
}
ControlStream還定義了一些特定的值來表示開頭和停止的時間。
MAXLONGLONG從不開頭,只有在graph停止的時候才停止
NULL,立即開頭和停止
例如,下面的代碼立即停止捕獲流。pBuild->ControlStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pCap,
0,0,//Startandstoptimes。
wStartCookie,wStopCookie);2掌握預覽視頻流
只要給ControlStream第一個參數設置成PIN_CATEGORY_PREVIEW就可以掌握預覽pin,整個函數的使用和掌握捕獲流一樣,但是唯一區分是在這里你沒法設置開頭和結束時間了,由于預覽的視頻流沒有時間戳,因此你必須使用NULL或者MAXLONGLONG.例子UseNULLtostartthepreviewstream:
pBuild-〉ControlStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pCap,
NULL,//Startnow.
0,//(Don’tcare。)
wStartCookie,wStopCookie);
UseMAXLONGLONGtostopthepreviewstream:
pBuild-〉ControlStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pCap,
0,//(Don’tcare。)
MAXLONGLONG,//Stopnow.
wStartCookie,wStopCookie);
3關于數據流的掌握
Pin的缺省的行為是傳遞sample,例如,如果你對PIN_CATEGORY_CAPTURE使用了ControlStream,但是對于PIN_CATEGORY_PREVIEW沒有使用該函數,因此,當你rungraph的時候,preview流會立即運行起來,而capture流則要等到你設置的時間運行。
6如何配置一個視頻捕獲設備
1顯示VFW驅動的視頻設備對話框
如果視頻捕獲設備采納的仍然是VFW方式的驅動程序,則必須支持下面三個對話框,用來設置視頻設備。
1VideoSource
用來選擇視頻輸入設備并且調整設備的設置,比如亮度和對比度。
2VideoFormat
用來設置楨的大小和位
3VideoDisplay
用來設置視頻的顯示參數
為了顯示上面的三個對話框,你可以dothefollowing
1停止graph.
2向捕獲filter懇求IAMVfwCaptureDialogs接口,如果成功,表明設備支持VFW驅動。
3調用IAMVfwCaptureDialogs::HasDialog來檢查驅動程序是否支持你懇求的對話框,如果支持,返回S_OK,否則返回S_FALSE。注意不要用SUCCEDED宏。
4如果驅動支持該對話框,調用IAMVfwCaptureDialogs::ShowDialog顯示該對話框。
5重新運行graph
代碼如下pControl—〉Stop();//Stopthegraph。
//QuerythecapturefilterfortheIAMVfwCaptureDialogsinterface。
IAMVfwCaptureDialogs*pVfw=0;
hr=pCap—>QueryInterface(IID_IAMVfwCaptureDialogs,(void**)&pVfw);
if(SUCCEEDED(hr))
{
//Checkifthedevicesupportsthisdialogbox。
if(S_OK==pVfw—>HasDialog(VfwCaptureDialog_Source))
{
//Showthedialogbox.
hr=pVfw—>ShowDialog(VfwCaptureDialog_Source,hwndParent);
}
}
pControl—〉Run();
2調整視頻的質量
WDM驅動的設備支持一些屬性可以用來調整視頻的質量,比如亮度,對比度,飽和度,等要向調整視頻的質量,dothefollowing
1從捕獲filter上懇求IAMVideoProcAmp接口
2對于你想調整的任何一個屬性,調用IAMVideoProcAmp::GetRange可以返回這個屬性賦值的范圍,缺省值,最小的增量值.IAMVideoProcAmp::Get返回當前正在使用的值。VideoProcAmpProperty枚舉每個屬性定義的標志.
3調用IAMVideoProcAmp::Set來設置這個屬性值。設置屬性的時候,不用停止graph.
看看下面的代碼是如何調整視頻的質量的HWNDhTrackbar;//Handletothetrackbarcontrol.
//InitializehTrackbar(notshown).//QuerythecapturefilterfortheIAMVideoProcAmpinterface。
IAMVideoProcAmp*pProcAmp=0;
hr=pCap—〉QueryInterface(IID_IAMVideoProcAmp,(void**)&pProcAmp);
if(FAILED(hr))
{
//ThedevicedoesnotsupportIAMVideoProcAmp,sodisablethecontrol.
EnableWindow(hTrackbar,FALSE);
}
else
{
longMin,Max,Step,Default,Flags,Val;//Gettherangeanddefaultvalue。
hr=m_pProcAmp->GetRange(VideoProcAmp_Brightness,&Min,&Max,&Step,
&Default,&Flags);
if(SUCCEEDED(hr))
{
//Getthecurrentvalue.
hr=m_pProcAmp->Get(VideoProcAmp_Brightness,&Val,&Flags);
}
if(SUCCEEDED(hr))
{
//Setthetrackbarrangeandposition。
SendMessage(hTrackbar,TBM_SETRANGE,TRUE,MAKELONG(Min,Max));
SendMessage(hTrackbar,TBM_SETPOS,TRUE,Val);
EnableWindow(hTrackbar,TRUE);
}
else
{
//Thispropertyisnotsupported,sodisablethecontrol.
EnableWindow(hTrackbar,FALSE);
}
}
3調整視頻輸出格式
我們知道視頻流可以有多種輸出格式,一個設備可以支持16-bitRGB,32—bitRGB,andYUYV,在每一種格式下,設備還可以調整視頻楨的大小.
在WDM驅動設備上,IAMStreamConfig接口用來報告設備輸出視頻的格式的,VFW設備,可以采納對話框的方式來設置,參見前面的內容。
捕獲Filter的捕獲pin和預覽pin都支持IAMStreamConfig接口,可以通過ICaptureGraphBuilder2::FindInterface獲得IAMStreamConfig接口。IAMStreamConfig*pConfig=NULL;
hr=pBuild—〉FindInterface(
&PIN_CATEGORY_PREVIEW,//Previewpin.
0,//Anymediatype。
pCap,//Pointertothecapturefilter.
IID_IAMStreamConfig,(void**)&pConfig);
設備還支持一系列的媒體類型,對于每一個媒體類型,設備都要支持一系列的屬性,比如,楨的大小,圖像如何縮放,楨率的范圍等。
通過IAMStreamConfig::GetNumberOfCapabilities獲得設備所支持的媒體類型的數量.這個方法返回兩個值,一個是媒體類型的數量,二是屬性所需結構的大小.
這個結構的大小很重要,由于這個方法是用于視頻和音頻的,視頻采納的是VIDEO_STREAM_CONFIG_CAPS結構,音頻用AUDIO_STREAM_CONFIG_CAPS結構。
通過函數IAMStreamConfig::GetStreamCaps來枚舉媒體類型,要給這個函數傳遞一個序號作為參數,這個函數返回媒體類型和相應的屬性結構體。看代碼把intiCount=0,iSize=0;
hr=pConfig—>GetNumberOfCapabilities(&iCount,&iSize);//Checkthesizetomakesurewepassinthecorrectstructure.
if(iSize==sizeof(VIDEO_STREAM_CONFIG_CAPS)
{
//Usethevideocapabilitiesstructure。
for(intiFormat=0;iFormat〈iCount;iFormat++)
{
VIDEO_STREAM_CONFIG_CAPSscc;
AM_MEDIA_TYPE*pmtConfig;
hr=pConfig->GetStreamCaps(iFormat,&pmtConfig,(BYTE*)&scc);
if(SUCCEEDED(hr))
{
/*Examinetheformat,andpossiblyuseit.*/
//Deletethemediatypewhenyouaredone。
hr=pConfig—>SetFormat(pmtConfig);//重新設置視頻格式
DeleteMediaType(pmtConfig);
}
}
你可以調用IAMStreamConfig::SetFormat設置新的媒體類型
hr=pConfig-〉SetFormat(pmtConfig);
如果pin沒有連接,當連接的時候就試圖用新的格式,如果pin已經在連接了,它就會用的新的媒體格式重新連接.在任何一種情況下,下游的filter都有可能拒絕新的媒體格式。
在SetFormat前你可以修改VIDEO_STREAM_CONFIG_CAPS結構來重新設置媒體類型。
例如:
如果GetStreamCaps返回的是24-bitRGBformat,楨的大小是320x240像素,你可以通過檢查媒體類型的majortype,subtpye,和format等值if((pmtConfig.majortype==MEDIATYPE_Video)&&
(pmtConfig。subtype==MEDIASUBTYPE_RGB24)&&
(pmtConfig.formattype==FORMAT_VideoInfo)&&
(pmtConfig.cbFormat〉=sizeof(VIDEOINFOHEADER))&&
(pmtConfig。pbFormat!=NULL))
{
VIDEOINFOHEADER*pVih=(VIDEOINFOHEADER*)pmtConfig。pbFormat;
//pVihcontainsthedetailedformatinformation.
LONGlWidth=pVih—〉bmiHeader。biWidth;
LONGlHeight=pVih—〉bmiHeader.biHeight;
}
VIDEO_STREAM_CONFIG_CAPS結構里包含了該媒體類型的視頻長度和寬度的最大值和最小值,還有遞增的幅度值,就是每次調整視頻size的幅度,例如,設備可能返回如下的值
?MinOutputSize:160x120
?MaxOutputSize:320x240
?OutputGranularityX:8pixels(horizontalstepsize)
?OutputGranularityY:8pixels(verticalstepsize)
這樣你可以在(160,168,176,.。。304,312,320)范圍內設置寬度,在(120,128,136,..。104,112,120)。設置高度值,
圖6
如果想設置新的值,直接修改在GetStreamCaps函數中返回的值即可,pVih-〉bmiHeader。biWidth=160;
pVih—>bmiHeader。biHeight=120;
pVih—〉bmiHeader.biSizeImage=DIBSIZE(pVih->bmiHeader);
然后將媒體類型傳遞給SetFormat函數,就可修改視頻格式了。
7將設備從系統中移走時的大事通知(DeviceremoveNotify)
如果用戶將一個graph正在使用的即插即用型的設備從系統中去掉,filter圖表管理器就會發送一個EC_DEVICE_LOST大事通知,如果該設備又可以使用了,filter圖表管理器就發送另外的一個EC_DEVICE_LOST通知,但是先前組建的捕獲filtergraph圖就沒法用了,用戶必須重新組建graph圖。
當系統中有新的設備添加時,dshow是不會發送任何通知的,所以,應用程序如果想要知道系統中何時添加新的設備,應用程序可以監控WM_DEVICECHANGE消息。
8從靜止圖像pin中捕獲圖片
有些照相機,攝像頭除了可以捕獲視頻流以外還可以捕獲單張的,靜止的圖片。通常,靜止的圖片的質量要比流的質量要高。攝像頭一般都一個按鈕來觸發,或者是支持軟件觸發。支持輸出靜態圖片的攝像頭一般都要供應一個靜態圖片pin,這個pin的種類是PIN_CATEGORY_STILL。
從設備中獵取靜態圖片,我們一般推舉使用windowsImageAcquisition(WIA)APIs。當然,你也可以用dshow來獵取圖片.
在graph運行的時候利用IAMVideoControl::SetMode來觸發靜態的pin.代碼如下pControl->Run();//Runthegraph.
IAMVideoControl*pAMVidControl=NULL;
hr=pCap-〉QueryInterface(IID_IAMVideoControl,(void**)&pAMVidControl);
if(SUCCEEDED(hr))
{
//Findthestillpin.
IPin*pPin=0;
hr=pBuild->FindPin(pCap,PINDIR_OUTPUT,&PIN_CATEGORY_STILL,0,
FALSE,0,&pPin);
if(SUCCEEDED(hr))
{
hr=pAMVidControl—>SetMode(pPin,VideoControlFlag_Trigger);
pPin—〉Release();
}
pAMVidControl—〉Release();
}
首先向captureFilter懇求IAMVideoContol,如果支持該接口,就調用ICaptureGraphBuilder2::FindPin懇求指向靜止pin的指針,然后調用pin的put_Mode方法。
依據不同的攝像頭,你可能靜態pin連接前要render該pin。
捕獲靜態圖片常用的filter是SampleGrabberfilter,SampleGrabber使用了一個用戶定義的回調汗水來處理圖片。關于這個filter的簡略用法,參見UsingtheSampleGrabber.。
下面的例子假設靜態pin傳遞的是沒有壓縮的RGB圖片.首先定義一個類,從ISampleGrabberCB繼承。//ClasstoholdthecallbackfunctionfortheSampleGrabberfilter.
classSampleGrabberCallback:publicISampleGrabberCB
{
//Implementationisdescribedlater。
}//Globalinstanceoftheclass。
SampleGrabberCallbackg_StillCapCB;
然后將捕獲filter的靜態pin連接到SampleGrabber,將SampleGrabber連接到NullRendererfilter.NullRenderer僅僅是將她接收到的sample丟棄掉.實際的工作都是在回調函數里進行,連接NullRenderer僅僅是為了給SampleGrabber's輸出pin上連接點東西。簡略見下面的代碼//AddtheSampleGrabberfiltertothegraph。
IBaseFilter*pSG_Filter;
hr=CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void**)&pSG_Filter);
hr=pGraph—>AddFilter(pSG_Filter,L"SampleGrab”);//AddtheNullRendererfiltertothegraph。
IBaseFilter*pNull;
hr=CoCreateInstance(CLSID_NullRendere,NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void**)&pNull);
hr=pGraph->AddFilter(pSG_Filter,L"NullRender”);
然后通過RenderStream將stillpin,samplegrabber,nullRenderer連接起來hr=pBuild->RenderStream(
&PIN_CATEGORY_STILL,//Connectthispin。。。
&MEDIATYPE_Video,//withthismediatype。..
pCap,//onthisfilter。.。
pSG_Filter,//totheSampleGrabber。。.
pNull);//。.。andfinallytotheNullRenderer。
然后調用ISampleGrabber指針,來通過這個指針可以安排內存。//ConfiguretheSampleGrabber.
ISampleGrabber*pSG;
hr=pSG_Filter—>QueryInterface(IID_ISampleGrabber,(void**)&pSG);
pSG—〉SetOneShot(FALSE);
pSG—〉SetBufferSamples(TRUE);
設置你的回調對象pSG—〉SetCallback(&g_StillCapCB,0);//0=UsetheSampleCBcallbackmethod
獵取靜態pin和samplegrabber之間連接所用的媒體類型//Storethemediatypeforlateruse。
AM_MEDIA_TYPEg
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 中國安全教育試題及答案
- 浙江省樂清外國語學院2025屆物理高二第二學期期末經典試題含解析
- 重慶市開州區開州中學2025年生物高二第二學期期末質量跟蹤監視模擬試題含解析
- 浙江省杭州市名校協作體2025屆生物高二下期末復習檢測試題含解析
- 云南省耿馬縣第一中學2025屆高二數學第二學期期末統考試題含解析
- 生態小區物業管理與生態保護合同范本
- 體育館場租賃合同范本及服務條款
- 房地產項目財務擔保貸款合同風險管理協議
- 餐飲酒店與體育賽事餐飲贊助合同
- 跨境電商物流中心廠房土地租賃及倉儲服務合同
- MOOC 跨文化交際通識通論-揚州大學 中國大學慕課答案
- 有機植物生產中允許使用的投入品
- 湘教版八年級下學期數學第4章一次函數復習第1課時課件
- 會計知識大賽初賽題庫
- 廣州一模讀后續寫+Ben+打破古董花瓶【核心素養提升+備課精講精研】 高三英語寫作專項
- 上消化道出血的護理ppt
- GB/T 28799.2-2020冷熱水用耐熱聚乙烯(PE-RT)管道系統第2部分:管材
- 施工現場監控設備安裝驗收單
- 小學常用教學方法-講授法課件
- GB∕T 7543-2020 一次性使用滅菌橡膠外科手套
- 《聊齋志異》原文及翻譯
評論
0/150
提交評論