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;
}