/* * $Id$ * * (C) 2006-2010 see AUTHORS * * This file is part of mplayerc. * * Mplayerc is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Mplayerc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "stdafx.h" #include "VideoDecDXVAAllocator.h" #include "MPCVideoDecFilter.h" CDXVA2Sample::CDXVA2Sample(CVideoDecDXVAAllocator *pAlloc, HRESULT *phr) : CMediaSample(NAME("CDXVA2Sample"), (CBaseAllocator*)pAlloc, phr, NULL, 0) , m_dwSurfaceId(0) { } //Note: CMediaSample does not derive from CUnknown, so we cannot use the // DECLARE_IUNKNOWN macro that is used by most of the filter classes. STDMETHODIMP CDXVA2Sample::QueryInterface(REFIID riid, __deref_out void **ppv) { CheckPointer(ppv,E_POINTER); ValidateReadWritePtr(ppv,sizeof(PVOID)); if (riid == __uuidof(IMFGetService)) { return GetInterface((IMFGetService*) this, ppv); } if (riid == __uuidof(IMPCDXVA2Sample)) { return GetInterface((IMPCDXVA2Sample*) this, ppv); } else { return CMediaSample::QueryInterface(riid, ppv); } } STDMETHODIMP_(ULONG) CDXVA2Sample::AddRef() { return __super::AddRef(); } STDMETHODIMP_(ULONG) CDXVA2Sample::Release() { // Return a temporary variable for thread safety. ULONG cRef = __super::Release(); return cRef; } // IMFGetService::GetService STDMETHODIMP CDXVA2Sample::GetService(REFGUID guidService, REFIID riid, LPVOID *ppv) { if (guidService != MR_BUFFER_SERVICE) { return MF_E_UNSUPPORTED_SERVICE; } else if (m_pSurface == NULL) { return E_NOINTERFACE; } else { return m_pSurface->QueryInterface(riid, ppv); } } // Override GetPointer because this class does not manage a system memory buffer. // The EVR uses the MR_BUFFER_SERVICE service to get the Direct3D surface. STDMETHODIMP CDXVA2Sample::GetPointer(BYTE ** ppBuffer) { return E_NOTIMPL; } // Sets the pointer to the Direct3D surface. void CDXVA2Sample::SetSurface(DWORD surfaceId, IDirect3DSurface9 *pSurf) { m_pSurface = pSurf; m_dwSurfaceId = surfaceId; } STDMETHODIMP_(int) CDXVA2Sample::GetDXSurfaceId() { return m_dwSurfaceId; } CVideoDecDXVAAllocator::CVideoDecDXVAAllocator(CMPCVideoDecFilter* pVideoDecFilter, HRESULT* phr) : CBaseAllocator(NAME("CVideoDecDXVAAllocator"), NULL, phr) { m_pVideoDecFilter = pVideoDecFilter; m_ppRTSurfaceArray = NULL; } CVideoDecDXVAAllocator::~CVideoDecDXVAAllocator() { Free(); } HRESULT CVideoDecDXVAAllocator::Alloc() { HRESULT hr; CComPtr pDXVA2Service; CheckPointer(m_pVideoDecFilter->m_pDeviceManager, E_UNEXPECTED); hr = m_pVideoDecFilter->m_pDeviceManager->GetVideoService (m_pVideoDecFilter->m_hDevice, IID_IDirectXVideoAccelerationService, (void**)&pDXVA2Service); CheckPointer (pDXVA2Service, E_UNEXPECTED); CAutoLock lock(this); hr = __super::Alloc(); if (SUCCEEDED(hr)) { // Free the old resources. Free(); m_nSurfaceArrayCount = m_lCount; // Allocate a new array of pointers. m_ppRTSurfaceArray = DNew IDirect3DSurface9*[m_lCount]; if (m_ppRTSurfaceArray == NULL) { hr = E_OUTOFMEMORY; } else { ZeroMemory(m_ppRTSurfaceArray, sizeof(IDirect3DSurface9*) * m_lCount); } } // Allocate the surfaces. D3DFORMAT m_dwFormat = m_pVideoDecFilter->m_VideoDesc.Format; if (SUCCEEDED(hr)) { hr = pDXVA2Service->CreateSurface( m_pVideoDecFilter->PictWidthRounded(), m_pVideoDecFilter->PictHeightRounded(), m_lCount - 1, (D3DFORMAT)m_dwFormat, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, m_ppRTSurfaceArray, NULL ); } if (SUCCEEDED(hr)) { // Important : create samples in reverse order ! for (m_lAllocated = m_lCount-1; m_lAllocated >= 0; m_lAllocated--) { CDXVA2Sample *pSample = DNew CDXVA2Sample(this, &hr); if (pSample == NULL) { hr = E_OUTOFMEMORY; break; } if (FAILED(hr)) { break; } // Assign the Direct3D surface pointer and the index. pSample->SetSurface(m_lAllocated, m_ppRTSurfaceArray[m_lAllocated]); // Add to the sample list. m_lFree.Add(pSample); } hr = m_pVideoDecFilter->CreateDXVA2Decoder (m_lCount, m_ppRTSurfaceArray); if (FAILED (hr)) Free(); } if (SUCCEEDED(hr)) { m_bChanged = FALSE; } return hr; } void CVideoDecDXVAAllocator::Free() { CMediaSample *pSample = NULL; m_pVideoDecFilter->FlushDXVADecoder(); // m_FreeSurface.RemoveAll(); do { pSample = m_lFree.RemoveHead(); if (pSample) { delete pSample; } } while (pSample); if (m_ppRTSurfaceArray) { for (long i = 0; i < m_nSurfaceArrayCount; i++) { if (m_ppRTSurfaceArray[i] != NULL) m_ppRTSurfaceArray[i]->Release(); } delete [] m_ppRTSurfaceArray; m_ppRTSurfaceArray = NULL; } m_lAllocated = 0; m_nSurfaceArrayCount = 0; }