Example of capturing video streams from a single camera

Source: Internet
Author: User

This program uses the functions in the previous article. These functions are provided in the previous article and will not be described in detail here. The source code and some simple comments are given below.

// Videocap1dlg. h: header file ------------------------------
//

# Pragma once
# Include "afxwin. H"

# Include "dshowutilities. H"

// Cvideocap1dlg dialog box
Class cvideocap1dlg: Public cdialog
{
// Construct
Public:
Cvideocap1dlg (cwnd * pparent = NULL); // standard Constructor

// Dialog box data
Enum {IDD = idd_videocap1_dialog };

Protected:
Virtual void dodataexchange (cdataexchange * PDX); // supported by DDX/DDV

// Implementation
Protected:
Hicon m_hicon;

// Message ing function generated
Virtual bool oninitdialog ();
Afx_msg void onsyscommand (uint NID, lparam );
Afx_msg void onpaint ();
Afx_msg hcursor onquerydragicon ();
Declare_message_map ()
Public:
// Obviously, this is a window for real-time video stream display.
Cstatic m_videowindow;
// The function to be rewritten
Afx_msg bool onerasebkgnd (CDC * PDC );
// Sets display attributes.
Ivideowindow * m_pvidwin;
Afx_msg void onbnclickedpreview ();
// Used to control the created filter graph, that is, stop, run, and pause.
Igraphbuilder * m_pgraph;
// Fiter graph can be conveniently generated when video streams are captured.
Icapturegraphbuilder2 * m_pgraphbuilder2;
Afx_msg void onbnclickedsavegrf ();
// Because the program can both preview and capture,
// There are the following two variables to indicate the current mode of the filter graph.
Bool m_fcapturegraphbuilt;
Bool m_fpreviewgraphbuilt;
// The capture filter
Ibasefilter * m_pvcap;
Ibasefilter * m_pmux;
// Indicates the current working status
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_pconfigavimux;
Afx_msg void onbnclickedbutton1 ();
// Add this function to release resources for convenience.
Void releasefilter (void );
Afx_msg void onbnclickedsetpin ();
};

// Videocap1dlg. cpp: implementation 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 function, video stream capturing devices in the system are enumerated and a filter graph is created for preview. Maybe I should separate the code. When we enumerate video stream capturing devices, we just let go when we get the first device.

Bool cvideocap1dlg: oninitdialog ()
{
Cdialog: oninitdialog ();

// Add the/"about.../" menu to the system menu.

// Idm_aboutbox must be in the range of system commands.
Assert (idm_aboutbox & 0xfff0) = idm_aboutbox );
Assert (idm_aboutbox <0xf000 );

Cmenu * psysmenu = getsystemmenu (false );
If (psysmenu! = NULL)
{
Cstring straboutmenu;
Straboutmenu. loadstring (ids_aboutbox );
If (! Straboutmenu. isempty ())
{
Psysmenu-> appendmenu (mf_separator );
Psysmenu-> appendmenu (mf_string, idm_aboutbox, straboutmenu );
}
}

// Set the icon in this dialog box. When the application main window is not a dialog box, the framework will automatically
// Perform this operation
SetIcon (m_hIcon, TRUE); // you can specify a large icon.
SetIcon (m_hIcon, FALSE); // you can specify a small icon.

// TODO: add additional initialization code here

// Initialize the COM library.
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED );

// 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 "));
};

