2025-11-28 00:35:46 +09:00

513 lines
9.5 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 "DShowPlayer.h"
#include "DshowUtil.h"
#include <Mfidl.h>
HRESULT InitializeEVR(IBaseFilter *pEVR, HWND hwnd, IMFVideoDisplayControl ** ppWc);
HRESULT InitWindowlessVMR9(IBaseFilter *pVMR, HWND hwnd, IVMRWindowlessControl9 ** ppWc);
HRESULT InitWindowlessVMR(IBaseFilter *pVMR, HWND hwnd, IVMRWindowlessControl** ppWc);
/// VMR-7 Wrapper
VMR7::VMR7() : m_pWindowless(NULL)
{
}
VMR7::~VMR7()
{
SAFE_RELEASE(m_pWindowless);
}
HRESULT VMR7::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
HRESULT hr = S_OK;
IBaseFilter *pVMR = NULL;
hr = AddFilterByCLSID(pGraph, CLSID_VideoMixingRenderer, &pVMR, L"VMR-7");
// Set windowless mode on the VMR. This must be done before the VMR is connected.
if (SUCCEEDED(hr))
{
hr = InitWindowlessVMR(pVMR, hwnd, &m_pWindowless);
}
return hr;
}
HRESULT VMR7::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pWindowless == NULL)
{
return S_OK;
}
HRESULT hr = S_OK;
BOOL bRemoved = FALSE;
IBaseFilter *pFilter = NULL;
hr = m_pWindowless->QueryInterface(__uuidof(IBaseFilter), (void**)&pFilter);
if (SUCCEEDED(hr))
{
hr = RemoveUnconnectedRenderer(pGraph, pFilter, &bRemoved);
// If we removed the VMR, then we also need to release our
// pointer to the VMR's windowless control interface.
if (bRemoved)
{
SAFE_RELEASE(m_pWindowless);
}
}
SAFE_RELEASE(pFilter);
return hr;
}
HRESULT VMR7::UpdateVideoWindow(HWND hwnd, const LPRECT prc)
{
HRESULT hr = S_OK;
if (m_pWindowless == NULL)
{
return S_OK; // no-op
}
if (prc)
{
hr = m_pWindowless->SetVideoPosition(NULL, prc);
}
else
{
RECT rc;
GetClientRect(hwnd, &rc);
hr = m_pWindowless->SetVideoPosition(NULL, &rc);
}
return hr;
}
HRESULT VMR7::Repaint(HWND hwnd, HDC hdc)
{
HRESULT hr = S_OK;
if (m_pWindowless)
{
hr = m_pWindowless->RepaintVideo(hwnd, hdc);
}
return hr;
}
HRESULT VMR7::DisplayModeChanged()
{
HRESULT hr = S_OK;
if (m_pWindowless)
{
hr = m_pWindowless->DisplayModeChanged();
}
return hr;
}
//-----------------------------------------------------------------------------
// InitWindowlessVMR
// Initialize the VMR-7 for windowless mode.
//-----------------------------------------------------------------------------
HRESULT InitWindowlessVMR(
IBaseFilter *pVMR, // Pointer to the VMR
HWND hwnd, // Clipping window
IVMRWindowlessControl** ppWC // Receives a pointer to the VMR.
)
{
IVMRFilterConfig* pConfig = NULL;
IVMRWindowlessControl *pWC = NULL;
HRESULT hr = S_OK;
// Set the rendering mode.
hr = pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
hr = pConfig->SetRenderingMode(VMRMode_Windowless);
}
// Query for the windowless control interface.
if (SUCCEEDED(hr))
{
hr = pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWC);
}
// Set the clipping window.
if (SUCCEEDED(hr))
{
hr = pWC->SetVideoClippingWindow(hwnd);
}
// Preserve aspect ratio by letter-boxing
if (SUCCEEDED(hr))
{
hr = pWC->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX);
}
// Return the IVMRWindowlessControl pointer to the caller.
if (SUCCEEDED(hr))
{
*ppWC = pWC;
(*ppWC)->AddRef();
}
SAFE_RELEASE(pConfig);
SAFE_RELEASE(pWC);
return hr;
}
/// VMR-9 Wrapper
VMR9::VMR9() : m_pWindowless(NULL)
{
}
VMR9::~VMR9()
{
SAFE_RELEASE(m_pWindowless);
}
HRESULT VMR9::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
HRESULT hr = S_OK;
IBaseFilter *pVMR = NULL;
hr = AddFilterByCLSID(pGraph, CLSID_VideoMixingRenderer9, &pVMR, L"VMR-9");
// Set windowless mode on the VMR. This must be done before the VMR is connected.
if (SUCCEEDED(hr))
{
hr = InitWindowlessVMR9(pVMR, hwnd, &m_pWindowless);
}
return hr;
}
HRESULT VMR9::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pWindowless == NULL)
{
return S_OK;
}
HRESULT hr = S_OK;
BOOL bRemoved = FALSE;
IBaseFilter *pFilter = NULL;
hr = m_pWindowless->QueryInterface(__uuidof(IBaseFilter), (void**)&pFilter);
if (SUCCEEDED(hr))
{
hr = RemoveUnconnectedRenderer(pGraph, pFilter, &bRemoved);
// If we removed the VMR, then we also need to release our
// pointer to the VMR's windowless control interface.
if (bRemoved)
{
SAFE_RELEASE(m_pWindowless);
}
}
SAFE_RELEASE(pFilter);
return hr;
}
HRESULT VMR9::UpdateVideoWindow(HWND hwnd, const LPRECT prc)
{
HRESULT hr = S_OK;
if (m_pWindowless == NULL)
{
return S_OK; // no-op
}
if (prc)
{
hr = m_pWindowless->SetVideoPosition(NULL, prc);
}
else
{
RECT rc;
GetClientRect(hwnd, &rc);
hr = m_pWindowless->SetVideoPosition(NULL, &rc);
}
return hr;
}
HRESULT VMR9::Repaint(HWND hwnd, HDC hdc)
{
HRESULT hr = S_OK;
if (m_pWindowless)
{
hr = m_pWindowless->RepaintVideo(hwnd, hdc);
}
return hr;
}
HRESULT VMR9::DisplayModeChanged()
{
HRESULT hr = S_OK;
if (m_pWindowless)
{
hr = m_pWindowless->DisplayModeChanged();
}
return hr;
}
//-----------------------------------------------------------------------------
// InitWindowlessVMR9
// Initialize the VMR-9 for windowless mode.
//-----------------------------------------------------------------------------
HRESULT InitWindowlessVMR9(
IBaseFilter *pVMR, // Pointer to the VMR
HWND hwnd, // Clipping window
IVMRWindowlessControl9** ppWC // Receives a pointer to the VMR.
)
{
IVMRFilterConfig9 * pConfig = NULL;
IVMRWindowlessControl9 *pWC = NULL;
HRESULT hr = S_OK;
// Set the rendering mode.
hr = pVMR->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
if (SUCCEEDED(hr))
{
hr = pConfig->SetRenderingMode(VMR9Mode_Windowless);
}
// Query for the windowless control interface.
if (SUCCEEDED(hr))
{
hr = pVMR->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC);
}
// Set the clipping window.
if (SUCCEEDED(hr))
{
hr = pWC->SetVideoClippingWindow(hwnd);
}
// Preserve aspect ratio by letter-boxing
if (SUCCEEDED(hr))
{
hr = pWC->SetAspectRatioMode(VMR9ARMode_LetterBox);
}
// Return the IVMRWindowlessControl pointer to the caller.
if (SUCCEEDED(hr))
{
*ppWC = pWC;
(*ppWC)->AddRef();
}
SAFE_RELEASE(pConfig);
SAFE_RELEASE(pWC);
return hr;
}
/// EVR Wrapper
EVR::EVR() : m_pEVR(NULL), m_pVideoDisplay(NULL)
{
}
EVR::~EVR()
{
SAFE_RELEASE(m_pEVR);
SAFE_RELEASE(m_pVideoDisplay);
}
HRESULT EVR::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
HRESULT hr = S_OK;
IBaseFilter *pEVR = NULL;
hr = AddFilterByCLSID(pGraph, CLSID_EnhancedVideoRenderer, &pEVR, L"EVR");
if (SUCCEEDED(hr))
{
hr = InitializeEVR(pEVR, hwnd, &m_pVideoDisplay);
}
if (SUCCEEDED(hr))
{
// Note: Because IMFVideoDisplayControl is a service interface,
// you cannot QI the pointer to get back the IBaseFilter pointer.
// Therefore, we need to cache the IBaseFilter pointer.
m_pEVR = pEVR;
m_pEVR->AddRef();
}
SAFE_RELEASE(pEVR);
return hr;
}
HRESULT EVR::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pEVR == NULL)
{
return S_OK;
}
HRESULT hr = S_OK;
BOOL bRemoved = FALSE;
hr = RemoveUnconnectedRenderer(pGraph, m_pEVR, &bRemoved);
if (bRemoved)
{
SAFE_RELEASE(m_pEVR);
SAFE_RELEASE(m_pVideoDisplay);
}
return hr;
}
HRESULT EVR::UpdateVideoWindow(HWND hwnd, const LPRECT prc)
{
HRESULT hr = S_OK;
if (m_pVideoDisplay == NULL)
{
return S_OK; // no-op
}
if (prc)
{
hr = m_pVideoDisplay->SetVideoPosition(NULL, prc);
}
else
{
RECT rc;
GetClientRect(hwnd, &rc);
hr = m_pVideoDisplay->SetVideoPosition(NULL, &rc);
}
return hr;
}
HRESULT EVR::Repaint(HWND hwnd, HDC hdc)
{
HRESULT hr = S_OK;
if (m_pVideoDisplay)
{
hr = m_pVideoDisplay->RepaintVideo();
}
return hr;
}
HRESULT EVR::DisplayModeChanged()
{
return S_OK; // No-op
}
//-----------------------------------------------------------------------------
// InitializeEVR
// Initialize the EVR filter.
//-----------------------------------------------------------------------------
HRESULT InitializeEVR(
IBaseFilter *pEVR, // Pointer to the EVR
HWND hwnd, // Clipping window
IMFVideoDisplayControl** ppDisplayControl
)
{
HRESULT hr = S_OK;
IMFGetService *pService = NULL;
IMFVideoDisplayControl *pDisplay = NULL;
hr = pEVR->QueryInterface(__uuidof(IMFGetService), (void**)&pService);
if (SUCCEEDED(hr))
{
hr = pService->GetService(
MR_VIDEO_RENDER_SERVICE,
__uuidof(IMFVideoDisplayControl),
(void**)&pDisplay
);
}
// Set the clipping window.
if (SUCCEEDED(hr))
{
hr = pDisplay->SetVideoWindow(hwnd);
}
// Preserve aspect ratio by letter-boxing
if (SUCCEEDED(hr))
{
hr = pDisplay->SetAspectRatioMode(MFVideoARMode_PreservePicture);
}
// Return the IMFVideoDisplayControl pointer to the caller.
if (SUCCEEDED(hr))
{
*ppDisplayControl = pDisplay;
(*ppDisplayControl)->AddRef();
}
SAFE_RELEASE(pService);
SAFE_RELEASE(pDisplay);
return hr;
}