www.pudn.com > WmformatScreen.rar > WmScreenDlg.cpp


// WmScreenDlg.cpp : implementation file 
// 
/** 
 ** Copyright (C) 2005 EnjoyView Inc., all rights reserved. 
 **           Your View, Our Passion. Just Enjoy It! 
 ** 
 **            http://spaces.msn.com/members/jemylu 
 ** 
 **/ 
 
/*************************************************************************/ 
 
#include "stdafx.h" 
#include "WmScreen.h" 
#include "WmScreenDlg.h" 
#include "safe_defs.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
 
//------------------------------------------------------------------------------ 
// Name: wmCopyMediaType() 
// Desc: Allocates memory for a WM_MEDIA_TYPE and its format data and  
//       copies an existing media type into it. 
//------------------------------------------------------------------------------ 
HRESULT wmCopyMediaType(WM_MEDIA_TYPE** ppmtDest, WM_MEDIA_TYPE* pmtSrc) 
{ 
	if (!ppmtDest) 
	{ 
		return E_POINTER; 
	} 
	if (!pmtSrc) 
	{ 
		return E_NOTIMPL; 
	} 
 
	// Create enough space for the media type and its format data 
	*ppmtDest = (WM_MEDIA_TYPE*) new BYTE[sizeof(WM_MEDIA_TYPE) + pmtSrc->cbFormat]; 
	if (!*ppmtDest) 
	{ 
		return E_OUTOFMEMORY; 
	} 
 
	// Copy the media type and the format data 
	memcpy(*ppmtDest, pmtSrc, sizeof(WM_MEDIA_TYPE)); 
	// Format data is immediately after media type 
	(*ppmtDest)->pbFormat = (((BYTE*) *ppmtDest) + sizeof(WM_MEDIA_TYPE));  
	memcpy((*ppmtDest)->pbFormat, pmtSrc->pbFormat, pmtSrc->cbFormat); 
	return S_OK; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CWmScreenDlg dialog 
 
CWmScreenDlg::CWmScreenDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CWmScreenDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CWmScreenDlg) 
	mTargetFile = _T("C:\\wm_screen.wmv"); 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
 
	mProfileManager = NULL; 
	mScreenMt = NULL; 
	mCaptureTimer = 0; 
	mImageSize    = 0; 
	mSamples      = 0; 
 
	mProfile = NULL; 
	mWriter  = NULL; 
} 
 
void CWmScreenDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CWmScreenDlg) 
	DDX_Control(pDX, IDC_BUTTON_STOP, mButtonStop); 
	DDX_Control(pDX, IDC_BUTTON_START, mButtonStart); 
	DDX_Text(pDX, IDC_EDIT_TARGET_FILE, mTargetFile); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CWmScreenDlg, CDialog) 
	//{{AFX_MSG_MAP(CWmScreenDlg) 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDC_BUTTON_START, OnButtonStart) 
	ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop) 
	ON_WM_DESTROY() 
	ON_WM_TIMER() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CWmScreenDlg message handlers 
 
BOOL CWmScreenDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// 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 
	 
	// TODO: Add extra initialization here 
 
	// Create a profile manager object 
	HRESULT hr = WMCreateProfileManager(&mProfileManager); 
	if (FAILED(hr)) 
	{ 
		AfxMessageBox("Failed to Create a Profile Manager."); 
		return TRUE; 
	} 
 
	// Check if Windows Media Screen codec is installed? 
	if (!IsCodecAvailable(WMMEDIASUBTYPE_MSS2, &mScreenMt)) 
	{ 
		if (!IsCodecAvailable(WMMEDIASUBTYPE_MSS1, &mScreenMt)) 
		{ 
			mButtonStart.EnableWindow(FALSE); 
			AfxMessageBox("Windows Media Screen codec is not available."); 
		} 
	} 
 
	// Init the asf writer 
	if (FAILED(InitAsfWriter())) 
	{ 
		mButtonStart.EnableWindow(FALSE); 
		AfxMessageBox("ASF Writer cannot be inited."); 
	} 
 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
// 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 CWmScreenDlg::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 CWmScreenDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
void CWmScreenDlg::OnDestroy()  
{ 
	BYTE * pBytes = (BYTE*) mScreenMt; 
	SAFE_ARRAY_DELETE(pBytes); 
 
	SAFE_RELEASE(mProfileManager); 
 
	OnButtonStop(); 
	SAFE_RELEASE(mProfile); 
	SAFE_RELEASE(mWriter); 
 
	CDialog::OnDestroy();	 
} 
 
