開発環境 Microsoft Visual Studio Express 2013 for Windows Desktop
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 Visual C++/Win32 プロジェクト
プロジェクト名 BasicPlayback
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト、SDLチェック

作りかけ。

参考

player.cpp
#pragma comment(lib, "mf")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "strmiids")
 
#include "player.h"
 
#pragma comment(lib, "shlwapi")
 
template <class Q>
HRESULT GetEventObject(IMFMediaEvent *pEvent, Q **ppObject)
{
	*ppObject = NULL;
 
	PROPVARIANT var;
	HRESULT hr = pEvent->GetValue(&var);
	if (SUCCEEDED(hr))
	{
		if (var.vt == VT_UNKNOWN)
		{
			hr = var.punkVal->QueryInterface(ppObject);
		}
		else
		{
			hr = MF_E_INVALIDTYPE;
		}
		PropVariantClear(&var);
	}
	return hr;
}
 
HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource);
 
HRESULT CreatePlaybackTopology(
	IMFMediaSource *pSource,
	IMFPresentationDescriptor *pPD,
	HWND hVideoWnd,
	IMFTopology **ppTopology);
 
HRESULT CPlayer::CreateInstance(
	HWND hVideo,
	HWND hEvent,
	CPlayer **ppPlayer)
{
	if (ppPlayer == NULL)
	{
		return E_POINTER;
	}
 
	CPlayer *pPlayer = new (std::nothrow) CPlayer(hVideo, hEvent);
	if (pPlayer == NULL)
	{
		return E_OUTOFMEMORY;
	}
 
	HRESULT hr = pPlayer->Initialize();
	if (SUCCEEDED(hr))
	{
		*ppPlayer = pPlayer;
	}
	else
	{
		pPlayer->Release();
	}
	return hr;
}
 
HRESULT CPlayer::Initialize()
{
	HRESULT hr = MFStartup(MF_VERSION);
	if (SUCCEEDED(hr))
	{
		m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (m_hCloseEvent == NULL)
		{
			hr = HRESULT_FROM_WIN32(GetLastError());
		}
	}
	return hr;
}
 
CPlayer::CPlayer(HWND hVideo, HWND hEvent) :
	m_pSession(NULL),
	m_pSource(NULL),
	m_pVideoDisplay(NULL),
	m_hwndVideo(hVideo),
	m_hwndEvent(hEvent),
	m_state(Closed),
	m_hCloseEvent(NULL),
	m_nRefCount(1)
{
}
 
CPlayer::~CPlayer()
{
	assert(m_pSession == NULL);
 
	Shutdown();
}
 
HRESULT CPlayer::QueryInterface(REFIID riid, void** ppv)
{
	static const QITAB qit[] =
	{
		QITABENT(CPlayer, IMFAsyncCallback),
		{ 0 }
	};
	return QISearch(this, qit, riid, ppv);
}
 
ULONG CPlayer::AddRef()
{
	return InterlockedIncrement(&m_nRefCount);
}
 
ULONG CPlayer::Release()
{
	ULONG uCount = InterlockedDecrement(&m_nRefCount);
	if (uCount == 0)
	{
		delete this;
	}
	return uCount;
}
 
HRESULT CPlayer::OpenURL(const WCHAR *sURL)
{
	IMFTopology *pTopology = NULL;
	IMFPresentationDescriptor *pSourcePD = NULL;
 
	HRESULT hr = CreateSession();
	if (FAILED(hr)) goto done;
 
	hr = CreateMediaSource(sURL, &m_pSource);
	if (FAILED(hr)) goto done;
 
	hr = m_pSource->CreatePresentationDescriptor(&pSourcePD);
	if (FAILED(hr)) goto done;
 
	hr = CreatePlaybackTopology(m_pSource, pSourcePD, m_hwndVideo, &pTopology);
	if (FAILED(hr)) goto done;
 
	hr = m_pSession->SetTopology(0, pTopology);
	if (FAILED(hr)) goto done;
 
	m_state = OpenPending;
 
done:
	if (FAILED(hr))
	{
		m_state = Closed;
	}
 
	SafeRelease(&pSourcePD);
	SafeRelease(&pTopology);
	return hr;
}
 
