天天看點

VMR9實作放大縮小

編者:李國帥

qq:9611153 微信lgs9611153

時間:2012/05/03 

若使用vmr9,測試了一下,需要使用無視窗模式,不能使用IVideoWindow接口,可以直接使用SetVideoPosition方法。

// VMR9 Headers
#include <d3d9.h>
#include <streams.h>
#include <strmif.h>
#include <control.h>
#include <evcode.h>
#include <vmr9.h>

public:
	HRESULT InitializeWindowlessVMR(IBaseFilter **ppVmr9);
	LONG SetZoomVideoWindow(RECT rcZoom);
	LONG PaintVideoWindow(HDC hdc);
	LONG ResetVideoWindow();

protected:
	CComPtr<IBaseFilter> m_pVmr9;
	IVMRWindowlessControl9 *m_pWC;
	RECT				m_rcClient;//播放區域
	RECT				m_rcVideo;//播放區域

//CGraphBase::CGraphBase(CWindow* pParent)
	m_pVmr9			= NULL;
	m_pWC			= NULL;
	memset(&m_rcVideo,0,sizeof(RECT));
	memset(&m_rcClient,0,sizeof(RECT));

//CGraphBase::~CGraphBase(void)
	SafeRelease(m_pWC);
	SafeRelease(m_pVmr9);

//CreatePlayer()
	// Create the Video Mixing Renderer and add it to the graph
	HRESULT hrVmr = InitializeWindowlessVMR(&m_pVmr9);

	_assert(SUCCEEDED(hrVmr) && m_pVmr9 != NULL);
	hr |= ConnectFilters(mGraph, pIDecoderFilter,m_pVmr9);

HRESULT CGraphBase::InitializeWindowlessVMR( IBaseFilter **ppVmr9 )
{
	if (!ppVmr9)
		return E_POINTER;
	*ppVmr9 = NULL;

	IBaseFilter* pVmr = NULL;
	// Create the VMR and add it to the filter graph.
	HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL,	CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
	if (SUCCEEDED(hr))
	{
		hr = mGraph->AddFilter(pVmr, L"Video Mixing Renderer 9");
		if (SUCCEEDED(hr))
		{
			// Set the rendering mode and number of streams
			CComPtr <IVMRFilterConfig9> pConfig;

			pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
			pConfig->SetRenderingMode(VMR9Mode_Windowless);

			hr = pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&m_pWC);
			if( SUCCEEDED(hr))
			{
				hr = m_pWC->SetVideoClippingWindow(m_pParent->m_hWnd);
				hr = m_pWC->SetBorderColor(RGB(0,0,0));
			}
#ifndef BILINEAR_FILTERING
			// Request point filtering (instead of bilinear filtering)
			// to improve the text quality.  In general, if you are
			// not scaling the app Image, you should use point filtering.
			// This is very important if you are doing source color keying.
			IVMRMixerControl9 *pMix;

			hr = pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix);
			if( SUCCEEDED(hr))
			{
				DWORD dwPrefs=0;
				hr = pMix->GetMixingPrefs(&dwPrefs);

				if (SUCCEEDED(hr))
				{
					dwPrefs |= MixerPref_PointFiltering;
					dwPrefs &= ~(MixerPref_BiLinearFiltering);

					hr = pMix->SetMixingPrefs(dwPrefs);
				}
				pMix->Release();
			}
#endif
		}
		else
		{
			//Msg(TEXT("Failed to add VMR to graph!  hr=0x%x\r\n"), hr);
		}
		// Don't release the pVmr interface because we are copying it into the caller's ppVmr9 pointer
		*ppVmr9 = pVmr;
	}
	else
	{
		//Msg(TEXT("Failed to create VMR!  hr=0x%x\r\n"), hr);
	}
	return hr;
}

