博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用DirectShow开发视频采集程序
阅读量:4149 次
发布时间:2019-05-25

本文共 23761 字,大约阅读时间需要 79 分钟。

{****************************************************************** * original by Microsoft * * CDSCapture class * * uses DirectShow and Windows Media + Vfw to capture from Hardware * * written by orthkon * www.mp3.com/orthkon * orthkon@mail.com ******************************************************************} unit DSCapture; interface uses Windows, DirectShow, ActiveX, DirectSound, Dialogs; const   IID_IPropertyBag : TGUID = '{55272A00-42CB-11CE-8135-00AA004BB851}';   WM_FGNOTIFY = $0400 + 1; type    PVIDEOINFOHEADER = ^TVIDEOINFOHEADER;    TVIDEOINFOHEADER = record     rcSource : TRECT;     rcTarget : TRECT;     dwBitRate : Cardinal;         // 波特率     dwBitErrorRate : Cardinal;    // 误码率     AvgTimePerFrame : Int64;   // 帧平均速度(100ns units)     bmiHeader : BITMAPINFOHEADER;   end;   TCapDeviceInfo = record     szName : String;     moniker : IMoniker;   end;       CDSCapture = class   public     constructor Create( handle : HWND );     destructor Destroy; override;     function Init : Boolean;     function EnumVideoDevices : String;     function EnumAudioDevices : String;     procedure ChooseDevices( szVideo, szAudio : String ); overload;   private     procedure CleanUp;     procedure BuildDeviceList;     procedure ChooseDevices( nmVideo, nmAudio : IMoniker ); overload;     function MakeBuilder : Boolean;     function MakeGraph : Boolean;     function InitCapFilters : Boolean;     function ErrMsg( szMsg : String; hr : HRESULT = 0 ) : Boolean;     procedure ResizeWindow( w, h : Integer );     procedure FreeCapFilters;     procedure NukeDownstream( pf : IBaseFilter );     procedure TearDownGraph;     function BuildPreviewGraph : Boolean;     function StartPreview : Boolean;     function StopPreview : Boolean;   end; implementation var   Graph : IGraphBuilder;   Builder : ICaptureGraphBuilder2;   VideoWindow : IVideoWindow;   MediaEvent : IMediaEventEx;   DroppedFrames : IAMDroppedFrames;   VideoCompression : IAMVideoCompression;   CaptureDialogs : IAMVfwCaptureDialogs;   AStreamConf : IAMStreamConfig;      // for audio cap   VStreamConf : IAMStreamConfig;      // for video cap   Render : IBaseFilter;   VCap : IBaseFilter;   ACap : IBaseFilter;   Sink : IFileSinkFilter;   ConfigAviMux : IConfigAviMux;   wachFriendlyName : String;   fCapAudioIsRelevant : Boolean = False;   fCapAudio : Boolean = False;   fCCAvail : Boolean = False;   fCapCC : Boolean = False;   fCaptureGraphBuilt : Boolean = False;   fPreviewGraphBuilt : Boolean = False;   fPreviewFaked : Boolean = False;   fCapturing : Boolean = False;   fPreviewing : Boolean = False;   fUseFrameRate : Boolean = False;   fWantPreview : Boolean = True;   FrameRate : double = 15;   hwOwner : HWND;   VideoDevices : array of TCapDeviceInfo;   AudioDevices : array of TCapDeviceInfo;   NumVD : Word = 0;    // 视频设备   NumAD : Word = 0;    // 音频设备   EnumVD : Word = 0;  // 当前视频设备   EnumAD : Word = 0;  // 当前音频设备   mVideo, mAudio : IMoniker;   gnRecurse : Integer; function CheckGUID( p1, p2 : TGUID ) : Boolean; var   i : Byte; begin   Result := False;   for i := 0 to 7 do if p1.D4[i] <> p2.D4[i] then Exit;   Result := ( p1.D1 = p2.D1 ) and ( p1.D2 = p2.D2 ) and ( p1.D3 = p2.D3 ); end; //  释放媒体类 (例如释放资源) procedure FreeMediaType( mt : TAM_MEDIA_TYPE ); begin   if mt.cbFormat <> 0 then begin     CoTaskMemFree( mt.pbFormat );     // Strictly unnecessary but tidier     mt.cbFormat := 0;     mt.pbFormat := nil;   end;   mt.pUnk := nil; end; procedure DeleteMediaType( pmt : PAM_MEDIA_TYPE ); begin   // 允许NULL   if pmt = nil then Exit;   FreeMediaType( pmt^ );   CoTaskMemFree( pmt ); end; // 创建采集 function CDSCapture.MakeBuilder : Boolean; begin   Result := True;   if Builder <> nil then Exit;   if CoCreateInstance( CLSID_CaptureGraphBuilder2, nil, CLSCTX_INPROC,         IID_ICaptureGraphBuilder2, Builder ) <> NOERROR then Result := False; end; // 创建graph function CDSCapture.MakeGraph : Boolean; begin   Result := True;   if Graph <> nil then Exit;   if CoCreateInstance( CLSID_FilterGraph, nil, CLSCTX_INPROC, 			       IID_IGraphBuilder, Graph ) <> NOERROR then Result := False; end; function CDSCapture.InitCapFilters : Boolean; label   InitCapFiltersFail,   SkipAudio; var   PropBag : IPropertyBag;   hr : HRESULT;   varOle : OleVariant;   //tmt : TAM_MEDIA_TYPE;   pmt : PAM_MEDIA_TYPE;   pvih : PVIDEOINFOHEADER;   Pin : IPin;   pins : IEnumPins;   n : Cardinal;   pinInfo : TPIN_INFO;   Found : Boolean; 	Ks : IKsPropertySet; 	guid : TGUID; 	dw : DWORD; 	fMatch : Boolean; begin   hr := 0;   Result := MakeBuilder;   if Result = False then begin     ErrMsg( 'Cannot instantiate graph builder' );     Exit;   end;   VCap := nil;   if mVideo <> nil then begin     hr := mVideo.BindToStorage( nil, nil, IID_IPropertyBag, PropBag );     if Succeeded( hr ) then begin       PropBag.Read( 'FriendlyName', varOle, nil );       if hr = NOERROR then wachFriendlyName := varOle;       PropBag := nil;     end;     hr := mVideo.BindToObject( nil, nil, IID_IBaseFilter, VCap );   end;   if VCap = nil then begin    ErrMsg( 'Error %x: Cannot create video capture filter', hr );    goto InitCapFiltersFail;   end;   //   // 创建filtergraph, 付给构造对象连接视频   // 采集Filter   //   Result := MakeGraph;   if Result = False then begin     ErrMsg( 'Cannot instantiate filtergraph' );     goto InitCapFiltersFail;   end;   hr := Builder.SetFiltergraph( Graph );   if hr <> NOERROR then begin    ErrMsg( 'Cannot give graph to builder' ); 	  goto InitCapFiltersFail;   end;   hr := Graph.AddFilter( VCap, nil );   if hr <> NOERROR then begin    ErrMsg( 'Error %x: Cannot add vidcap to filtergraph', hr ); 	  goto InitCapFiltersFail;   end;   // 调用FindInterface,确定流的源(如WDM TVTuners或Crossbars)   // 用于得到驱动程序名称,端口连接前此界面可能无效   //或根本无法调用   hr := Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Interleaved, 		    VCap, @IID_IAMVideoCompression, VideoCompression );   if hr <> S_OK then begin     Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Video, 		    VCap, @IID_IAMVideoCompression, VideoCompression );   end;    // 设置帧速率和采集尺寸   hr := Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Interleaved, 			VCap, @IID_IAMStreamConfig, VStreamConf );   if hr <> NOERROR then begin     hr := Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Video,         VCap,	@IID_IAMStreamConfig, VStreamConf );     if hr <> NOERROR then begin 	    // this means we can't set frame rate (non-DV only) 	    ErrMsg( 'Error %x: Cannot find VCapture:IAMStreamConfig', hr );    end;   end;   fCapAudioIsRelevant := True;   // 缺省采集格式   if ( VStreamConf <> nil ) and ( VStreamConf.GetFormat( pmt ) = S_OK ) then begin     // DV capture 不使用VIDEOINFOHEADER    if CheckGUID( pmt^.formattype, FORMAT_VideoInfo ) then begin       // 窗口大小调整       gnRecurse := 0;       pvih := pmt.pbFormat;       ResizeWindow( pvih^.bmiHeader.biWidth, abs( pvih^.bmiHeader.biHeight ) ); 	  end; 	  if not CheckGUID( pmt^.majortype, MEDIATYPE_Video ) then begin 	    // 此采集filter 采集其他视频.       fCapAudioIsRelevant := False;       fCapAudio := False; 	  end;     DeleteMediaType( pmt );   end;   // 显示对话框   // NOTE:  仅VFW支持   Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Video,     VCap, @IID_IAMVfwCaptureDialogs, CaptureDialogs );   Found := False;   fMatch := False;   Pin := nil;   if Succeeded( VCap.EnumPins( pins ) ) then begin     while not Found and ( S_OK = pins.Next( 1, pin, n ) ) do begin       if S_OK = pin.QueryPinInfo( pinInfo ) then begin         if pinInfo.dir = PINDIR_INPUT then begin 			    // ANALOGVIDEOIN input pin?        if pin.QueryInterface( IID_IKsPropertySet, Ks ) = S_OK then begin          if Ks.Get( AMPROPSETID_Pin, 0, nil, 0,          @guid, sizeof( TGUID ), dw ) = S_OK then begin           if CheckGuid( guid, PIN_CATEGORY_ANALOGVIDEOIN ) then fMatch := True;             end; 			      Ks := nil;        end;        if fMatch then begin             Found := TRUE;        end;         end;         pinInfo.pFilter := nil;       end;       pin := nil;     end;     pins := nil;   end;   // there's no point making an audio capture filter   if fCapAudioIsRelevant = False then	goto SkipAudio;   // 创建音频采集filter, 尽管可能用不到   if mAudio = nil then begin    // 不采集音频 	  fCapAudio := FALSE; 	  goto SkipAudio;   end;   ACap := nil;   mAudio.BindToObject( nil, nil, IID_IBaseFilter, ACap );   if ACap = nil then begin    // 不采集音频 	  fCapAudio := FALSE; 	  ErrMsg( 'Cannot create audio capture filter' ); 	  goto SkipAudio;   end;   //   // 放置音频插件   //   hr := Graph.AddFilter( ACap, nil );   if hr <> NOERROR then begin     ErrMsg( 'Error %x: Cannot add audcap to filtergraph', hr );     goto InitCapFiltersFail;   end;   // Calling FindInterface below will result in building the upstream   // section of the capture graph (any WDM TVAudio's or Crossbars we might   // need).   // !!! What if this interface isn't supported?   // we use this interface to set the captured wave format   hr := Builder.FindInterface( @PIN_CATEGORY_CAPTURE, @MEDIATYPE_Audio, 			ACap, @IID_IAMStreamConfig, AStreamConf );   if hr <> NOERROR then begin     ErrMsg( 'Cannot find ACapture:IAMStreamConfig' );   end; SkipAudio:   // Can this filter do closed captioning?   FillChar( guid, SizeOf( TGUID ), 0 );   hr := Builder.FindPin( VCap, PINDIR_OUTPUT, @PIN_CATEGORY_VBI, nil, FALSE, 0, Pin);   if hr <> S_OK then hr := Builder.FindPin( VCap, PINDIR_OUTPUT, @PIN_CATEGORY_CC,	nil, FALSE, 0, Pin );   if hr = S_OK then begin    Pin := nil;    fCCAvail := TRUE;   end else fCapCC := FALSE;	// can't capture it, then   // potential debug output - what the graph looks like   // DumpGraph(gcap.pFg, 1);   Result := TRUE;   Exit; InitCapFiltersFail:   FreeCapFilters;   Result := False;   Exit; end; // build the preview graph! // // !!! PLEASE NOTE !!!  Some new WDM devices have totally separate capture // and preview settings.  An application that wishes to preview and then // capture may have to set the preview pin format using IAMStreamConfig on the // preview pin, and then again on the capture pin to capture with that format. // In this sample app, there is a separate page to set the settings on the // capture pin and one for the preview pin.  To avoid the user // having to enter the same settings in 2 dialog boxes, an app can have its own // UI for choosing a format (the possible formats can be enumerated using // IAMStreamConfig) and then the app can programmatically call IAMStreamConfig // to set the format on both pins. // function CDSCapture.BuildPreviewGraph : Boolean; var   cy, cyBorder : Integer;   hr : HRESULT;   pmt : PAM_MEDIA_TYPE;   rc : TRect;   pvih : PVIDEOINFOHEADER; begin   // we have one already   if fPreviewGraphBuilt then begin     Result := True;     Exit;   end; 	Result := False;   // No rebuilding while we're running   if fCapturing or fPreviewing then Exit;   // We don't have the necessary capture filters   if VCap = nil then Exit;   if ( ACap = nil ) and fCapAudio then Exit;   // we already have another graph built... tear down the old one   if fCaptureGraphBuilt then TearDownGraph;   //   // Render the preview pin - even if there is not preview pin, the capture   // graph builder will use a smart tee filter and provide a preview.   //   // !!! what about latency/buffer issues?   // NOTE that we try to render the interleaved pin before the video pin, because   // if BOTH exist, it's a DV filter and the only way to get the audio is to use   // the interleaved pin.  Using the Video pin on a DV filter is only useful if   // you don't want the audio.   hr := Builder.RenderStream( @PIN_CATEGORY_PREVIEW, @MEDIATYPE_Interleaved, VCap, nil, nil );   if hr = VFW_S_NOPREVIEWPIN then begin    // preview was faked up for us using the (only) capture pin 	  fPreviewFaked := TRUE;   end else if hr <> S_OK then begin    // maybe it's DV?     hr := Builder.RenderStream( @PIN_CATEGORY_PREVIEW, @MEDIATYPE_Video, VCap, nil, nil );     if hr = VFW_S_NOPREVIEWPIN then begin 	    // preview was faked up for us using the (only) capture pin 	    fPreviewFaked := TRUE;     end else if hr <> S_OK then begin 	    ErrMsg( 'This graph cannot preview!' );     end;   end;   //   // Render the closed captioning pin? It could be a CC or a VBI category pin,   // depending on the capture driver   //   if fCapCC then begin    hr := Builder.RenderStream( @PIN_CATEGORY_CC, nil, VCap, nil, nil ); 	  if hr <> NOERROR then begin       hr := Builder.RenderStream( @PIN_CATEGORY_VBI, nil, VCap, nil, nil ); 	    if hr <> NOERROR then begin         ErrMsg( 'Cannot render closed captioning' );         // so what? goto SetupCaptureFail;       end;     end;   end;   //   // Get the preview window to be a child of our app's window   //   // This will find the IVideoWindow interface on the renderer.  It is   // important to ask the filtergraph for this interface... do NOT use   // ICaptureGraphBuilder2::FindInterface, because the filtergraph needs to   // know we own the window so it can give us display changed messages, etc.   hr := Graph.QueryInterface( IID_IVideoWindow, VideoWindow );   if hr <> NOERROR then begin    ErrMsg( 'This graph cannot preview properly' );   end else begin 	  VideoWindow.put_Owner( hwOwner );    // We own the window now    VideoWindow.put_WindowStyle( WS_CHILD );    // you are now a child 	  // give the preview window all our space but where the status bar is    GetClientRect( hwOwner, rc ); 	  cyBorder := GetSystemMetrics( SM_CYBORDER );    cy := cyBorder;// + statusGetHeight(); 	  rc.bottom := rc.bottom - cy;    VideoWindow.SetWindowPosition( 0, 0, rc.right, rc.bottom ); // be this big 	  VideoWindow.put_Visible( TRUE );   end;   // now tell it what frame rate to capture at.  Just find the format it   // is capturing with, and leave everything alone but change the frame rate   // No big deal if it fails.  It's just for preview   // !!! Should we then talk to the preview pin?   if ( VStreamConf <> nil ) and fUseFrameRate then begin    hr := VStreamConf.GetFormat( pmt ); 	  // DV capture does not use a VIDEOINFOHEADER     if hr = NOERROR then begin       if CheckGuid( pmt^.formattype, FORMAT_VideoInfo ) then begin         pvih := pmt^.pbFormat;        pvih^.AvgTimePerFrame := round( 10000000 / FrameRate ); 	      hr := VStreamConf.SetFormat( pmt^ ); 		    if hr <> NOERROR then ErrMsg( '%x: Cannot set frame rate for preview', hr );       end;       DeleteMediaType( pmt );    end;   end;   // make sure we process events while we're previewing!   hr := Graph.QueryInterface( IID_IMediaEventEx, MediaEvent );   if hr = NOERROR then begin     MediaEvent.SetNotifyWindow( hwOwner, WM_FGNOTIFY, 0 );   end;   // All done.   // potential debug output - what the graph looks like   // DumpGraph(gcap.pFg, 1);   fPreviewGraphBuilt := TRUE;   Result := True; end; // Start previewing // function CDSCapture.StartPreview : Boolean; var   MC : IMediaControl;   hr : HRESULT; begin   // way ahead of you   if fPreviewing then begin     Result := True;     Exit;   end;   Result := False;   if not fPreviewGraphBuilt then Exit;   // run the graph   hr := Graph.QueryInterface( IID_IMediaControl, MC );   if Succeeded( hr ) then begin    hr := MC.Run; 	  if FAILED( hr ) then begin 	    // stop parts that ran 	    MC.Stop;    end; 	  MC := nil;   end;   if FAILED( hr ) then begin 	  ErrMsg( 'Error %x: Cannot run preview graph', hr ); 	  Exit;   end;   fPreviewing := TRUE;   Result := True; end; // stop the preview graph // function CDSCapture.StopPreview : Boolean; var   MC : IMediaControl;   hr : HRESULT; begin   Result := False;   // way ahead of you   if not fPreviewing then Exit;   // stop the graph   MC := nil;   if Graph <> nil then begin     hr := Graph.QueryInterface( IID_IMediaControl, MC );     if SUCCEEDED( hr ) then begin      hr := MC.Stop; 	    MC := nil;     end;     if FAILED( hr ) then begin      ErrMsg( 'Error %x: Cannot stop preview graph', hr ); 	    Exit;     end;   end;   fPreviewing := FALSE;   // !!! get rid of menu garbage   InvalidateRect( hwOwner, nil, TRUE );   Result := TRUE; end; // Tear down everything downstream of a given filter procedure CDSCapture.NukeDownstream( pf : IBaseFilter ); var   pP, pTo : IPin;   u : Cardinal;   pins : IEnumPins;   pininfo : TPIN_INFO;   hr : HRESULT; begin   //DbgLog((LOG_TRACE,1,TEXT("Nuking...")));   pins := nil;   hr := pf.EnumPins( pins );   pins.Reset;   while hr = NOERROR do begin     hr := pins.Next( 1, pP, u );    if ( hr = S_OK ) and ( pP <> nil ) then begin 	    pP.ConnectedTo( pTo ); 	    if pTo <> nil then begin         hr := pTo.QueryPinInfo( pininfo );         if hr = NOERROR then begin         if pininfo.dir = PINDIR_INPUT then begin 		        NukeDownstream( pininfo.pFilter ); 		        Graph.Disconnect( pTo ); 		        Graph.Disconnect( pP );             Graph.RemoveFilter( pininfo.pFilter ); 		      end;           pininfo.pFilter := nil;         end;         pTo := nil;       end;       pP := nil;     end;   end;   pins := nil; end; // Tear down everything downstream of the capture filters, so we can build // a different capture graph.  Notice that we never destroy the capture filters // and WDM filters upstream of them, because then all the capture settings // we've set would be lost. // procedure CDSCapture.TearDownGraph; begin   Sink := nil;   ConfigAviMux := nil;   Render := nil;   if VideoWindow <> nil then begin    // stop drawing in our window, or we may get wierd repaint effects 	  VideoWindow.put_Owner( 0 );    VideoWindow.put_Visible( FALSE );   end;   VideoWindow := nil;   MediaEvent := nil;   DroppedFrames := nil;   // destroy the graph downstream of our capture filters   if VCap <> nil then NukeDownstream( VCap );   if ACap <> nil then	NukeDownstream( ACap );   // potential debug output - what the graph looks like   // if (gcap.pFg) DumpGraph(gcap.pFg, 1);   fCaptureGraphBuilt := FALSE;   fPreviewGraphBuilt := FALSE;   fPreviewFaked := FALSE; end; // all done with the capture filters and the graph builder // procedure CDSCapture.FreeCapFilters; begin   Graph := nil;   Builder := nil;   VCap := nil;   ACap := nil;   AStreamConf := nil;   VStreamConf := nil;   VideoCompression := nil;   CaptureDialogs := nil; end; // make sure the preview window inside our window is as big as the // dimensions of captured video, or some capture cards won't show a preview. // (Also, it helps people tell what size video they're capturing) // We will resize our app's window big enough so that once the status bar // is positioned at the bottom there will be enough room for the preview // window to be w x h // procedure CDSCapture.ResizeWindow( w, h : Integer ); var   rcW, rcC : TRECT;   cyBorder, xExtra, yExtra : Integer; begin     cyBorder := GetSystemMetrics( SM_CYBORDER );     gnRecurse := gnRecurse + 1;     GetWindowRect( hwOwner, rcW );     GetClientRect( hwOwner, rcC );     xExtra := rcW.right - rcW.left - rcC.right;     yExtra := rcW.bottom - rcW.top - rcC.bottom + cyBorder;// + statusGetHeight();     rcC.right := w;     rcC.bottom := h;     SetWindowPos( hwOwner, 0, 0, 0, rcC.right + xExtra, rcC.bottom + yExtra, SWP_NOZORDER or SWP_NOMOVE );     // we may need to recurse once.  But more than that means the window cannot     // be made the size we want, trying will just stack fault.     //     if gnRecurse = 1 then     if ( ( rcC.right + xExtra <> rcW.right - rcW.left ) and ( w > GetSystemMetrics( SM_CXMIN ) ) )     or ( rcC.bottom + yExtra <> rcW.bottom - rcW.top ) then ResizeWindow( w, h );     gnRecurse := gnRecurse - 1; end; function CDSCapture.EnumVideoDevices : String; begin   if EnumVD < NumVD then begin     Result := VideoDevices[EnumVD].szName;     EnumVD := EnumVD + 1;   end else begin     Result := ';     EnumVD := 0;   end; end; function CDSCapture.EnumAudioDevices : String; begin   if EnumAD < NumAD then begin     Result := AudioDevices[EnumAD].szName;     EnumAD := EnumAD + 1;   end else begin     Result := ';     EnumAD := 0;   end; end; procedure CDSCapture.ChooseDevices( nmVideo, nmAudio : IMoniker ); begin   if ( mVideo <> nmVideo ) or ( mAudio <> nmAudio ) then begin     if nmVideo <> nil then nmVideo._AddRef;     if nmAudio <> nil then nmAudio._AddRef;     mVideo := nil;     mAudio := nil;     mVideo := nmVideo;     mAudio := nmAudio;     if fCaptureGraphBuilt or fPreviewGraphBuilt then TearDownGraph;     FreeCapFilters;     InitCapFilters;     if fWantPreview then begin       BuildPreviewGraph;       StartPreview;     end;   end; end; procedure CDSCapture.ChooseDevices( szVideo, szAudio : String ); var   nmVideo, nmAudio : IMoniker;   i : Word; begin   nmVideo := nil;   nmAudio := nil;   if szVideo <> ' then if szVideo[1] = '&' then szVideo := Copy( szVideo, 2, Length( szVideo ) - 1 );   if szAudio <> ' then if szAudio[1] = '&' then szAudio := Copy( szAudio, 2, Length( szAudio ) - 1 );   i := 0;   while i < NumVD do begin     if VideoDevices[i].szName = szVideo then nmVideo := VideoDevices[i].moniker;     i := i + 1;   end;   i := 0;   while i < NumAD do begin     if AudioDevices[i].szName = szAudio then nmAudio := AudioDevices[i].moniker;     i := i + 1;   end;   ChooseDevices( nmVideo, nmAudio );   nmVideo := nil;   nmAudio := nil; end; procedure CDSCapture.BuildDeviceList; var   SysDevEnum : ICreateDevEnum;   EnumCat : IEnumMoniker;   Moniker : IMoniker;   cFetched : Longint;   PropBag : IPropertyBag;   varName : OleVariant; begin   SysDevEnum := nil;   CoCreateInstance( CLSID_SystemDeviceEnum, nil, CLSCTX_INPROC, IID_ICreateDevEnum, SysDevEnum );   //SysDevEnum.CreateClassEnumerator( CLSID_VideoCompressorCategory, EnumCat, 0 );   // enum available video capture devices   EnumCat := nil;   SysDevEnum.CreateClassEnumerator( CLSID_VideoInputDeviceCategory, EnumCat, 0 );   while EnumCat.Next( 1, Moniker, @cFetched ) = S_OK do begin     Moniker.BindToStorage( nil, nil, IID_IPropertyBag, PropBag );     PropBag.Read( 'FriendlyName', varName, nil );     NumVD := NumVD + 1;     SetLength( VideoDevices, NumVD );     VideoDevices[NumVD-1].szName := varName;     VideoDevices[NumVD-1].moniker := Moniker;     PropBag := nil;     Moniker := nil;   end;   // enum available audio capture devices   EnumCat := nil;   SysDevEnum.CreateClassEnumerator( CLSID_AudioInputDeviceCategory, EnumCat, 0 );   while EnumCat.Next( 1, Moniker, @cFetched ) = S_OK do begin     Moniker.BindToStorage( nil, nil, IID_IPropertyBag, PropBag );     PropBag.Read( 'FriendlyName', varName, nil );     NumAD := NumAD + 1;     SetLength( AudioDevices, NumAD );     AudioDevices[NumAD-1].szName := varName;     AudioDevices[NumAD-1].Moniker := Moniker;     PropBag := nil;     Moniker := nil;   end;   EnumCat := nil;   SysDevEnum := nil; end; function CDSCapture.Init : Boolean; begin   Result := False;   // Create the filter graph.   if CoCreateInstance( CLSID_FilterGraph, nil, CLSCTX_INPROC,     IID_IGraphBuilder, Graph ) <> S_OK then Exit;   // Create the capture graph builder.   if CoCreateInstance( CLSID_CaptureGraphBuilder2, nil, CLSCTX_INPROC,     IID_ICaptureGraphBuilder2, Builder ) <> S_OK then Exit;   Builder.SetFiltergraph( Graph );   BuildDeviceList;   Result := ( NumVD > 0 ) or ( NumAd > 0 ); end; function CDSCapture.ErrMsg( szMsg : String; hr : HRESULT = 0 ) : Boolean; begin   MessageBox( GetForegroundWindow, PChar( szMsg ), 'DirectShow - Capture', MB_OK or MB_ICONSTOP );   Result := False; end; procedure CDSCapture.CleanUp; begin   Graph := nil;   Builder := nil;   VideoWindow := nil;   MediaEvent := nil;   DroppedFrames := nil;   VideoCompression := nil;   CaptureDialogs := nil;   AStreamConf := nil;   VStreamConf := nil;   Render := nil;   VCap := nil;   ACap := nil;   Sink := nil;   ConfigAviMux := nil; end; constructor CDSCapture.Create( handle : HWND ); begin   CleanUp;   hwOwner := handle; end; destructor CDSCapture.Destroy; begin   StopPreview;   CleanUp; end; end.