void CWmScreenDlg::OnButtonStart()  
{ 
	mButtonStart.EnableWindow(FALSE); 
	mButtonStop.EnableWindow(TRUE); 
	UpdateData(TRUE); 
	mSamples = 0; 
 
	HRESULT hr = NOERROR; 
 
	do  
	{ 
		// Set output file 
		WCHAR * pOutputFile = mTargetFile.AllocSysString(); 
		hr = mWriter->SetOutputFilename(pOutputFile); 
		::SysFreeString(pOutputFile); 
		BREAK_IF_FAILED(hr); 
 
		hr = mWriter->BeginWriting(); 
		BREAK_IF_FAILED(hr); 
 
	} while (FALSE); 
 
 
	// Start a timer to capture screen 
	if (mCaptureTimer == 0) 
	{ 
		mCaptureTimer = SetTimer(100, 1000, NULL); 
	} 
} 
 
void CWmScreenDlg::OnButtonStop()  
{ 
	mButtonStop.EnableWindow(FALSE); 
	mButtonStart.EnableWindow(TRUE); 
 
	// Stop the timer to capture screen 
	if (mCaptureTimer != 0) 
	{ 
		KillTimer(mCaptureTimer); 
		mCaptureTimer = 0; 
	} 
 
	mWriter->EndWriting(); 
} 
 
void CWmScreenDlg::OnTimer(UINT nIDEvent)  
{ 
	if (nIDEvent == mCaptureTimer) 
	{ 
		HRESULT hr = NOERROR; 
		DWORD sampleSize = mImageSize; 
		INSSBuffer * pSample = NULL; 
 
		do 
		{ 
			// Get a free sample 
			hr = mWriter->AllocateSample(sampleSize, &pSample); 
			BREAK_IF_FAILED(hr); 
 
			PBYTE pBuffer = NULL; 
			hr = pSample->GetBuffer(&pBuffer); 
			BREAK_IF_FAILED(hr); 
 
			// Fill the sample data 
#if 0 
			static PBYTE ptmpBuffer = NULL; 
			static DWORD tmpsamplesize = 0; 
			if(ptmpBuffer==NULL) 
			{ 
				mGrabber.CaptureAFrame(pBuffer, &sampleSize); 
				ptmpBuffer = (PBYTE)malloc(sampleSize); 
				memcpy(ptmpBuffer, pBuffer,sampleSize); 
				tmpsamplesize = sampleSize; 
			}else{ 
				sampleSize = tmpsamplesize; 
				memcpy(pBuffer,ptmpBuffer,sampleSize); 
			} 
#else 
			mGrabber.CaptureAFrame(pBuffer, &sampleSize); 
#endif 
			hr = pSample->SetLength(sampleSize); 
			BREAK_IF_FAILED(hr); 
 
			DWORD flags = WM_SF_CLEANPOINT; 
			if (mSamples == 0) 
			{ 
				flags |= WM_SF_DISCONTINUITY; 
			} 
 
			QWORD timestamp = mSamples * 1000000 * 10 ; 
			// Deliver the sample to the writer 
			hr = mWriter->WriteSample(0, timestamp, flags, pSample); 
			mSamples++; 
			BREAK_IF_FAILED(hr); 
 
		} while (FALSE); 
 
		SAFE_RELEASE(pSample); 
	} 
 
	CDialog::OnTimer(nIDEvent); 
} 
 
 
HRESULT CWmScreenDlg::InitAsfWriter(void) 
{ 
	HRESULT hr = NOERROR; 
 
	do  
	{ 
		// Create asf writer and retrieve some interfaces 
		hr = WMCreateWriter(NULL, &mWriter); 
		BREAK_IF_FAILED(hr); 
 
		// Create a profile using Windows Media Video 9 Screen 
		hr = CreateProfile(&mProfile); 
		BREAK_IF_FAILED(hr); 
 
		// Set the profile to the writer 
		hr = mWriter->SetProfile(mProfile); 
		BREAK_IF_FAILED(hr); 
 
		// Config input 
		hr = ConfigInput(mWriter); 
		BREAK_IF_FAILED(hr); 
 
	} while (FALSE); 
 
	return hr; 
} 
 