HRESULT CPlayer::Pause()
{
	if (m_state != Started)
	{
		return MF_E_INVALIDREQUEST;
	}
	if (m_pSession == NULL || m_pSource == NULL)
	{
		return E_UNEXPECTED;
	}
 
	HRESULT hr = m_pSession->Pause();
	if (SUCCEEDED(hr))
	{
		m_state = Paused;
	}
 
	return hr;
}
 
HRESULT CPlayer::Stop()
{
	if (m_state != Started && m_state != Paused)
	{
		return MF_E_INVALIDREQUEST;
	}
	if (m_pSession == NULL)
	{
		return E_UNEXPECTED;
	}
 
	HRESULT hr = m_pSession->Stop();
	if (SUCCEEDED(hr))
	{
		m_state = Stopped;
	}
	return hr;
}
 
HRESULT CPlayer::Repaint()
{
	if (m_pVideoDisplay)
	{
		return m_pVideoDisplay->RepaintVideo();
	}
	else
	{
		return S_OK;
	}
}
 
HRESULT CPlayer::ResizeVideo(WORD width, WORD height)
{
	if (m_pVideoDisplay)
	{
		RECT rcDest = { 0, 0, width, height };
 
		return m_pVideoDisplay->SetVideoPosition(NULL, &rcDest);
	}
	else
	{
		return S_OK;
	}
}
 
HRESULT CPlayer::Invoke(IMFAsyncResult *pResult)
{
	MediaEventType meType = MEUnknown;
 
	IMFMediaEvent *pEvent = NULL;
 
	HRESULT hr = m_pSession->EndGetEvent(pResult, &pEvent);
	if (FAILED(hr)) goto done;
 
	hr = pEvent->GetType(&meType);
	if (FAILED(hr)) goto done;
 
	if (meType == MESessionClosed)
	{
		SetEvent(m_hCloseEvent);
	}
	else
	{
		hr = m_pSession->BeginGetEvent(this, NULL);
		if (FAILED(hr)) goto done;
	}
 
	if (m_state != Closing)
	{
		pEvent->AddRef();
 
		PostMessage(m_hwndEvent, WM_APP_PLAYER_EVENT,
			(WPARAM)pEvent, (LPARAM)meType);
	}
 
done:
	SafeRelease(&pEvent);
	return S_OK;
}
 
HRESULT CPlayer::HandleEvent(UINT_PTR pEventPtr)
{
	HRESULT hrStatus = S_OK;
	MediaEventType meType = MEUnknown;
 
	IMFMediaEvent *pEvent = (IMFMediaEvent*)pEventPtr;
 
	if (pEvent == NULL)
	{
		return E_POINTER;
	}
 
	HRESULT hr = pEvent->GetType(&meType);
	if (FAILED(hr)) goto done;
 
	hr = pEvent->GetStatus(&hrStatus);
 
	if (SUCCEEDED(hr) && FAILED(hrStatus))
	{
		hr = hrStatus;
	}
	if (FAILED(hr)) goto done;
 
	switch (meType)
	{
	case MESessionTopologyStatus:
		hr = OnTopologyStatus(pEvent);
		break;
 
	case MEEndOfPresentation:
		hr = OnPresentationEnded(pEvent);
		break;
 
	case MENewPresentation:
		hr = OnNewPresentation(pEvent);
		break;
 
	default:
		hr = OnSessionEvent(pEvent, meType);
		break;
	}
 
done:
	SafeRelease(&pEvent);
	return hr;
}
 
HRESULT CPlayer::Shutdown()
{
	HRESULT hr = CloseSession();
 
	MFShutdown();
 
	if (m_hCloseEvent)
	{
		CloseHandle(m_hCloseEvent);
		m_hCloseEvent = NULL;
	}
 
	return hr;
}
 
HRESULT CPlayer::OnTopologyStatus(IMFMediaEvent *pEvent)
{
	UINT32 status;
 
	HRESULT hr = pEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, &status);
	if (SUCCEEDED(hr) && (status == MF_TOPOSTATUS_READY))
	{
		SafeRelease(&m_pVideoDisplay);
 
		(void)MFGetService(m_pSession, MR_VIDEO_RENDER_SERVICE,
			IID_PPV_ARGS(&m_pVideoDisplay));
 
		hr = StartPlayback();
	}
	return hr;
}
 
