////////////////////////////////////////////////////////////////////////// // // device.cpp: Manages the Direct3D device // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // ////////////////////////////////////////////////////////////////////////// #include "ARMFCaptureD3D.h" #include "BufferLock.h" #include "debug.h" #include "ARAnalyse.h" extern ARAnalyse *g_pAnalyse; void TransformImage_RGB24( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_RGB32( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_YUY2( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_NV12( BYTE* pDst, LONG dstStride, const BYTE* pSrc, LONG srcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst); RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR); HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); inline LONG Width(const RECT& r) { return r.right - r.left; } inline LONG Height(const RECT& r) { return r.bottom - r.top; } // Static table of output formats and conversion functions. struct ConversionFunction { GUID subtype; IMAGE_TRANSFORM_FN xform; }; ConversionFunction g_FormatConversions[] = { { MFVideoFormat_RGB32, TransformImage_RGB32 }, { MFVideoFormat_RGB24, TransformImage_RGB24 }, { MFVideoFormat_YUY2, TransformImage_YUY2 }, { MFVideoFormat_NV12, TransformImage_NV12 } }; const DWORD g_cFormats = ARRAYSIZE(g_FormatConversions); //------------------------------------------------------------------- // Constructor //------------------------------------------------------------------- DrawDevice::DrawDevice() : m_hwnd(NULL), m_pDevice(NULL), m_pSwapChain(NULL), m_pVertexBuffer(NULL), m_pIndexBuffer(NULL), #ifdef DX9 m_pD3D(NULL), m_format(D3DFMT_UNKNOWN), #else m_format(DXGI_FORMAT_UNKNOWN), #endif m_width(0), m_height(0), m_lDefaultStride(0), m_interlace(MFVideoInterlace_Unknown), m_convertFn(NULL) { m_PixelAR.Denominator = m_PixelAR.Numerator = 1; ZeroMemory(&m_d3dpp, sizeof(m_d3dpp)); } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- DrawDevice::~DrawDevice() { DestroyDevice(); } void DrawDevice::GetSize(UINT* width, UINT *height) const { *width = m_width; *height = m_height; } //------------------------------------------------------------------- // GetFormat // // Get a supported output format by index. //------------------------------------------------------------------- HRESULT DrawDevice::GetFormat(DWORD index, GUID *pSubtype) const { if (index < g_cFormats) { *pSubtype = g_FormatConversions[index].subtype; return S_OK; } return MF_E_NO_MORE_TYPES; } //------------------------------------------------------------------- // IsFormatSupported // // Query if a format is supported. //------------------------------------------------------------------- BOOL DrawDevice::IsFormatSupported(REFGUID subtype) const { for (DWORD i = 0; i < g_cFormats; i++) { if (subtype == g_FormatConversions[i].subtype) { return TRUE; } } return FALSE; } //------------------------------------------------------------------- // CreateDevice // // Create the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::CreateDevice(HWND hwnd) { HRESULT hr = S_OK; if (m_pDevice) { return S_OK; } #ifdef DX9 // Create the Direct3D object. if (m_pD3D == NULL) { m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (m_pD3D == NULL) { return E_FAIL; } } D3DPRESENT_PARAMETERS pp = { 0 }; D3DDISPLAYMODE mode = { 0 }; pp.BackBufferFormat = D3DFMT_A8R8G8B8; pp.SwapEffect = D3DSWAPEFFECT_FLIP; pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; pp.Windowed = TRUE; pp.hDeviceWindow = hwnd; hr = m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &mode ); if (FAILED(hr)) { goto done; } hr = m_pD3D->CheckDeviceType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format, pp.BackBufferFormat, TRUE // windowed ); if (FAILED(hr)) { goto done; } hr = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &pp, &m_pDevice ); #else DXGI_SWAP_CHAIN_DESC pp = { 0 }; ZeroMemory( &pp, sizeof( pp ) ); pp.BufferCount = 1; //pp.BufferDesc.Width = width; //pp.BufferDesc.Height = height; pp.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; pp.BufferDesc.RefreshRate.Numerator = 0; //users =0, originally 60 pp.BufferDesc.RefreshRate.Denominator = 0; pp.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; //pp.SwapEffect = D3DSWAPEFFECT_COPY; //pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; pp.Windowed = TRUE; pp.OutputWindow = hwnd; D3D_FEATURE_LEVEL FeatureLevels = D3D_FEATURE_LEVEL_11_0; hr = D3D11CreateDevice( NULL,D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &FeatureLevels, 1, D3D11_SDK_VERSION, &m_pDevice, &FeatureLevels, &m_pDeviceContext ); #endif if (FAILED(hr)) { goto done; } // Turn on Blending m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); m_pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); m_hwnd = hwnd; m_d3dpp = pp; done: return hr; } //------------------------------------------------------------------- // SetConversionFunction // // Set the conversion function for the specified video format. //------------------------------------------------------------------- HRESULT DrawDevice::SetConversionFunction(REFGUID subtype) { m_convertFn = NULL; for (DWORD i = 0; i < g_cFormats; i++) { if (g_FormatConversions[i].subtype == subtype) { m_convertFn = g_FormatConversions[i].xform; return S_OK; } } return MF_E_INVALIDMEDIATYPE; } //------------------------------------------------------------------- // SetVideoType // // Set the video format. //------------------------------------------------------------------- HRESULT DrawDevice::SetVideoType(IMFMediaType *pType) { HRESULT hr = S_OK; GUID subtype = { 0 }; MFRatio PAR = { 0 }; // Find the video subtype. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) { goto done; } // Choose a conversion function. // (This also validates the format type.) hr = SetConversionFunction(subtype); if (FAILED(hr)) { goto done; } // // Get some video attributes. // // Get the frame size. hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &m_width, &m_height); if (FAILED(hr)) { goto done; } // Get the interlace mode. Default: assume progressive. m_interlace = (MFVideoInterlaceMode)MFGetAttributeUINT32( pType, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive ); // Get the image stride. hr = GetDefaultStride(pType, &m_lDefaultStride); if (FAILED(hr)) { goto done; } // Get the pixel aspect ratio. Default: Assume square pixels (1:1) hr = MFGetAttributeRatio( pType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&PAR.Numerator, (UINT32*)&PAR.Denominator ); if (SUCCEEDED(hr)) { m_PixelAR = PAR; } else { m_PixelAR.Numerator = m_PixelAR.Denominator = 1; } #ifdef DX9 m_format = (D3DFORMAT)subtype.Data1; #else m_format = (DXGI_FORMAT)subtype.Data1; #endif // Create Direct3D swap chains. hr = CreateSwapChains(); if (FAILED(hr)) { goto done; } // Update the destination rectangle for the correct // aspect ratio. UpdateDestinationRect(); done: if (FAILED(hr)) { #ifdef DX9 m_format = D3DFMT_UNKNOWN; #else m_format = DXGI_FORMAT_UNKNOWN; #endif m_convertFn = NULL; } return hr; } //------------------------------------------------------------------- // UpdateDestinationRect // // Update the destination rectangle for the current window size. // The destination rectangle is letterboxed to preserve the // aspect ratio of the video image. //------------------------------------------------------------------- void DrawDevice::UpdateDestinationRect() { RECT rcClient; RECT rcSrc = { 0, 0, m_width, m_height }; GetClientRect(m_hwnd, &rcClient); rcSrc = CorrectAspectRatio(rcSrc, m_PixelAR); m_rcDest = LetterBoxRect(rcSrc, rcClient); } //------------------------------------------------------------------- // CreateSwapChains // // Create Direct3D swap chains. //------------------------------------------------------------------- HRESULT DrawDevice::CreateSwapChains() { HRESULT hr = S_OK; #ifdef DX9 D3DPRESENT_PARAMETERS pp = { 0 }; SafeRelease(&m_pSwapChain); pp.BackBufferWidth = m_width; pp.BackBufferHeight = m_height; pp.Windowed = TRUE; pp.SwapEffect = D3DSWAPEFFECT_FLIP; pp.hDeviceWindow = m_hwnd; pp.BackBufferFormat = D3DFMT_A8R8G8B8; pp.Flags = D3DPRESENTFLAG_VIDEO | D3DPRESENTFLAG_DEVICECLIP | D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; //pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; pp.BackBufferCount = 2; hr = m_pDevice->CreateAdditionalSwapChain(&pp, &m_pSwapChain); #else DXGI_SWAP_CHAIN_DESC pp = { 0 }; SafeRelease(&m_pSwapChain); pp.BufferCount = 1; pp.BufferDesc.Width = m_width; pp.BufferDesc.Height = m_height; pp.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; pp.BufferDesc.RefreshRate.Numerator = 0; //users =0, originally 60 pp.BufferDesc.RefreshRate.Denominator = 0; pp.Windowed = TRUE; pp.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //D3DSWAPEFFECT_FLIP; pp.OutputWindow = m_hwnd; pp.Flags = DXGI_SWAP_CHAIN_FLAG_NONPREROTATED; /* D3DPRESENTFLAG_VIDEO | D3DPRESENTFLAG_DEVICECLIP | D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;*/ //pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; IDXGIDevice* m_pDXGIDevice; IDXGIAdapter* m_pDXGIAdapter; IDXGIFactory* m_pDXGIFactory; hr = m_pDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)& m_pDXGIDevice); if ( hr != S_OK ) { DBGMSG(L"cDX10Mananger::Initialise(): Unable to get DXGIDevice (hr = 0x%0X)\n", hr ); return hr; } hr = m_pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)& m_pDXGIAdapter); if ( hr != S_OK ) { DBGMSG(L"cDX10Mananger::Initialise(): Unable to get DXGIAdapter (hr = 0x%0X)\n", hr ); return hr; } hr = m_pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)& m_pDXGIFactory); if ( hr != S_OK ) { DBGMSG(L"cDX10Mananger::Initialise(): Unable to get DXGIFactory (hr = 0x%0X)\n", hr ); return hr; } hr = m_pDXGIFactory->CreateSwapChain(m_pDevice, &pp, &m_pSwapChain ); #endif return hr; } //------------------------------------------------------------------- // DrawFrame // // Draw the video frame. //------------------------------------------------------------------- HRESULT DrawDevice::DrawFrame(IMFMediaBuffer *pBuffer) { if (m_convertFn == NULL) { return MF_E_INVALIDREQUEST; } HRESULT hr = S_OK; BYTE *pbScanline0 = NULL; LONG lStride = 0; #ifdef DX9 D3DLOCKED_RECT lr; IDirect3DSurface9 *pSurf = NULL; IDirect3DSurface9 *pBB = NULL; #else DXGI_MAPPED_RECT lr; IDXGISurface *pSurf = NULL; IDXGISurface *pBB = NULL; #endif if (m_pDevice == NULL || m_pSwapChain == NULL) { return S_OK; } VideoBufferLock buffer(pBuffer); // Helper object to lock the video buffer. hr = TestCooperativeLevel(); if (FAILED(hr)) { goto done; } // Lock the video buffer. This method returns a pointer to the first scan // line in the image, and the stride in bytes. hr = buffer.LockBuffer(m_lDefaultStride, m_height, &pbScanline0, &lStride); if (FAILED(hr)) { goto done; } #ifdef DX9 // Get the swap-chain surface. hr = m_pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf); if (FAILED(hr)) { goto done; } // Lock the swap-chain surface. hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK ); #else // Get the swap-chain surface. hr = m_pSwapChain->GetBuffer(0, __uuidof(pSurf), reinterpret_cast(&pSurf)); if (FAILED(hr)) { goto done; } // Lock the swap-chain surface. hr = pSurf->Map( &lr, DXGI_MAP_WRITE ); #endif if (FAILED(hr)) { goto done; } // Convert the frame. This also copies it to the Direct3D surface. m_convertFn( (BYTE*)lr.pBits, lr.Pitch, pbScanline0, lStride, m_width, m_height ); #ifdef DX9 hr = pSurf->UnlockRect(); if (FAILED(hr)) { goto done; } // Color fill the back buffer. hr = m_pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB); if (FAILED(hr)) { goto done; } hr = m_pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0x80, 0x80, 0x80)); if (FAILED(hr)) { goto done; } // Blit the frame. hr = m_pDevice->StretchRect(pSurf, NULL, pBB, &m_rcDest, D3DTEXF_LINEAR); if (FAILED(hr)) { goto done; } RenderObjects(); // Present the frame. hr = m_pDevice->Present(NULL, NULL, NULL, NULL); #else hr = pSurf->Unmap(); if (FAILED(hr)) { goto done; } //Create a render target view ID3D11Texture2D *pBackBuffer; ID3D11RenderTargetView *g_pRenderTargetView; hr = m_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&pBackBuffer ); if (FAILED(hr)) { goto done; } hr = m_pDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView ); pBackBuffer->Release(); if (FAILED(hr)) { goto done; } m_pDeviceContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL ); // // Clear the backbuffer // float ClearColor[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; // RGBA m_pDeviceContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); if (FAILED(hr)) { goto done; } // Blit the frame. //hr = m_pDeviceContext->StretchRect(pSurf, NULL, pBB, &m_rcDest, D3DTEXF_LINEAR); if (FAILED(hr)) { goto done; } // Present the frame. hr = m_pSwapChain->Present(0,0); #endif done: #ifdef DX9 SafeRelease(&pBB); if ( pSurf) SafeRelease(&pSurf); #endif return hr; } //------------------------------------------------------------------- // TestCooperativeLevel // // Test the cooperative-level status of the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::TestCooperativeLevel() { if (m_pDevice == NULL) { return E_FAIL; } HRESULT hr = S_OK; #ifdef DX9 // Check the current status of D3D9 device. hr = m_pDevice->TestCooperativeLevel(); switch (hr) { case D3D_OK: break; case D3DERR_DEVICELOST: hr = S_OK; case D3DERR_DEVICENOTRESET: hr = ResetDevice(); break; default: // Some other failure. break; } #endif return hr; } //------------------------------------------------------------------- // ResetDevice // // Resets the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::ResetDevice() { HRESULT hr = S_OK; #ifdef DX9 if (m_pDevice) { D3DPRESENT_PARAMETERS d3dpp = m_d3dpp; hr = m_pDevice->Reset(&d3dpp); if (FAILED(hr)) { DestroyDevice(); } } if (m_pDevice == NULL) { hr = CreateDevice(m_hwnd); if (FAILED(hr)) { goto done; } } if ((m_pSwapChain == NULL) && (m_format != D3DFMT_UNKNOWN)) { hr = CreateSwapChains(); if (FAILED(hr)) { goto done; } UpdateDestinationRect(); } #else if (m_pDevice) { DestroyDevice(); } if (m_pDevice == NULL) { hr = CreateDevice(m_hwnd); if (FAILED(hr)) { goto done; } } if ((m_pSwapChain == NULL) && (m_format != DXGI_FORMAT_UNKNOWN)) { hr = CreateSwapChains(); if (FAILED(hr)) { goto done; } UpdateDestinationRect(); } #endif done: return hr; } //------------------------------------------------------------------- // DestroyDevice // // Release all Direct3D resources. //------------------------------------------------------------------- void DrawDevice::DestroyDevice() { SafeRelease(&m_pSwapChain); SafeRelease(&m_pDevice); #ifdef DX9 SafeRelease(&m_pD3D); if ( m_pVertexBuffer ) SafeRelease(&m_pVertexBuffer); if ( m_pIndexBuffer ) SafeRelease(&m_pIndexBuffer); #endif } struct CUSTOMVERTEX {FLOAT X, Y, Z,RHW; DWORD COLOR;}; typedef struct CUSTOMVERTEX CustomVertex; #define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) #define TRSF( axe, data ) (translate##axe + (scale##axe * data)); HRESULT DrawDevice::RenderObjects() { HRESULT hr = S_OK; //const ARFloat* nMatrix; DWORD color = D3DCOLOR_ARGB(127, 0, 127, 0); int count = g_pAnalyse->markers.size(); if ( !count ) return hr; //D3DMATRIX world_matrix; //D3DMATRIX view_matrix; //D3DMATRIX projection_matrix; //nMatrix = g_pAnalyse->getModelViewMatrix(); // ////OpenGL // //m0 m4 m8 m12 // //m1 m5 m9 m13 // //m2 m6 m10 m14 // //m3 m7 m11 m15 // //WPF // //M11 M12 M13 M14 // //M21 M22 M23 M24 // //M31 M32 M33 M34 // //M41 M42 M43 M44 // //view_matrix._11 = nMatrix[0]; // view_matrix._12 = nMatrix[4]; // view_matrix._13 = nMatrix[8]; // view_matrix._14 = nMatrix[12]; // view_matrix._21 = nMatrix[1]; // view_matrix._22 = nMatrix[5]; // view_matrix._23 = nMatrix[9]; // view_matrix._24 = nMatrix[13]; // view_matrix._31 = nMatrix[2]; // view_matrix._32 = nMatrix[6]; // view_matrix._33 = nMatrix[10]; // view_matrix._34 = nMatrix[14]; // view_matrix._41 = nMatrix[3]; // view_matrix._42 = nMatrix[7]; // view_matrix._43 = nMatrix[11]; // view_matrix._44 = nMatrix[15]; //nMatrix = g_pAnalyse->getProjectionMatrix(); //projection_matrix._11 = nMatrix[0]; // projection_matrix._12 = nMatrix[4]; // projection_matrix._13 = nMatrix[8]; // projection_matrix._14 = nMatrix[12]; // projection_matrix._21 = nMatrix[1]; // projection_matrix._22 = nMatrix[5]; // projection_matrix._23 = nMatrix[9]; // projection_matrix._24 = nMatrix[13]; // projection_matrix._31 = nMatrix[2]; // projection_matrix._32 = nMatrix[6]; // projection_matrix._33 = nMatrix[10]; // projection_matrix._34 = nMatrix[14]; // projection_matrix._41 = nMatrix[3]; // projection_matrix._42 = nMatrix[7]; // projection_matrix._43 = nMatrix[11]; // projection_matrix._44 = nMatrix[15]; float scaleX = (float)(m_rcDest.right - m_rcDest.left ) / (float)m_width; float scaleY = (float)(m_rcDest.bottom - m_rcDest.top ) / (float)m_height; float translateX = m_rcDest.left; float translateY = m_rcDest.top; CustomVertex *quad = new CustomVertex[4*count]; short *indexes = new short[6*count]; int i =0; for( ARAnalyse::MarkersMap::iterator iter = g_pAnalyse->markers.begin(); iter != g_pAnalyse->markers.end(); iter++) { int index = i*4; ARToolKitPlus::ARMarkerInfo info = g_pAnalyse->getDetectedMarker(i++); quad[index].X = TRSF( X, info.vertex[0][0]) ; quad[index].Y = TRSF( Y, (m_height - info.vertex[0][1])); quad[index].Z = 0.0; quad[index].RHW = 1.0f; quad[index++].COLOR = color; quad[index].X = TRSF( X, info.vertex[1][0]); quad[index].Y = TRSF( Y, (m_height - info.vertex[1][1])); quad[index].Z = 0; quad[index].RHW = 1.0f; quad[index++].COLOR = color; quad[index].X = TRSF( X, info.vertex[2][0]); quad[index].Y = TRSF( Y, (m_height - info.vertex[2][1])); quad[index].Z = 0; quad[index].RHW = 1.0f; quad[index++].COLOR = color; quad[index].X = TRSF( X, info.vertex[3][0]); quad[index].Y = TRSF( Y, (m_height - info.vertex[3][1])); quad[index].Z = 0; quad[index].RHW = 1.0f; quad[index].COLOR = color; } int j = 0; for ( int i = 0; i < count; i++ ) { int index = i*4; indexes[j++] = index+0; indexes[j++] = index+2; indexes[j++] = index+1; indexes[j++] = index+3; indexes[j++] = index+2; indexes[j++] = index+0; } //if ( !m_pVertexBuffer ) //{ // // dim the vertex buffer to containt maximun markers //hr = m_pDevice->CreateVertexBuffer(4*4096 *sizeof(CustomVertex), D3DUSAGE_WRITEONLY, CUSTOMFVF, D3DPOOL_DEFAULT, &m_pVertexBuffer, NULL); //if(FAILED(hr)) goto done; //} //if ( !m_pIndexBuffer ) //{ // // dim the index buffer to containt maximun markers //hr = m_pDevice->CreateIndexBuffer(6*4096*sizeof(short), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL); //if(FAILED(hr)) goto done; //} //// copy vertex buffer //VOID* pVoid; //hr = m_pVertexBuffer->Lock(0, 0, (void**)&pVoid, 0); //if(FAILED(hr)) goto done; // //memcpy(pVoid, quad,4*count*sizeof(CustomVertex)); //m_pVertexBuffer->Unlock(); //// copy index buffer //hr = m_pIndexBuffer->Lock(0, 0, (void**)&pVoid, 0); //if(FAILED(hr)) goto done; // //memcpy(pVoid, indexes, 6*count*sizeof(short)); //m_pIndexBuffer->Unlock(); //memset( (void*) &world_matrix , 0, sizeof( world_matrix )); ////D3DMatrixIdentity( &world_matrix ); //world_matrix._11 = scaleX; //world_matrix._22 = scaleY; //world_matrix._33 = 1.0; //scale Z //world_matrix._41 = translateX; //world_matrix._42 = translateY; //world_matrix._43 = 0.0; // translate Z //world_matrix._44 = 1.0; //m_pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME); //m_pDevice->SetRenderState(D3DRS_LIGHTING, true); //m_pDevice->LightEnable( 0, TRUE ); m_pDevice->BeginScene(); //m_pDevice->SetTransform(D3DTS_WORLD, &world_matrix); //m_pDevice->SetTransform(D3DTS_VIEW, &view_matrix); //m_pDevice->SetTransform(D3DTS_PROJECTION, &projection_matrix); m_pDevice->SetFVF(CUSTOMFVF); //m_pDevice->SetIndices(m_pIndexBuffer); //m_pDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(CustomVertex)); //m_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4*count, 0, 2*count); //m_pDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, 4*count, 0, 2*count); m_pDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4*count, 2*count, indexes, D3DFMT_INDEX16,quad,sizeof(CustomVertex)); m_pDevice->EndScene(); //m_pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID); done: delete quad; delete indexes; return hr; } //------------------------------------------------------------------- // // Conversion functions // //------------------------------------------------------------------- __forceinline BYTE Clip(int clr) { return (BYTE)(clr < 0 ? 0 : ( clr > 255 ? 255 : clr )); } __forceinline RGBQUAD ConvertYCrCbToRGB( int y, int cr, int cb ) { RGBQUAD rgbq; int c = y - 16; int d = cb - 128; int e = cr - 128; rgbq.rgbRed = Clip(( 298 * c + 409 * e + 128) >> 8); rgbq.rgbGreen = Clip(( 298 * c - 100 * d - 208 * e + 128) >> 8); rgbq.rgbBlue = Clip(( 298 * c + 516 * d + 128) >> 8); return rgbq; } //------------------------------------------------------------------- // TransformImage_RGB24 // // RGB-24 to RGB-32 //------------------------------------------------------------------- void TransformImage_RGB24( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { for (DWORD y = 0; y < dwHeightInPixels; y++) { RGBTRIPLE *pSrcPel = (RGBTRIPLE*)pSrc; DWORD *pDestPel = (DWORD*)pDest; for (DWORD x = 0; x < dwWidthInPixels; x++) { #ifdef DX9 pDestPel[x] = D3DCOLOR_XRGB( pSrcPel[x].rgbtRed, pSrcPel[x].rgbtGreen, pSrcPel[x].rgbtBlue ); #else pDestPel[x] = pSrcPel[x].rgbtRed; #endif } pSrc += lSrcStride; pDest += lDestStride; } } //------------------------------------------------------------------- // TransformImage_RGB32 // // RGB-32 to RGB-32 // // Note: This function is needed to copy the image from system // memory to the Direct3D surface. //------------------------------------------------------------------- void TransformImage_RGB32( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { MFCopyImage(pDest, lDestStride, pSrc, lSrcStride, dwWidthInPixels * 4, dwHeightInPixels); } //------------------------------------------------------------------- // TransformImage_YUY2 // // YUY2 to RGB-32 //------------------------------------------------------------------- void TransformImage_YUY2( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { for (DWORD y = 0; y < dwHeightInPixels; y++) { RGBQUAD *pDestPel = (RGBQUAD*)pDest; WORD *pSrcPel = (WORD*)pSrc; for (DWORD x = 0; x < dwWidthInPixels; x += 2) { // Byte order is U0 Y0 V0 Y1 int y0 = (int)LOBYTE(pSrcPel[x]); int u0 = (int)HIBYTE(pSrcPel[x]); int y1 = (int)LOBYTE(pSrcPel[x + 1]); int v0 = (int)HIBYTE(pSrcPel[x + 1]); pDestPel[x] = ConvertYCrCbToRGB(y0, v0, u0); pDestPel[x + 1] = ConvertYCrCbToRGB(y1, v0, u0); } pSrc += lSrcStride; pDest += lDestStride; } } //------------------------------------------------------------------- // TransformImage_NV12 // // NV12 to RGB-32 //------------------------------------------------------------------- void TransformImage_NV12( BYTE* pDst, LONG dstStride, const BYTE* pSrc, LONG srcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { const BYTE* lpBitsY = pSrc; const BYTE* lpBitsCb = lpBitsY + (dwHeightInPixels * srcStride);; const BYTE* lpBitsCr = lpBitsCb + 1; for (UINT y = 0; y < dwHeightInPixels; y += 2) { const BYTE* lpLineY1 = lpBitsY; const BYTE* lpLineY2 = lpBitsY + srcStride; const BYTE* lpLineCr = lpBitsCr; const BYTE* lpLineCb = lpBitsCb; LPBYTE lpDibLine1 = pDst; LPBYTE lpDibLine2 = pDst + dstStride; for (UINT x = 0; x < dwWidthInPixels; x += 2) { int y0 = (int)lpLineY1[0]; int y1 = (int)lpLineY1[1]; int y2 = (int)lpLineY2[0]; int y3 = (int)lpLineY2[1]; int cb = (int)lpLineCb[0]; int cr = (int)lpLineCr[0]; RGBQUAD r = ConvertYCrCbToRGB(y0, cr, cb); lpDibLine1[0] = r.rgbBlue; lpDibLine1[1] = r.rgbGreen; lpDibLine1[2] = r.rgbRed; lpDibLine1[3] = 0; // Alpha r = ConvertYCrCbToRGB(y1, cr, cb); lpDibLine1[4] = r.rgbBlue; lpDibLine1[5] = r.rgbGreen; lpDibLine1[6] = r.rgbRed; lpDibLine1[7] = 0; // Alpha r = ConvertYCrCbToRGB(y2, cr, cb); lpDibLine2[0] = r.rgbBlue; lpDibLine2[1] = r.rgbGreen; lpDibLine2[2] = r.rgbRed; lpDibLine2[3] = 0; // Alpha r = ConvertYCrCbToRGB(y3, cr, cb); lpDibLine2[4] = r.rgbBlue; lpDibLine2[5] = r.rgbGreen; lpDibLine2[6] = r.rgbRed; lpDibLine2[7] = 0; // Alpha lpLineY1 += 2; lpLineY2 += 2; lpLineCr += 2; lpLineCb += 2; lpDibLine1 += 8; lpDibLine2 += 8; } pDst += (2 * dstStride); lpBitsY += (2 * srcStride); lpBitsCr += srcStride; lpBitsCb += srcStride; } } //------------------------------------------------------------------- // LetterBoxDstRect // // Takes a src rectangle and constructs the largest possible // destination rectangle within the specifed destination rectangle // such thatthe video maintains its current shape. // // This function assumes that pels are the same shape within both the // source and destination rectangles. // //------------------------------------------------------------------- RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst) { // figure out src/dest scale ratios int iSrcWidth = Width(rcSrc); int iSrcHeight = Height(rcSrc); int iDstWidth = Width(rcDst); int iDstHeight = Height(rcDst); int iDstLBWidth; int iDstLBHeight; if (MulDiv(iSrcWidth, iDstHeight, iSrcHeight) <= iDstWidth) { // Column letter boxing ("pillar box") iDstLBWidth = MulDiv(iDstHeight, iSrcWidth, iSrcHeight); iDstLBHeight = iDstHeight; } else { // Row letter boxing. iDstLBWidth = iDstWidth; iDstLBHeight = MulDiv(iDstWidth, iSrcHeight, iSrcWidth); } // Create a centered rectangle within the current destination rect RECT rc; LONG left = rcDst.left + ((iDstWidth - iDstLBWidth) / 2); LONG top = rcDst.top + ((iDstHeight - iDstLBHeight) / 2); SetRect(&rc, left, top, left + iDstLBWidth, top + iDstLBHeight); return rc; } //----------------------------------------------------------------------------- // CorrectAspectRatio // // Converts a rectangle from the source's pixel aspect ratio (PAR) to 1:1 PAR. // Returns the corrected rectangle. // // For example, a 720 x 486 rect with a PAR of 9:10, when converted to 1x1 PAR, // is stretched to 720 x 540. //----------------------------------------------------------------------------- RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR) { // Start with a rectangle the same size as src, but offset to the origin (0,0). RECT rc = {0, 0, src.right - src.left, src.bottom - src.top}; if ((srcPAR.Numerator != 1) || (srcPAR.Denominator != 1)) { // Correct for the source's PAR. if (srcPAR.Numerator > srcPAR.Denominator) { // The source has "wide" pixels, so stretch the width. rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator); } else if (srcPAR.Numerator < srcPAR.Denominator) { // The source has "tall" pixels, so stretch the height. rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator); } // else: PAR is 1:1, which is a no-op. } return rc; } //----------------------------------------------------------------------------- // GetDefaultStride // // Gets the default stride for a video frame, assuming no extra padding bytes. // //----------------------------------------------------------------------------- HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride) { LONG lStride = 0; // Try to get the default stride from the media type. HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride); if (FAILED(hr)) { // Attribute not set. Try to calculate the default stride. GUID subtype = GUID_NULL; UINT32 width = 0; UINT32 height = 0; // Get the subtype and the image size. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (SUCCEEDED(hr)) { hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height); } if (SUCCEEDED(hr)) { hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride); } // Set the attribute for later reference. if (SUCCEEDED(hr)) { (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride)); } } if (SUCCEEDED(hr)) { *plStride = lStride; } return hr; }