// Unicode文字セット
#pragma comment(lib, "strmiids.lib")
#include <DShow.h>
#include <d3d9.h>
#include <vmr9.h>
#define SAFE_RELEASE(x) { if (x) { x->Release(); x = NULL; } }
#define CLASS_NAME TEXT("dshow2")
#define WINDOW_NAME TEXT("dshow2")
// 関数プロトタイプ宣言
HRESULT OpenFile(HWND hWnd, LPCWSTR pszFileName);
HRESULT InitWndlessVMR(HWND hWnd, IGraphBuilder *pGraph, IVMRWindowlessControl9 **ppWndless);
HRESULT SetVideoPos(HWND hWnd, int nMode);
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 外部変数構造体
static struct {
IGraphBuilder *pGraph;
IMediaControl *pControl;
IVMRWindowlessControl9 *pWndless;
SIZE size;
int nPlay;
} g;
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hWnd;
MSG msg = {NULL};
HRESULT hr;
// COMライブラリの初期化
hr = CoInitialize(NULL);
if (FAILED(hr)) {
return 0;
}
// ウィンドウクラスの登録
ZeroMemory(&wcx, sizeof wcx);
wcx.cbSize = sizeof wcx;
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = MainWndProc;
wcx.hInstance = hInstance;
wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
// wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 黒がいいかも
wcx.lpszClassName = CLASS_NAME;
if (RegisterClassEx(&wcx) == 0) {
goto Exit;
}
// ウィンドウの作成
hWnd = CreateWindow(CLASS_NAME, WINDOW_NAME,
WS_OVERLAPPEDWINDOW,
// CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
100, 100, 640, 480,
NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
goto Exit;
}
// DirectShowフィルタの準備
hr = OpenFile(hWnd, L"c:\\tmp\\hoge.mp4");
if (FAILED(hr)) {
goto Exit;
}
ShowWindow(hWnd, nCmdShow);
// 動画再生
hr = g.pControl->Run();
g.nPlay = 1;
// メッセージループ
do {
Sleep(1);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} while (msg.message != WM_QUIT);
// 動画停止
hr = g.pControl->Stop();
Sleep(1000);
Exit:
SAFE_RELEASE(g.pWndless);
SAFE_RELEASE(g.pControl);
SAFE_RELEASE(g.pGraph);
CoUninitialize();
return msg.wParam;
}
//------------------------------------------------------------------------------
HRESULT OpenFile(HWND hWnd, LPCWSTR pszFile)
{
// フィルタグラフの作成
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&g.pGraph));
// メディアコントロールインターフェイスの取得
if (SUCCEEDED(hr)) {
hr = g.pGraph->QueryInterface(IID_PPV_ARGS(&g.pControl));
}
// ウィンドウレスコントロールの作成
if (SUCCEEDED(hr)) {
hr = InitWndlessVMR(hWnd, g.pGraph, &g.pWndless);
}
// グラフを作成する
if (SUCCEEDED(hr)) {
hr = g.pGraph->RenderFile(pszFile, NULL);
}
// 描画領域の設定
if (SUCCEEDED(hr)) {
hr = g.pWndless->GetNativeVideoSize(&g.size.cx, &g.size.cy, NULL, NULL);
}
if (SUCCEEDED(hr)) {
hr = SetVideoPos(hWnd, 2);
}
return hr;
}
//------------------------------------------------------------------------------
HRESULT InitWndlessVMR(HWND hWnd, IGraphBuilder *pGraph, IVMRWindowlessControl9 **ppWndless)
{
IBaseFilter *pVmr = NULL;
IVMRWindowlessControl9 *pWndless = NULL;
if (!pGraph || !ppWndless) {
return E_POINTER;
}
// VMRを作成する
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pVmr));
// フィルタグラフにVMRを追加する
if (SUCCEEDED(hr)) {
hr = pGraph->AddFilter(pVmr, L"VMR-9");
}
// レンダリングモードを設定する
IVMRFilterConfig9 *pConfig = NULL;
if (SUCCEEDED(hr)) {
hr = pVmr->QueryInterface(IID_IVMRFilterConfig9, (LPVOID *)&pConfig);
}
if (SUCCEEDED(hr)) {
hr = pConfig->SetRenderingMode(VMR9Mode_Windowless);
}
SAFE_RELEASE(pConfig);
// ウィンドウを設定する
if (SUCCEEDED(hr)) {
hr = pVmr->QueryInterface(IID_PPV_ARGS(&pWndless));
}
if (SUCCEEDED(hr)) {
hr = pWndless->SetVideoClippingWindow(hWnd);
if (SUCCEEDED(hr)) {
*ppWndless = pWndless;
} else {
SAFE_RELEASE(pWndless);
}
}
// pWndless->SetAspectRatioMode(VMR9ARMode_LetterBox);
SAFE_RELEASE(pVmr);
return hr;
}
//------------------------------------------------------------------------------
HRESULT SetVideoPos(HWND hWnd, int nMode)
{
RECT rcSrc;
RECT rcDst;
SetRect(&rcSrc, 0, 0, g.size.cx, g.size.cy);
if (1 <= nMode && nMode <= 4) {
SetRect(&rcDst, 0, 0, rcSrc.right * nMode / 2, rcSrc.bottom * nMode / 2);
AdjustWindowRectEx(&rcDst, WS_OVERLAPPEDWINDOW, FALSE, 0);
SetWindowPos(hWnd, NULL, 0, 0, rcDst.right - rcDst.left, rcDst.bottom - rcDst.top,
SWP_NOZORDER | SWP_NOMOVE);
}
GetClientRect(hWnd, &rcDst);
return g.pWndless->SetVideoPosition(&rcSrc, &rcDst);
}
//------------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CHAR:
switch (wParam) {
case VK_SPACE:
if (g.nPlay) {
g.pControl->Pause();
g.nPlay = 0;
} else {
g.pControl->Run();
g.nPlay = 1;
}
break;
case 's':
g.pControl->StopWhenReady();
g.nPlay = 0;
break;
case '1': case '2': case '3': case '4':
SetVideoPos(hWnd, wParam - '0');
break;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
}
break;
case WM_SIZE:
SetVideoPos(hWnd, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}