Click here to Skip to main content
Click here to Skip to main content
Articles » Multimedia » DirectX » General » Downloads
 
Add your own
alternative version

Streaming Server using Direct Show and Windows Media Format

, 13 May 2010 CPOL
A simple streaming server using Direct Show and Windows Media Format SDK
Server.zip
Server
Release
Server.exe
res
Server.ico
Server.clw
Server.dsp
Server.dsw
Server.opt
Server.plg
// ServerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

#define ID_PAUSE_STATE_PAUSE "Pause"
#define ID_PAUSE_STATE_RUN "Run"


class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServerDlg dialog

CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CServerDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CServerDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_pWriter2 = NULL;
	m_pNetSink = NULL;
	m_pProvider = NULL;
	m_pGraph=NULL;
}

void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CServerDlg)
	DDX_Control(pDX, IDC_STATIC_URL, m_StaticUrl);
	DDX_Control(pDX, IDC_EDIT_PORT, m_EditPort);
	DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
	DDX_Control(pDX, IDC_BUTTON_PAUSE, m_btnPause);
	DDX_Control(pDX, IDC_BUTTON_START, m_btnStart);
	DDX_Control(pDX, IDC_COMBO_AUDEO_DEVICES, m_CboAudioDevices);
	DDX_Control(pDX, IDC_COMBO_VIDEO_DEVICES, m_CboVideoDevices);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CServerDlg, CDialog)
	//{{AFX_MSG_MAP(CServerDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_START, OnButtonStart)
	ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnButtonPause)
	ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CServerDlg message handlers

BOOL CServerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in 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 (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	GetVideoDevices("",NULL);//Fill video device combo
	GetAudeoDevices("",NULL);//Fill audeo device combo
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CServerDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CServerDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CServerDlg::OnButtonStart() 
{

	if(StartStreaming())
	{
		m_btnStart.EnableWindow(FALSE);
		m_btnPause.EnableWindow(TRUE);
		m_btnStop.EnableWindow(TRUE);
		AfxMessageBox("Streaming started successfully");
	}
	else
	{
		AfxMessageBox("Start streaming failed");
	}
}


CServerDlg::GetVideoDevices(CString strDevName,IBaseFilter **pFilter)
{
	try
	{
		CoInitialize(NULL);
		int id = 0;
		ULONG cRetrieved;
		IMoniker *pM;
		
		// enumerate all video capture devices
		CComPtr<ICreateDevEnum> pCreateDevEnum;
		HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
				  IID_ICreateDevEnum, (void**)&pCreateDevEnum);
		if (FAILED(hr))
		{
			return FALSE;
		}

		CComPtr<IEnumMoniker> pEm;
		hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
									&pEm, 0);
		if (FAILED(hr))
		{
			return FALSE;
		}
		pEm->Reset();
		
		while(hr = pEm->Next(1, &pM, &cRetrieved), 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 strdev[2048];		
					WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, strdev, 2048, NULL, NULL);
					if(strDevName=="")
					{
						m_CboVideoDevices.AddString(strdev);
					}
					else
					{
						if(strDevName==strdev)
						{
							pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
							break;
						}
					}

					SysFreeString(var.bstrVal);
				}
				pBag->Release();
			}
			pM->Release();
		}
		return TRUE;
	}
	catch(...)
	{
		return FALSE;
	}
}

CServerDlg::GetAudeoDevices(CString strDevName,IBaseFilter **pFilter)
{
	try
	{
		

		CoInitialize(NULL);
		int id = 0;
		ULONG cRetrieved;
		IMoniker *pM;
		
		// 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_AudioInputDeviceCategory,
									&pEm, 0);
		if (hr != NOERROR) 
		{
			return FALSE;
		}

		pEm->Reset();
		while(hr = pEm->Next(1, &pM, &cRetrieved), 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 strDev[2048];		
					WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, strDev, 2048, NULL, NULL);
					if(strDevName=="")
					{
						m_CboAudioDevices.AddString(strDev);
					}
					else
					{
						if(strDevName==strDev)
						{
							pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
							break;
						}
					}

					SysFreeString(var.bstrVal);
				}
				pBag->Release();
			}
			pM->Release();
		}
		return TRUE;
	}
	catch(...)
	{
		return FALSE;
	}
}


