| 
									
										
										
										
											2018-10-03 22:02:46 +08:00
										 |  |  | // Copyright (c) 2016-2018 Easy2D - Nomango
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					
						
							|  |  |  | // of this software and associated documentation files (the "Software"), to deal
 | 
					
						
							|  |  |  | // in the Software without restriction, including without limitation the rights
 | 
					
						
							|  |  |  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					
						
							|  |  |  | // copies of the Software, and to permit persons to whom the Software is
 | 
					
						
							|  |  |  | // furnished to do so, subject to the following conditions:
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // The above copyright notice and this permission notice shall be included in
 | 
					
						
							|  |  |  | // all copies or substantial portions of the Software.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					
						
							|  |  |  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					
						
							|  |  |  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					
						
							|  |  |  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					
						
							|  |  |  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					
						
							|  |  |  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					
						
							|  |  |  | // THE SOFTWARE.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-05 13:33:39 +08:00
										 |  |  | #include "..\e2dtool.h"
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | #include <cguid.h>
 | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | #define MF_CLASS_NAME		L"MediaFoundationCallbackWnd"
 | 
					
						
							|  |  |  | #define WM_APP_PLAYER_EVENT	(WM_APP + 1)
 | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 20:19:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | namespace | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HINSTANCE media_instance = nullptr; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	inline void Trace(wchar_t* msg) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		WARN("Trace error: %s.", msg); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inline void Trace(wchar_t* msg, HRESULT hr) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		WARN("Trace error: %s (%#X).", msg, hr); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | e2d::Music::Music() | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	: m_pSession(nullptr) | 
					
						
							|  |  |  | 	, m_pSource(nullptr) | 
					
						
							|  |  |  | 	, m_hwndEvent(nullptr) | 
					
						
							|  |  |  | 	, m_state(State::Closed) | 
					
						
							|  |  |  | 	, m_hCloseEvent(nullptr) | 
					
						
							|  |  |  | 	, m_nTimes(0) | 
					
						
							| 
									
										
										
										
											2018-04-24 10:35:58 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (!media_instance) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		media_instance = ::GetModuleHandle(NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		WNDCLASS wc; | 
					
						
							|  |  |  | 		wc.style = 0; | 
					
						
							|  |  |  | 		wc.lpfnWndProc = Music::MediaProc; | 
					
						
							|  |  |  | 		wc.cbClsExtra = 0; | 
					
						
							|  |  |  | 		wc.cbWndExtra = 0; | 
					
						
							|  |  |  | 		wc.hInstance = media_instance; | 
					
						
							|  |  |  | 		wc.hIcon = 0; | 
					
						
							|  |  |  | 		wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); | 
					
						
							|  |  |  | 		wc.hbrBackground = NULL; | 
					
						
							|  |  |  | 		wc.lpszMenuName = NULL; | 
					
						
							|  |  |  | 		wc.lpszClassName = MF_CLASS_NAME; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!::RegisterClass(&wc)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_hwndEvent = ::CreateWindowExW( | 
					
						
							|  |  |  | 		WS_EX_APPWINDOW, | 
					
						
							|  |  |  | 		MF_CLASS_NAME, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							|  |  |  | 		WS_POPUPWINDOW, | 
					
						
							|  |  |  | 		0, 0, 0, 0, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							|  |  |  | 		media_instance, | 
					
						
							|  |  |  | 		NULL | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_hwndEvent) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		::SetWindowLongW(m_hwndEvent, GWLP_USERDATA, (LONG_PTR)this); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_hCloseEvent = ::CreateEventW(NULL, FALSE, FALSE, NULL); | 
					
						
							|  |  |  | 	if (m_hCloseEvent == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ThrowIfFailed( | 
					
						
							|  |  |  | 			HRESULT_FROM_WIN32(GetLastError()) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:07:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 22:42:34 +08:00
										 |  |  | e2d::Music::Music(const e2d::String & file_path) | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-06 10:25:29 +08:00
										 |  |  | 	this->Load(file_path); | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:07:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | e2d::Music::Music(const Resource& res) | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-06 10:25:29 +08:00
										 |  |  | 	this->Load(res); | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:07:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | e2d::Music::~Music() | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-04 22:42:34 +08:00
										 |  |  | 	Close(); | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (m_hCloseEvent) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		::CloseHandle(m_hCloseEvent); | 
					
						
							|  |  |  | 		m_hCloseEvent = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DestroyWindow(m_hwndEvent); | 
					
						
							| 
									
										
										
										
											2018-07-08 02:41:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-06 10:25:29 +08:00
										 |  |  | bool e2d::Music::Load(const e2d::String & file_path) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// 1. Create a new media session.
 | 
					
						
							|  |  |  | 	// 2. Create the media source.
 | 
					
						
							|  |  |  | 	// 3. Create the topology.
 | 
					
						
							|  |  |  | 	// 4. Queue the topology [asynchronous]
 | 
					
						
							|  |  |  | 	// 5. Start playback [asynchronous - does not happen in this method.]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IMFTopology *pTopology = NULL; | 
					
						
							|  |  |  | 	IMFPresentationDescriptor* pSourcePD = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Close the old session, if any.
 | 
					
						
							|  |  |  | 	Close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create the media session.
 | 
					
						
							|  |  |  | 	HRESULT hr = MFCreateMediaSession(NULL, &m_pSession); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-08-12 12:06:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Start pulling events from the media session
 | 
					
						
							|  |  |  | 	hr = m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-08-12 12:06:06 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create the media source.
 | 
					
						
							|  |  |  | 	hr = CreateMediaSource(static_cast<WCHAR*>(file_path), &m_pSource); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create the presentation descriptor for the media source.
 | 
					
						
							|  |  |  | 	hr = m_pSource->CreatePresentationDescriptor(&pSourcePD); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-24 15:47:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create a partial topology.
 | 
					
						
							|  |  |  | 	hr = CreatePlaybackTopology(m_pSource, pSourcePD, &pTopology); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Set the topology on the media session.
 | 
					
						
							|  |  |  | 	hr = m_pSession->SetTopology(0, pTopology); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	m_state = State::Loaded; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// If SetTopology succeeds, the media session will queue an 
 | 
					
						
							|  |  |  | 	// MESessionTopologySet event.
 | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_state = State::Closed; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	SafeRelease(pSourcePD); | 
					
						
							|  |  |  | 	SafeRelease(pTopology); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool e2d::Music::Load(const Resource& res) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 	////////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool e2d::Music::Play(int loop_count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_pSession == NULL || m_pSource == NULL) | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HRESULT hr = StartPlayback(); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_nTimes = loop_count; | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | void e2d::Music::Pause() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_state != State::Started) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (m_pSession == NULL || m_pSource == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HRESULT hr = m_pSession->Pause(); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_state = State::Paused; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | void e2d::Music::Stop() | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (m_state != State::Started && m_state != State::Paused) | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (m_pSession == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HRESULT hr = m_pSession->Stop(); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_state = State::Stopped; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | void e2d::Music::Close() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//  The IMFMediaSession::Close method is asynchronous, but the 
 | 
					
						
							|  |  |  | 	//  e2d::Music::CloseSession method waits on the MESessionClosed event.
 | 
					
						
							|  |  |  | 	//  
 | 
					
						
							|  |  |  | 	//  MESessionClosed is guaranteed to be the last event that the 
 | 
					
						
							|  |  |  | 	//  media session fires.
 | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HRESULT hr = S_OK; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// First close the media session.
 | 
					
						
							|  |  |  | 	if (m_pSession) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		DWORD dwWaitResult = 0; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		m_state = State::Closing; | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		hr = m_pSession->Close(); | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Wait for the close operation to complete
 | 
					
						
							|  |  |  | 		if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			WaitForSingleObject(m_hCloseEvent, 5000); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-19 20:40:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Complete shutdown operations.
 | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Shut down the media source. (Synchronous operation, no events.)
 | 
					
						
							|  |  |  | 		if (m_pSource) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			(void)m_pSource->Shutdown(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Shut down the media session. (Synchronous operation, no events.)
 | 
					
						
							|  |  |  | 		if (m_pSession) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			(void)m_pSession->Shutdown(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	SafeRelease(m_pSource); | 
					
						
							|  |  |  | 	SafeRelease(m_pSession); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_state = State::Closed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool e2d::Music::IsPlaying() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return m_state == State::Started; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool e2d::Music::SetVolume(float volume) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!m_pSession) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IMFSimpleAudioVolume* pAudioVolume = NULL; | 
					
						
							|  |  |  | 	HRESULT hr = GetSimpleAudioVolume(&pAudioVolume); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		volume = std::min(std::max(volume, 0.f), 1.f); | 
					
						
							|  |  |  | 		hr = pAudioVolume->SetMasterVolume(volume); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	SafeRelease(pAudioVolume); | 
					
						
							|  |  |  | 	return SUCCEEDED(hr); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | float e2d::Music::GetVolume() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!m_pSession) | 
					
						
							|  |  |  | 		return 0.f; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	float volume = 0.f; | 
					
						
							|  |  |  | 	IMFSimpleAudioVolume* pAudioVolume = NULL; | 
					
						
							|  |  |  | 	HRESULT hr = GetSimpleAudioVolume(&pAudioVolume); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hr = pAudioVolume->GetMasterVolume(&volume); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	SafeRelease(pAudioVolume); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		return volume; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	return 0.f; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::QueryInterface(REFIID riid, void** ppv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static const QITAB qit[] = | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		QITABENT(Music, IMFAsyncCallback), | 
					
						
							|  |  |  | 		{ 0 } | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	return QISearch(this, qit, riid, ppv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ULONG e2d::Music::AddRef() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return InterlockedIncrement(&m_nRefCount); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ULONG e2d::Music::Release() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ULONG uCount = InterlockedDecrement(&m_nRefCount); | 
					
						
							|  |  |  | 	if (uCount == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		delete this; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	return uCount; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::GetParameters(DWORD *, DWORD *) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// Implementation of this method is optional.
 | 
					
						
							|  |  |  | 	return E_NOTIMPL; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:27:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::Invoke(IMFAsyncResult *pResult) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	MediaEventType meType = MEUnknown;  // Event type
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IMFMediaEvent *pEvent = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get the event from the event queue.
 | 
					
						
							|  |  |  | 	HRESULT hr = m_pSession->EndGetEvent(pResult, &pEvent); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the event type. 
 | 
					
						
							|  |  |  | 	hr = pEvent->GetType(&meType); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (meType == MESessionClosed) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// The session was closed. 
 | 
					
						
							|  |  |  | 		// The application is waiting on the m_hCloseEvent event handle. 
 | 
					
						
							|  |  |  | 		SetEvent(m_hCloseEvent); | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// For all other events, get the next event in the queue.
 | 
					
						
							|  |  |  | 		hr = m_pSession->BeginGetEvent(this, NULL); | 
					
						
							|  |  |  | 		if (FAILED(hr)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check the application state. 
 | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// If a call to IMFMediaSession::Close is pending, it means the 
 | 
					
						
							|  |  |  | 	// application is waiting on the m_hCloseEvent event and
 | 
					
						
							|  |  |  | 	// the application's message loop is blocked. 
 | 
					
						
							| 
									
										
										
										
											2018-02-06 21:11:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Otherwise, post a private window message to the application. 
 | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (m_state != State::Closing) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Leave a reference count on the event.
 | 
					
						
							|  |  |  | 		pEvent->AddRef(); | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		::PostMessage(m_hwndEvent, WM_APP_PLAYER_EVENT, (WPARAM)pEvent, (LPARAM)meType); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pEvent); | 
					
						
							|  |  |  | 	return S_OK; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::StartPlayback() | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	PROPVARIANT varStart; | 
					
						
							|  |  |  | 	PropVariantInit(&varStart); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT hr = m_pSession->Start(&GUID_NULL, &varStart); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Note: Start is an asynchronous operation. However, we
 | 
					
						
							|  |  |  | 		// can treat our state as being already started. If Start
 | 
					
						
							|  |  |  | 		// fails later, we'll get an MESessionStarted event with
 | 
					
						
							|  |  |  | 		// an error code, and we will update our state then.
 | 
					
						
							|  |  |  | 		m_state = State::Started; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	PropVariantClear(&varStart); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::HandleEvent(UINT_PTR pEventPtr) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	HRESULT hrStatus = S_OK; | 
					
						
							|  |  |  | 	MediaEventType meType = MEUnknown; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IMFMediaEvent *pEvent = (IMFMediaEvent*)pEventPtr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pEvent == NULL) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		return E_POINTER; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the event type.
 | 
					
						
							|  |  |  | 	HRESULT hr = pEvent->GetType(&meType); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get the event status. If the operation that triggered the event 
 | 
					
						
							|  |  |  | 	// did not succeed, the status is a failure code.
 | 
					
						
							|  |  |  | 	hr = pEvent->GetStatus(&hrStatus); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if the async operation succeeded.
 | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr) && FAILED(hrStatus)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hr = hrStatus; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (meType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case MEEndOfPresentation: | 
					
						
							|  |  |  | 		printf("%d\n", m_nTimes); | 
					
						
							|  |  |  | 		if (m_nTimes) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 			--m_nTimes; | 
					
						
							|  |  |  | 			hr = StartPlayback(); | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_state = State::Stopped; | 
					
						
							|  |  |  | 			hr = S_OK; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case MENewPresentation: | 
					
						
							|  |  |  | 		hr = OnNewPresentation(pEvent); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pEvent); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::OnNewPresentation(IMFMediaEvent *pEvent) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	IMFPresentationDescriptor *pPD = NULL; | 
					
						
							|  |  |  | 	IMFTopology *pTopology = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get the presentation descriptor from the event.
 | 
					
						
							|  |  |  | 	PROPVARIANT var; | 
					
						
							|  |  |  | 	HRESULT hr = pEvent->GetValue(&var); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (var.vt == VT_UNKNOWN) | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		hr = var.punkVal->QueryInterface(&pPD); | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hr = MF_E_INVALIDTYPE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	PropVariantClear(&var); | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create a partial topology.
 | 
					
						
							|  |  |  | 	hr = CreatePlaybackTopology(m_pSource, pPD, &pTopology); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-02 23:49:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Set the topology on the media session.
 | 
					
						
							|  |  |  | 	hr = m_pSession->SetTopology(0, pTopology); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	m_state = State::Loaded; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pTopology); | 
					
						
							|  |  |  | 	SafeRelease(pPD); | 
					
						
							|  |  |  | 	return S_OK; | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::GetSimpleAudioVolume(IMFSimpleAudioVolume ** ppAudioVolume) const | 
					
						
							| 
									
										
										
										
											2018-05-17 23:53:27 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (ppAudioVolume == NULL) | 
					
						
							|  |  |  | 		return E_POINTER; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	IMFGetService* pGetService = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HRESULT hr = m_pSession->QueryInterface(IID_IMFGetService, (void **)&pGetService); | 
					
						
							|  |  |  | 	if (SUCCEEDED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		hr = pGetService->GetService(MR_CAPTURE_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(ppAudioVolume)); | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	SafeRelease(pGetService); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							| 
									
										
										
										
											2017-12-08 15:37:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource) | 
					
						
							| 
									
										
										
										
											2018-05-22 11:58:45 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID; | 
					
						
							| 
									
										
										
										
											2018-05-22 11:58:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	IMFSourceResolver* pSourceResolver = NULL; | 
					
						
							|  |  |  | 	IUnknown* pSource = NULL; | 
					
						
							| 
									
										
										
										
											2018-05-22 11:58:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create the source resolver.
 | 
					
						
							|  |  |  | 	HRESULT hr = MFCreateSourceResolver(&pSourceResolver); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Use the source resolver to create the media source.
 | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Note: For simplicity this sample uses the synchronous method to create 
 | 
					
						
							|  |  |  | 	// the media source. However, creating a media source can take a noticeable
 | 
					
						
							|  |  |  | 	// amount of time, especially for a network source. For a more responsive 
 | 
					
						
							|  |  |  | 	// UI, use the asynchronous BeginCreateObjectFromURL method.
 | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	hr = pSourceResolver->CreateObjectFromURL( | 
					
						
							|  |  |  | 		sURL,                       // URL of the source.
 | 
					
						
							|  |  |  | 		MF_RESOLUTION_MEDIASOURCE,  // Create a source object.
 | 
					
						
							|  |  |  | 		NULL,                       // Optional property store.
 | 
					
						
							|  |  |  | 		&ObjectType,        // Receives the created object type. 
 | 
					
						
							|  |  |  | 		&pSource            // Receives a pointer to the media source.
 | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the IMFMediaSource interface from the media source.
 | 
					
						
							|  |  |  | 	hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource)); | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pSourceResolver); | 
					
						
							|  |  |  | 	SafeRelease(pSource); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::CreateMediaSinkActivate( | 
					
						
							|  |  |  | 	IMFStreamDescriptor *pSourceSD, | 
					
						
							|  |  |  | 	IMFActivate **ppActivate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IMFMediaTypeHandler *pHandler = NULL; | 
					
						
							|  |  |  | 	IMFActivate *pActivate = NULL; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the media type handler for the stream.
 | 
					
						
							|  |  |  | 	HRESULT hr = pSourceSD->GetMediaTypeHandler(&pHandler); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the major media type.
 | 
					
						
							|  |  |  | 	GUID guidMajorType; | 
					
						
							|  |  |  | 	hr = pHandler->GetMajorType(&guidMajorType); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create an IMFActivate object for the renderer, based on the media type.
 | 
					
						
							|  |  |  | 	if (MFMediaType_Audio == guidMajorType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// Create the audio renderer.
 | 
					
						
							|  |  |  | 		hr = MFCreateAudioRendererActivate(&pActivate); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (MFMediaType_Video == guidMajorType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// Create the video renderer.
 | 
					
						
							|  |  |  | 		hr = MFCreateVideoRendererActivate(m_hwndEvent, &pActivate); | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Unknown stream type. 
 | 
					
						
							|  |  |  | 		hr = E_FAIL; | 
					
						
							|  |  |  | 		// Optionally, you could deselect this stream instead of failing.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Return IMFActivate pointer to caller.
 | 
					
						
							|  |  |  | 	*ppActivate = pActivate; | 
					
						
							|  |  |  | 	(*ppActivate)->AddRef(); | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pHandler); | 
					
						
							|  |  |  | 	SafeRelease(pActivate); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::AddSourceNode( | 
					
						
							|  |  |  | 	IMFTopology *pTopology, | 
					
						
							|  |  |  | 	IMFMediaSource *pSource, | 
					
						
							|  |  |  | 	IMFPresentationDescriptor *pPD, | 
					
						
							|  |  |  | 	IMFStreamDescriptor *pSD, | 
					
						
							|  |  |  | 	IMFTopologyNode **ppNode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IMFTopologyNode *pNode = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create the node.
 | 
					
						
							|  |  |  | 	HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Set the attributes.
 | 
					
						
							|  |  |  | 	hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Add the node to the topology.
 | 
					
						
							|  |  |  | 	hr = pTopology->AddNode(pNode); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Return the pointer to the caller.
 | 
					
						
							|  |  |  | 	*ppNode = pNode; | 
					
						
							|  |  |  | 	(*ppNode)->AddRef(); | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pNode); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::AddOutputNode( | 
					
						
							|  |  |  | 	IMFTopology *pTopology, | 
					
						
							|  |  |  | 	IMFActivate *pActivate, | 
					
						
							|  |  |  | 	DWORD dwId, | 
					
						
							|  |  |  | 	IMFTopologyNode **ppNode) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	IMFTopologyNode *pNode = NULL; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create the node.
 | 
					
						
							|  |  |  | 	HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Set the object pointer.
 | 
					
						
							|  |  |  | 	hr = pNode->SetObject(pActivate); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Set the stream sink ID attribute.
 | 
					
						
							|  |  |  | 	hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Add the node to the topology.
 | 
					
						
							|  |  |  | 	hr = pTopology->AddNode(pNode); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Return the pointer to the caller.
 | 
					
						
							|  |  |  | 	*ppNode = pNode; | 
					
						
							|  |  |  | 	(*ppNode)->AddRef(); | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pNode); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::AddBranchToPartialTopology( | 
					
						
							|  |  |  | 	IMFTopology *pTopology, | 
					
						
							|  |  |  | 	IMFMediaSource *pSource, | 
					
						
							|  |  |  | 	IMFPresentationDescriptor *pPD, | 
					
						
							|  |  |  | 	DWORD iStream) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	//  Add a topology branch for one stream.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//  For each stream, this function does the following:
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//    1. Creates a source node associated with the stream. 
 | 
					
						
							|  |  |  | 	//    2. Creates an output node for the renderer. 
 | 
					
						
							|  |  |  | 	//    3. Connects the two nodes.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//  The media session will add any decoders that are needed.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-25 16:44:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	if (fSelected) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Create the media sink activation object.
 | 
					
						
							|  |  |  | 		hr = CreateMediaSinkActivate(pSD, &pSinkActivate); | 
					
						
							|  |  |  | 		if (FAILED(hr)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Add a source node for this stream.
 | 
					
						
							|  |  |  | 		hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode); | 
					
						
							|  |  |  | 		if (FAILED(hr)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Create the output node for the renderer.
 | 
					
						
							|  |  |  | 		hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode); | 
					
						
							|  |  |  | 		if (FAILED(hr)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		// Connect the source node to the output node.
 | 
					
						
							|  |  |  | 		hr = pSourceNode->ConnectOutput(0, pOutputNode, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// else: If not selected, don't add the branch. 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pSD); | 
					
						
							|  |  |  | 	SafeRelease(pSinkActivate); | 
					
						
							|  |  |  | 	SafeRelease(pSourceNode); | 
					
						
							|  |  |  | 	SafeRelease(pOutputNode); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | HRESULT e2d::Music::CreatePlaybackTopology( | 
					
						
							|  |  |  | 	IMFMediaSource *pSource, | 
					
						
							|  |  |  | 	IMFPresentationDescriptor *pPD, | 
					
						
							|  |  |  | 	IMFTopology **ppTopology) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IMFTopology *pTopology = NULL; | 
					
						
							|  |  |  | 	DWORD cSourceStreams = 0; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Create a new topology.
 | 
					
						
							|  |  |  | 	HRESULT hr = MFCreateTopology(&pTopology); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// Get the number of streams in the media source.
 | 
					
						
							|  |  |  | 	hr = pPD->GetStreamDescriptorCount(&cSourceStreams); | 
					
						
							|  |  |  | 	if (FAILED(hr)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	// For each stream, create the topology nodes and add them to the topology.
 | 
					
						
							|  |  |  | 	for (DWORD i = 0; i < cSourceStreams; i++) | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i); | 
					
						
							|  |  |  | 		if (FAILED(hr)) | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 			goto done; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Return the IMFTopology pointer to the caller.
 | 
					
						
							|  |  |  | 	*ppTopology = pTopology; | 
					
						
							|  |  |  | 	(*ppTopology)->AddRef(); | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | done: | 
					
						
							|  |  |  | 	SafeRelease(pTopology); | 
					
						
							|  |  |  | 	return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LRESULT e2d::Music::MediaProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (Msg) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case WM_APP_PLAYER_EVENT: | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 			Music * music = reinterpret_cast<Music*>( | 
					
						
							|  |  |  | 				static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			if (music) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				music->HandleEvent(wParam); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2018-02-01 22:07:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return ::DefWindowProc(hWnd, Msg, wParam, lParam); | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-11 20:00:21 +08:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2018-01-30 16:45:38 +08:00
										 |  |  | } |