// Helper method 
HRESULT CWmScreenDlg::GetMediaTypeDetails(IWMMediaProps * pProps, BYTE** outDetails) 
{ 
	if (pProps == NULL) 
	{ 
		return E_FAIL; 
	} 
 
	HRESULT hr = NOERROR; 
	BYTE * pMediaType = NULL; 
	DWORD  cbTypeSize = 0; 
	do 
	{ 
		// Get the size of the media type structure.		 
		hr = pProps->GetMediaType(NULL, &cbTypeSize); 
		BREAK_IF_FAILED(hr); 
 
		// Allocate memory for the media type structure. 
		pMediaType = new BYTE[cbTypeSize]; 
		if (pMediaType == NULL) 
		{ 
			hr = E_OUTOFMEMORY; 
			break; 
		} 
 
		// Get the media type structure. 
		hr = pProps->GetMediaType((WM_MEDIA_TYPE*)pMediaType, &cbTypeSize); 
 
	} while (FALSE); 
 
	if (SUCCEEDED(hr)) 
	{ 
		*outDetails = pMediaType; 
	} 
	else 
	{ 
		if (pMediaType) 
		{ 
			delete[] pMediaType; 
			pMediaType = NULL; 
		} 
	} 
	return hr; 
} 
 
// Check if specified codec exists. If yes, copy mediatype out. 
BOOL CWmScreenDlg::IsCodecAvailable(GUID inSubtype, WM_MEDIA_TYPE ** outMt) 
{ 
	HRESULT hr = NOERROR; 
	BOOL found = FALSE; 
	IWMCodecInfo * pCodecInfo = NULL; 
 
	do 
	{ 
		// Get the IWMCodecInfo interface 
		hr = mProfileManager->QueryInterface(IID_IWMCodecInfo, (void**) &pCodecInfo); 
		if (FAILED(hr)) 
		{ 
			AfxMessageBox("Failed to Get the IWMCodecInfo Interface."); 
			break; 
		} 
		 
		DWORD				cFormats = 0; 
		IWMStreamConfig*	pConfig  = NULL; 
		IWMMediaProps*		pProps   = NULL; 
		BYTE *	pMediaType = NULL; 
 
		// Retrieve the number of supported codecs on the system. 
		DWORD cCodecs  = 0; 
		hr = pCodecInfo->GetCodecInfoCount(WMMEDIATYPE_Video, &cCodecs); 
 
		// Loop through all the audio codecs. 
		for (DWORD i = 0; i < cCodecs; i++) 
		{ 
			hr = pCodecInfo->GetCodecFormatCount(WMMEDIATYPE_Video, i, &cFormats); 
			BREAK_IF_FAILED(hr); 
 
			if (cFormats > 0) 
			{ 
				// Get stream config interfaces 
				hr = pCodecInfo->GetCodecFormat(WMMEDIATYPE_Video, i, 0, &pConfig); 
				BREAK_IF_FAILED(hr); 
				hr = pConfig->QueryInterface(IID_IWMMediaProps, (void**)&pProps); 
				BREAK_IF_FAILED(hr); 
 
				// Get the media type details 
				hr = GetMediaTypeDetails(pProps, &pMediaType); 
				BREAK_IF_FAILED(hr); 
 
				WM_MEDIA_TYPE * pwmType = (WM_MEDIA_TYPE*) pMediaType; 
				if (pwmType->subtype == inSubtype) 
				{ 
#ifdef _DEBUG 
					WMVIDEOINFOHEADER * pvi = (WMVIDEOINFOHEADER*) pwmType->pbFormat; 
					LONG formatSize = pwmType->cbFormat; 
					LONG viSize = sizeof(WMVIDEOINFOHEADER); 
					if (formatSize > viSize) 
					{ 
						TRACE("Extra data is appended after WMVIDEOINFOHEADER.\n"); 
					} 
#endif // _DEBUG 
					// Save this media type for later use 
					wmCopyMediaType(outMt, pwmType); 
					found = TRUE; 
					break; 
				} 
			} 
 
			SAFE_ARRAY_DELETE(pMediaType); 
			SAFE_RELEASE(pProps); 
			SAFE_RELEASE(pConfig); 
		} 
 
		SAFE_ARRAY_DELETE(pMediaType); 
		SAFE_RELEASE(pProps); 
		SAFE_RELEASE(pConfig); 
 
	} while (FALSE); 
 
	SAFE_RELEASE(pCodecInfo); 
 
	return found; 
} 
 