LONG CGraphBase::SetZoomVideoWindow(RECT rcZoom)
{
	if (m_pWC == NULL) return 0;
	// Track the movement of the container window and resize as needed

	GetClientRect(m_pParent->m_hWnd, &m_rcClient);// Get the window client area.
	//SetRect(&m_rcClient, 0, 0, m_rcClient.right/2, m_rcClient.bottom/2); // Set the destination rectangle.
	if(m_rcClient.right<=m_rcClient.left || m_rcClient.bottom<=m_rcClient.top) return FALSE;

	ATLASSERT(rcZoom.right>0 && rcZoom.bottom>0);//代表不縮放
	if(rcZoom.right<=0 || rcZoom.bottom<=0) return FALSE;//

	long lWidth, lHeight;
	HRESULT hr = m_pWC->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
	if (!SUCCEEDED(hr))return FALSE;
	if ((lWidth == 0) && (lHeight == 0))return FALSE;

	if (m_rcVideo.bottom == 0 || m_rcVideo.right == 0)
	{
		SetRect(&m_rcVideo, 0, 0, lWidth, lHeight);//原始狀态// Set the source rectangle.
		//SetRect(&rcSrc, 0, 0, lWidth/2, lHeight/2);//測試
	}

	RECT rcZoomVideo;//裝置上放大的區域
	memset(&rcZoomVideo,0,sizeof(RECT));

	double WidthRate = (double)(m_rcVideo.right-m_rcVideo.left) /(double)(m_rcClient.right-m_rcClient.left);
	rcZoomVideo.left = (LONG)((rcZoom.left-m_rcClient.left) * WidthRate + m_rcVideo.left);
	rcZoomVideo.right = (LONG)((rcZoom.right-m_rcClient.left) * WidthRate  + m_rcVideo.left);

	double HeightRate = (double)(m_rcVideo.bottom-m_rcVideo.top)/(double)(m_rcClient.bottom-m_rcClient.top);
	rcZoomVideo.top = (LONG)((rcZoom.top-m_rcClient.top) * HeightRate + m_rcVideo.top);
	rcZoomVideo.bottom = (LONG)((rcZoom.bottom-m_rcClient.top) * HeightRate  + m_rcVideo.top);

	CopyRect(&m_rcVideo,&rcZoomVideo);

	HRESULT hr = m_pWC->SetVideoPosition(&m_rcVideo, &m_rcClient); // Set the video position.
	if (FAILED(hr))
	{
		//Msg(TEXT("SetVideoPosition FAILED!  hr=0x%x\r\n"), hr);
	}
	return hr;
}

LONG CGraphBase::PaintVideoWindow( HDC hdc )
{
	if (m_pWC == NULL) return 0;

	RECT        rcClient;
	GetClientRect(*m_pParent, &rcClient);

	// Find the region where the application can paint by subtracting
	// the video destination rectangle from the client area.
	// (Assume that g_rcDest was calculated previously.)
	HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
	HRGN rgnVideo  = CreateRectRgnIndirect(&m_rcClient);
	CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);

	// Paint on window.
	HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
	FillRgn(hdc, rgnClient, hbr);

	// Clean up.
	DeleteObject(hbr);
	DeleteObject(rgnClient);
	DeleteObject(rgnVideo);

	// Request the VMR to paint the video.
	HRESULT hr = m_pWC->RepaintVideo(*m_pParent, hdc);
	if (SUCCEEDED(hr))return 1;
	return 0;
}

LONG CGraphBase::ResetVideoWindow()
{
	if (m_pWC == NULL) return 0;

	long lWidth, lHeight;
	HRESULT hr = m_pWC->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
	if (!SUCCEEDED(hr))return 0;
	if ((lWidth == 0) && (lHeight == 0))return 0;

	SetRect(&m_rcVideo, 0, 0, lWidth, lHeight);//原始狀态
	m_pWC->SetVideoPosition(&m_rcVideo, &m_rcClient); // Set the video position.

	return 1;
}
           

重新整理函數:

因為使用vmr的無視窗模式,播放區域自己就是控件視窗,是以不需要專門的設定視窗大小,也不需要在視窗graph之後和onsize的時候重新設定。

重新整理一下即可。

LRESULT CxxPlayer::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// reset video window
	if(m_hWnd==NULL || !::IsWindow(m_hWnd))return S_OK;

	RECT rect;
	GetClientRect(&rect);

	if(m_pCurGraph!=NULL)
	{
		ShowWindow(SW_HIDE);
		m_pCurGraph->SetDisplayRect(m_hWnd,&rect);//不需要
		m_pCurGraph->SetZoomVideoWindow(m_rcZoom);
		ShowWindow(SW_SHOW);
	}
	return 0;
}
BOOL CGraphBase::SetDisplayRect(HWND inWindow,LPRECT pRect)
{
	CheckPointer(m_pWC, FALSE);

	m_pWC->SetVideoClippingWindow(inWindow);

	if (pRect != NULL)
	{
		SetWindowPos(inWindow,HWND_TOPMOST,pRect->left,pRect->top,pRect->right,pRect->bottom,SWP_SHOWWINDOW);
	}
	// Restore the video window
	m_pWC->RepaintVideo(inWindow,m_pParent->GetDC());

	return TRUE;
}
           

繼續閱讀