HRESULT CServerDlg::ConnectFilters(IGraphBuilder *pGraph, 
        IBaseFilter *pFirst, IBaseFilter *pSecond)
{
	try
	{
		//CString strAsfVideoPin="Video Input 01";
		 IPin *pOut = NULL, *pIn = NULL;
		HRESULT hr = GetPin(pSecond, PINDIR_INPUT, &pIn);

		if (FAILED(hr)) return hr;
		// The previous filter may have multiple outputs, so try each one!
		IEnumPins  *pEnum;
		pFirst->EnumPins(&pEnum);
		while(pEnum->Next(1, &pOut, 0) == S_OK)
		{
				PIN_DIRECTION PinDirThis;
				pOut->QueryDirection(&PinDirThis);
				if (PINDIR_OUTPUT == PinDirThis)
				{
					hr = pGraph->Connect(pOut, pIn);
					switch(hr)
					{
					case S_OK:
							break;
					case VFW_S_PARTIAL_RENDER:
							AfxMessageBox("VFW_S_PARTIAL_RENDER");
						break;
					case E_ABORT:
							  AfxMessageBox("E_ABORT");
						break;
					case E_POINTER:
							AfxMessageBox("E_POINTER");
						break;
					case VFW_E_CANNOT_CONNECT:
							 AfxMessageBox("VFW_E_CANNOT_CONNECT");
						break;
					case VFW_E_NOT_IN_GRAPH:
							  AfxMessageBox("VFW_E_NOT_IN_GRAPH");
						break;
					}		
					
				   if(!FAILED(hr))
					{
						   break;
					}
				}
				pOut->Release();
		}
		pEnum->Release();
		pIn->Release();
		pOut->Release();
		return hr;
	}
	catch(...)
	{
		return -1;
	}
}

HRESULT CServerDlg::GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)
{
	try
	{
		int i=0;
		IEnumPins  *pEnum;
		IPin       *pPin;
		pFilter->EnumPins(&pEnum);
		while(pEnum->Next(1, &pPin, 0) == S_OK)
		{
			 PIN_DIRECTION PinDirThis;
			 pPin->QueryDirection(&PinDirThis);
			 if (PinDir == PinDirThis)
			 {
				pEnum->Release();
				*ppPin = pPin;
				return S_OK;

			 }
			 pPin->Release();
		}
		pEnum->Release();
		return E_FAIL;  
	}
	catch(...)
	{
		return E_FAIL;
	}
}

BOOL CServerDlg::StartStreaming()
{

///////////////////////////////////////////////////////////////////////////////////
	//CREATING GRAPH
///////////////////////////////////////////////////////////////////////////////////

	HRESULT hr = CoInitialize(NULL); 
	if(FAILED(hr)) 
		return FALSE;

	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph); 

	if(FAILED(hr)) 
		return FALSE;