HRESULT CPlayer::OnPresentationEnded(IMFMediaEvent *pEvent)
{
	m_state = Stopped;
	return S_OK;
}
 
HRESULT CPlayer::OnNewPresentation(IMFMediaEvent *pEvent)
{
	IMFPresentationDescriptor *pPD = NULL;
	IMFTopology *pTopology = NULL;
 
	HRESULT hr = GetEventObject(pEvent, &pPD);
	if (FAILED(hr)) goto done;
 
	hr = CreatePlaybackTopology(m_pSource, pPD, m_hwndVideo, &pTopology);
	if (FAILED(hr)) goto done;
 
	hr = m_pSession->SetTopology(0, pTopology);
	if (FAILED(hr)) goto done;
 
	m_state = OpenPending;
 
done:
	SafeRelease(&pTopology);
	SafeRelease(&pPD);
	return S_OK;
}
 
HRESULT CPlayer::CreateSession()
{
	HRESULT hr = CloseSession();
	if (FAILED(hr)) goto done;
 
	assert(m_state == Closed);
 
	hr = MFCreateMediaSession(NULL, &m_pSession);
	if (FAILED(hr)) goto done;
 
	hr = m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL);
	if (FAILED(hr)) goto done;
 
	m_state = Ready;
 
done:
	return hr;
}
 
HRESULT CPlayer::CloseSession()
{
	HRESULT hr = S_OK;
 
	SafeRelease(&m_pVideoDisplay);
 
	if (m_pSession)
	{
		DWORD dwWaitResult = 0;
 
		m_state = Closing;
 
		hr = m_pSession->Close();
 
		if (SUCCEEDED(hr))
		{
			dwWaitResult = WaitForSingleObject(m_hCloseEvent, 5000);
			if (dwWaitResult == WAIT_TIMEOUT)
			{
				assert(FALSE);
			}
		}
	}
 
	if (SUCCEEDED(hr))
	{
 
		if (m_pSource)
		{
			(void)m_pSource->Shutdown();
		}
 
		if (m_pSession)
		{
			(void)m_pSession->Shutdown();
		}
	}
 
	SafeRelease(&m_pSource);
	SafeRelease(&m_pSession);
	m_state = Closed;
	return hr;
}
 
HRESULT CPlayer::StartPlayback()
{
	assert(m_pSession != NULL);
 
	PROPVARIANT varStart;
	PropVariantInit(&varStart);
 
	HRESULT hr = m_pSession->Start(&GUID_NULL, &varStart);
	if (SUCCEEDED(hr))
	{
		m_state = Started;
	}
	PropVariantClear(&varStart);
	return hr;
}
 
HRESULT CPlayer::Play()
{
	if (m_state != Paused && m_state != Stopped)
	{
		return MF_E_INVALIDREQUEST;
	}
	if (m_pSession == NULL || m_pSource == NULL)
	{
		return E_UNEXPECTED;
	}
	return StartPlayback();
}
 
HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource)
{
	MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
 
	IMFSourceResolver *pSourceResolver = NULL;
	IUnknown *pSource = NULL;
 
	HRESULT hr = MFCreateSourceResolver(&pSourceResolver);
	if (FAILED(hr)) goto done;
 
	hr = pSourceResolver->CreateObjectFromURL(
		sURL,
		MF_RESOLUTION_MEDIASOURCE,
		NULL,
		&ObjectType,
		&pSource
		);
	if (FAILED(hr)) goto done;
 
	hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource));
 
done:
	SafeRelease(&pSourceResolver);
	SafeRelease(&pSource);
	return hr;
}
 
HRESULT CreateMediaSinkActivate(
	IMFStreamDescriptor *pSourceSD,
	HWND hVideoWindow,
	IMFActivate **ppActivate)
{
	IMFMediaTypeHandler *pHandler = NULL;
	IMFActivate *pActivate = NULL;
 
	HRESULT hr = pSourceSD->GetMediaTypeHandler(&pHandler);
	if (FAILED(hr)) goto done;
 
	GUID guidMajorType;
	hr = pHandler->GetMajorType(&guidMajorType);
	if (FAILED(hr)) goto done;
 
	if (MFMediaType_Audio == guidMajorType)
	{
		hr = MFCreateAudioRendererActivate(&pActivate);
	}
	else if (MFMediaType_Video == guidMajorType)
	{
		hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);
	}
	else
	{
		hr = E_FAIL;
	}
	if (FAILED(hr)) goto done;
 
	*ppActivate = pActivate;
	(*ppActivate)->AddRef();
 
