946 lines
20 KiB
C++
946 lines
20 KiB
C++
//------------------------------------------------------------------------------
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "MFPlayer.h"
|
|
#include "Player2.h"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateInstance
|
|
//
|
|
// Creates an instance of the MFPlayer2 object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::CreateInstance(HWND hwndEvent, HWND hwndVideo, MFPlayer2 **ppPlayer)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
MFPlayer2 *pPlayer = new (std::nothrow) MFPlayer2(hwndEvent);
|
|
if (pPlayer == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pPlayer->Initialize(hwndVideo);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppPlayer = pPlayer;
|
|
(*ppPlayer)->AddRef();
|
|
}
|
|
|
|
SafeRelease(&pPlayer);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
MFPlayer2::MFPlayer2(HWND hwndEvent) :
|
|
m_cRef(1),
|
|
m_pPlayer(NULL),
|
|
m_hwndEvent(hwndEvent),
|
|
m_bHasVideo(FALSE),
|
|
m_fZoom(1.0f),
|
|
m_pVolume(NULL),
|
|
m_fRate(1.0f),
|
|
m_caps(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Destructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
MFPlayer2::~MFPlayer2()
|
|
{
|
|
if (m_pVolume)
|
|
{
|
|
(void)m_pVolume->EnableNotifications(FALSE);
|
|
}
|
|
|
|
SafeRelease(&m_pPlayer);
|
|
SafeRelease(&m_pVolume);
|
|
}
|
|
|
|
//***************************** IUnknown methods *****************************//
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// AddRef
|
|
//------------------------------------------------------------------------------
|
|
|
|
ULONG MFPlayer2::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Release
|
|
//------------------------------------------------------------------------------
|
|
|
|
ULONG MFPlayer2::Release()
|
|
{
|
|
ULONG uCount = InterlockedDecrement(&m_cRef);
|
|
if (uCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return uCount;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// QueryInterface
|
|
//------------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP MFPlayer2::QueryInterface(REFIID riid, void** ppv)
|
|
{
|
|
static const QITAB qit[] =
|
|
{
|
|
QITABENT(MFPlayer2, IMFPMediaPlayerCallback),
|
|
{ 0 },
|
|
};
|
|
return QISearch(this, qit, riid, ppv);
|
|
}
|
|
|
|
|
|
//********************* IMFPMediaPlayerCallback methods **********************//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// OnMediaPlayerEvent
|
|
//
|
|
// Notifies the object of an MFPlay event.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MFPlayer2::OnMediaPlayerEvent(MFP_EVENT_HEADER * pEventHeader)
|
|
{
|
|
if (FAILED(pEventHeader->hrEvent))
|
|
{
|
|
NotifyError(pEventHeader->hrEvent);
|
|
return;
|
|
}
|
|
|
|
switch (pEventHeader->eEventType)
|
|
{
|
|
case MFP_EVENT_TYPE_MEDIAITEM_CREATED:
|
|
OnMediaItemCreated(MFP_GET_MEDIAITEM_CREATED_EVENT(pEventHeader));
|
|
break;
|
|
|
|
case MFP_EVENT_TYPE_MEDIAITEM_SET:
|
|
OnMediaItemSet(MFP_GET_MEDIAITEM_SET_EVENT(pEventHeader));
|
|
break;
|
|
|
|
case MFP_EVENT_TYPE_RATE_SET:
|
|
OnRateSet(MFP_GET_RATE_SET_EVENT(pEventHeader));
|
|
break;
|
|
|
|
case MFP_EVENT_TYPE_PLAYBACK_ENDED:
|
|
case MFP_EVENT_TYPE_STOP:
|
|
SetPlaybackRate(1.0f);
|
|
break;
|
|
|
|
}
|
|
|
|
NotifyState(pEventHeader->eState);
|
|
}
|
|
|
|
|
|
//*************************** Other class methods ****************************//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// OpenURL
|
|
//
|
|
// Open a media file by URL.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::OpenURL(const WCHAR *sURL)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (sURL == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_pPlayer == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
// Create a new media item for this URL.
|
|
hr = m_pPlayer->CreateMediaItemFromURL(sURL, FALSE, 0, NULL);
|
|
|
|
// The CreateMediaItemFromURL method completes asynchronously. When it does,
|
|
// MFPlay sends an MFP_EVENT_TYPE_MEDIAITEM_CREATED event.
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Play
|
|
//
|
|
// Start playback.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::Play()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->Play();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Pause
|
|
//
|
|
// Pause playback.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::Pause()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->Pause();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Shutdown
|
|
//
|
|
// Shutdown the MFPlay object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::Shutdown()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->Shutdown();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetState
|
|
//
|
|
// Get the current state of the MFPlay object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetState(MFP_MEDIAPLAYER_STATE *pState)
|
|
{
|
|
if (pState == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
MFP_MEDIAPLAYER_STATE state = MFP_MEDIAPLAYER_STATE_EMPTY;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->GetState(&state);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pState = state;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetMetadata
|
|
//
|
|
// Get a read-only property store that contains metadata for the current
|
|
// media file.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetMetadata(IPropertyStore **ppProp)
|
|
{
|
|
if (ppProp == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if (m_pPlayer == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
IMFPMediaItem *pItem = NULL;
|
|
IPropertyStore *pProp = NULL;
|
|
|
|
hr = m_pPlayer->GetMediaItem(&pItem);
|
|
if (FAILED(hr)) { goto done; }
|
|
|
|
hr = pItem->GetMetadata(&pProp);
|
|
if (FAILED(hr)) { goto done; }
|
|
|
|
*ppProp = pProp;
|
|
(*ppProp)->AddRef();
|
|
|
|
done:
|
|
SafeRelease(&pProp);
|
|
SafeRelease(&pItem);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// HasVideo
|
|
//
|
|
// Queries if current media file has a video stream.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::HasVideo(BOOL *pfHasVideo)
|
|
{
|
|
if (pfHasVideo == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pfHasVideo = m_bHasVideo;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetZoom
|
|
//
|
|
// Sets the video zoom level.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetZoom(float fZoom)
|
|
{
|
|
if (fZoom < 1.0f)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (m_fZoom == fZoom)
|
|
{
|
|
return S_OK; // no-op
|
|
}
|
|
|
|
m_fZoom = fZoom;
|
|
|
|
return SetZoom();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetZoom
|
|
//
|
|
// Sets the video zoom level (using the current cached zoom value).
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetZoom()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_bHasVideo && m_pPlayer)
|
|
{
|
|
if (m_fZoom == 1.0f)
|
|
{
|
|
// For 100% zoom, the normalized rectangle is {0,0,1,1}.
|
|
|
|
MFVideoNormalizedRect nrcSource = { 0.0f, 0.0f, 1.0f, 1.0f };
|
|
|
|
hr = m_pPlayer->SetVideoSourceRect(&nrcSource);
|
|
}
|
|
else
|
|
{
|
|
// For higher zoom levels, calculate the normalized rectangle.
|
|
|
|
float fMargin = (0.5f - (0.5f / m_fZoom));
|
|
|
|
MFVideoNormalizedRect nrcSource = {
|
|
fMargin, fMargin, (1.0f - fMargin), (1.0f - fMargin)
|
|
};
|
|
|
|
hr = m_pPlayer->SetVideoSourceRect(&nrcSource);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// UpdateVideo
|
|
//
|
|
// Call this method to repaint the current video frame or when the video
|
|
// window is resized.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::UpdateVideo()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->UpdateVideo();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetVolume
|
|
//
|
|
// Sets the audio volume.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetVolume(float fLevel)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pVolume)
|
|
{
|
|
hr = m_pVolume->SetVolume(fLevel);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetVolume
|
|
//
|
|
// Gets the audio volume.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetVolume(float *pfLevel)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pfLevel == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_pVolume)
|
|
{
|
|
hr = m_pVolume->GetVolume(pfLevel);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetMute
|
|
//
|
|
// Mutes or unmutes the audio.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetMute(BOOL bMute)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pVolume)
|
|
{
|
|
hr = m_pVolume->SetMute(bMute);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetMute
|
|
//
|
|
// Gets the audio mute state.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetMute(BOOL *pbMute)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pbMute == NULL)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_pVolume)
|
|
{
|
|
hr = m_pVolume->GetMute(pbMute);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CanSeek
|
|
//
|
|
// Queries whether the current media file is seekable.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::CanSeek(BOOL *pbCanSeek)
|
|
{
|
|
*pbCanSeek = ((m_caps & MFP_MEDIAITEM_CAN_SEEK) && !(m_caps & MFP_MEDIAITEM_HAS_SLOW_SEEK));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetDuration
|
|
//
|
|
// Gets the playback duration.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetDuration(MFTIME *phnsDuration)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
PROPVARIANT var;
|
|
PropVariantInit(&var);
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->GetDuration(
|
|
MFP_POSITIONTYPE_100NS,
|
|
&var
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*phnsDuration = var.uhVal.QuadPart;
|
|
}
|
|
}
|
|
|
|
PropVariantClear(&var);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetCurrentPosition
|
|
//
|
|
// Gets the current playback position.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::GetCurrentPosition(MFTIME *phnsPosition)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
PROPVARIANT var;
|
|
PropVariantInit(&var);
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->GetPosition(
|
|
MFP_POSITIONTYPE_100NS,
|
|
&var
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*phnsPosition = var.hVal.QuadPart;
|
|
}
|
|
}
|
|
|
|
PropVariantClear(&var);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetPosition
|
|
//
|
|
// Sets the current playback position.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetPosition(MFTIME hnsPosition)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
PROPVARIANT var;
|
|
PropVariantInit(&var);
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
var.vt = VT_I8;
|
|
var.hVal.QuadPart = hnsPosition;
|
|
|
|
hr = m_pPlayer->SetPosition(
|
|
MFP_POSITIONTYPE_100NS,
|
|
&var
|
|
);
|
|
}
|
|
|
|
PropVariantClear(&var);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CanFastForward
|
|
//
|
|
// Queries whether the current media file supports fast-forward playback.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::CanFastForward(BOOL *pbCanFF)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bCanFF = FALSE;
|
|
|
|
float fSlowest = 0.0f, fFastest = 0.0f;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
// Ask for the supported rates in the forward direction.
|
|
hr = m_pPlayer->GetSupportedRates(TRUE, &fSlowest, &fFastest);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && fFastest > 1.0f)
|
|
{
|
|
bCanFF = TRUE;
|
|
}
|
|
|
|
*pbCanFF = bCanFF;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CanRewind
|
|
//
|
|
// Queries whether the current media file supports reverse playback.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::CanRewind(BOOL *pbCanRewind)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bCanRew = FALSE;
|
|
|
|
float fSlowest = 0.0f, fFastest = 0.0f;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
// Ask for the supported rates in the reverse direction.
|
|
hr = m_pPlayer->GetSupportedRates(FALSE, &fSlowest, &fFastest);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bCanRew = TRUE;
|
|
}
|
|
|
|
*pbCanRewind = bCanRew;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetPlaybackRate
|
|
//
|
|
// Sets the playback rate.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetPlaybackRate(float fRate)
|
|
{
|
|
if (fRate == GetNominalRate())
|
|
{
|
|
return S_OK; // no-op
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = m_pPlayer->SetRate(fRate);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_fRate = fRate;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// FastForward
|
|
//
|
|
// Switches to fast-forward playback, as follows:
|
|
// - If the current rate is < 0 (reverse play), switch to 1x speed.
|
|
// - Otherwise, double the current playback rate.
|
|
//
|
|
// This method is just for convenience; the app could call SetPlaybackRate.
|
|
//------------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::FastForward()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
float fTarget = GetNominalRate() * 2;
|
|
|
|
if (fTarget <= 0.0f)
|
|
{
|
|
fTarget = 1.0f;
|
|
}
|
|
|
|
hr = SetPlaybackRate(fTarget);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// FastForward
|
|
//
|
|
// Switches to reverse playback, as follows:
|
|
// - If the current rate is > 0 (forward playback), switch to -1x speed.
|
|
// - Otherwise, double the current (reverse) playback rate.
|
|
//
|
|
// This method is for convenience; the app could call SetPlaybackRate.
|
|
//------------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::Rewind()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
float fTarget = GetNominalRate() * 2;
|
|
|
|
if (fTarget >= 0.0f)
|
|
{
|
|
fTarget = -1.0f;
|
|
}
|
|
|
|
hr = SetPlaybackRate(fTarget);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FrameStep
|
|
//
|
|
// Steps forward one frame.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::FrameStep()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_pPlayer)
|
|
{
|
|
hr = m_pPlayer->FrameStep();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetEffect
|
|
//
|
|
// Adds a video or audio effect.
|
|
//
|
|
// To remove all effects, pass NULL.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::SetEffect(IMFTransform *pMFT)
|
|
{
|
|
if (m_pPlayer == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pMFT == NULL)
|
|
{
|
|
hr = m_pPlayer->RemoveAllEffects();
|
|
}
|
|
else
|
|
{
|
|
hr = m_pPlayer->InsertEffect(pMFT, TRUE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Initialize
|
|
// Creates an instance of the MFPlay player object.
|
|
//
|
|
// hwndVideo:
|
|
// Handle to the video window.
|
|
//------------------------------------------------------------------------------
|
|
|
|
HRESULT MFPlayer2::Initialize(HWND hwndVideo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
SafeRelease(&m_pPlayer);
|
|
|
|
hr = MFPCreateMediaPlayer(
|
|
NULL,
|
|
FALSE, // Start playback automatically?
|
|
0, // Flags
|
|
this, // Callback pointer
|
|
hwndVideo, // Video window
|
|
&m_pPlayer
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Also create the object that manages to audio session.
|
|
// This can fail if the machine does not have an audio end-point.
|
|
|
|
HRESULT hrAudio = CAudioSessionVolume::CreateInstance(
|
|
WM_AUDIO_EVENT,
|
|
m_hwndEvent,
|
|
&m_pVolume
|
|
);
|
|
|
|
if (SUCCEEDED(hrAudio))
|
|
{
|
|
// Ask for audio session events.
|
|
hrAudio = m_pVolume->EnableNotifications(TRUE);
|
|
}
|
|
|
|
if (FAILED(hrAudio))
|
|
{
|
|
SafeRelease(&m_pVolume);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// MFPlay event handler functions.
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// OnMediaItemCreated
|
|
//
|
|
// Called when the CreateMediaItem method completes.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MFPlayer2::OnMediaItemCreated(MFP_MEDIAITEM_CREATED_EVENT *pEvent)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IUnknown *pMFT = NULL;
|
|
|
|
m_bHasVideo = TRUE;
|
|
|
|
if ((m_pPlayer != NULL) && (pEvent->pMediaItem != NULL))
|
|
{
|
|
BOOL bHasVideo = FALSE, bIsSelected = FALSE;
|
|
|
|
hr = pEvent->pMediaItem->HasVideo(&bHasVideo, &bIsSelected);
|
|
if (FAILED(hr)) { goto done; }
|
|
|
|
m_bHasVideo = bHasVideo && bIsSelected;
|
|
|
|
hr = m_pPlayer->SetMediaItem(pEvent->pMediaItem);
|
|
if (FAILED(hr)) { goto done; }
|
|
}
|
|
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
NotifyError(hr);
|
|
}
|
|
SafeRelease(&pMFT);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// OnMediaItemSet
|
|
//
|
|
// Called when the SetMediaItem method completes.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MFPlayer2::OnMediaItemSet(MFP_MEDIAITEM_SET_EVENT *pEvent)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = pEvent->header.hrEvent;
|
|
if (FAILED(hr)) { goto done; }
|
|
|
|
if (pEvent->pMediaItem)
|
|
{
|
|
hr = pEvent->pMediaItem->GetCharacteristics(&m_caps);
|
|
if (FAILED(hr)) { goto done; }
|
|
}
|
|
|
|
hr = m_pPlayer->Play();
|
|
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
NotifyError(hr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// OnRateSet
|
|
//
|
|
// Called when the SetRate method completes.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MFPlayer2::OnRateSet(MFP_RATE_SET_EVENT *pEvent)
|
|
{
|
|
m_fRate = pEvent->flRate;
|
|
}
|
|
|
|
|