Newer
Older
PrismSoftware / ECTrainer2 / DShowMovie.cpp
#include "DShowMovie.h"
#include "myWinUtils.h"

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "Strmiids.lib")
#define _WIN32_DCOM     // CoInitializeEx関数の呼び出しに必要

// コンストラクタ
DShowMovie::DShowMovie() 
	: _pD3D(NULL)
	, _pD3DDev(NULL)
	, _pGB(NULL)
	, _pVMR9(NULL)
	, _pSource(NULL)
	, _pCGB2(NULL)
	, _pMediaCont(NULL)
	, _pMediaEvent(NULL)
	, _pMediaPosition(NULL)
	, _hWnd(NULL)
{
}

// デストラクタ
DShowMovie::~DShowMovie() {
	SAFE_RELEASE(_pMediaPosition);
	SAFE_RELEASE(_pMediaEvent);
	SAFE_RELEASE(_pMediaCont);
	SAFE_RELEASE(_pCGB2);
	SAFE_RELEASE(_pSource);
	SAFE_RELEASE(_pVMR9);
	SAFE_RELEASE(_pGB);
	SAFE_RELEASE(_pD3DDev);
	SAFE_RELEASE(_pD3D);
	CoUninitialize();
}

// DirectXの初期化
bool DShowMovie::InitDx(HINSTANCE hInstance, RECT dispRect) {
	// ウインドウクラスの設定
	TCHAR gName[100] = _T("Video Window");
	WNDCLASSEX wcex = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
								 (HBRUSH)(COLOR_WINDOW + 1), NULL, (TCHAR*)gName, NULL };
	if (!RegisterClassEx(&wcex)) return 0;

	// フルスクリーン用にポップアップウィンドウを作成
	if (!(_hWnd = CreateWindow(gName, gName, WS_POPUPWINDOW, dispRect.left, dispRect.top,
		dispRect.right - dispRect.left, dispRect.bottom - dispRect.top,
		NULL, NULL, hInstance, NULL)))
		return false;

	// Direct3Dの初期化
	if (!(_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return false;

	// フルスクリーン用に初期化パラメータを設定
	D3DPRESENT_PARAMETERS d3dpp = { (UINT)(dispRect.right - dispRect.left),
		(UINT)(dispRect.bottom - dispRect.top), D3DFMT_A8R8G8B8, 0, D3DMULTISAMPLE_NONE, 0,
		D3DSWAPEFFECT_DISCARD, _hWnd, FALSE, 0, D3DFMT_UNKNOWN, D3DPRESENT_RATE_DEFAULT, 0 };

	if (FAILED(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _hWnd,
		D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &_pD3DDev))) {

		CHECK(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _hWnd,
			D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_pD3DDev));
		mwut::DebugPrintf(_T("Software DirectX\n"));
	} else {
		mwut::DebugPrintf(_T("Hardware DirectX\n"));
	}

	// COMの初期化
	CHECK(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));

	return true;
}

// 動画再生
bool DShowMovie::PlayMovie(std::wstring movie) {
	this->StopMovie();

	// フィルタグラフマネージャの作成
	CHECK(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&_pGB));

	// VRM9フィルタの作成と登録
	CHECK(CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&_pVMR9));
	CHECK(_pGB->AddFilter(_pVMR9, L"VMR9"));       // フィルタグラフに登録

	// VRM9をウィンドウレスモードにする
	IVMRFilterConfig* pVMRCfg = NULL;
	CHECK(_pVMR9->QueryInterface(IID_IVMRFilterConfig9, (void**)&pVMRCfg));
	CHECK(pVMRCfg->SetRenderingMode(VMRMode_Windowless));
	pVMRCfg->Release();     // IVMRFilterConfigはもう必要ない

	// 描画ウィンドウの指定
	IVMRWindowlessControl9* pVMRWndCont = NULL;
	CHECK(_pVMR9->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pVMRWndCont));
	CHECK(pVMRWndCont->SetVideoClippingWindow(_hWnd));

	// ソースフィルタの生成と登録
	CHECK(_pGB->AddSourceFilter(movie.c_str(), movie.c_str(), &_pSource));

	// CaptureGraphBuilder2インターフェイスの取得
	CHECK(CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&_pCGB2));
	CHECK(_pCGB2->SetFiltergraph(_pGB));

	// フィルタの接続
	CHECK(_pCGB2->RenderStream(0, 0, _pSource, 0, _pVMR9));
	CHECK(_pCGB2->RenderStream(0, &MEDIATYPE_Audio, _pSource, 0, 0));

	// 描画領域の設定(接続後でないとエラーになる)
	LONG W, H;
	CHECK(pVMRWndCont->GetNativeVideoSize(&W, &H, NULL, NULL));
	RECT SrcR, DestR;
	SetRect(&SrcR, 0, 0, W, H);
	GetClientRect(_hWnd, &DestR);
	CHECK(pVMRWndCont->SetVideoPosition(&SrcR, &DestR));
	pVMRWndCont->Release();         // ウィンドウレスコントロールはもう必要ない

	// メディアコントロールインターフェイスの取得
	CHECK(_pGB->QueryInterface(IID_IMediaControl, (void**)&_pMediaCont));

	// メディアイベントインターフェイスの取得
	CHECK(_pGB->QueryInterface(IID_IMediaEvent, (void**)&_pMediaEvent));

	// メディアポジションインターフェイスの取得
	CHECK(_pGB->QueryInterface(IID_IMediaPosition, (void**)&_pMediaPosition));

	ShowWindow(_hWnd, SW_SHOWNORMAL);
	CHECK(_pMediaCont->Run());

	return true;
}

// 動画停止
bool DShowMovie::StopMovie() {
	if (_pMediaCont) _pMediaCont->Stop();
	SAFE_RELEASE(_pMediaPosition);
	SAFE_RELEASE(_pMediaEvent);
	SAFE_RELEASE(_pMediaCont);
	SAFE_RELEASE(_pCGB2);
	SAFE_RELEASE(_pSource);
	SAFE_RELEASE(_pVMR9);
	SAFE_RELEASE(_pGB);
	if (_hWnd) ShowWindow(_hWnd, SW_HIDE);
	return true;
}

// 再生状態の確認
bool DShowMovie::IsPlaying() {
	return (_pGB != NULL);
}

// 再生状態の取得
FILTER_STATE DShowMovie::GetMovieState() {
	if (!_pMediaCont) return State_Stopped;
	FILTER_STATE fs;
	_pMediaCont->GetState(100, (OAFilterState*)&fs);
	return fs;
}

// 再生が最後まで到達したか
bool DShowMovie::IsReachToEnd() {
	if (!_pMediaEvent) return false;
	long eventCode;
	auto rv = _pMediaEvent->WaitForCompletion(0, &eventCode);
	//mwut::DebugPrintf(_T("eventCode %d (%d,%d,%d)\n"), eventCode, EC_COMPLETE, EC_ERRORABORT, EC_USERABORT);
	return (eventCode == EC_COMPLETE);
}

// 再生位置の取得
double DShowMovie::GetPlayPos() {
	if (!_pMediaPosition) return -1.0;
	REFTIME tm;
	_pMediaPosition->get_CurrentPosition(&tm);
	return tm;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	if (msg == WM_DESTROY) { PostQuitMessage(0); return 0; }
	return DefWindowProc(hWnd, msg, wParam, lParam);
}