done:
	SafeRelease(&pHandler);
	SafeRelease(&pActivate);
	return hr;
}
 
HRESULT AddSourceNode(
	IMFTopology *pTopology,
	IMFMediaSource *pSource,
	IMFPresentationDescriptor *pPD,
	IMFStreamDescriptor *pSD,
	IMFTopologyNode **ppNode)
{
	IMFTopologyNode *pNode = NULL;
 
	HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD);
	if (FAILED(hr)) goto done;
 
	hr = pTopology->AddNode(pNode);
	if (FAILED(hr)) goto done;
 
	*ppNode = pNode;
	(*ppNode)->AddRef();
 
done:
	SafeRelease(&pNode);
	return hr;
}
 
HRESULT AddOutputNode(
	IMFTopology *pTopology,
	IMFActivate *pActivate,
	DWORD dwId,
	IMFTopologyNode **ppNode)
{
	IMFTopologyNode *pNode = NULL;
 
	HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetObject(pActivate);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId);
	if (FAILED(hr)) goto done;
 
	hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
	if (FAILED(hr)) goto done;
 
	hr = pTopology->AddNode(pNode);
	if (FAILED(hr)) goto done;
 
	*ppNode = pNode;
	(*ppNode)->AddRef();
 
done:
	SafeRelease(&pNode);
	return hr;
}
 
HRESULT AddBranchToPartialTopology(
	IMFTopology *pTopology,
	IMFMediaSource *pSource,
	IMFPresentationDescriptor *pPD,
	DWORD iStream,
	HWND hVideoWnd)
{
	IMFStreamDescriptor *pSD = NULL;
	IMFActivate *pSinkActivate = NULL;
	IMFTopologyNode *pSourceNode = NULL;
	IMFTopologyNode *pOutputNode = NULL;
 
	BOOL fSelected = FALSE;
 
	HRESULT hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD);
	if (FAILED(hr)) goto done;
 
	if (fSelected)
	{
		hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate);
		if (FAILED(hr)) goto done;
 
		hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode);
		if (FAILED(hr)) goto done;
 
		hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode);
		if (FAILED(hr)) goto done;
 
		hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);
	}
 
done:
	SafeRelease(&pSD);
	SafeRelease(&pSinkActivate);
	SafeRelease(&pSourceNode);
	SafeRelease(&pOutputNode);
	return hr;
}
 
HRESULT CreatePlaybackTopology(
	IMFMediaSource *pSource,
	IMFPresentationDescriptor *pPD,
	HWND hVideoWnd,
	IMFTopology **ppTopology)
{
	IMFTopology *pTopology = NULL;
	DWORD cSourceStreams = 0;
 
	HRESULT hr = MFCreateTopology(&pTopology);
	if (FAILED(hr)) goto done;
 
	hr = pPD->GetStreamDescriptorCount(&cSourceStreams);
	if (FAILED(hr)) goto done;
 
	for (DWORD i = 0; i < cSourceStreams; i++)
	{
		hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i, hVideoWnd);
		if (FAILED(hr)) goto done;
	}
 
	*ppTopology = pTopology;
	(*ppTopology)->AddRef();
 
done:
	SafeRelease(&pTopology);
	return hr;
}
 

player.h
#include <new>
#include <Windows.h>
#include <ShObjIdl.h>
#include <Shlwapi.h>
#include <assert.h>
#include <strsafe.h>
 
#include <mfapi.h>
#include <mfidl.h>
#include <Mferror.h>
#include <evr.h>
 
#include "resource.h"
 
template <class T> void SafeRelease(T **ppT)
{
	if (*ppT)
	{
		(*ppT)->Release();
		*ppT = NULL;
	}
}
 
const UINT WM_APP_PLAYER_EVENT = WM_APP + 1;
 
enum PlayerState
{
	Closed = 0,
	Ready,
	OpenPending,
	Started,
	Paused,
	Stopped,
	Closing
};
 
class CPlayer : public IMFAsyncCallback
{
public:
	static HRESULT CreateInstance(HWND hVideo, HWND hEvent, CPlayer **ppPlayer);
 
	STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();
 
	STDMETHODIMP GetParameters(DWORD*, DWORD*)
	{
		return E_NOTIMPL;
	}
	STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult);
 
	HRESULT OpenURL(const WCHAR *sURL);
	HRESULT Play();
	HRESULT Pause();
	HRESULT Stop();
	HRESULT Shutdown();
	HRESULT HandleEvent(UINT_PTR pUnkPtr);
	PlayerState GetState() const { return m_state; }
 
	HRESULT Repaint();
	HRESULT ResizeVideo(WORD width, WORD height);
 
	BOOL HasVideo() const { return (m_pVideoDisplay != NULL); }
 
protected:
 
	CPlayer(HWND hVideo, HWND hEvent);
 
	virtual ~CPlayer();
 
	HRESULT Initialize();
	HRESULT CreateSession();
	HRESULT CloseSession();
	HRESULT StartPlayback();
 
	virtual HRESULT OnTopologyStatus(IMFMediaEvent *pEvent);
	virtual HRESULT OnPresentationEnded(IMFMediaEvent *pEvent);
	virtual HRESULT OnNewPresentation(IMFMediaEvent *pEvent);
 
	virtual HRESULT OnSessionEvent(IMFMediaEvent*, MediaEventType)
	{
		return S_OK;
	}
 
protected:
	long m_nRefCount;
 
	IMFMediaSession *m_pSession;
	IMFMediaSource *m_pSource;
	IMFVideoDisplayControl *m_pVideoDisplay;
 
	HWND m_hwndVideo;
	HWND m_hwndEvent;
	PlayerState m_state;
	HANDLE m_hCloseEvent;
};
 

player.rc
#include "resource.h"
 
#include <windows.h>
 
IDC_MFPLAYBACK MENU
BEGIN
	POPUP "&File"
	BEGIN
		MENUITEM "&Open File", ID_FILE_OPENFILE
		MENUITEM "Open &Url", ID_FILE_OPENURL
		MENUITEM SEPARATOR
		MENUITEM "E&xit", IDM_EXIT
	END
END
 
IDD_OPENURL DIALOGEX 0, 0, 186, 90
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Open URL"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
	DEFPUSHBUTTON	"OK",IDOK,75,69,50,14
	PUSHBUTTON	"Cancel",IDCANCEL,129,69,50,14
	EDITTEXT	IDC_EDIT_URL,7,21,172,14,ES_AUTOHSCROLL
	LTEXT		"Enter the URL to open:",IDC_STATIC,7,7,104,8
END
 

resource.h
#define IDD_MFPLAYBACK_DIALOG	102
#define IDM_EXIT		105
#define IDC_MFPLAYBACK		109
#define IDD_OPENURL		129
#define IDC_EDIT_URL		1000
#define ID_FILE_OPENFILE	32771
#define ID_FILE_OPENURL		32772
#define IDC_STATIC		-1
 

winmaincpp
#include "player.h"
 
PCWSTR szTitle = L"BasicPlayback";
PCWSTR szWindowClass = L"MFBASICPLAYBACK";
 
HINSTANCE g_hInstance;
BOOL g_bRepaintClient = TRUE;
CPlayer *g_pPlayer = NULL;
 
BOOL InitInstance(HINSTANCE hInst, int nCmdShow);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK OpenUrlDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void NotifyError(HWND hwnd, PCWSTR pszErrorMessage, HRESULT hrErr);
void UpdateUI(HWND hwnd, PlayerState state);
HRESULT AllocGetWindowText(HWND hwnd, WCHAR **pszText, DWORD *pcchLen);
 
LRESULT OnCreateWindow(HWND hwnd);
void OnFileOpen(HWND hwnd);
void OnOpenURL(HWND hwnd);
void OnPlayerEvent(HWND hwnd, WPARAM pUnkPtr);
void OnPaint(HWND hwnd);
void OnResize(WORD width, WORD height);
void OnKeyPress(WPARAM key);
 
