STDMETHODIMP CLAVSubtitleConsumer::ProcessFrame(LAVFrame *pFrame) { CheckPointer(m_pProvider, E_FAIL); HRESULT hr = S_OK; LPDIRECT3DSURFACE9 pSurface = nullptr; // Wait for the requested frame m_evFrame.Wait(); if (m_SubtitleFrame != nullptr) { int count = 0; if (FAILED(m_SubtitleFrame->GetBitmapCount(&count))) { count = 0; } if (count == 0) { SafeRelease(&m_SubtitleFrame); return S_FALSE; } BYTE *data[4] = {0}; ptrdiff_t stride[4] = {0}; LAVPixelFormat format = pFrame->format; int bpp = pFrame->bpp; if (pFrame->format == LAVPixFmt_DXVA2) { // Copy the surface, if required if (!(pFrame->flags & LAV_FRAME_FLAG_BUFFER_MODIFY)) { IMediaSample *pOrigSample = (IMediaSample *)pFrame->data[0]; LPDIRECT3DSURFACE9 pOrigSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; hr = m_pLAVVideo->GetD3DBuffer(pFrame); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"CLAVSubtitleConsumer::ProcessFrame: getting a new D3D buffer failed")); } else { IMediaSample *pNewSample = (IMediaSample *)pFrame->data[0]; pSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; IDirect3DDevice9 *pDevice = nullptr; if (SUCCEEDED(hr = pSurface->GetDevice(&pDevice))) { hr = pDevice->StretchRect(pOrigSurface, nullptr, pSurface, nullptr, D3DTEXF_NONE); if (SUCCEEDED(hr)) { pFrame->flags |= LAV_FRAME_FLAG_BUFFER_MODIFY|LAV_FRAME_FLAG_DXVA_NOADDREF; pOrigSurface = nullptr; // Release the surface, we only want to hold a ref on the media buffer pSurface->Release(); } SafeRelease(&pDevice); } if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"CLAVSubtitleConsumer::ProcessFrame: processing d3d buffer failed, restoring previous buffer")); pNewSample->Release(); pSurface->Release(); pFrame->data[0] = (BYTE *)pOrigSample; pFrame->data[3] = (BYTE *)pOrigSurface; } } } pSurface = (LPDIRECT3DSURFACE9)pFrame->data[3]; D3DSURFACE_DESC surfaceDesc; pSurface->GetDesc(&surfaceDesc); D3DLOCKED_RECT LockedRect; hr = pSurface->LockRect(&LockedRect, nullptr, 0); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"pSurface->LockRect failed (hr: %X)", hr)); SafeRelease(&m_SubtitleFrame); return E_FAIL; } data[0] = (BYTE *)LockedRect.pBits; data[1] = data[0] + (surfaceDesc.Height * LockedRect.Pitch); stride[0] = LockedRect.Pitch; stride[1] = LockedRect.Pitch; format = LAVPixFmt_NV12; bpp = 8; } else { if (!(pFrame->flags & LAV_FRAME_FLAG_BUFFER_MODIFY)) { CopyLAVFrameInPlace(pFrame); } memcpy(&data, &pFrame->data, sizeof(pFrame->data)); memcpy(&stride, &pFrame->stride, sizeof(pFrame->stride)); } RECT videoRect; ::SetRect(&videoRect, 0, 0, pFrame->width, pFrame->height); RECT subRect; m_SubtitleFrame->GetOutputRect(&subRect); ULONGLONG id; POINT position; SIZE size; const uint8_t *rgbData; int pitch; for (int i = 0; i < count; i++) { if (FAILED(m_SubtitleFrame->GetBitmap(i, &id, &position, &size, (LPCVOID *)&rgbData, &pitch))) { DbgLog((LOG_TRACE, 10, L"GetBitmap() failed on index %d", i)); break; } ProcessSubtitleBitmap(format, bpp, videoRect, data, stride, subRect, position, size, rgbData, pitch); } if (pSurface) pSurface->UnlockRect(); SafeRelease(&m_SubtitleFrame); return S_OK; } return S_FALSE; }
// draw 3D objects and so on void RenderScene() { ///////////////////////// // 1. draw the scene into the render target ///////////////////////// // current hardware backbuffer LPDIRECT3DSURFACE9 pHWBackBuffer = NULL; gpD3DDevice->GetRenderTarget(0, &pHWBackBuffer); // draw onto the render target LPDIRECT3DSURFACE9 pSceneSurface = NULL; if (SUCCEEDED(gpSceneRenderTarget->GetSurfaceLevel(0, &pSceneSurface))) { gpD3DDevice->SetRenderTarget(0, pSceneSurface); pSceneSurface->Release(); pSceneSurface = NULL; } // clear what's drawn in the last frame gpD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0); // make the view matrix D3DXMATRIXA16 matView; D3DXVECTOR3 vEyePt(gWorldCameraPosition.x, gWorldCameraPosition.y, gWorldCameraPosition.z); D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec); // projection matrix D3DXMATRIXA16 matProjection; D3DXMatrixPerspectiveFovLH(&matProjection, FOV, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE); // for each frame, we roate 0.4 degree gRotationY += 0.4f * PI / 180.0f; if (gRotationY > 2 * PI) { gRotationY -= 2 * PI; } // world matrix D3DXMATRIXA16 matWorld; D3DXMatrixRotationY(&matWorld, gRotationY); // concatenate world/view/projection matrices D3DXMATRIXA16 matWorldView; D3DXMATRIXA16 matWorldViewProjection; D3DXMatrixMultiply(&matWorldView, &matWorld, &matView); D3DXMatrixMultiply(&matWorldViewProjection, &matWorldView, &matProjection); // set shader global variables gpEnvironmentMappingShader->SetMatrix("gWorldMatrix", &matWorld); gpEnvironmentMappingShader->SetMatrix("gWorldViewProjectionMatrix", &matWorldViewProjection); gpEnvironmentMappingShader->SetVector("gWorldLightPosition", &gWorldLightPosition); gpEnvironmentMappingShader->SetVector("gWorldCameraPosition", &gWorldCameraPosition); gpEnvironmentMappingShader->SetVector("gLightColor", &gLightColor); gpEnvironmentMappingShader->SetTexture("DiffuseMap_Tex", gpStoneDM); gpEnvironmentMappingShader->SetTexture("SpecularMap_Tex", gpStoneSM); gpEnvironmentMappingShader->SetTexture("NormalMap_Tex", gpStoneNM); gpEnvironmentMappingShader->SetTexture("EnvironmentMap_Tex", gpSnowENV); // start a shader UINT numPasses = 0; gpEnvironmentMappingShader->Begin(&numPasses, NULL); { for (UINT i = 0; i < numPasses; ++i) { gpEnvironmentMappingShader->BeginPass(i); { // draw a sphere gpTeapot->DrawSubset(0); } gpEnvironmentMappingShader->EndPass(); } } gpEnvironmentMappingShader->End(); ///////////////////////// // 2. apply post-processing ///////////////////////// // use hardware backbuffer gpD3DDevice->SetRenderTarget(0, pHWBackBuffer); pHWBackBuffer->Release(); pHWBackBuffer = NULL; // post process effect to use LPD3DXEFFECT effectToUse = gpNoEffect; if (gPostProcessIndex == 1) { effectToUse = gpGrayScale; } else if (gPostProcessIndex == 2) { effectToUse = gpSepia; } effectToUse->SetTexture("SceneTexture_Tex", gpSceneRenderTarget); effectToUse->Begin(&numPasses, NULL); { for (UINT i = 0; i < numPasses; ++i) { effectToUse->BeginPass(i); { // draw a fullscreen quad gpD3DDevice->SetStreamSource(0, gpFullscreenQuadVB, 0, sizeof(float)* 5); gpD3DDevice->SetIndices(gpFullscreenQuadIB); gpD3DDevice->SetVertexDeclaration(gpFullscreenQuadDecl); gpD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 2); } effectToUse->EndPass(); } } effectToUse->End(); }
HRESULT CDxtexDoc::LoadAlphaIntoSurface(CString& strPath, LPDIRECT3DSURFACE9 psurf) { HRESULT hr; D3DSURFACE_DESC sd; LPDIRECT3DDEVICE9 pd3ddev = PDxtexApp()->Pd3ddev(); LPDIRECT3DTEXTURE9 ptexAlpha; LPDIRECT3DSURFACE9 psurfAlpha; LPDIRECT3DSURFACE9 psurfTarget; psurf->GetDesc(&sd); // Load the alpha BMP into psurfAlpha, a new A8R8G8B8 surface hr = D3DXCreateTextureFromFileEx(pd3ddev, strPath, sd.Width, sd.Height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &ptexAlpha); hr = ptexAlpha->GetSurfaceLevel(0, &psurfAlpha); // Copy the target surface into an A8R8G8B8 surface hr = pd3ddev->CreateOffscreenPlainSurface(sd.Width, sd.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &psurfTarget, NULL); hr = D3DXLoadSurfaceFromSurface(psurfTarget, NULL, NULL, psurf, NULL, NULL, D3DX_DEFAULT, 0); // Fill in the alpha channels of psurfTarget based on the blue channel of psurfAlpha D3DLOCKED_RECT lrSrc; D3DLOCKED_RECT lrDest; hr = psurfAlpha->LockRect(&lrSrc, NULL, D3DLOCK_READONLY); hr = psurfTarget->LockRect(&lrDest, NULL, 0); DWORD xp; DWORD yp; DWORD* pdwRowSrc = (DWORD*)lrSrc.pBits; DWORD* pdwRowDest = (DWORD*)lrDest.pBits; DWORD* pdwSrc; DWORD* pdwDest; DWORD dwAlpha; LONG dataBytesPerRow = 4 * sd.Width; for (yp = 0; yp < sd.Height; yp++) { pdwSrc = pdwRowSrc; pdwDest = pdwRowDest; for (xp = 0; xp < sd.Width; xp++) { dwAlpha = *pdwSrc << 24; *pdwDest &= 0x00ffffff; *pdwDest |= dwAlpha; pdwSrc++; pdwDest++; } pdwRowSrc += lrSrc.Pitch / 4; pdwRowDest += lrDest.Pitch / 4; } psurfAlpha->UnlockRect(); psurfTarget->UnlockRect(); // Copy psurfTarget back into real surface hr = D3DXLoadSurfaceFromSurface(psurf, NULL, NULL, psurfTarget, NULL, NULL, D3DX_DEFAULT, 0); // Release allocated interfaces ReleasePpo(&psurfTarget); ReleasePpo(&psurfAlpha); ReleasePpo(&ptexAlpha); return S_OK; }