///////////////////////////////////////////////////////////////////////////////////

	/*///////////////////////////////////////////////////////
	Get the Device and add to graph
	///////////////////////////////////////////////////////*/
	CString strVidDevName,strAudDevice;
	m_CboVideoDevices.GetWindowText(strVidDevName);
	m_CboAudioDevices.GetWindowText(strAudDevice);

	if(!GetVideoDevices(strVidDevName, &m_pVidDeviceFilter))
		return FALSE;

	if(!GetAudeoDevices(strAudDevice, &m_pAudDeviceFilter))
		return FALSE;


	hr=m_pGraph->AddFilter(m_pVidDeviceFilter,L"Vid Capture Filter");
	if(FAILED(hr)) 
		return FALSE;

	hr=m_pGraph->AddFilter(m_pAudDeviceFilter,L"Aud Capture Filter");
	if(FAILED(hr)) 
		return FALSE;
	


	hr = CoCreateInstance(CLSID_WMAsfWriter,NULL,CLSCTX_INPROC_SERVER, 
                      IID_IBaseFilter, (void **) &m_pWMASFWritter); 


	if(FAILED(hr)) 
		return FALSE;

	hr=m_pGraph->AddFilter(m_pWMASFWritter,L"ASF Writter");
	if(FAILED(hr)) 
		return FALSE;
	
	hr = m_pWMASFWritter->QueryInterface( IID_IFileSinkFilter, (void**)&m_pFileSinkFilter );
	if(FAILED(hr)) 
		return FALSE;

	hr = m_pFileSinkFilter->SetFileName(L"C:\\test.wmv", NULL);
	if(FAILED(hr)) 
		return FALSE;

	if (FAILED(hr = m_pWMASFWritter->QueryInterface(IID_IServiceProvider, (void**)&m_pProvider)))
	{
		AfxMessageBox("Getting service provider failed");
		return FALSE;
	}

	if (FAILED(hr = m_pProvider->QueryService(IID_IWMWriterAdvanced2, IID_IWMWriterAdvanced2, (void**)&m_pWriter2)))
	{
		AfxMessageBox ("Query Service form IServiceProvider failed");
		return FALSE;
	}

	if (FAILED(hr = m_pWriter2->SetLiveSource(TRUE)))
	{
		AfxMessageBox ("Setting live source failed");
		return FALSE;
	}

	if (FAILED(hr = m_pWriter2->RemoveSink(0)))//For the time being we removing the default sink...
	{
		AfxMessageBox (" Remove Sink failed");
		return FALSE;
	}

	m_pProvider->Release();

 
	if (FAILED(hr = WMCreateWriterNetworkSink(&m_pNetSink)))
	{
		AfxMessageBox ("WMCreateWriterNetworkSink failed");
		return FALSE;
	}


	CString strPort="";
	m_EditPort.GetWindowText(strPort);

	DWORD dwPort = 8080;

	if(strPort!="")
	{
		dwPort=atoi(strPort);
	}

	if (FAILED(hr = m_pNetSink->Open(&dwPort)))
	{
		AfxMessageBox ("Port opening failed");
		return FALSE;
	}

	WCHAR url[256];
	DWORD len = 256;

	hr = m_pNetSink->GetHostURL(url, &len);

	if(SUCCEEDED(hr))
	{
		CString strUrl(url);
		m_StaticUrl.SetWindowText(strUrl);
	}

	if (FAILED(m_pWriter2->AddSink(m_pNetSink)))
	{
		AfxMessageBox ("AddSink failed");
		return FALSE;
	}
	

///////////////////////////////////////////////////////////////////////////
//Run the graph
///////////////////////////////////////////////////////////////////////////

	hr=ConnectFilters(m_pGraph, m_pVidDeviceFilter,m_pWMASFWritter,"Video Input 01");
	if(FAILED(hr)) 
		return FALSE;

	hr=ConnectFilters(m_pGraph, m_pAudDeviceFilter,m_pWMASFWritter);
	if(FAILED(hr)) 
		return FALSE;

	

	hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaControl);
	if(FAILED(hr)) 
		return FALSE;

	hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent); 
	if(FAILED(hr)) 
		return FALSE;

	hr = m_pMediaControl -> Run( ); 

	if(FAILED(hr))
	{
		AfxMessageBox ("Media Control Run failed");
		return FALSE;
	}

	long evCode=0;
	//hr=pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till its done.

	return TRUE;

}


IPin* CServerDlg::GetPinByName(IBaseFilter *pFilter, LPCOLESTR pinname)
{
	try
	{
		// GET PIN BY NAME

		IEnumPins* pEnum;
		IPin*      pPin;

		HRESULT hr = pFilter->EnumPins(&pEnum);
		if (FAILED(hr))
			return NULL;

		while(pEnum->Next(1, &pPin, 0) == S_OK)
		{
			PIN_INFO pinfo;
			pPin->QueryPinInfo(&pinfo);
			BOOL found = !_wcsicmp(pinname, pinfo.achName);

			if (pinfo.pFilter) 
				pinfo.pFilter->Release();

			if (found) 
			{
				return pPin;
			};
			pPin->Release();
		}
		return NULL;
	}
	catch(...)
	{
		return NULL;
	}
}