转载地址:http://lrsti.baihongyu.com/

你可能感兴趣的文章
rootkit related
查看>>
配置文件的重要性------轻化操作
查看>>
又是缓存惹的祸!!!
查看>>
为什么要实现程序指令和程序数据的分离?
查看>>
我对C++ string和length方法的一个长期误解------从protobuf序列化说起(没处理好会引起数据丢失、反序列化失败哦!)
查看>>
一起来看看protobuf中容易引起bug的一个细节
查看>>
无protobuf协议情况下的反序列化------貌似无解, 其实有解!
查看>>
make -n(仅列出命令, 但不会执行)用于调试makefile
查看>>
makefile中“-“符号的使用
查看>>
go语言如何从终端逐行读取数据?------用bufio包
查看>>
go的值类型和引用类型------重要的概念
查看>>
求二叉树中结点的最大值(所有结点的值都是正整数)
查看>>
用go的flag包来解析命令行参数
查看>>
来玩下go的http get
查看>>
队列和栈的本质区别
查看>>
matlab中inline的用法
查看>>
如何用matlab求函数的最值?
查看>>
Git从入门到放弃
查看>>
java8采用stream对集合的常用操作
查看>>
EasySwift/YXJOnePixelLine 极其方便的画出真正的一个像素的线
查看>>