// Device enumeration starts below !!! 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 ")
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 (SUCCEEDED (hr ))
{
Hr = m_pGraph-> AddFilter (m_pVCap, L "Capture Filter ");
If (SUCCEEDED (hr ))
AfxMessageBox (TEXT ("add capture filter to the filter graph success "));
}
If (succeeded (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_videoappsmodifystyle (0, ws_clipchildren );
 
Return true; // return true unless the control focus is set.
}

The following functions are required. Otherwise, problems may occur when the window is re-painted.

Bool cvideocap1dlg: onerasebkgnd (CDC * PDC)
{
// Todo: add the message processing program code and/or call the default value here
Crect RC;
M_videowindow.getwindowrect (& rc );
Screentoclient (& rc );
PDC-> excludecliprect (& rc );
Return cdialog: onerasebkgnd (PDC );
}

The following function creates a filter graph for preview and sets the window position for preview. At the beginning, you also need to determine whether the image is being previewed or captured, and then there are different responses accordingly, such as clearing the fiter graph for capturing the image and creating your own fiter graph, or exit directly.

Void cvideocap1dlg: onbnclickedpreview ()
{
// Todo: add the control notification handler code here
Hresult hR = 0;
Am_media_type * PMT;

If (! M_fpreviewgraphbuilt) // if not have one then cocould build one
{
// No rebuilding while we're re running
// If the preview button is clicked during capture
// You can preview the content during capture, but the content is also collected during preview.
// If you click preview, make it preview separately and stop capture.
If (m_fcapturing)
{
M_pmediacontrol-> stop ();
M_fcapturing = false;
}
// We don't 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;
}
// The following statement automatically generates a filter graph from the source filter.
HR = m_pgraphbuilder2-> 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 "));

//--------------------------------------------------------------------------
// Sets video preview.
Updatedata (true );
M_fpreviewgraphbuilt = true; // The preview filter graph is successfully created.

//----------------------------------------------------------------------
// Get the media control object.
HR = m_pgraph-> QueryInterface (iid_imediacontrol, (void **) & m_pmediacontrol );
If (succeeded (HR ))
{
Afxmessagebox (text ("m_pcontrol success "));
}
Else afxmessagebox (text ("m_pcontrol failed "));
// Start to run the filter graph.

M_pmediacontrol-> Run ();
M_fpreviewing = true;
}

//---------------------------------------------------------------------
// Show out in the screen, and make some settings so that the captured image can be displayed.
// Setting the video window,
// Note that these settings can only be set after the filter graph is created. Otherwise, they will not work.
HR = m_pgraph-> QueryInterface (iid_ivideowindow, (void **) & m_pvidwin );
If (succeeded (HR ))
{
HR = m_pvidwin-> put_owner (oahwnd) m_video?#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 construct a filter graph captured by the video stream. It is the same as the above. If a filter graph that does not meet the requirements already exists, delete it first, then create a new one.

Void CVideoCap1Dlg: OnBnClickedCapture ()
{
// TODO: add the control notification handler code here
HRESULT hr;
AM_MEDIA_TYPE * pmt = 0;

// We have one already
// M_fCaptureGraphBuilt and m_fPreviewGraphBuilt can have only one TRUE
If (m_fCaptureGraphBuilt)
{
If (! M_fCapturing)
{
M_pmediacontrol-> Run ();
M_fcapturing = true;
}
Return;
}

// No rebuilding while we're re running
// When a filter graph is running, it cannot be created.
If (m_fpreviewing)
{
M_pmediacontrol-> stop ();
M_fpreviewing = false;
}

// Delete the old filter graph

If (m_fpreviewgraphbuilt)
{
: Teardowngraph (m_pgraph, m_pvidwin, m_pvcap );
M_fpreviewgraphbuilt = false;
}

// Set the location where the file is saved
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 the chain 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 describes how to establish 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 filter graph is re-created, so...
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, and make some settings so that the captured image can be displayed.
// Setting the Video Window
Hr = m_pGraph-> QueryInterface (IID_IVideoWindow, (void **) & m_pVidWin );
If (SUCCEEDED (hr ))
{
Hr = m_pVidWin-> put_Owner (OAHWND) m_video?#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 attribute page of the Source Filter. You can directly modify the attribute page.

Void cvideocap1dlg: onbnclickedbutton1 () // open the properties page of the capture filter settings
{
// Todo: add the control notification handler code here

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. achname, // 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. pElems );
}

The following function code is used to open and set the pin property page.

Void CVideoCap1Dlg: OnBnClickedSetPin ()
{
// TODO: add the control notification handler code here
CWnd tt;
Tt. GetActiveWindow ();
 

HRESULT hr;
IAMStreamConfig * pSC;

// You can set the pin attribute only after the pin is stopped.

If (m_fCapturing | m_fPreviewing)
{
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 cocould 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;
HR = PSC-> QueryInterface (iid_ispecifypropertypages,
(Void **) & pspec );
If (hR = s_ OK)
{
HR = pspec-> getpages (& cauuid );
// Display the property page
HR = olecreatepropertyframe (TT. m_hwnd, 30, 30, null, 1,
(Iunknown **) & PSC, cauuid. celems,
(Guid *) cauuid. pelems, 0, 0, null );

//!!! What if changing output formats couldn't reconnect
// And the graph is broken? Shouldn't be possible...
Cotaskmemfree (cauuid. pelems );
Pspec-> release ();
PSC-> release ();
}

}

The following function is written only for convenience. However, this is a good programming method, and there are some issues that have not been processed before.

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 used for final processing.

Void cvideocap1dlg: onclose ()
{
// Todo: add the message processing program code and/or call the default value here
If (m_pmediacontrol)
{
M_pmediacontrol-> stop ();
}
Couninitialize ();
Releasefilter ();

Cdialog: onclose ();
}

The following function is also introduced in the previous article to debug and save the filter graph
Most of this function is copied from Ms DirectShow for Digital Video & TV as is. It feels good.

Void cvideocap1dlg: onbnclickedsavegrf ()
{
// Todo: add the control notification handler code here
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_clu_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_clu_exclusive,
0, 0, & pStream );
If (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 <void **> (& pPersist ));
Hr = pPersist-> Save (pStream, TRUE );
PStream-> Release ();
PPersist-> Release ();

If (SUCCEEDED (hr ))
{
Hr = pStorage-> Commit (STGC_DEFAULT );
If (FAILED (hr ))
{
AfxMessageBox (TEXT ("can not store it "));
}
}
PStorage-> Release ();

}
}

In this way, a program that can both Preview and Capture is ready, isn't it difficult?

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.