Visual C ++ programming for camera video capturing

Source: Internet
Author: User
Preface

DirectShow is a set of development kits provided by Microsoft for streaming media processing on the Windows platform and released together with the DirectX Development Kit. DirectShow provides powerful support for capturing and playback of Multimedia Streams. Using DirectShow to develop applications, we can easily capture data from the acquisition card that supports the WDM driver model, and perform corresponding post-processing and even storage into files.

DirectShow is based on COM. To compile DirectShow applications, you need to understand the basic knowledge of COM Client programming. DirectShow provides a large number of interfaces, but it is not easy to find in programming. If you can build a video capture class to encapsulate some common actions, it is more convenient.

  Programming Logic

To create a video capture application more easily, DirectShow provides an object called capture graph builder. Capture graph Builder provides the icapturegraphbuilder2 interface, which can be used to create and control the capture graph.

To create a video capturing program, you must first obtain and initialize the icapturegraphbuilder2 interface, and then select an appropriate video capturing device. After the device is selected, create a capture filter for the device, and then call addfilter to add the capture filter to the filter graph.

If you only want to use a camera for real-time monitoring, you only need to call icapturegraphbuilder2: renderstream on the basis of the above:

ICaptureGraphBuilder2 * pBuild; // Capture Graph Builder
// Some initialization code is omitted
IBaseFilter * pCap; // Video capture filter.
// The initialization and addition of Filter Graph code are omitted.
PBuild-> RenderStream (& PIN_CATEGORY_PREVIEW, & MEDIATYPE_Video, pCap, NULL, NULL );

DirectShow provides a method to capture static images: Use the sample grabber filter. Follow these three steps:

Step 1: Define a class to implement the callback interface isamplegrabbercb for sample grabber:

Class CSampleGrabberCB: public ISampleGrabberCB
{
// Complete it in the class provided later
}
CSampleGrabberCB mCB;

Step 2: Call renderstream to connect still pin, sample grabber, and default Renderer Filter.

Step 3: Configure sample grabber to capture data.

Implementation of CCaptureVideo for video capturing