HRESULT CServerDlg::ConnectFilters(IGraphBuilder *pGraph, 
        IBaseFilter *pFirst, IBaseFilter *pSecond,CString strAsfFilterPin)
{
	try
	{
		 IPin *pOut = NULL, *pIn = NULL;
		 HRESULT hr=0;
		//HRESULT hr = GetPin(pSecond, PINDIR_INPUT, &pIn);
		 pIn=GetPinByName(pSecond,strAsfFilterPin.AllocSysString()); //Get pin by name...

		if (FAILED(hr)) return hr;
		// The previous filter may have multiple outputs, so try each one!
		IEnumPins  *pEnum;
		pFirst->EnumPins(&pEnum);
		while(pEnum->Next(1, &pOut, 0) == S_OK)
		{
				PIN_DIRECTION PinDirThis;
				pOut->QueryDirection(&PinDirThis);
				if (PINDIR_OUTPUT == PinDirThis)
				{
					hr = pGraph->Connect(pOut, pIn);
					switch(hr)
					{
					case S_OK:
							//AfxMessageBox("Connection Success");
							break;
					case VFW_S_PARTIAL_RENDER:
							AfxMessageBox("VFW_S_PARTIAL_RENDER");
						break;
					case E_ABORT:
							  AfxMessageBox("E_ABORT");
						break;
					case E_POINTER:
							AfxMessageBox("E_POINTER");
						break;
					case VFW_E_CANNOT_CONNECT:
							 AfxMessageBox("VFW_E_CANNOT_CONNECT");
						break;
					case VFW_E_NOT_IN_GRAPH:
							  AfxMessageBox("VFW_E_NOT_IN_GRAPH");
						break;
					}		
					
				   if(!FAILED(hr))
					{
						   break;
					}
				}
				pOut->Release();
		}
		pEnum->Release();
		pIn->Release();
		pOut->Release();
		return hr;
	}
	catch(...)
	{
		return -1;
	}
}


void CServerDlg::OnButtonPause() 
{
	HRESULT hr=0;
	CString strPauseState;
	m_btnPause.GetWindowText(strPauseState);
	if(strPauseState==ID_PAUSE_STATE_PAUSE)
	{
		if(m_pMediaControl)
		{
			hr=m_pMediaControl->Pause();
			if(!(FAILED(hr)))
			{
				m_btnPause.SetWindowText(ID_PAUSE_STATE_RUN);
				m_btnStop.EnableWindow(TRUE);
			}
		}
	}
	else if(strPauseState==ID_PAUSE_STATE_RUN)
	{
		if(m_pMediaControl)
		{
			hr=m_pMediaControl->Run();
			if(!(FAILED(hr)))
			{
				m_btnPause.SetWindowText(ID_PAUSE_STATE_PAUSE);
				m_btnStop.EnableWindow(TRUE);
			}
		}
	}
}

void CServerDlg::OnButtonStop() 
{
	HRESULT hr=0;
	if(m_pMediaControl)
	{
		hr=m_pMediaControl->Stop();	
		if((!FAILED(hr)))
		{
			m_btnPause.EnableWindow(FALSE);
			m_btnStop.EnableWindow(FALSE);
			m_btnStart.EnableWindow(FALSE);
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rajeev K R Pala
Technical Lead
India India
I am an iOS\VC++\.net software developer from India. I am currently employed as Software Engineer in a Product company. The main technologies I used are Objective C,VC++,MFC,C#.NET,DirectShow,COM,Windows media Format etc...
 
- 4+ Years in iOS Development
- 3+ years in VC++\MFC programming
- 3+ years in .NET programming
- 2+ years in COM,DirectShow,Windows media Format
 
I'm looking to advance my Software Engineering career by learning new technologies and extending my programming experience.
 
EMail : rajeevkr.asr@gmail.com
Skype : rajeevkr_asr

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411022.1 | Last Updated 13 May 2010
Article Copyright 2010 by Rajeev K R Pala
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid