できるだけサンプルから変えないように変えないようにとしてきましたが、内容に矛盾がある以上Graohic的な部分とRunMessageloopみたいなwindowsチックな部分は別のクラスにしなければなりませんね。
コード:
// 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) Microsoft Corporation. All rights reserved
#include "SimpleDirect2dApplication.h"
#include <tchar.h>
#include "GameMain.h"
//
// Provides the entry point to the application.
//
int WINAPI WinMain(
HINSTANCE /* hInstance */,
HINSTANCE /* hPrevInstance */,
LPSTR /* lpCmdLine */,
int /* nCmdShow */
)
{
// Ignore the return value because we want to continue running even in the
// unlikely event that HeapSetInformation fails.
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
if (SUCCEEDED(CoInitialize(NULL)))
{
{
Graphic app;
if (SUCCEEDED(app.Initialize()))
{
//oGameMain(&app);
GameMain Gmain(&app);
Gmain.Main(&app);
}
}
CoUninitialize();
}
return 0;
}
//
// Initialize members.
//
Graphic::Graphic() :
m_hwnd(NULL),
m_pD2DFactory(NULL),
m_pWICFactory(NULL),
m_pDWriteFactory(NULL),
m_pRenderTarget(NULL),
m_pTextFormat(NULL),
m_pPathGeometry(NULL),
m_pLinearGradientBrush(NULL),
m_pBlackBrush(NULL),
m_pGridPatternBitmapBrush(NULL)
// m_pBitmap(NULL),
//m_pAnotherBitmap(NULL)
{
}
//
// Release resources.
//
Graphic::~Graphic()
{
SafeRelease(&m_pD2DFactory);
SafeRelease(&m_pWICFactory);
SafeRelease(&m_pDWriteFactory);
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pTextFormat);
SafeRelease(&m_pPathGeometry);
SafeRelease(&m_pLinearGradientBrush);
SafeRelease(&m_pBlackBrush);
SafeRelease(&m_pGridPatternBitmapBrush);
// SafeRelease(&m_pBitmap);
// SafeRelease(&m_pAnotherBitmap);
}
//
// Creates the application window and initializes
// device-independent resources.
//
HRESULT Graphic::Initialize()
{
//DemoApp.hr=CreateDeviceIndependentResources();
HRESULT hr;
// Initialize device-indpendent resources, such
// as the Direct2D factory.
hr=CreateDeviceIndependentResources();
if (SUCCEEDED(hr))
{
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Graphic::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = L"D2DDemoApp";
RegisterClassEx(&wcex);
// Create the application window.
//
// Because the CreateWindow function takes its size in pixels, we
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
// Create the application window.
m_hwnd = CreateWindow(
L"D2DDemoApp",
L"WindowTitle",
WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,//サイズ変更と最大化をブロック
CW_USEDEFAULT,
CW_USEDEFAULT,
800,//static_cast<UINT>(ceil(800.f * dpiX / 96.f)),
600,//static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
}
}
return hr;
}
//
// Create resources which are not bound
// to any device. Their lifetime effectively extends for the
// duration of the app. These resources include the Direct2D,
// DirectWrite, and WIC factories; and a DirectWrite Text Format object
// (used for identifying particular font characteristics) and
// a Direct2D geometry.
//
HRESULT Graphic::CreateDeviceIndependentResources()
{
static const WCHAR msc_fontName[] = L"Verdana";
static const FLOAT msc_fontSize = 50;
HRESULT hr;
ID2D1GeometrySink *pSink = NULL;
// Create a Direct2D factory.
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
if (SUCCEEDED(hr))
{
// Create WIC factory.
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&m_pWICFactory)
);
}
if (SUCCEEDED(hr))
{
// Create a DirectWrite factory.
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(m_pDWriteFactory),
reinterpret_cast<IUnknown **>(&m_pDWriteFactory)
);
}
if (SUCCEEDED(hr))
{
// Create a DirectWrite text format object.
hr = m_pDWriteFactory->CreateTextFormat(
msc_fontName,
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
msc_fontSize,
L"", //locale
&m_pTextFormat
);
}
if (SUCCEEDED(hr))
{
// Center the text horizontally and vertically.
m_pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
m_pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
// Create a path geometry.
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
}
if (SUCCEEDED(hr))
{
// Use the geometry sink to write to the path geometry.
hr = m_pPathGeometry->Open(&pSink);
}
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
pSink->BeginFigure(
D2D1::Point2F(0, 0),
D2D1_FIGURE_BEGIN_FILLED
);
pSink->AddLine(D2D1::Point2F(200, 0));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(150, 50),
D2D1::Point2F(150, 150),
D2D1::Point2F(200, 200))
);
pSink->AddLine(D2D1::Point2F(0, 200));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(50, 150),
D2D1::Point2F(50, 50),
D2D1::Point2F(0, 0))
);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
return hr;
}
//
// This method creates resources which are bound to a particular
// Direct3D device. It's all centralized here, in case the resources
// need to be recreated in case of Direct3D device loss (eg. display
// change, remoting, removal of video card, etc).
//
HRESULT Graphic::CreateDeviceResources()
{
HRESULT hr = S_OK;
if (!m_pRenderTarget)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// Create a Direct2D render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
// Create a black brush.
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&m_pBlackBrush
);
}
if (SUCCEEDED(hr))
{
ID2D1GradientStopCollection *pGradientStops = NULL;
// Create a linear gradient.
static const D2D1_GRADIENT_STOP stops[] =
{
{ 0.f, { 0.f, 1.f, 1.f, 0.25f } },
{ 1.f, { 0.f, 0.f, 1.f, 1.f } },
};
hr = m_pRenderTarget->CreateGradientStopCollection(
stops,
ARRAYSIZE(stops),
&pGradientStops
);
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(100, 0),
D2D1::Point2F(100, 200)),
D2D1::BrushProperties(),
pGradientStops,
&m_pLinearGradientBrush
);
pGradientStops->Release();
}
}
if (SUCCEEDED(hr))
{
hr = CreateGridPatternBrush(m_pRenderTarget, &m_pGridPatternBitmapBrush);
}
}
return hr;
}
//LoadGraphics
ID2D1Bitmap* Graphic::LoadGr(TCHAR *text){
ID2D1Bitmap *Gr=NULL;
if (SUCCEEDED(hr))
{
// Create a bitmap by loading it from a file.
hr = LoadBitmapFromFile(
m_pRenderTarget,
m_pWICFactory,
text,
0,
0,
&Gr
);
}
return Gr;
}
//
// Creates a pattern brush.
//
HRESULT Graphic::CreateGridPatternBrush(
ID2D1RenderTarget *pRenderTarget,
ID2D1BitmapBrush **ppBitmapBrush
)
{
HRESULT hr = S_OK;
// Create a compatible render target.
ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL;
hr = pRenderTarget->CreateCompatibleRenderTarget(
D2D1::SizeF(10.0f, 10.0f),
&pCompatibleRenderTarget
);
if (SUCCEEDED(hr))
{
// Draw a pattern.
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
if (SUCCEEDED(hr))
{
pCompatibleRenderTarget->BeginDraw();
pCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 0.0f, 10.0f, 1.0f), pGridBrush);
pCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 0.1f, 1.0f, 10.0f), pGridBrush);
pCompatibleRenderTarget->EndDraw();
// Retrieve the bitmap from the render target.
ID2D1Bitmap *pGridBitmap = NULL;
hr = pCompatibleRenderTarget->GetBitmap(&pGridBitmap);
if (SUCCEEDED(hr))
{
// Choose the tiling mode for the bitmap brush.
D2D1_BITMAP_BRUSH_PROPERTIES brushProperties =
D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
// Create the bitmap brush.
hr = m_pRenderTarget->CreateBitmapBrush(pGridBitmap, brushProperties, ppBitmapBrush);
pGridBitmap->Release();
}
pGridBrush->Release();
}
pCompatibleRenderTarget->Release();
}
return hr;
}
//
// Discard device-specific resources which need to be recreated
// when a Direct3D device is lost
//
void Graphic::DiscardDeviceResources()
{
SafeRelease(&m_pRenderTarget);
// SafeRelease(&m_pBitmap);
SafeRelease(&m_pBlackBrush);
SafeRelease(&m_pLinearGradientBrush);
// SafeRelease(&m_pAnotherBitmap);
SafeRelease(&m_pGridPatternBitmapBrush);
}
//
// The main window message loop.
//
int Graphic::RunMessageLoop()
{
MSG msg;
//HWND
hr=CreateDeviceResources();
//for(;;){
if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)!=0){
if (!GetMessage (&msg,NULL,0,0)){//WM_QUITが来てた時の /* メッセージ処理 */
//MessageBox(NULL,L"終了処理",L"てすてす",MB_OK);
return 0;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
//MessageBox(NULL,L"PM後",L"てすてす",MB_OK);
}
return 1;
//}
}
void Graphic::paint(ID2D1Bitmap *Gr,float x,float y){//
HWND Hwnd=m_hwnd;
PAINTSTRUCT ps;
BeginPaint(Hwnd, &ps);
OnRender(Gr,x,y);
EndPaint(Hwnd, &ps);
}
HRESULT Graphic::Bpaint(){
m_pRenderTarget->BeginDraw();
return 0;
}
HRESULT Graphic::Epaint(){
hr = m_pRenderTarget->EndDraw();
return 0;
}
void Graphic::ClearScreen(){
//m_pRenderTarget->BeginDraw();
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));//画面を白でクリア
//m_pRenderTarget->EndDraw();
}
HRESULT Graphic::OnRender(ID2D1Bitmap *Gr,float x,float y)//
{
if(Gr==NULL){
MessageBox(NULL,L"画像が読みこまれていません。",L"エラー",MB_OK);
return -1;
}
if (SUCCEEDED(Graphic::hr) && !(m_pRenderTarget->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
{
//static const WCHAR sc_helloWorld[] = L"Hello, World!";//テキスト
// Retrieve the size of the render target.
//D2D1_SIZE_F renderTargetSize = m_pRenderTarget->GetSize();
//m_pRenderTarget->BeginDraw();
//m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
//m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));//画面を白でクリア
// Draw a bitmap
D2D1_SIZE_F size = Gr->GetSize();
m_pRenderTarget->DrawBitmap(
Gr,
D2D1::RectF(
x,
y,//renderTargetSize.height- size.height,
(x)+size.width,
(y)+size.height)
);
//hr = m_pRenderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
}
return hr;
}
//
// If the application receives a WM_SIZE message, this method
// resize the render target appropriately.
//
void Graphic::OnResize(UINT width, UINT height)
{
if (m_pRenderTarget)
{
D2D1_SIZE_U size;
size.width = width;
size.height = height;
// Note: This method can fail, but it's okay to ignore the
// error here -- it will be repeated on the next call to
// EndDraw.
m_pRenderTarget->Resize(size);
}
}
//
// The window message handler.
//
//注)多分ここで開始、終了、読み込み等の処理を行なっている気がするので移植する必要あり
LRESULT CALLBACK Graphic::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
Graphic *pGraphic = (Graphic *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pGraphic)
);
//HWND hWnd;
/*IntPtr hMenu = GetSystemMenu(hWnd, 0);
RemoveMenu(hWnd,SC_MINIMIZE); */
result = 1;
}
else
{
Graphic *pGraphic = reinterpret_cast<Graphic *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
bool wasHandled = false;
if (pGraphic)
{
switch (message)
{
case WM_SIZE://
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pGraphic->OnResize(width, height);
}
result = 0;
wasHandled = true;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
case WM_ERASEBKGND:
{
return FALSE;
}
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
//
// Creates a Direct2D bitmap from a resource in the
// application resource file.
//
HRESULT Graphic::LoadResourceBitmap(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR resourceName,
PCWSTR resourceType,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
HRSRC imageResHandle = NULL;
HGLOBAL imageResDataHandle = NULL;
void *pImageFile = NULL;
DWORD imageFileSize = 0;
// Locate the resource.
imageResHandle = FindResourceW(HINST_THISCOMPONENT, resourceName, resourceType);
hr = imageResHandle ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Load the resource.
imageResDataHandle = LoadResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageResDataHandle ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Lock it to get a system memory pointer.
pImageFile = LockResource(imageResDataHandle);
hr = pImageFile ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Calculate the size.
imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageFileSize ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Create a WIC stream to map onto the memory.
hr = pIWICFactory->CreateStream(&pStream);
}
if (SUCCEEDED(hr))
{
// Initialize the stream with the memory pointer and size.
hr = pStream->InitializeFromMemory(
reinterpret_cast<BYTE*>(pImageFile),
imageFileSize
);
}
if (SUCCEEDED(hr))
{
// Create a decoder for the stream.
hr = pIWICFactory->CreateDecoderFromStream(
pStream,
NULL,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
);
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
}
else
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
if (SUCCEEDED(hr))
{
//create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}
//
// Creates a Direct2D bitmap from the specified
// file name.
//
HRESULT Graphic::LoadBitmapFromFile(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
hr = pIWICFactory->CreateDecoderFromFilename(
uri,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
else // Don't scale the image.
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
if (SUCCEEDED(hr))
{
// Create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}