// CCaptureVideo video capture Class header file
//////////////////////////////////////// /////////////////////////////
# If! Defined (afx_capturevideo_h1_f5345aa4_a39f_4b07_b843_3d87c4287aa01_encoded _)
# Define afx_capturevideo_h1_f5345aa4_a39f_4b07_b843_3d87c4287aa01_encoded _
//////////////////////////////////////// /////////////////////////////
// CaptureVideo. h: header file
//////////////////////////////////////// /////////////////////////////
# If _ msc_ver> 1000
# Pragma once
# Endif // _ msc_ver> 1000
# Include <atlbase. h>
# Include <windows. h>
# Include <dshow. h>
# Ifndef safe_release
# Define safe_release (X )/
If (null! = X )/
{/
X-> release ();/
X = NULL ;/
}
# Endif
Class csamplegrabbercb;
Class ccapturevideo: Public cwnd
{
Friend class csamplegrabbercb;
Public:
Void graboneframe (bool bgrab );
Hresult Init (INT ideviceid, hwnd );
Int enumdevices (hwnd hlist );
Ccapturevideo ();
Virtual ~ Ccapturevideo ();
Private:
HWND m_hWnd;
IGraphBuilder * m_pGB;
ICaptureGraphBuilder2 * m_pCapture;
IBaseFilter * m_pBF;
IMediaControl * m_pMC;
IVideoWindow * m_pVW;
CComPtr <ISampleGrabber> m_pGrabber;
Protected:
Void FreeMediaType (AM_MEDIA_TYPE & mt );
Bool BindFilter (int deviceId, IBaseFilter ** pFilter );
Void ResizeVideoWindow ();
HRESULT SetupVideoWindow ();
HRESULT InitCaptureGraphBuilder ();
};
# Endif //! Defined (afx_capturevideo_h1_f5345aa4_a39f_4b07_b843_3d87c4287aa01_encoded _)
//-------------------------------------------------------------------
// The implementation file CaptureVideo. cpp of the CCaptureVideo video capture class
//-------------------------------------------------------------------
// CaptureVideo. cpp: implementation of the CCaptureVideo class.
//
//////////////////////////////////////// /////////////////////////////
# Include "stdafx. h"
# Include "CaptureVideo. h"
# Ifdef _ DEBUG
# Undef THIS_FILE
Static char THIS_FILE [] =__ FILE __;
# Define new DEBUG_NEW
# Endif
BOOL bOneShot = FALSE; // global variable
Class CSampleGrabberCB: public ISampleGrabberCB
{
Public:
Long lWidth;
Long lHeight;
TCHAR m_szFileName [MAX_PATH]; // bitmap file name
CSampleGrabberCB (){
Strcpy (m_szFileName, "c: // donaldo.bmp ");
}
STDMETHODIMP _ (ULONG) AddRef () {return 2 ;}
STDMETHODIMP _ (ULONG) Release () {return 1 ;}
Stdmethodimp QueryInterface (refiid riid, void ** GMM ){
If (riid = iid_isamplegrabbercb | riid = iid_iunknown ){
* GMM = (void *) static_cast <isamplegrabbercb *> (this );
Return noerror;
}
Return e_nointerface;
}
Stdmethodimp samplecb (double sampletime, imediasample * psample ){
Return 0;
}
Stdmethodimp buffercb (double dblsampletime, byte * pbuffer, long lbuffersize ){
If (! Boneshot) return 0;
 
If (! Pbuffer) return e_pointer;
Savebitmap (pbuffer, lbuffersize );
Boneshot = false;
Return 0;
}
// Create a bitmap file
Bool savebitmap (byte * pbuffer, long lbuffersize)
{
Handle HF = createfile (
M_szfilename, generic_write, file_assist_read, null,
Create_always, null, null );
If (HF = invalid_handle_value) return 0;
// Write the file header
Bitmapfileheader BFH;
Memset (& BFH, 0, sizeof (BFH ));
BFH. bftype = 'mb ';
BFH. bfsize = sizeof (BFH) + lbuffersize + sizeof (bitmapinfoheader );
BFH. bfoffbits = sizeof (bitmapinfoheader) + sizeof (bitmapfileheader );
DWORD dwwritten = 0;
Writefile (HF, & BFH, sizeof (BFH), & dwwritten, null );
// Write bitmap format
Bitmapinfoheader BiH;
Memset (& BiH, 0, sizeof (BiH ));
BiH. bisize = sizeof (BiH );
BiH. biwidth = lwidth;
BiH. biheight = lheight;
BiH. biplanes = 1;
BiH. bibitcount = 24;
Writefile (HF, & BiH, sizeof (BiH), & dwwritten, null );
// Write bitmap data
Writefile (HF, pbuffer, lbuffersize, & dwwritten, null );
Closehandle (HF );
Return 0;
}
};
Csamplegrabbercb MCB;
//////////////////////////////////////// //////////////////////////////
// Construction/destruction
//////////////////////////////////////// //////////////////////////////
Ccapturevideo: ccapturevideo ()
{
// Com library intialization
If (failed (coinitialize (null)/*, coinit_apartmentthreaded )))*/
{
Afxmessagebox ("coinitialize failed! /R/N ");
Return;
}
M_hwnd = NULL;
M_pvw = NULL;
M_pmc = NULL;
M_pGB = NULL;
M_pCapture = NULL;
}
CCaptureVideo ::~ CCaptureVideo ()
{
// Stop media playback
If (m_pMC) m_pMC-> Stop ();
If (m_pVW ){
M_pVW-> put_Visible (OAFALSE );
M_pVW-> put_Owner (NULL );
}
SAFE_RELEASE (m_pCapture );
SAFE_RELEASE (m_pMC );
SAFE_RELEASE (m_pGB );
SAFE_RELEASE (m_pBF );
CoUninitialize ();
}
Int CCaptureVideo: EnumDevices (HWND hList)
{
If (! HList)
Return-1;
Int id = 0;

// Enumerate video capturing devices
ICreateDevEnum * pCreateDevEnum;
HRESULT hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **) & pCreateDevEnum );

If (hr! = NOERROR) return-1;
CComPtr <IEnumMoniker> pEm;
Hr = pCreateDevEnum-> CreateClassEnumerator (CLSID_VideoInputDeviceCategory, & pEm, 0 );

If (HR! = Noerror) Return-1;
PEM-> Reset ();
Ulong cfetched;
Imoniker * PM;
While (hR = PEM-> next (1, & PM, & cfetched), HR = s_ OK)
{
Ipropertybag * pbag;
HR = PM-> bindtostorage (0, 0, iid_ipropertybag, (void **) & pbag );
If (succeeded (HR ))
{
Variant var;
Var. Vt = vt_bstr;
HR = pbag-> Read (L "friendlyname", & var, null );
If (hR = noerror)
{
Tchar STR [2048];
Id ++;
Widechartomultibyte (cp_acp, 0, var. bstrval,-1, STR, 2048, null, null );
: Sendmessage (hlist, cb_addstring, 0, (lparam) Str );
Sysfreestring (var. bstrval );
}
Pbag-> release ();
}
PM-> Release ();
}
Return id;
}
HRESULT CCaptureVideo: Init (int iDeviceID, HWND hWnd)
{
HRESULT hr;
Hr = InitCaptureGraphBuilder ();
If (FAILED (hr )){
AfxMessageBox ("Failed to get video interfaces! ");
Return hr;
}
// Bind Device Filter. We know the device because the id was passed in
If (! BindFilter (iDeviceID, & m_pBF) return S_FALSE;
Hr = m_pGB-> AddFilter (m_pBF, L "Capture Filter ");
// Hr = m_pCapture-> RenderStream (& PIN_CATEGORY_PREVIEW, & MEDIATYPE_Video,
// M_pBF, NULL, NULL );
// Create a sample grabber
Hr = m_pGrabber.CoCreateInstance (CLSID_SampleGrabber );
If (! M_pGrabber ){
Afxmessagebox ("fail to create samplegrabber, maybe qedit. dll is not registered? ");
Return hr;
}
Ccomqiptr <ibasefilter, & iid_ibasefilter> pgrabbase (m_pgrabber );

// Set the video format
Am_media_type MT;
Zeromemory (& mt, sizeof (am_media_type ));
Mt. majortype = mediatype_video;
Mt. Subtype = mediasubtype_rgb24;
HR = m_pgrabber-> setmediatype (& mt );

If (failed (HR )){
Afxmessagebox ("fail to set media type! ");
Return hr;
}
HR = m_pgb-> addfilter (pgrabbase, l "Grabber ");
If (failed (HR )){
Afxmessagebox ("fail to put sample grabber in graph ");
Return hr;
}

// Try to render preview/capture pin
Hr = m_pCapture-> RenderStream (& PIN_CATEGORY_PREVIEW, & MEDIATYPE_Video, m_pBF, pGrabBase, NULL );
If (FAILED (hr ))
Hr = m_pCapture-> RenderStream (& PIN_CATEGORY_CAPTURE, & MEDIATYPE_Video, m_pBF, pGrabBase, NULL );

If (FAILED (hr )){
AfxMessageBox ("Can't build the graph ");
Return hr;
}
 
Hr = m_pGrabber-> GetConnectedMediaType (& mt );
If (FAILED (hr )){
AfxMessageBox ("Failt to read the connected media type ");
Return hr;
}

VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mt. pbFormat;
MCB. lWidth = vih-> bmiHeader. biWidth;
MCB. lHeight = vih-> bmiHeader. biHeight;
FreeMediaType (mt );
Hr = m_pGrabber-> SetBufferSamples (FALSE );
HR = m_pgrabber-> setoneshot (false );
HR = m_pgrabber-> setcallback (& McB, 1 );

// Set the video capture window
M_hwnd = hwnd;
Setupvideowindow ();
HR = m_pmc-> Run (); // start video capture
If (failed (HR) {afxmessagebox ("couldn't run the graph! "); Return hr ;}
Return s_ OK;
}
Bool ccapturevideo: bindfilter (INT DeviceID, ibasefilter ** pfilter)
{
If (DeviceID <0)
Return false;

// Enumerate all Video Capture Devices
Ccomptr <icreatedevenum> pcreatedevenum;
Hresult hR = cocreateinstance (clsid_systemdeviceenum, null, clsctx_inproc_server,
Iid_icreatedevenum, (void **) & pcreatedevenum );
If (HR! = Noerror)
{
Return false;
}
Ccomptr <ienummoniker> PEM;
HR = pcreatedevenum-> createclassenumerator (clsid_videoinputdevicecategory, & PEM, 0 );
If (HR! = Noerror)
{
Return false;
}
PEM-> Reset ();
Ulong cfetched;
Imoniker * PM;
Int Index = 0;
While (hR = PEM-> next (1, & PM, & cfetched), HR = s_ OK, index <= DeviceID)
{
Ipropertybag * pbag;
HR = PM-> bindtostorage (0, 0, iid_ipropertybag, (void **) & pbag );
If (succeeded (HR ))
{
Variant var;
Var. Vt = vt_bstr;
HR = pbag-> Read (L "friendlyname", & var, null );
If (hR = noerror)
{
If (Index = DeviceID)
{
PM-> BindToObject (0, 0, IID_IBaseFilter, (void **) pFilter );
}
SysFreeString (var. bstrVal );
}
PBag-> Release ();
}
PM-> Release ();
Index ++;
}
Return true;
}

HRESULT CCaptureVideo: InitCaptureGraphBuilder ()
{
HRESULT hr;

// Create the IGraphBuilder Interface
Hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) & m_pGB );
// Create ICaptureGraphBuilder2 Interface
Hr = CoCreateInstance (CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) & m_pCapture );
If (FAILED (hr) return hr;
M_pCapture-> SetFiltergraph (m_pGB );
Hr = m_pGB-> QueryInterface (IID_IMediaControl, (void **) & m_pMC );
If (FAILED (hr) return hr;
Hr = m_pGB-> QueryInterface (IID_IVideoWindow, (LPVOID *) & m_pVW );
If (FAILED (hr) return hr;
Return hr;
}
HRESULT CCaptureVideo: SetupVideoWindow ()
{
HRESULT hr;
Hr = m_pVW-> put_Owner (OAHWND) m_hWnd );
If (FAILED (hr) return hr;
Hr = m_pVW-> put_WindowStyle (WS_CHILD | WS_CLIPCHILDREN );
If (FAILED (hr) return hr;
ResizeVideoWindow ();
Hr = m_pVW-> put_Visible (OATRUE );
Return hr;
}
Void CCaptureVideo: ResizeVideoWindow ()
{
If (m_pVW ){
// Fill the image with the entire window
CRect rc;
: Getclientrect (m_hwnd, & rc );
M_pvw-> setwindowposition (0, 0, RC. Right, RC. Bottom );
}
}
Void ccapturevideo: graboneframe (bool bgrab)
{
Boneshot = bgrab;
}
Void ccapturevideo: freemediatype (am_media_type & mt)
{
If (mt. cbformat! = 0 ){
Cotaskmemfree (pvoid) Mt. pbformat );
// Strictly unnecessary but tidier
Mt. cbformat = 0;
Mt. pbformat = NULL;
}
If (mt. Punk! = NULL ){
Mt. Punk-> release ();
Mt. Punk = NULL;
}
}

How to use the video capture class CCaptureVideo

After the CCaptureVideo class is built, it is much easier to use. In programming, we only need to use the following three class member functions to capture videos with cameras:

① Int EnumDevices (HWND hList); // hList is the handle of the drop-down list box. This function is used to enumerate all video capturing devices installed in the current system.

② HRESULT Init (int iDeviceID, HWND hWnd); // iDeviceID is the sequence number of the video capturing device, and hWnd is the handle of the video capturing window.

③ Void GrabOneFrame (BOOL bGrab); // call GrabOneFrame (true) to capture the current static image and save it to the hard disk.
  
Example: use MFC AppWizard (exe) to create a dialog box application named ds. Add a drop-down list box (IDC_COMBO1) and two buttons (IDC_PHOTO and IDC_HAVEALOOK) to the dialog box) and a Picture control (ID: IDC_STATIC_SCREEN, Type: Rectangle, Color: Gray ).

1. Use the Wizard to add member variables

CStatic m_staticScreen; // IDC_STATIC_SCREEN
CComboBox m_ListCtrl; // IDC_COMBO1
CCaptureVideo m_cap;

2. Add the following code for BOOL CDsDlg: OnInitDialog:

// TODO: Add extra initialization here
M_cap.EnumDevices (m_ListCtrl );
M_ListCtrl.SetCurSel (0 );

3. Add the following code for the OK button:

Void CDsDlg: OnOK ()
{
// You only need four lines of code to capture the video.
UpdateData ();
HWND hWnd = m_staticScreen.GetSafeHwnd ();
HRESULT hr = m_cap.Init (m_ListCtrl.GetCurSel (), hWnd );
GetDlgItem (IDOK)-> EnableWindow (FALSE );
}

4. If you want to capture static images, add the following code for the camera button:

Void CDsDlg: OnPhoto ()
{
M_cap.GrabOneFrame (true );
}

When running the program, you only need to press OK after selecting the camera. The actual effect is shown in:

  Conclusion

The video capturing class CcaptureVideo and examples provided in this article are debugged in the Win2K + DirectX9 SDK + VC6 environment. Note: during compilation, the Strmiids. lib Quartz. lib library files are required (included in the DirectX9 SDK ).

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.