Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

665 lines
17 KiB

//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//----------------------------------------------------------------------------
// VMRProp.cpp
//
// Created 3/18/2001
// Author: Steve Rowe [StRowe]
//
//----------------------------------------------------------------------------
#include <windowsx.h>
#include <streams.h>
#include <atlbase.h>
#include <commctrl.h>
#include <stdio.h>
#include <shlobj.h> // for SHGetSpecialFolderPath
#include "resource.h"
#ifdef FILTER_DLL
#include <initguid.h>
#endif
#include "vmrprop.h"
#ifdef FILTER_DLL
STDAPI DllRegisterServer()
{
AMTRACE((TEXT("DllRegisterServer")));
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
AMTRACE((TEXT("DllUnregisterServer")));
return AMovieDllRegisterServer2( FALSE );
}
CFactoryTemplate g_Templates[] = {
{
L"",
&CLSID_VMRFilterConfigProp,
CVMRFilterConfigProp::CreateInstance
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
#endif // #ifdef FILTER_DLL
//
// Constructor
//
CVMRFilterConfigProp::CVMRFilterConfigProp(LPUNKNOWN pUnk, HRESULT *phr) :
CBasePropertyPage(NAME("Filter Config Page"),pUnk,IDD_FILTERCONFIG,IDS_TITLE_FILTERCONFIG),
m_pIFilterConfig(NULL),
m_pIMixerControl(NULL),
m_dwNumPins(1),
m_pEventSink(NULL),
m_CurPin(0),
m_XPos(0.0F),
m_YPos(0.0F),
m_XSize(1.0F),
m_YSize(1.0F),
m_Alpha(1.0F)
{
ASSERT(phr);
}
//
// Create a quality properties object
//
CUnknown * CVMRFilterConfigProp::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
ASSERT(phr);
CUnknown * pUnknown = new CVMRFilterConfigProp(pUnk, phr);
if (pUnknown == NULL)
{
*phr = E_OUTOFMEMORY;
}
return pUnknown;
}
//
// OnConnect
//
// Override CBasePropertyPage method.
// Notification of which filter this property page will communicate with
// We query the object for the IVMRFilterConfig interface.
//
HRESULT CVMRFilterConfigProp::OnConnect(IUnknown *pUnknown)
{
ASSERT(NULL != pUnknown);
ASSERT(NULL == m_pIFilterConfig);
ASSERT(NULL == m_pIMixerControl);
HRESULT hr = pUnknown->QueryInterface(IID_IVMRFilterConfig, (void **) &m_pIFilterConfig);
if (FAILED(hr) || NULL == m_pIFilterConfig)
{
return E_NOINTERFACE;
}
// Get the IMediaEventSink interface. We use this later to tell graphedit that we updated the number of pins
CComPtr<IBaseFilter> pFilter;
hr = pUnknown->QueryInterface(IID_IBaseFilter, (void **) &pFilter);
if (FAILED(hr) || !pFilter)
{
return E_NOINTERFACE;
}
FILTER_INFO Info;
hr = pFilter->QueryFilterInfo(&Info);
if (FAILED(hr))
{
return E_FAIL;
}
hr = Info.pGraph->QueryInterface(IID_IMediaEventSink, (void**) &m_pEventSink);
Info.pGraph->Release(); // the IFilterGraph pointer is ref counted. We need to release it or leak.
if (FAILED(hr) || NULL == m_pEventSink)
{
return E_NOINTERFACE;
}
return NOERROR;
} // OnConnect
//
// OnDisconnect
//
// Override CBasePropertyPage method.
// Release all interfaces we referenced in OnConnect
//
HRESULT CVMRFilterConfigProp::OnDisconnect(void)
{
if (m_pIFilterConfig)
{
m_pIFilterConfig->Release();
m_pIFilterConfig = NULL;
}
if (m_pIMixerControl)
{
m_pIMixerControl->Release();
m_pIMixerControl = NULL;
}
if (m_pEventSink)
{
m_pEventSink->Release();
m_pEventSink = NULL;
}
return NOERROR;
} // OnDisconnect
//
// OnReceiveMessage
//
// Override CBasePropertyPage method.
// Handles the messages for our property window
//
INT_PTR CVMRFilterConfigProp::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
HANDLE_MSG(hwnd, WM_HSCROLL, OnHScroll);
} // switch
return CBasePropertyPage::OnReceiveMessage(hwnd,uMsg,wParam,lParam);
} // OnReceiveMessage
//
// OnCommand
//
// Handles the command messages for our property window
//
void CVMRFilterConfigProp::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{
case IDC_NUMPINS:
if (EN_CHANGE == codeNotify)
{
SetDirty();
break;
}
break;
// the selected pin changed
case IDC_PINSELECT:
if (CBN_SELCHANGE == codeNotify)
{
m_CurPin = ComboBox_GetCurSel(GetDlgItem(m_Dlg, IDC_PINSELECT));
InitConfigControls(m_CurPin);
break;
}
break;
// Reset X position to center
case IDC_XPOS_STATIC:
if (STN_CLICKED == codeNotify)
{
m_XPos = 0.0F;
UpdatePinPos(m_CurPin);
HWND hwndT;
int pos;
TCHAR sz[32];
hwndT = GetDlgItem(m_Dlg, IDC_XPOS_SLIDER );
pos = int(1000 * m_XPos) + 1000;
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_XPos);
SetDlgItemText(m_Dlg, IDC_XPOS, sz);
}
break;
// Reset Y position to center
case IDC_YPOS_STATIC:
if (STN_CLICKED == codeNotify)
{
m_YPos = 0.0F;
UpdatePinPos(m_CurPin);
HWND hwndT;
int pos;
TCHAR sz[32];
pos = int(1000 * m_YPos) + 1000;
hwndT = GetDlgItem(m_Dlg, IDC_YPOS_SLIDER );
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_YPos);
SetDlgItemText(m_Dlg, IDC_YPOS, sz);
}
break;
// Capture the current video image
case IDC_SNAPSHOT:
CaptureCurrentImage();
break;
}
} // OnCommand
//
// OnApplyChanges
//
// Override CBasePropertyPage method.
// Called when the user clicks ok or apply.
// We update the number of pins on the VMR.
//
HRESULT CVMRFilterConfigProp::OnApplyChanges()
{
ASSERT(m_pIFilterConfig);
BOOL Success;
m_dwNumPins = GetDlgItemInt(m_Dlg, IDC_NUMPINS, &Success, FALSE);
//
// Set Number of Streams
//
HRESULT hr = m_pIFilterConfig->SetNumberOfStreams(m_dwNumPins);
if (SUCCEEDED(hr) && !m_pIMixerControl)
{
hr = m_pIFilterConfig->QueryInterface(IID_IVMRMixerControl, (void **) &m_pIMixerControl);
if (SUCCEEDED(hr))
{
// select the last pin connected because this will be highest in the z-order
m_CurPin = m_dwNumPins - 1;
InitConfigControls(m_CurPin);
}
}
// Notify the graph so it will draw the new pins
if (m_pEventSink)
{
hr = m_pEventSink->Notify(EC_GRAPH_CHANGED, 0, 0);
}
return NOERROR;
} // OnApplyChanges
//
// SetDirty
//
// Sets m_hrDirtyFlag and notifies the property page site of the change
//
void CVMRFilterConfigProp::SetDirty()
{
m_bDirty = TRUE;
if (m_pPageSite)
{
m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
}
} // SetDirty
//
// OnActivate
//
// Override CBasePropertyPage method.
// Called when the page is being displayed. Used to initialize page contents.
//
HRESULT CVMRFilterConfigProp::OnActivate()
{
ASSERT(m_pIFilterConfig);
HRESULT hr = m_pIFilterConfig->GetNumberOfStreams(&m_dwNumPins);
if (NULL == m_pIMixerControl)
{
hr = m_pIFilterConfig->QueryInterface(IID_IVMRMixerControl, (void **) &m_pIMixerControl);
// if IMixerControl is exposed, the VMR is in mixing mode
if (S_OK == hr && m_pIMixerControl)
{
// if this is the first time, select the last pin connected because this will be highest in the z-order
m_CurPin = m_dwNumPins - 1;
InitConfigControls(m_CurPin);
}
}
else
{
InitConfigControls(m_CurPin);
}
BOOL bSet = SetDlgItemInt(m_Dlg, IDC_NUMPINS, m_dwNumPins, 0);
ASSERT(bSet);
// Set the range of the spin control
HWND hSpin = GetDlgItem(m_Dlg, IDC_PINSPIN);
if(hSpin)
{
SendMessage(hSpin, UDM_SETRANGE32, 1, 16);
}
return NOERROR;
} // OnActivate
//
// InitConfigControls
//
// Enable and update the content of the configuration controls .
//
void CVMRFilterConfigProp::InitConfigControls(DWORD pin)
{
// If this call fails, the pins are not connected or there is no mixing control.
if (FAILED(UpdateMixingData(pin)))
{
return;
}
//
// Populate Combo List Box and Enable Pin Config Controls
//
CComPtr<IBaseFilter> pFilter;
HRESULT hr = m_pIFilterConfig->QueryInterface(IID_IBaseFilter, (void **) &pFilter);
if (FAILED(hr) || !pFilter)
{
return;
}
CComPtr<IEnumPins> pEnum;
hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr) || !pEnum)
{
return;
}
HWND hCtl = GetDlgItem(m_Dlg, IDC_PINSELECT);
ComboBox_ResetContent(GetDlgItem(m_Dlg, IDC_PINSELECT));
pEnum->Reset();
IPin * pPin;
PIN_INFO Info;
TCHAR szPinName[255]; // pin names are 32 characters or less. This should be sufficient for a long time to come.
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
hr = pPin->QueryPinInfo(&Info);
if (SUCCEEDED(hr))
{
#ifdef UNICODE
_tcscpy(szPinName, Info.achName);
#else
WideCharToMultiByte(CP_ACP, NULL, Info.achName, -1, szPinName, 255, NULL, NULL);
#endif
ComboBox_AddString(GetDlgItem(m_Dlg, IDC_PINSELECT), szPinName);
pPin->Release();
Info.pFilter->Release();
}
}
ComboBox_SetCurSel(GetDlgItem(m_Dlg, IDC_PINSELECT), pin); // select the pin
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_PINSELECT), TRUE);
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_XPOS_SLIDER), TRUE);
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_YPOS_SLIDER), TRUE);
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER), TRUE);
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER), TRUE);
ComboBox_Enable(GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER), TRUE);
// Initialize the sliders
HWND hwndT;
int pos;
TCHAR sz[32];
hwndT = GetDlgItem(m_Dlg, IDC_XPOS_SLIDER );
pos = int(1000 * m_XPos) + 1000;
SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_XPos);
SetDlgItemText(m_Dlg, IDC_XPOS, sz);
pos = int(1000 * m_YPos) + 1000;
hwndT = GetDlgItem(m_Dlg, IDC_YPOS_SLIDER );
SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_YPos);
SetDlgItemText(m_Dlg, IDC_YPOS, sz);
pos = int(1000 * m_XSize) + 1000;
hwndT = GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER );
SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_XSize);
SetDlgItemText(m_Dlg, IDC_XSIZE, sz);
pos = int(1000 * m_YSize) + 1000;
hwndT = GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER );
SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_YSize);
SetDlgItemText(m_Dlg, IDC_YSIZE, sz);
pos = int(1000 * m_Alpha);
hwndT = GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER );
SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(1000)));
SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
_stprintf(sz, TEXT("%.3f"), m_Alpha);
SetDlgItemText(m_Dlg, IDC_ALPHA, sz);
}// InitConfigControls
//
// OnHScroll
//
// Handles the scroll messages for our property window
//
void CVMRFilterConfigProp::OnHScroll(HWND hwnd, HWND hwndCtrl, UINT code, int pos)
{
ASSERT(m_pIMixerControl);
TCHAR sz[32];
if (GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER ) == hwndCtrl) {
pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
m_Alpha = (FLOAT)pos / 1000.0F;
UpdatePinAlpha(m_CurPin);
_stprintf(sz, TEXT("%.3f"), m_Alpha);
SetDlgItemText(m_Dlg, IDC_ALPHA, sz);
}
else if (GetDlgItem(m_Dlg, IDC_XPOS_SLIDER ) == hwndCtrl) {
pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
m_XPos = ((FLOAT)pos - 1000.0F) / 1000.0F;
UpdatePinPos(m_CurPin);
_stprintf(sz, TEXT("%.3f"), m_XPos);
SetDlgItemText(m_Dlg, IDC_XPOS, sz);
}
else if (GetDlgItem(m_Dlg, IDC_YPOS_SLIDER ) == hwndCtrl) {
pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
m_YPos = ((FLOAT)pos - 1000.0F) / 1000.0F;
UpdatePinPos(m_CurPin);
_stprintf(sz, TEXT("%.3f"), m_YPos);
SetDlgItemText(m_Dlg, IDC_YPOS, sz);
}
else if (GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER ) == hwndCtrl) {
pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
m_XSize = ((FLOAT)pos - 1000.0F) / 1000.0F;
UpdatePinPos(m_CurPin);
_stprintf(sz, TEXT("%.3f"), m_XSize);
SetDlgItemText(m_Dlg, IDC_XSIZE, sz);
}
else if (GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER ) == hwndCtrl) {
pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
m_YSize = ((FLOAT)pos - 1000.0F) / 1000.0F;
UpdatePinPos(m_CurPin);
_stprintf(sz, TEXT("%.3f"), m_YSize);
SetDlgItemText(m_Dlg, IDC_YSIZE, sz);
}
} // OnHScroll
//
// UpdatePinAlpha
//
// Update the alpha value of a stream
//
void CVMRFilterConfigProp::UpdatePinAlpha(DWORD dwStreamID)
{
if (m_pIMixerControl)
{
m_pIMixerControl->SetAlpha(dwStreamID, m_Alpha);
}
} // UpdatePinAlpha
//
// UpdatePinPos
//
// Update the position rectangle of a stream
//
void CVMRFilterConfigProp::UpdatePinPos(DWORD dwStreamID)
{
NORMALIZEDRECT r = {m_XPos, m_YPos, m_XPos + m_XSize, m_YPos + m_YSize};
if (m_pIMixerControl)
{
m_pIMixerControl->SetOutputRect(dwStreamID, &r);
}
} // UpdatePinPos
//
// UpdateMixingData
//
// Query the filter for the current alpha value and position of a stream
//
HRESULT CVMRFilterConfigProp::UpdateMixingData(DWORD dwStreamID)
{
NORMALIZEDRECT r;
if (m_pIMixerControl)
{
HRESULT hr = m_pIMixerControl->GetOutputRect(dwStreamID, &r);
if (FAILED(hr))
{
return hr;
}
m_XPos = r.left;
m_YPos = r.top;
m_XSize = r.right - r.left;
m_YSize = r.bottom - r.top;
return m_pIMixerControl->GetAlpha(dwStreamID, &m_Alpha);
}
return E_NOINTERFACE;
} // UpdateMixingData
//
// Data types and macros used for image capture
//
typedef LPBITMAPINFOHEADER PDIB;
#define BFT_BITMAP 0x4d42 /* 'BM' */
#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
? (int)(1 << (int)(lpbi)->biBitCount) \
: (int)(lpbi)->biClrUsed)
#define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + \
(int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
#define DibPaletteSize(lpbi) (DibNumColors(lpbi) * sizeof(RGBQUAD))
//
// SaveCapturedImage
//
// Save a captured image (bitmap) to a file
//
bool CVMRFilterConfigProp::SaveCapturedImage(TCHAR* szFile, BYTE* lpCurrImage)
{
BITMAPFILEHEADER hdr;
DWORD dwSize;
PDIB pdib = (PDIB)lpCurrImage;
//fh = OpenFile(szFile,&of,OF_CREATE|OF_READWRITE);
HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return FALSE;
dwSize = DibSize(pdib);
hdr.bfType = BFT_BITMAP;
hdr.bfSize = dwSize + sizeof(BITMAPFILEHEADER);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize +
DibPaletteSize(pdib);
DWORD dwWritten;
WriteFile(hFile, (LPVOID)&hdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
if (sizeof(BITMAPFILEHEADER) != dwWritten)
return FALSE;
WriteFile(hFile, (LPVOID)pdib, dwSize, &dwWritten, NULL);
if (dwSize != dwWritten)
return FALSE;
CloseHandle(hFile);
return TRUE;
}
//
// CaptureCurrentImage
//
// Captures the current VMR image and save it to a file
//
void CVMRFilterConfigProp::CaptureCurrentImage(void)
{
IBasicVideo* iBV;
BYTE* lpCurrImage = NULL;
HRESULT hr = m_pIFilterConfig->QueryInterface(IID_IBasicVideo, (LPVOID*)&iBV);
if (SUCCEEDED(hr)) {
LONG BuffSize = 0;
hr = iBV->GetCurrentImage(&BuffSize, NULL);
if (SUCCEEDED(hr)) {
lpCurrImage = new BYTE[BuffSize];
if (lpCurrImage) {
hr = iBV->GetCurrentImage(&BuffSize, (long*)lpCurrImage);
if (FAILED(hr)) {
delete lpCurrImage;
lpCurrImage = NULL;
}
}
}
} // QI
if (lpCurrImage) {
// Get the path to the My Pictures folder. Create it if it doesn't exist.
// If we can't get it, don't use a path. Picture will then be saved in
// current working directory.
TCHAR tszPath[MAX_PATH];
if (!SHGetSpecialFolderPath(NULL, tszPath, CSIDL_MYPICTURES, TRUE))
{
tszPath[0]=TEXT('\0');
}
DWORD dwTime = timeGetTime();
TCHAR szFile[MAX_PATH];
wsprintf(szFile, TEXT("%s\\VMRImage%X.bmp"), tszPath, dwTime);
SaveCapturedImage(szFile, lpCurrImage);
delete lpCurrImage;
}
if (iBV) {
iBV->Release();
}
}