HRESULT CWmScreenDlg::CreateProfile(IWMProfile ** ppProfile) 
{ 
	HRESULT hr = NOERROR; 
	IWMProfile *		pProfile = NULL; 
	IWMStreamConfig *	pConfig = NULL; 
	IWMMediaProps *		pProps  = NULL; 
	 
	do  
	{ 
		// Create an empty profile object 
		hr = mProfileManager->CreateEmptyProfile(WMT_VER_9_0, &pProfile); 
		BREAK_IF_FAILED(hr); 
 
		// Create a new video stream 
		hr = pProfile->CreateNewStream(WMMEDIATYPE_Video, &pConfig); 
		BREAK_IF_FAILED(hr); 
 
		hr = pConfig->QueryInterface(IID_IWMMediaProps, (void**)&pProps); 
		BREAK_IF_FAILED(hr); 
 
		WMVIDEOINFOHEADER * pVidHdr = (WMVIDEOINFOHEADER*) mScreenMt->pbFormat; 
		pVidHdr->AvgTimePerFrame    = 1000000; // 10fps 
		pVidHdr->dwBitRate = 500000; 
		pVidHdr->bmiHeader.biWidth  = mGrabber.GetImageWidth(); 
		pVidHdr->bmiHeader.biHeight = mGrabber.GetImageHeight(); 
	//	pVidHdr->bmiHeader.biWidth  = cPreferredWidth; 
	//	pVidHdr->bmiHeader.biHeight = cPreferredHeight; 
		hr = pProps->SetMediaType(mScreenMt); 
		BREAK_IF_FAILED(hr); 
 
		hr = pConfig->SetStreamName(L"Screen"); 
		hr = pConfig->SetBitrate(500000); 
		hr = pConfig->SetBufferWindow(3000); 
		hr = pConfig->SetStreamNumber(1); 
		// Add this video stream to the profile 
		hr = pProfile->AddStream(pConfig); 
		BREAK_IF_FAILED(hr); 
 
	} while (FALSE); 
 
	if (SUCCEEDED(hr)) 
	{ 
		pProfile->AddRef(); 
		*ppProfile = pProfile; 
	} 
 
	SAFE_RELEASE(pProfile); 
	SAFE_RELEASE(pProps); 
	SAFE_RELEASE(pConfig); 
 
	return hr; 
} 
 
HRESULT CWmScreenDlg::ConfigInput(IWMWriter* pWriter) 
{ 
	HRESULT hr = NOERROR; 
	IWMInputMediaProps * pProps = NULL; 
	BYTE* pMediaType = NULL; 
 
	do 
	{ 
		hr = pWriter->GetInputProps(0, &pProps); 
		BREAK_IF_FAILED(hr); 
 
#ifdef _DEBUG 
		GUID guidInputType; 
		pProps->GetType(&guidInputType); 
		if (guidInputType == WMMEDIATYPE_Video) 
		{ 
			TRACE("This should be an video input.\n"); 
		} 
#endif // _DEBUG 
 
		// Get the media type details 
		hr = GetMediaTypeDetails(pProps, &pMediaType); 
		BREAK_IF_FAILED(hr); 
 
		WM_MEDIA_TYPE * pType = (WM_MEDIA_TYPE*) pMediaType; 
		 
		WMVIDEOINFOHEADER* pVidHdr = (WMVIDEOINFOHEADER*) pType->pbFormat; 
		pVidHdr->AvgTimePerFrame   = 1000000; // 10fps 
		ZeroMemory(&pVidHdr->bmiHeader, sizeof(BITMAPINFOHEADER)); 
		pVidHdr->bmiHeader.biSize  = sizeof(BITMAPINFOHEADER);		 
		pVidHdr->bmiHeader.biPlanes= 1; 
		pVidHdr->bmiHeader.biWidth = mGrabber.GetImageWidth(); 
		pVidHdr->bmiHeader.biHeight= mGrabber.GetImageHeight(); 
		pVidHdr->bmiHeader.biBitCount  = WORD(mGrabber.GetBitDepth()); 
		pVidHdr->bmiHeader.biSizeImage = mImageSize = mGrabber.GetImageSize(); 
		// Assume: the color depth of display is more than 24 bits 
		if (pVidHdr->bmiHeader.biBitCount == 32) 
		{ 
			pType->subtype = WMMEDIASUBTYPE_RGB32; 
		} 
		else 
		{ 
			pType->subtype = WMMEDIASUBTYPE_RGB24; 
		} 
 
		hr = pProps->SetMediaType(pType); 
		BREAK_IF_FAILED(hr); 
 
		// Save changes back to the writer!!! 
		hr = pWriter->SetInputProps(0, pProps); 
		BREAK_IF_FAILED(hr); 
 
	} while (FALSE); 
 
	SAFE_ARRAY_DELETE(pMediaType); 
	SAFE_RELEASE(pProps); 
 
	return hr; 
}