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