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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微澜-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值