This program is used in front of a function in an article. These functions have been given in the articles in front, and no longer narrate here. The following is given from the source code and some simple comments.
// videocap1dlg.h: header file ----------------------------- //
#pragma overce # include "afxwin.h"
#include "dshowutilities.h"
// cvideocap1dlg dialog class cvideocap1dlg: public cdialog {// Construction public: cvideocap1dlg (cwnd * pparent = null); // Standard constructor
// Dialog Box Data ENUM {IDD = IDD_VIDEOCAP1_DIALOG};
Protected: Virtual Void DodataExchange (CDataExchange * PDX); // DDX / DDV Support
// Realize Protected: hicon m_hicon;
// message mapping function generated virtual BOOL OnInitDialog (); afx_msg void OnSysCommand (UINT nID, LPARAM lParam); afx_msg void OnPaint (); afx_msg HCURSOR OnQueryDragIcon (); DECLARE_MESSAGE_MAP () public: // Obviously, this is a Real-time display video stream window cstatic m_videoWindow; // Remote function AFX_MSG BOOL OneRaseBkGnd (CDC * PDC); // Some properties for setting display, etc. IvideoWindow * m_pvidwin; AFX_MSG void OnbnclickedPreview (); // on the created filter graph for controlling, i.e. stop, run and pause IGraphBuilder * m_pGraph; // capture the video stream, they can easily generate fiter graph ICaptureGraphBuilder2 * m_pGraphBuilder2; afx_msg void OnBnClickedSaveGrf (); // Since the program In the preview, it can be captured, and the settings of the two variables below, indicating what models that are now created now, and the model of Filter Graph Bool M_FCapturegraphBuill; Bool M_FPREVIEWGRAPHBUILT; // The Capture Filter IBaseFilter * m_PVCAP; IBASEFILTER * m_pMux; // indicate what kind of work is now in a state bool m_fCapturing; bool m_fPreviewing; IMediaControl * m_pMediaControl; // we use this interface to set the frame rate and get the capture size IAMStreamConfig * m_pVSC; afx_msg void OnClose (); afx_msg Void onbnclickedcapture (); ifilesinkfilter * m_psink; iConfigavimux * m_pconfigavimu X; AFX_MSG void OnbnclickedButton1 (); // In order to release resources, it is convenient to add this function void ReleaseFilter (void); AFX_MSG void OnbnclickedSetPin ();
// VideoCap1dlg.cpp: Implement file ------------------- //
CVideoCap1Dlg :: CVideoCap1Dlg (CWnd * pParent / * = NULL * /): CDialog (CVideoCap1Dlg :: IDD, pParent), m_pVidWin (NULL), m_pGraph (NULL), m_pGraphBuilder2 (NULL), m_fCaptureGraphBuilt (false), m_fPreviewGraphBuilt (false) , m_pVCap (NULL), m_fCapturing (false), m_fPreviewing (false), m_pMediaControl (NULL), m_pVSC (NULL), m_pSink (NULL), m_pMux (NULL), m_pConfigAviMux (NULL) {m_hIcon = AfxGetApp () -> LoadIcon ( IDR_MAINFRAME);} void cvideoCap1dlg :: DODATAEXCHANGE (CDATAEXCHANGE * PDX) {cdialog :: DODATAEXCHANGE (PDX); DDX_Control (PDX, IDC_Video_Window, M_VideoWindow);
In the following functions, enumerate the video stream capture device in the system and established a Filter Graph for preview. Maybe I should separate these code separately. Here is when enumerating the video stream capture equipment, just getting the first device.
Bool cvideocap1dlg :: oninitdialog () {cdialog :: oninitdialog ();
// Add / "About ... /" menu item to the system menu.
// IDM_Aboutbox must be within the system command range. Assert (IDM_ABOUTBOX & 0xFFF0) == idm_aboutbox); assert (IDM_aboutbox <0xf000);
CMenu * pSysMenu = GetSystemMenu (FALSE); if (pSysMenu = NULL!) {CString strAboutMenu; strAboutMenu.LoadString (IDS_ABOUTBOX); if {pSysMenu-> AppendMenu (MF_SEPARATOR) (strAboutMenu.IsEmpty ()!); PSysMenu-> AppendMenu ( MF_String, IDM_AboutBox, Straboutmenu);}}
/ / Set the icon of this dialog. When the application main window is not a dialog, the framework will automatically / / perform this SETICON (M_HICON, TRUE); // Set large icon seticon (m_hicon, false); // Set small icon
// Todo: Add additional initialization code here
// Initialize The CORARY. CoinitializeEx (Null, Coinit_ApartmentThread;
// Create The filter graph Manager. HRESULT HR; HR = COCREATEINSTANCE (CLSID_FILTERGRAPH, NULL, CLSCTX_INPROC_SERVER, IID_IGRAPHBUILDER, (Void **) & m_pgraph);
if (SUCCEEDED (hr)) {// Create the Capture Graph Builder hr = CoCreateInstance (CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **) & m_pGraphBuilder2);. m_pGraphBuilder2-> SetFiltergraph (m_pGraph); if (SUCCEEDED (hr) ) {AFXMessageBox (Text ("m_pgraph success"));} else afxMessageBox (Text ("m_pgraph failed");}; // The following starts the device enumeration! ! ! NEED more NOTICE
/ / -------------------------------------------------------------------------------------------- --------------------------- // ENUMERATE All Video Capture Devices
// Create the System Device Enumerator ICreateDevEnum * pCreateDevEnum = 0;. Hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **) & pCreateDevEnum); if (! Hr = NOERROR) {AfxMessageBox (TEXT ( "Error Creating Device ENUMERATOR "); RETURN FALSE;
// Create an enumerator for the video capture category IEnumMoniker * pEnum = 0; hr = pCreateDevEnum-> CreateClassEnumerator (CLSID_VideoInputDeviceCategory, & pEnum, 0); if (! Hr = NOERROR) {AfxMessageBox (TEXT ( "Sorry, you have no video capture Hardware./r/n/r/n ") Text (" Video Capture Will NOT FUNCTION ProPerly. ")); Return False;}
IMONIKER * PMONIKER; IF (Penum-> Next (1, & PMoniker, NULL) == S_OK) // Just Get The first One {
HR = PMoniker-> BindToobject (0, 0, IID_IBASEFILTER, (Void **) & m_pvcap; if (successded (HR)) {hr = m_pgraph-> addfilter (M_PVCAP, L "Capture Filter"); if (succeeded (HR) )) AFXMessageBox ("Add Capture Filter to the Filter Graph Success"));} if (successded (HR)) {AFXMESSAGEBOX (Text ("Device Init Success"));}} PMoniker-> Release (); / / Since we're embedding video in a child window of a dialog, // we must set the WS_CLIPCHILDREN style to prevent the bounding // rectangle from drawing over our video frames. // // Neglecting to set this style can lead to situations When the video // is ERASED and replaced with the default color of the bounding rectangle. m_videoWindow.ModifyStyle (0, ws_clipchildren); return true; // Returns true} unless the focus of the control is set, otherwise returns true}
The following functions are required, otherwise the window will generate problems
BOOL CVideoCap1Dlg :: OnEraseBkgnd (CDC * pDC) {// TODO: add this message handler code, and / or calling the default value CRect rc; m_VideoWindow.GetWindowRect (& rc); ScreenToClient (& rc); pDC-> ExcludeClipRect (& rc) Return CDialog :: OneRaseBkGnd (PDC);
The following function is to create a filter graph for preview, and set the preview window position. At the beginning, it is necessary to judge whether it is already preview, or is capturing, then there is a different reaction, such as clearing the capture image for capture images, newly built your own Fiter Graph, or returned directly.
Void cvideoCap1dlg :: OnbnclickedPreview () {// Todo: Add control notification handler code HRESULT HR = 0; AM_MEDIA_TYPE * PMT;
If (! m_fpreviewgraphbuilt) // if not have one the could build one {// no rebuilding while we're running // If you click on the Preview button // Although the user can do when Capture is in CAPTURE Preview, but in the preview, it is also collected // If you click Preview, let him preview, stop Capture. if (m_fCapturing) {m_pMediaControl-> Stop (); m_fCapturing = FALSE;} // We do not have the necessary capture filters if (m_pVCap == NULL) return; // we already have another graph built ... tear down the old one if (m_fCaptureGraphBuilt) {:: TearDownGraph (m_pGraph, m_pVidWin, m_pVCap); m_fCaptureGraphBuilt = FALSE;} // following this statement is automatically generates a filter graph hr = m_pGraphBuilder2- from Source filter> RenderStream (& PIN_CATEGORY_PREVIEW , & MEDIATYPE_Video, m_pVCap, NULL, NULL); if (SUCCEEDED (hr)) {AfxMessageBox (TEXT ( "preview graph build success"));} else AfxMessageBox (TEXT ( "preview graph build failed")); // - -------------------------------------------------- ---------------------- // Set updatedata (TRUE) for video preview; m_fpreviewgraphbuilt = true; // successfully created Preview Filter GRAPH
/ / -------------------------------------------------------------------------------------------- ---------------------- // Get the Media Control Object. Hr = m_pgraph-> queryinterface (IID_IMEDIACONTROL, (VOID **) & m_pmediacontrol; if (successded) (HR)) {AFXMessageBox (Text ("m_pcontrol success")));} else afxMessageBox (Text ("M_PControl Failed"); // Start running Filter Graph
m_pmediacontrol-> run (); m_fpreviewing = true;
/ / -------------------------------------------------------------------------------------------- --------------------- // show out in the screen, make some settings, make the captured image can be displayed // setting the video window, // pay attention These settings must be set after the Filter Graph created, otherwise it is not hr = m_pgraph-> queryinterface (IID_IVideoWindow, (Void **) & m_pvidwin; if (successdeded (HR)) {hr = m_pvidwin-> Put_owner ((OAHWND) ) m_VideoWindow.GetSafeHwnd ()); if (SUCCEEDED (hr)) {// The video window must have the WS_CHILD style hr = m_pVidWin-> put_WindowStyle (WS_CHILD); // Read coordinates of video container window RECT rc; m_VideoWindow.GetClientRect (& rc); Long width = rc.right - rc.left; long height = rc.bottom - rc.top; // ignore the video's original size and stretch to fit bound rectangle hr = m_pvidwin-> setWindowPosition (rc.left, Rc.top, width, height; m_pvidwin-> put_visible (oatrue);}}}
The following function is used to construct a Filter Graph that is captured by the video stream, as in the case mentioned above, if there is already a Filter Graph that does not meet the requirements, then delete it first, then build new.
Void cvideoCap1dlg :: OnbnclickedCapture () {// Todo: Add control notification handler code HRESULT HR; am_media_type * pmt = 0;
// we have one already // m_fCaptureGraphBuilt m_fPreviewGraphBuilt and only one of them is TRUE if (m_fCaptureGraphBuilt) {if (m_fCapturing!) {M_pMediaControl-> Run (); m_fCapturing = TRUE;} return;}
// no rebuilding while we're running {m_pMediacontrol-> stop (); m_fprevious = false;}
/ / Remove the old Filter Graph
IF (m_fpreviewgraphbuilt) {:: teardowngraph (m_pgraph, m_pvidwin, m_pvcap); m_fpreviewgraphbuilt = false;}
// Set the place for saving files CFiledialog DLG (TRUE); if (DLG.Domodal () == iDok) {wchar wfilename [Max_Path]; MultibyTetowideChar (CP_ACP, 0, DLG.GetPathName (), -1, wfilename, max_path) ; hr = m_pGraphBuilder2-> SetOutputFileName (& MEDIASUBTYPE_Avi, wFileName, & m_pMux, & m_pSink); if (hr = NOERROR!) {AfxMessageBox (TEXT ( "Can not set output file")); return;} hr = m_pMux-> QueryInterface (IID_IConfigAviMux , (void **) & m_pConfigAviMux); if ((hr == NOERROR) && (m_pConfigAviMux)) {m_pConfigAviMux-> SetOutputCompatibilityIndex (TRUE);} // capture strand stream hr = m_pGraphBuilder2-> RenderStream (& PIN_CATEGORY_CAPTURE, & MEDIATYPE_Video, m_pVCap, NULL, M_PMUX); if (hr! = Noerror) {AFXMessageBox (Text ("Can not Render Capture Stream");} m_fcapturegraphbuilt = true;
// The following is the establishment of a video preview link
HR = m_pgraphbuilder2-> renderstream (& pin_category_preview, & mediatype_video, m_pvcap, null, null); if (Failed (HR)) {AFXMessageBox (Text ("CAN NOT RENDER Preview Stream");}
// Get the Media Control Object. Because the Filter Graph is re-established, it is. . . hr = m_pGraph-> QueryInterface (IID_IMediaControl, (void **) & m_pMediaControl); if (SUCCEEDED (hr)) {AfxMessageBox (TEXT ( "m_pControl success"));} else AfxMessageBox (TEXT ( "m_pControl failed"));
M_PMediaControl-> run (); m_fcapturing = TRUE;
/ / -------------------------------------------------------------------------------------------- --------------------- // show out in the screen, make some settings, make the captured image can be displayed // setting the video hr = m_pgraph- > QueryInterface (IID_IVideoWindow, (void **) & m_pVidWin); if (SUCCEEDED (hr)) {hr = m_pVidWin-> put_Owner ((OAHWND) m_VideoWindow.GetSafeHwnd ()); if (SUCCEEDED (hr)) {// The video window must have the WS_CHILD style hr = m_pVidWin-> put_WindowStyle (WS_CHILD); // Read coordinates of video container window RECT rc; m_VideoWindow.GetClientRect (& rc); long width = rc.right - rc.left; long height = rc. bottom - rc.top; // Ignore the video's original size and stretch to fit bounding rectangle hr = m_pVidWin-> SetWindowPosition (rc.left, rc.top, width, height); m_pVidWin-> put_Visible (OATRUE);}}} } The following function is used to display the property page of the Source Filter, through this property page, you can modify it directly.
Void cvideoCap1dlg :: OnbnclickedButton1 () // Open the property page of the setting of the Capture Filter {// Todo: Add control notification handler code
CWnd tt; tt.getactiveWindow ();
ISpecifyPropertyPages * pProp; HRESULT hr = m_pVCap-> QueryInterface (IID_ISpecifyPropertyPages, (void **) & pProp); if (SUCCEEDED (hr)) {// Get the filter's name and IUnknown pointer FILTER_INFO FilterInfo;. Hr = m_pVCap-> QueryFilterInfo ( & Filterinfo); IUNKNOWN * Pfilterunk; M_PVCAP-> Queryinterface (IID_IUNKNOWN, (Void **) & pfilterunk);
// Show the page. Cauuid CAGUID; PPROP-> GetPages (& CAGUID); Pprop-> Release (); OlecreatePropertyFrame (tt.m_hwnd, // parent window 0, 0, // reserved filterinfo.chname, // CAPTION for THE dialog box 1, // Number of objects (just the filter) & pFilterUnk, // Array of object pointers. caGUID.cElems, // Number of property pages caGUID.pElems, // Array of property page CLSIDs 0, // Locale identifier 0, null // reserved); // clean up. Pfilterunk-> release (); filterinfo.pgraph-> release (); cotaskmemfree (caguid.plems);
The following function code is used for the opening and setting of the PIN property page.
Void cvideoCap1dlg :: OnbnclickedSetpin () {// Todo: Add control notification handler code CWND TT; tt.getActiveWindow ();
HRESULT HR; IAMSTREAMCONFIG * PSC;
// Only after stopping, the PIN property can be set.
IF (m_fcapturing || m_fpreview) {m_pmediacontrol-> stop (); if (m_fcapturing) m_fcapturing = false; if (m_fpreviewing) m_fpreviewing = false;}
if (m_fCaptureGraphBuilt || m_fPreviewGraphBuilt) {:: TearDownGraph (m_pGraph, m_pVidWin, m_pVCap); // graph could prevent dialog working if (m_fCaptureGraphBuilt) m_fCaptureGraphBuilt = FALSE; if (m_fPreviewGraphBuilt) m_fPreviewGraphBuilt = FALSE;}
HR = m_pgraphbuilder2-> FindInterface (& Pin_category_capture, & mediatype_video, m_pvcap, IID_IAMSTREAMCONFIG, (VOID **) & PSC);
ISpecifyPropertyPages * pSpec; CAUUID cauuid; hr = pSC-> QueryInterface (IID_ISpecifyPropertyPages, (void **) & pSpec); if (hr == S_OK) {hr = pSpec-> GetPages (& cauuid); // Properties Page hr = OleCreatePropertyFrame (tt.m_hwnd, 30, 30, null, 1, (iunknown **) & PSC, cauiD.celems, (guid *) cauuid.PELEMS, 0, 0, null); // !!! What if Changing Output Formats Couldn 't reconnect // and the graph is broker? Shouldn't Be Possible ... cotaskmemfree (cauiD.PELEMS); pspec-> release (); psc-> release ();
}
The following function is only written for convenience, but this is a good programming method, and there is some place in the front.
void CVideoCap1Dlg :: ReleaseFilter (void) {SAFE_RELEASE (m_pVidWin); SAFE_RELEASE (m_pGraph); SAFE_RELEASE (m_pGraphBuilder2); SAFE_RELEASE (m_pVCap); SAFE_RELEASE (m_pMux); SAFE_RELEASE (m_pMediaControl); SAFE_RELEASE (m_pVSC); SAFE_RELEASE (m_pSink); SAFE_RELEASE (m_pconfigavimux);
}
This function is the final ending process
Void cvideoCap1dlg :: OnClose () {// Todo: Add message handler code and / or call default value if (m_pmediacontrol) {m_pmediacontrol-> stop ();} countedfilter ();
CDIALOG :: onClose ();
The following is also introduced in the previous article. To debug, save the Filter Graph's function is from MS DirectShow for Digital Video & TV, it feels good.
Void cvideocap1dlg :: OnbnclickedSavegrf () {// Todo: Add control notification handler code HRESULT HR; CFiledialog DLG (TRUE);
IF (DLG.Domodal () == idok) {wchar wfilename [max_path]; multibytetowidechar (CP_ACP, 0, DLG.GetPathName (), -1, wfilename, max_path;
IStorage * pstorage = NULL;
// First, create a document file that will hold the GRF file hr = :: StgCreateDocfile (wFileName, STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, & pStorage); if (FAILED (hr)) {AfxMessageBox (TEXT ( "Can not create a document ")); return;} // Next, create a stream to store WCHAR wszStreamName [] = L." ActiveMovieGraph "; IStream * pStream; hr = pStorage-> CreateStream (wszStreamName, STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0 , 0, & pstream); Failed (HR)) {AFXMessageBox (Text ("Can Not Create A Stream"); PStorage-> Release (); Return;}
. // The IpersistStream :: Save method converts a stream // into a persistent object IPersistStream * pPersist = NULL; m_pGraph-> QueryInterface (IID_IPersistStream, reinterpret_cast
IF (succeededed (hr)) {hr = pstorage-> commit (STGC_DEFAULT); if (Failed (HR)) {AFXMessageBox (Text ("Can Not Store It");}} PStorage-> Release ();
}
In this way, a process that can preview and Capture can be done, is it not too difficult?