struct OpenUrlDialogInfo
{
	WCHAR *pszURL;
	DWORD cch;
};
 
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
{
	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
 
	MSG msg;
 
	if (!InitInstance(hInstance, nCmdShow))
	{
		NotifyError(NULL, L"Could not initialize the application.",
			HRESULT_FROM_WIN32(GetLastError()));
		return FALSE;
	}
 
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
 
	if (g_pPlayer)
	{
		g_pPlayer->Shutdown();
		SafeRelease(&g_pPlayer);
	}
	return 0;
}
 
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
	HWND hwnd;
	WNDCLASSEX wcex = { sizeof WNDCLASSEX };
 
	g_hInstance = hInst;
 
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.hInstance = hInst;
	wcex.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MFPLAYBACK);
	wcex.lpszClassName = szWindowClass;
 
	if (RegisterClassEx(&wcex) == 0)
	{
		return FALSE;
	}
 
	hwnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
 
	if (hwnd == 0)
	{
		return FALSE;
	}
 
	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
 
	return TRUE;
}
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		return OnCreateWindow(hwnd);
 
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDM_EXIT:
			DestroyWindow(hwnd);
			break;
		case ID_FILE_OPENFILE:
			OnFileOpen(hwnd);
			break;
		case ID_FILE_OPENURL:
			OnOpenURL(hwnd);
			break;
 
		default:
			return DefWindowProc(hwnd, message, wParam, lParam);
		}
		break;
 
	case WM_PAINT:
		OnPaint(hwnd);
		break;
 
	case WM_SIZE:
		OnResize(LOWORD(lParam), HIWORD(lParam));
		break;
 
	case WM_ERASEBKGND:
		return 1;
 
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
 
	case WM_CHAR:
		OnKeyPress(wParam);
		break;
 
	case WM_APP_PLAYER_EVENT:
		OnPlayerEvent(hwnd, wParam);
		break;
 
	default:
		return DefWindowProc(hwnd, message, wParam, lParam);
	}
	return 0;
}
 
void OnFileOpen(HWND hwnd)
{
	IFileOpenDialog *pFileOpen = NULL;
	IShellItem *pItem = NULL;
	PWSTR pszFilePath = NULL;
 
	HRESULT hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL,
		CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));
	if (FAILED(hr)) goto done;
 
	hr = pFileOpen->Show(NULL);
	if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
	{
		hr = S_OK;
		goto done;
	}
	else if (FAILED(hr))
	{
		goto done;
	}
 
	hr = pFileOpen->GetResult(&pItem);
	if (FAILED(hr)) goto done;
 
	hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
	if (FAILED(hr)) goto done;
 
	hr = g_pPlayer->OpenURL(pszFilePath);
	if (SUCCEEDED(hr))
	{
		UpdateUI(hwnd, OpenPending);
	}
 
done:
	if (FAILED(hr))
	{
		NotifyError(hwnd, L"Could not open the file.", hr);
		UpdateUI(hwnd, Closed);
	}
	CoTaskMemFree(pszFilePath);
	SafeRelease(&pItem);
	SafeRelease(&pFileOpen);
}
 
void OnOpenURL(HWND hwnd)
{
	HRESULT hr = S_OK;
 
	OpenUrlDialogInfo url = { 0 };
 
	if (IDOK == DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_OPENURL), hwnd,
		OpenUrlDialogProc, (LPARAM)&url))
	{
		hr = g_pPlayer->OpenURL(url.pszURL);
		if (SUCCEEDED(hr))
		{
			UpdateUI(hwnd, OpenPending);
		}
		else
		{
			NotifyError(hwnd, L"Could not open this URL.", hr);
			UpdateUI(hwnd, Closed);
		}
	}
 
	CoTaskMemFree(url.pszURL);
}
 
LRESULT OnCreateWindow(HWND hwnd)
{
	HRESULT hr = CPlayer::CreateInstance(hwnd, hwnd, &g_pPlayer);
	if (SUCCEEDED(hr))
	{
		UpdateUI(hwnd, Closed);
		return 0;
	}
	else
	{
		NotifyError(NULL, L"Could not initialize the player object.", hr);
		return -1;
	}
}
 
void OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hwnd, &ps);
 
	if (g_pPlayer && g_pPlayer->HasVideo())
	{
		g_pPlayer->Repaint();
	}
	else
	{
		RECT rc;
		GetClientRect(hwnd, &rc);
		FillRect(hdc, &rc, (HBRUSH)COLOR_WINDOW);
	}
	EndPaint(hwnd, &ps);
}
 
