830 lines
21 KiB
C++
830 lines
21 KiB
C++
|
|
/***************************************************************************************
|
||
|
|
*
|
||
|
|
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||
|
|
*
|
||
|
|
* By downloading, copying, installing or using the software you agree to this license.
|
||
|
|
* If you do not agree to this license, do not download, install,
|
||
|
|
* copy or use the software.
|
||
|
|
*
|
||
|
|
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
|
||
|
|
*
|
||
|
|
* Redistribution and use in binary forms, with or without modification, are permitted.
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
|
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
|
||
|
|
* language governing permissions and limitations under the License.
|
||
|
|
*
|
||
|
|
****************************************************************************************/
|
||
|
|
|
||
|
|
#include "sys_inc.h"
|
||
|
|
#include "video_render_d3d.h"
|
||
|
|
#include "lock.h"
|
||
|
|
|
||
|
|
/***************************************************************************************/
|
||
|
|
|
||
|
|
static void * g_d3d_mutex = sys_os_create_mutex();
|
||
|
|
|
||
|
|
const DWORD g_YUV420ps30_main[] =
|
||
|
|
{
|
||
|
|
0xffff0300, 0x003ffffe, 0x42415443, 0x0000001c, 0x000000c7, 0xffff0300,
|
||
|
|
0x00000004, 0x0000001c, 0x20000102, 0x000000c0, 0x0000006c, 0x00010003,
|
||
|
|
0x00000001, 0x00000074, 0x00000000, 0x00000084, 0x00020003, 0x00000001,
|
||
|
|
0x00000074, 0x00000000, 0x0000008c, 0x00000003, 0x00000001, 0x00000074,
|
||
|
|
0x00000000, 0x00000094, 0x00000002, 0x00000001, 0x000000a0, 0x000000b0,
|
||
|
|
0x78655455, 0x00657574, 0x000c0004, 0x00010001, 0x00000001, 0x00000000,
|
||
|
|
0x78655456, 0x00657574, 0x78655459, 0x00657574, 0x6e617274, 0x72617073,
|
||
|
|
0x00746e65, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x3f800000,
|
||
|
|
0x00000000, 0x00000000, 0x00000000, 0x335f7370, 0x4d00305f, 0x6f726369,
|
||
|
|
0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
|
||
|
|
0x656c6970, 0x2e392072, 0x392e3432, 0x322e3934, 0x00373033, 0x05000051,
|
||
|
|
0xa00f0001, 0x3f950a81, 0x3fcc4a9d, 0xbf5fcbb4, 0x00000000, 0x05000051,
|
||
|
|
0xa00f0002, 0x3f950a81, 0xbec89507, 0xbf501eac, 0x3f081b65, 0x05000051,
|
||
|
|
0xa00f0003, 0x3f950a81, 0x40011a54, 0xbf8af5f5, 0x00000000, 0x05000051,
|
||
|
|
0xa00f0004, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f,
|
||
|
|
0x80000005, 0x90030000, 0x0200001f, 0x80010005, 0x90030001, 0x0200001f,
|
||
|
|
0x80020005, 0x90030002, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f,
|
||
|
|
0x90000000, 0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042,
|
||
|
|
0x800f0000, 0x90e40002, 0xa0e40802, 0x02000001, 0x80040000, 0x80000000,
|
||
|
|
0x03000042, 0x800f0001, 0x90e40000, 0xa0e40800, 0x04000004, 0x80090000,
|
||
|
|
0x80000001, 0xa0640004, 0xa0250004, 0x03000008, 0x80010800, 0xa0e40001,
|
||
|
|
0x80f80000, 0x03000042, 0x800f0001, 0x90e40001, 0xa0e40801, 0x02000001,
|
||
|
|
0x80020000, 0x80000001, 0x03000009, 0x80020800, 0xa0e40002, 0x80e40000,
|
||
|
|
0x03000008, 0x80040800, 0xa0e40003, 0x80f40000, 0x02000001, 0x80080800,
|
||
|
|
0xa0000000, 0x0000ffff
|
||
|
|
};
|
||
|
|
|
||
|
|
const DWORD g_YUV420ps20_main[] =
|
||
|
|
{
|
||
|
|
0xffff0200, 0x003ffffe, 0x42415443, 0x0000001c, 0x000000c7, 0xffff0200,
|
||
|
|
0x00000004, 0x0000001c, 0x20000102, 0x000000c0, 0x0000006c, 0x00010003,
|
||
|
|
0x00000001, 0x00000074, 0x00000000, 0x00000084, 0x00020003, 0x00000001,
|
||
|
|
0x00000074, 0x00000000, 0x0000008c, 0x00000003, 0x00000001, 0x00000074,
|
||
|
|
0x00000000, 0x00000094, 0x00000002, 0x00000001, 0x000000a0, 0x000000b0,
|
||
|
|
0x78655455, 0x00657574, 0x000c0004, 0x00010001, 0x00000001, 0x00000000,
|
||
|
|
0x78655456, 0x00657574, 0x78655459, 0x00657574, 0x6e617274, 0x72617073,
|
||
|
|
0x00746e65, 0x00030000, 0x00010001, 0x00000001, 0x00000000, 0x3f800000,
|
||
|
|
0x00000000, 0x00000000, 0x00000000, 0x325f7370, 0x4d00305f, 0x6f726369,
|
||
|
|
0x74666f73, 0x29522820, 0x534c4820, 0x6853204c, 0x72656461, 0x6d6f4320,
|
||
|
|
0x656c6970, 0x2e392072, 0x392e3432, 0x322e3934, 0x00373033, 0x05000051,
|
||
|
|
0xa00f0001, 0x3f950a81, 0x00000000, 0x3fcc4a9d, 0xbf5fcbb4, 0x05000051,
|
||
|
|
0xa00f0002, 0x3f950a81, 0xbec89507, 0xbf501eac, 0x3f081b65, 0x05000051,
|
||
|
|
0xa00f0003, 0x3f950a81, 0x40011a54, 0x00000000, 0xbf8af5f5, 0x05000051,
|
||
|
|
0xa00f0004, 0x3f800000, 0x00000000, 0x00000000, 0x00000000, 0x0200001f,
|
||
|
|
0x80000000, 0xb0030000, 0x0200001f, 0x80000000, 0xb0030001, 0x0200001f,
|
||
|
|
0x80000000, 0xb0030002, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f,
|
||
|
|
0x90000000, 0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042,
|
||
|
|
0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40001,
|
||
|
|
0xa0e40801, 0x03000042, 0x800f0002, 0xb0e40002, 0xa0e40802, 0x02000001,
|
||
|
|
0x80080003, 0xa0000000, 0x02000001, 0x80020000, 0x80000001, 0x02000001,
|
||
|
|
0x80040000, 0x80000002, 0x02000001, 0x80080000, 0xa0000004, 0x03000009,
|
||
|
|
0x80010003, 0xa0e40001, 0x80e40000, 0x03000009, 0x80020003, 0xa0e40002,
|
||
|
|
0x80e40000, 0x03000009, 0x80040003, 0xa0e40003, 0x80e40000, 0x02000001,
|
||
|
|
0x800f0800, 0x80e40003, 0x0000ffff
|
||
|
|
};
|
||
|
|
|
||
|
|
/***************************************************************************************/
|
||
|
|
|
||
|
|
CD3DVideoRender::CD3DVideoRender()
|
||
|
|
: CVideoRender()
|
||
|
|
, m_pD3D9(NULL)
|
||
|
|
, m_pD3DD9(NULL)
|
||
|
|
, m_pRenderSurface(NULL)
|
||
|
|
, m_pVertices(NULL)
|
||
|
|
, m_pPixelShader(NULL)
|
||
|
|
, m_pPixelConstTable(NULL)
|
||
|
|
, m_hTransparent(NULL)
|
||
|
|
, m_nFlip(GS_NONE)
|
||
|
|
, m_dTransparent(0.0f)
|
||
|
|
, m_dwColor(0)
|
||
|
|
, m_bReset(FALSE)
|
||
|
|
{
|
||
|
|
m_pTexture[0] = NULL;
|
||
|
|
m_pTexture[1] = NULL;
|
||
|
|
m_pTexture[2] = NULL;
|
||
|
|
|
||
|
|
m_pTexTemp[0] = NULL;
|
||
|
|
m_pTexTemp[1] = NULL;
|
||
|
|
m_pTexTemp[2] = NULL;
|
||
|
|
|
||
|
|
m_hYUVTexture[0] = NULL;
|
||
|
|
m_hYUVTexture[1] = NULL;
|
||
|
|
m_hYUVTexture[2] = NULL;
|
||
|
|
|
||
|
|
memset(&m_dstRect, 0, sizeof(RECT));
|
||
|
|
memset(&m_srcRect, 0, sizeof(RECT));
|
||
|
|
}
|
||
|
|
|
||
|
|
CD3DVideoRender::~CD3DVideoRender()
|
||
|
|
{
|
||
|
|
unInit();
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::init(WId wid, int w, int h, int videofmt)
|
||
|
|
{
|
||
|
|
HWND hWnd = (HWND)wid;
|
||
|
|
|
||
|
|
CLock lock(g_d3d_mutex);
|
||
|
|
|
||
|
|
m_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
|
||
|
|
if (NULL == m_pD3D9)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, Direct3DCreate9 failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
HRESULT hr;
|
||
|
|
D3DPRESENT_PARAMETERS D3DPP;
|
||
|
|
|
||
|
|
initD3DPP(&D3DPP, hWnd);
|
||
|
|
|
||
|
|
if (!initDevice(&D3DPP, hWnd))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, initDevice failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX3);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetFVF failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (initShader(g_YUV420ps30_main, g_YUV420ps20_main) == FALSE)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, initShader failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, Clear failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CVideoRender::init(wid, w, h, videofmt);
|
||
|
|
|
||
|
|
m_bInited = initImageBuffer(w, h, videofmt);
|
||
|
|
|
||
|
|
return m_bInited;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CD3DVideoRender::unInit()
|
||
|
|
{
|
||
|
|
CLock lock(g_d3d_mutex);
|
||
|
|
|
||
|
|
freeImageBuffer();
|
||
|
|
|
||
|
|
if (m_pPixelShader)
|
||
|
|
{
|
||
|
|
m_pPixelShader->Release();
|
||
|
|
m_pPixelShader = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pPixelConstTable)
|
||
|
|
{
|
||
|
|
m_pPixelConstTable->Release();
|
||
|
|
m_pPixelConstTable = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pD3DD9)
|
||
|
|
{
|
||
|
|
m_pD3DD9->Release();
|
||
|
|
m_pD3DD9 = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pD3D9)
|
||
|
|
{
|
||
|
|
m_pD3D9->Release();
|
||
|
|
m_pD3D9 = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_bInited = FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::initD3DPP(D3DPRESENT_PARAMETERS * pD3DPP, HWND hWnd)
|
||
|
|
{
|
||
|
|
memset(pD3DPP, 0, sizeof(D3DPRESENT_PARAMETERS));
|
||
|
|
|
||
|
|
pD3DPP->Windowed = TRUE;
|
||
|
|
pD3DPP->hDeviceWindow = hWnd;
|
||
|
|
|
||
|
|
pD3DPP->Flags = D3DPRESENTFLAG_VIDEO;
|
||
|
|
pD3DPP->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
|
||
|
|
pD3DPP->BackBufferCount = 1;
|
||
|
|
pD3DPP->BackBufferFormat = D3DFMT_UNKNOWN;
|
||
|
|
|
||
|
|
pD3DPP->BackBufferWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||
|
|
pD3DPP->BackBufferHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||
|
|
|
||
|
|
//
|
||
|
|
// Mark the back buffer lockable if software DXVA2 could be used.
|
||
|
|
// This is because software DXVA2 device requires a lockable render target
|
||
|
|
// for the optimal performance.
|
||
|
|
//
|
||
|
|
pD3DPP->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
|
||
|
|
|
||
|
|
pD3DPP->SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::initDevice(D3DPRESENT_PARAMETERS * pD3DPP, HWND hWnd)
|
||
|
|
{
|
||
|
|
HRESULT hr;
|
||
|
|
UINT AdapterToUse = D3DADAPTER_DEFAULT;
|
||
|
|
D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
|
||
|
|
|
||
|
|
DWORD thread_modes[] = { D3DCREATE_MULTITHREADED, 0 };
|
||
|
|
DWORD vertex_modes[] = { D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
|
||
|
|
D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
||
|
|
D3DCREATE_MIXED_VERTEXPROCESSING,
|
||
|
|
D3DCREATE_SOFTWARE_VERTEXPROCESSING };
|
||
|
|
|
||
|
|
for (size_t t = 0; t < ARRAY_SIZE(thread_modes); t++)
|
||
|
|
{
|
||
|
|
for (size_t v = 0; v < ARRAY_SIZE(vertex_modes); v++)
|
||
|
|
{
|
||
|
|
DWORD creationFlags = thread_modes[t] | vertex_modes[v];
|
||
|
|
|
||
|
|
hr = m_pD3D9->CreateDevice(AdapterToUse,
|
||
|
|
DeviceType, hWnd,
|
||
|
|
creationFlags,
|
||
|
|
pD3DPP, &m_pD3DD9);
|
||
|
|
if (SUCCEEDED(hr))
|
||
|
|
{
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::initImageBuffer(int w, int h, int videofmt)
|
||
|
|
{
|
||
|
|
RECT rect;
|
||
|
|
GetClientRect((HWND)m_hWnd, &rect);
|
||
|
|
|
||
|
|
m_srcRect.left = m_srcRect.top = 0;
|
||
|
|
m_srcRect.right = w;
|
||
|
|
m_srcRect.bottom = h;
|
||
|
|
|
||
|
|
m_dstRect.left = rect.left;
|
||
|
|
m_dstRect.top = rect.top;
|
||
|
|
m_dstRect.right = rect.right;
|
||
|
|
m_dstRect.bottom = rect.bottom;
|
||
|
|
|
||
|
|
m_verPoint[0] = D3DXVECTOR4(m_dstRect.left-0.5f, m_dstRect.top-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[1] = D3DXVECTOR4(m_dstRect.right-0.5f, m_dstRect.top-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[2] = D3DXVECTOR4(m_dstRect.right-0.5f, m_dstRect.bottom-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[3] = D3DXVECTOR4(m_dstRect.left-0.5f, m_dstRect.bottom-0.5f, 0.0f, 1.0f);
|
||
|
|
|
||
|
|
float dx = 1.0f / w;
|
||
|
|
float dy = 1.0f / h;
|
||
|
|
|
||
|
|
m_texPoint[0] = D3DXVECTOR2(dx * m_srcRect.left, dy * m_srcRect.top);
|
||
|
|
m_texPoint[1] = D3DXVECTOR2(dx * m_srcRect.right, dy * m_srcRect.top);
|
||
|
|
m_texPoint[2] = D3DXVECTOR2(dx * m_srcRect.right, dy * m_srcRect.bottom);
|
||
|
|
m_texPoint[3] = D3DXVECTOR2(dx * m_srcRect.left, dy * m_srcRect.bottom);
|
||
|
|
|
||
|
|
HRESULT hr = m_pD3DD9->CreateVertexBuffer(4 * sizeof(YUV_VERTEX),
|
||
|
|
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,
|
||
|
|
D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX3, D3DPOOL_DEFAULT, &m_pVertices, NULL);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, CreateVertexBuffer failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
int i;
|
||
|
|
YUV_VERTEX * pVB;
|
||
|
|
|
||
|
|
hr = m_pVertices->Lock(0, 0, (void**)&pVB, 0);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
pVB[i].pos = m_verPoint[i];
|
||
|
|
pVB[i].color = m_dwColor;
|
||
|
|
pVB[i].tex1 = pVB[i].tex2 = pVB[i].tex3 = m_texPoint[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pVertices->Unlock();
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < 3; i++)
|
||
|
|
{
|
||
|
|
int Width = w;
|
||
|
|
int Height = h;
|
||
|
|
|
||
|
|
if (i != 0)
|
||
|
|
{
|
||
|
|
Width /= 2;
|
||
|
|
Height /= 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->CreateTexture(Width, Height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &m_pTexture[i], NULL);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, CreateTexture failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pTexTemp[Y_TEX] = m_pTexture[Y_TEX];
|
||
|
|
|
||
|
|
if (VIDEO_FMT_YV12 == videofmt)
|
||
|
|
{
|
||
|
|
m_pTexTemp[U_TEX] = m_pTexture[V_TEX];
|
||
|
|
m_pTexTemp[V_TEX] = m_pTexture[U_TEX];
|
||
|
|
}
|
||
|
|
else if (VIDEO_FMT_YUV420P == videofmt)
|
||
|
|
{
|
||
|
|
m_pTexTemp[U_TEX] = m_pTexture[U_TEX];
|
||
|
|
m_pTexTemp[V_TEX] = m_pTexture[V_TEX];
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
|
||
|
|
done:
|
||
|
|
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CD3DVideoRender::freeImageBuffer()
|
||
|
|
{
|
||
|
|
if (m_pVertices)
|
||
|
|
{
|
||
|
|
m_pVertices->Release();
|
||
|
|
m_pVertices = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0 ; i < COUNT_YUV_TEX; i++)
|
||
|
|
{
|
||
|
|
if (m_pTexture[i])
|
||
|
|
{
|
||
|
|
m_pTexture[i]->Release();
|
||
|
|
m_pTexture[i] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::initShader(const DWORD * pCode3, const DWORD * pCode2)
|
||
|
|
{
|
||
|
|
D3DCAPS9 caps;
|
||
|
|
HRESULT hr = S_OK;
|
||
|
|
|
||
|
|
hr = m_pD3DD9->GetDeviceCaps(&caps);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
const DWORD * pCode;
|
||
|
|
|
||
|
|
if (caps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
|
||
|
|
{
|
||
|
|
pCode = pCode3;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pCode = pCode2;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->CreatePixelShader(pCode, &m_pPixelShader);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = D3DXGetShaderConstantTable(pCode, &m_pPixelConstTable);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_hYUVTexture[Y_TEX] = m_pPixelConstTable->GetConstantByName(NULL, "YTextue");
|
||
|
|
if (m_hYUVTexture[Y_TEX] == NULL)
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_hYUVTexture[U_TEX] = m_pPixelConstTable->GetConstantByName(NULL, "UTextue");
|
||
|
|
if (m_hYUVTexture[U_TEX] == NULL)
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_hYUVTexture[V_TEX] = m_pPixelConstTable->GetConstantByName(NULL, "VTextue");
|
||
|
|
if (m_hYUVTexture[V_TEX] == NULL)
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
UINT count;
|
||
|
|
|
||
|
|
hr = m_pPixelConstTable->GetConstantDesc(m_hYUVTexture[Y_TEX], &m_dYUVTexture[Y_TEX], &count);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pPixelConstTable->GetConstantDesc(m_hYUVTexture[U_TEX], &m_dYUVTexture[U_TEX], &count);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pPixelConstTable->GetConstantDesc(m_hYUVTexture[V_TEX], &m_dYUVTexture[V_TEX], &count);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_hTransparent = m_pPixelConstTable->GetConstantByName(NULL, "transparent");
|
||
|
|
if (m_hTransparent == NULL)
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pPixelConstTable->SetDefaults(m_pD3DD9);
|
||
|
|
|
||
|
|
done:
|
||
|
|
|
||
|
|
return SUCCEEDED(hr) ? TRUE : FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::resetDevice()
|
||
|
|
{
|
||
|
|
freeImageBuffer();
|
||
|
|
|
||
|
|
if (m_pPixelShader)
|
||
|
|
{
|
||
|
|
m_pPixelShader->Release();
|
||
|
|
m_pPixelShader = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pPixelConstTable)
|
||
|
|
{
|
||
|
|
m_pPixelConstTable->Release();
|
||
|
|
m_pPixelConstTable = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
HRESULT hr;
|
||
|
|
D3DPRESENT_PARAMETERS D3DPP;
|
||
|
|
|
||
|
|
initD3DPP(&D3DPP, (HWND)m_hWnd);
|
||
|
|
|
||
|
|
hr = m_pD3DD9->Reset(&D3DPP);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX3);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetFVF failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (initShader(g_YUV420ps30_main, g_YUV420ps20_main) == FALSE)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, initShader failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, Clear failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return initImageBuffer(m_nVideoWidth, m_nVideoHeight, m_nVideoFmt);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::setImageArgs(float Transparent, GEOMETRICTRANSFORMATION flip, RECT * pDstRect, RECT * pSrcRect)
|
||
|
|
{
|
||
|
|
BOOL bSet = FALSE;
|
||
|
|
|
||
|
|
if (m_dTransparent != Transparent)
|
||
|
|
{
|
||
|
|
m_dTransparent = Transparent;
|
||
|
|
m_dwColor = ((DWORD)( 255 * Transparent ) << 24) | 0x00ffffff;
|
||
|
|
bSet = TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (memcmp(&m_dstRect, pDstRect, sizeof(RECT)) != 0)
|
||
|
|
{
|
||
|
|
memcpy(&m_dstRect, pDstRect, sizeof(RECT));
|
||
|
|
|
||
|
|
m_verPoint[0] = D3DXVECTOR4(m_dstRect.left-0.5f, m_dstRect.top-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[1] = D3DXVECTOR4(m_dstRect.right-0.5f, m_dstRect.top-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[2] = D3DXVECTOR4(m_dstRect.right-0.5f, m_dstRect.bottom-0.5f, 0.0f, 1.0f);
|
||
|
|
m_verPoint[3] = D3DXVECTOR4(m_dstRect.left-0.5f, m_dstRect.bottom-0.5f, 0.0f, 1.0f);
|
||
|
|
bSet = TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (memcmp(&m_srcRect, pSrcRect, sizeof(RECT)) != 0 || flip != m_nFlip)
|
||
|
|
{
|
||
|
|
float dx = 1.0f / m_nVideoWidth;
|
||
|
|
float dy = 1.0f / m_nVideoHeight;
|
||
|
|
|
||
|
|
memcpy(&m_srcRect, pSrcRect, sizeof(RECT));
|
||
|
|
|
||
|
|
m_texPoint[0] = D3DXVECTOR2(dx * m_srcRect.left, dy * m_srcRect.top);
|
||
|
|
m_texPoint[1] = D3DXVECTOR2(dx * m_srcRect.right, dy * m_srcRect.top);
|
||
|
|
m_texPoint[2] = D3DXVECTOR2(dx * m_srcRect.right, dy * m_srcRect.bottom);
|
||
|
|
m_texPoint[3] = D3DXVECTOR2(dx * m_srcRect.left, dy * m_srcRect.bottom);
|
||
|
|
|
||
|
|
if (flip & GS_UPPER_DOWN_FLIP)
|
||
|
|
{
|
||
|
|
D3DXVECTOR2 temp = m_texPoint[0];
|
||
|
|
m_texPoint[0] = m_texPoint[3];
|
||
|
|
m_texPoint[3] = temp;
|
||
|
|
|
||
|
|
temp = m_texPoint[1];
|
||
|
|
m_texPoint[1] = m_texPoint[2];
|
||
|
|
m_texPoint[2] = temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (flip & GS_LEFT_RIGHT_FLIP)
|
||
|
|
{
|
||
|
|
D3DXVECTOR2 temp = m_texPoint[0];
|
||
|
|
m_texPoint[0] = m_texPoint[1];
|
||
|
|
m_texPoint[1] = temp;
|
||
|
|
|
||
|
|
temp = m_texPoint[2];
|
||
|
|
m_texPoint[2] = m_texPoint[3];
|
||
|
|
m_texPoint[3] = temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_nFlip = flip;
|
||
|
|
bSet = TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return bSet;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::setImage(GEOMETRICTRANSFORMATION flip, RECT * pDstRect, RECT * pSrcRect)
|
||
|
|
{
|
||
|
|
if (!setImageArgs(1.0f, flip, pDstRect, pSrcRect))
|
||
|
|
{
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
YUV_VERTEX * pVB;
|
||
|
|
HRESULT hr = m_pVertices->Lock(0, 0, (void**)&pVB, D3DLOCK_DISCARD);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0 ; i < 4 ; i++)
|
||
|
|
{
|
||
|
|
pVB[i].pos = m_verPoint[i];
|
||
|
|
pVB[i].color = m_dwColor;
|
||
|
|
pVB[i].tex1 = pVB[i].tex2 = pVB[i].tex3 = m_texPoint[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pVertices->Unlock();
|
||
|
|
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CD3DVideoRender::render(AVFrame * frame, int mode)
|
||
|
|
{
|
||
|
|
HRESULT hr = S_OK;
|
||
|
|
|
||
|
|
if (m_bReset)
|
||
|
|
{
|
||
|
|
if (resetDevice())
|
||
|
|
{
|
||
|
|
m_bReset = FALSE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!m_bInited || m_bReset || NULL == frame)
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pD3DD9)
|
||
|
|
{
|
||
|
|
hr = m_pD3DD9->TestCooperativeLevel();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, TestCooperativeLevel failed. (hr=0x%0lx)\r\n", __FUNCTION__, hr);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_nVideoWidth != frame->width || m_nVideoHeight != frame->height)
|
||
|
|
{
|
||
|
|
freeImageBuffer();
|
||
|
|
|
||
|
|
if (!initImageBuffer(frame->width, frame->height, m_nVideoFmt))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, initImageBuffer failed\r\n", __FUNCTION__);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_nVideoWidth = frame->width;
|
||
|
|
m_nVideoHeight = frame->height;
|
||
|
|
}
|
||
|
|
|
||
|
|
RECT rect;
|
||
|
|
GetClientRect((HWND)m_hWnd, &rect);
|
||
|
|
|
||
|
|
RECT targetRect;
|
||
|
|
RECT sourceRect;
|
||
|
|
|
||
|
|
sourceRect.left = 0;
|
||
|
|
sourceRect.top = 0;
|
||
|
|
sourceRect.right = frame->width;
|
||
|
|
sourceRect.bottom = frame->height;
|
||
|
|
|
||
|
|
if (mode == RENDER_MODE_KEEP)
|
||
|
|
{
|
||
|
|
int rectw = rect.right - rect.left;
|
||
|
|
int recth = rect.bottom - rect.top;
|
||
|
|
|
||
|
|
double dw = rectw / (double) m_nVideoWidth;
|
||
|
|
double dh = recth / (double) m_nVideoHeight;
|
||
|
|
double rate = (dw > dh) ? dh : dw;
|
||
|
|
|
||
|
|
int rw = (int)(m_nVideoWidth * rate);
|
||
|
|
int rh = (int)(m_nVideoHeight * rate);
|
||
|
|
|
||
|
|
targetRect.left = (rectw - rw) / 2;
|
||
|
|
targetRect.top = (recth - rh) / 2;
|
||
|
|
targetRect.right = targetRect.left + rw;
|
||
|
|
targetRect.bottom = targetRect.top + rh;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
targetRect = rect;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0 ; i < 3 ; i++)
|
||
|
|
{
|
||
|
|
int w = m_nVideoWidth;
|
||
|
|
int h = m_nVideoHeight;
|
||
|
|
|
||
|
|
if (i != 0)
|
||
|
|
{
|
||
|
|
w /= 2;
|
||
|
|
h /= 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
BYTE * pSrc = frame->data[i];
|
||
|
|
D3DLOCKED_RECT lrect;
|
||
|
|
|
||
|
|
hr = m_pTexture[i]->LockRect(0, &lrect, NULL, D3DLOCK_DISCARD);
|
||
|
|
if (SUCCEEDED(hr))
|
||
|
|
{
|
||
|
|
BYTE * pDest = (BYTE*) lrect.pBits;
|
||
|
|
|
||
|
|
for (int j = 0 ; j < h; j++)
|
||
|
|
{
|
||
|
|
memcpy(pDest, pSrc, w);
|
||
|
|
|
||
|
|
pDest += lrect.Pitch;
|
||
|
|
pSrc += frame->linesize[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pTexture[i]->UnlockRect(0);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, LockRect failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// begin draw
|
||
|
|
hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pRenderSurface);
|
||
|
|
if (SUCCEEDED(hr))
|
||
|
|
{
|
||
|
|
m_pD3DD9->ColorFill(m_pRenderSurface, &rect, D3DCOLOR_ARGB(0xff,0x0,0x0,0x0));
|
||
|
|
m_pD3DD9->SetRenderTarget(0, m_pRenderSurface);
|
||
|
|
m_pRenderSurface->Release();
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->BeginScene();
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, BeginScene failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX3);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetFVF failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetPixelShader(m_pPixelShader);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetPixelShader failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pPixelConstTable->SetFloat(m_pD3DD9, m_hTransparent, 1.0);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetFloat failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
setImage(GS_NONE, &targetRect, &sourceRect);
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetTexture(m_dYUVTexture[Y_TEX].RegisterIndex, m_pTexTemp[Y_TEX]);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetTexture failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetTexture(m_dYUVTexture[U_TEX].RegisterIndex, m_pTexTemp[U_TEX]);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetTexture failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetTexture(m_dYUVTexture[V_TEX].RegisterIndex, m_pTexTemp[V_TEX]);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetTexture failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->SetStreamSource(0, m_pVertices, 0, sizeof(YUV_VERTEX));
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, SetStreamSource failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, DrawPrimitive failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->EndScene();
|
||
|
|
if (FAILED(hr))
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_ERR, "%s, EndScene failed\r\n", __FUNCTION__);
|
||
|
|
goto done;
|
||
|
|
}
|
||
|
|
|
||
|
|
hr = m_pD3DD9->Present(&rect, &rect, NULL, NULL);
|
||
|
|
|
||
|
|
done:
|
||
|
|
|
||
|
|
if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET)
|
||
|
|
{
|
||
|
|
log_print(HT_LOG_DBG, "%s, device lost!\r\n", __FUNCTION__);
|
||
|
|
|
||
|
|
m_bReset = TRUE;
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return SUCCEEDED(hr) ? TRUE : FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|