This is a dialog-based program. The source code refers to Microsoft's DirectShow examples and an English to describe how to write program code in the book of the DirectShow program.
First of all, because of the playback of the video stream, you have to give the video stream on the dialog, let's get the Picture Control Control to the dialog box, set its ID to IDC_Video_Window, and let it type is Rectangle, and let the variable of the name of M_VideoWindow and it is associated with the name of the CSTATIC, so that Idc_Video_Window can be controlled by m_videoWindow. That is: void CplayMediaDlg :: DoDataExchange (CDataExchange * pDX) {CDialog :: DoDataExchange (pDX); DDX_Control (pDX, IDC_VIDEO_WINDOW, m_VideoWindow);} This code can be used by adding classvizard manner, the code can also add their own hand.
Since DirectShow uses COM technology, even if you only want to write DirectShow applications, you must also understand the component object model.
Playing video streams and audio streams in an automated manner is relatively simple, and below is some source code, and some of them will explain.
// playmediadlg.h: header file //
#pragma overce # include "afxwin.h"
#include
// CPlayMediadlg dialog Class CPlayMediadlg: public cdialog {// Construct Public: cPlayMediadlg (CWND * PParent = NULL); // Standard Construction Function
// dialog box data enum {IDD = IDD_PLAYMEDIA_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: CStatic m_VideoWindow; afx_msg BOOL OnEraseBkgnd (CDC * PDC); AFX_MSG Void OnBnclickedOpen (); // Graph Builder Interface, this is an interface for controlling Filter Graph creation, etc., which has corresponding functions igraphbuilder * pgraph; // media control interface, which is used for control flow the run, stop, pause interface, which has the corresponding function IMediaControl * pControl; afx_msg void OnBnClickedPlay (); afx_msg void OnBnClickedPause (); afx_msg void OnBnClickedStop (); afx_msg void OnClose (); // for controlling what is displayed The interface of the place, to display the video stream to use the function ivideoWindow * m_pvidwin in this interface; // record a few Pause button int m_pausepress; AFX_MSG void onbnclickedSave ();}; in playmediadlg.cpp Specific function code.
// PlayMediadlg.cpp ---------------------------------------
CplayMediaDlg :: CplayMediaDlg (CWnd * pParent / * = NULL * /): CDialog (CplayMediaDlg :: IDD, pParent), pGraph (NULL), pControl (NULL), m_pVidWin (NULL), m_pausePress (0) {m_hIcon = AfxGetApp ( ) -> loadicon (idR_mainframe);
Bool CPlayMediadlg :: OnNitDialog () {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
// 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);. // Initialize the COM library HRESULT hr = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);. if (FAILED (hr )) {AFXMessageBox (Text ("Cannot Initialize the COM");
The method defines the interface // // Create the Filter Graph Manager and query for interfaces.// CoCreateInstance is used for obtaining interface hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) & pGraph); if ( Failed (HR)) {AFXMessageBox (Text ("Cannot Create Filter Graph Manager));
// Use IGraphBuilder :: QueryInterface (inherited from IUnknown) // to get the IMediaControl interface hr = pGraph-> QueryInterface (IID_IMediaControl, (void **) & pControl);. If (FAILED (hr)) {AfxMessageBox (TEXT ( " Can not obtain the media control interface "); pgraph-> release (); pgraph = null;}
// for display hr = pGraph-> QueryInterface (IID_IVideoWindow, (void **) & m_pVidWin); if (FAILED (hr)) {AfxMessageBox (TEXT ( "can not obtain the video window interface")); pControl-> Release ( ); PControl = NULL; pgraph-> release (); pgraph = null;}
Return True; // Returns true} unless the focus of the control is set.
The above functions are actually got the interface when the dialog is created, and the following function is a function of playing the file (audio or video file).
Void CPlayMediadlg :: OnBnclickedOpen () {// Todo: Add control notification handler code // Establish Filter Graph
HRESULT HR; CFILDIALOG DLG (TRUE); if (DLG.Domodal () == iDok) {
// TO Build The Filter Graph, ONLY One Call is Required. // We make the renderfile call to the filter graph manager // to which we pass the name of the media file. // The following lines of conversion are important, in fact That is to convert ASCII code into unicode wchar wfilename [max_path]; multibytetowidechar (CP_ACP, 0, DLG.GETPATHNAME (), -1, wfilename, max_path); // This is actually the format of DirectShow automatically according to the files you want to play, Generate filter graphhr = pgraph-> renderfile ((lpcwstr) WFileName, NULL); if (Failed (HR)) {AFXMessageBox (Text ("Can not open the file");}
// The code for setting the location of the display, here is the setting of the display HRESULT 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 reccTangle hr = m_pvidwin-> setWindowPosition (rc.left, rc.top, width, height); m_pvidwin-> put_visible (oatrue);}
}
}
The following three functions are a message response function added for a button control.
Void CPlayMediadlg :: OnbnclickedPlay () {// Todo: Add control notification handler code // Run the graph hResult HR = PControl-> run ();
}
Void CPlayMediadlg :: OnbnclickedPause () {// Todo: Add control notification handler code HRESULT HR = PControl-> pause (); if (Failed (HR)) {AFXMessageBox (Text ("can not pause the filter graph" );
Void CPlayMediadlg :: OnbnclickedStop () {// Todo: Add control notification handler code HRESULT HR = PControl-> stop (); if (Failed (HR)) {AFXMessageBox (Text ("can not stop stop the filter graph" ));
}
When the dialog is turned off, you have to do some work.
Void CPlayMediadlg :: ONCLOSE () {// Todo: Add message handler code and / or call default value now release everything and clean up. PControl-> release (); pgraph-> release (); m_pvidwin-> Release (); Couninitialize ();
CDIALOG :: onClose ();
The following is modified from a English book, the use is to save the current filter graph, so that the debugging will be more convenient, when you use Graph Edit to see you.
Void CPlayMediadlg :: OnBnclickedSave () {// 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); 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; 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 simple DirectShow stream media player is completed.
Feeling on writing DirectShow applications, different places in each program are different in Filter Graph, different Filter Graph's streaming media is different, others are like displaying the code of the video stream is the same. . And here, because the DirectShow automatically generates Filter Graph, so only one line of code hr = pgraph-> renderfile ((lpcwstr) wfilename, null); Many times, it is necessary to build a filter graph, which will be more complicated. Also, when another file is turned on, the filter graph generated by the original file should be deleted, but it is not available here. Also, there is also a place that is not very thoughtful. Further improvement will be improved.