void OnResize(WORD width, WORD height)
{
	if (g_pPlayer)
	{
		g_pPlayer->ResizeVideo(width, height);
	}
}
 
void OnKeyPress(WPARAM key)
{
	switch (key)
	{
	case VK_SPACE:
		if (g_pPlayer->GetState() == Started)
		{
			g_pPlayer->Pause();
		}
		else if (g_pPlayer->GetState() == Paused)
		{
			g_pPlayer->Play();
		}
		break;
	}
}
 
void OnPlayerEvent(HWND hwnd, WPARAM pUnkPtr)
{
	HRESULT hr = g_pPlayer->HandleEvent(pUnkPtr);
	if (FAILED(hr))
	{
		NotifyError(hwnd, L"An error occurred.", hr);
	}
	UpdateUI(hwnd, g_pPlayer->GetState());
}
 
void UpdateUI(HWND hwnd, PlayerState state)
{
	BOOL bWaiting = FALSE;
	BOOL bPlayback = FALSE;
 
	assert(g_pPlayer != NULL);
 
	switch (state)
	{
	case OpenPending:
		bWaiting = TRUE;
		break;
 
	case Started:
		bPlayback = TRUE;
		break;
 
	case Paused:
		bPlayback = TRUE;
		break;
	}
 
	HMENU hMenu = GetMenu(hwnd);
	UINT uEnable = MF_BYCOMMAND | (bWaiting ? MF_GRAYED : MF_ENABLED);
 
	EnableMenuItem(hMenu, ID_FILE_OPENFILE, uEnable);
	EnableMenuItem(hMenu, ID_FILE_OPENURL, uEnable);
 
	if (bPlayback && g_pPlayer->HasVideo())
	{
		g_bRepaintClient = FALSE;
	}
	else
	{
		g_bRepaintClient = TRUE;
	}
}
 
void NotifyError(HWND hwnd, PCWSTR pszErrorMessage, HRESULT hrErr)
{
	const size_t MESSAGE_LEN = 512;
	WCHAR message[MESSAGE_LEN];
 
	if (SUCCEEDED(StringCchPrintf(message, MESSAGE_LEN, L"%s (HRESULT = 0x%X)",
		pszErrorMessage, hrErr)))
	{
		MessageBox(hwnd, message, NULL, MB_OK | MB_ICONERROR);
	}
}
 
INT_PTR CALLBACK OpenUrlDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static OpenUrlDialogInfo *pUrl = NULL;
 
	BOOL result = FALSE;
 
	switch (message)
	{
	case WM_INITDIALOG:
		pUrl = (OpenUrlDialogInfo*)lParam;
		return (INT_PTR)TRUE;
 
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			if (pUrl)
			{
				if (SUCCEEDED(AllocGetWindowText(GetDlgItem(hDlg, IDC_EDIT_URL),
					&pUrl->pszURL, &pUrl->cch)))
				{
					result = TRUE;
				}
			}
			EndDialog(hDlg, result ? IDOK : IDABORT);
			break;
 
		case IDCANCEL:
			EndDialog(hDlg, LOWORD(IDCANCEL));
			break;
		}
		return (INT_PTR)FALSE;
	}
	return (INT_PTR)FALSE;
}
 
HRESULT AllocGetWindowText(HWND hwnd, WCHAR **pszText, DWORD *pcchLen)
{
	if (pszText == NULL || pcchLen == NULL)
	{
		return E_POINTER;
	}
 
	*pszText = NULL;
 
	int cch = GetWindowTextLength(hwnd);
	if (cch < 0)
	{
		return E_UNEXPECTED;
	}
 
	PWSTR pszTmp = (PWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (cch + 1));
 
	if (!pszTmp)
	{
		return E_OUTOFMEMORY;
	}
 
	if (cch == 0)
	{
		pszTmp[0] = L'\0';
	}
	else
	{
		int res = GetWindowText(hwnd, pszTmp, (cch + 1));
 
		if (res == 0)
		{
			CoTaskMemFree(pszTmp);
			return __HRESULT_FROM_WIN32(GetLastError());
		}
	}
 
	*pszText = pszTmp;
 
	*pcchLen = static_cast<DWORD>(cch);
 
	return S_OK;
}
 
最終更新:2014年07月16日 14:22