備註:本文主要針對DirectX 9.0版原本討論的。
在開始這篇文章以前,咱們先闡述一下一些名詞:DX、DDraw、DirectShow、D3D、DirectX、DirectDraw
等。html
首先咱們理一理他們之間的關係,這些關鍵詞統稱DirectX,簡稱DX,它有一下成員:git
DirectDraw
(簡稱DDraw
) 和Direct3D
(簡稱D3D
)技術。
DirectDraw
主要負責2D加速,以實現對顯卡內存和系統內存的直接操做;Direct3D
主要提供三維繪圖硬件接口,它是開發三維DirectX遊戲的基礎。DirectX
組件的API功能。DirectShow Filter
的簡化模型,提供更方便的流數據處理方案。連接DirectX和DirectShow介紹和區別
連接DirectShow和DirectX有什麼區別web
D3D顯示YUV方式有兩種:紋理(Texture)方式和表面(Surface)方式。而Texture方式又能夠包含使用Shader及不使用Shader方式。緩存
這部分代碼參考的前輩的項目,如今把鏈接發出來:D3D三層Texture紋理經像素着色器實現渲染YUV420P 第二版
直接上代碼:頭文件d3dUtility.h
網絡
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.h // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __d3dUtilityH__ #define __d3dUtilityH__ #include <d3dx9.h> #include <string> #include <limits> #include <Windows.h> namespace d3d { // // Init // bool InitD3D( HINSTANCE hInstance, // [in] Application instance. int width, int height, // [in] Backbuffer dimensions. bool windowed, // [in] Windowed (true)or full screen (false). D3DDEVTYPE deviceType, // [in] HAL or REF IDirect3DDevice9** device);// [out]The created device. int EnterMsgLoop( bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // // Cleanup // template<class T> void Release(T t) { if( t ) { t->Release(); t = 0; } } template<class T> void Delete(T t) { if( t ) { delete t; t = 0; } } // // Colors // const D3DXCOLOR WHITE( D3DCOLOR_XRGB(255, 255, 255) ); const D3DXCOLOR BLACK( D3DCOLOR_XRGB( 0, 0, 0) ); const D3DXCOLOR RED( D3DCOLOR_XRGB(255, 0, 0) ); const D3DXCOLOR GREEN( D3DCOLOR_XRGB( 0, 255, 0) ); const D3DXCOLOR BLUE( D3DCOLOR_XRGB( 0, 0, 255) ); const D3DXCOLOR YELLOW( D3DCOLOR_XRGB(255, 255, 0) ); const D3DXCOLOR CYAN( D3DCOLOR_XRGB( 0, 255, 255) ); const D3DXCOLOR MAGENTA( D3DCOLOR_XRGB(255, 0, 255) ); // // Lights // D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color); D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color); D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color); // // Materials // D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p); const D3DMATERIAL9 WHITE_MTRL = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f); const D3DMATERIAL9 RED_MTRL = InitMtrl(RED, RED, RED, BLACK, 2.0f); const D3DMATERIAL9 GREEN_MTRL = InitMtrl(GREEN, GREEN, GREEN, BLACK, 2.0f); const D3DMATERIAL9 BLUE_MTRL = InitMtrl(BLUE, BLUE, BLUE, BLACK, 2.0f); const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 2.0f); // // Bounding Objects // struct BoundingBox { BoundingBox(); bool isPointInside(D3DXVECTOR3& p); D3DXVECTOR3 _min; D3DXVECTOR3 _max; }; struct BoundingSphere { BoundingSphere(); D3DXVECTOR3 _center; float _radius; }; // // Constants // const float INFINITY0 = FLT_MAX; const float EPSILON = 0.001f; // // Drawing // // Function references "desert.bmp" internally. This file must // be in the working directory. bool DrawBasicScene( IDirect3DDevice9* device,// Pass in 0 for cleanup. float scale); // uniform scale // // Vertex Structures // struct Vertex { Vertex(){} Vertex(float x, float y, float z, float nx, float ny, float nz, float u, float v) { _x = x; _y = y; _z = z; _nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } float _x, _y, _z; float _nx, _ny, _nz; float _u, _v; static const DWORD FVF; }; // // Randomness // // Desc: Return random float in [lowBound, highBound] interval. float GetRandomFloat(float lowBound, float highBound); // Desc: Returns a random vector in the bounds specified by min and max. void GetRandomVector( D3DXVECTOR3* out, D3DXVECTOR3* min, D3DXVECTOR3* max); // // Conversion // DWORD FtoDw(float f); } #endif // __d3dUtilityH__
cpp文件:d3dUtility.cpp
app
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUtility.h" // vertex formats const DWORD d3d::Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; bool d3d::InitD3D( HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device) { // // Create the main application window. // WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)d3d::WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "Direct3D9App"; if( !RegisterClass(&wc) ) { ::MessageBox(0, "RegisterClass() - FAILED", 0, 0); return false; } HWND hwnd = 0; hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App", WS_EX_TOPMOST, 0, 0, 1024, 768, 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); if( !hwnd ) { ::MessageBox(0, "CreateWindow() - FAILED", 0, 0); return false; } ::ShowWindow(hwnd, SW_SHOW); ::UpdateWindow(hwnd); // // Init D3D: // HRESULT hr = 0; // Step 1: Create the IDirect3D9 object. IDirect3D9* d3d9 = 0; d3d9 = Direct3DCreate9(D3D_SDK_VERSION); if( !d3d9 ) { ::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0); return false; } // Step 2: Check for hardware vp. D3DCAPS9 caps; d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps); int vp = 0; if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; // Step 3: Fill out the D3DPRESENT_PARAMETERS structure. D3DDISPLAYMODE d3ddm; UINT adapter = D3DADAPTER_DEFAULT; IDirect3D9_GetAdapterDisplayMode(d3d9, adapter, &d3ddm); // 默認不使用多采樣 D3DMULTISAMPLE_TYPE multiType = D3DMULTISAMPLE_NONE; if(d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, !windowed, D3DMULTISAMPLE_4_SAMPLES, NULL) == D3D_OK) { // 保存多采樣類型 multiType = D3DMULTISAMPLE_4_SAMPLES; } D3DPRESENT_PARAMETERS d3dpp; d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; d3dpp.BackBufferCount = 1; d3dpp.MultiSampleType = multiType; d3dpp.MultiSampleQuality = 0; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hwnd; d3dpp.Windowed = windowed; d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; d3dpp.Flags = 0; d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Step 4: Create the device. hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // primary adapter deviceType, // device type hwnd, // window associated with device vp, // vertex processing &d3dpp, // present parameters device); // return created device if( FAILED(hr) ) { // try again using a 16-bit depth buffer d3dpp.AutoDepthStencilFormat = D3DFMT_D16; hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device); if( FAILED(hr) ) { d3d9->Release(); // done with d3d9 object ::MessageBox(0, "CreateDevice() - FAILED", 0, 0); return false; } } d3d9->Release(); // done with d3d9 object return true; } int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) ) { MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); //static float lastTime = (float)timeGetTime(); DWORD lastTime = GetTickCount(); while(msg.message != WM_QUIT) { if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { //float currTime = (float)timeGetTime(); DWORD currTime = GetTickCount(); float timeDelta = (currTime - lastTime)*0.001f; ptr_display(timeDelta); lastTime = currTime; } } return msg.wParam; } D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Direction = *direction; return light; } D3DLIGHT9 d3d::InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_POINT; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Position = *position; light.Range = 1000.0f; light.Falloff = 1.0f; light.Attenuation0 = 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; return light; } D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_SPOT; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Position = *position; light.Direction = *direction; light.Range = 1000.0f; light.Falloff = 1.0f; light.Attenuation0 = 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; light.Theta = 0.5f; light.Phi = 0.7f; return light; } D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p) { D3DMATERIAL9 mtrl; mtrl.Ambient = a; mtrl.Diffuse = d; mtrl.Specular = s; mtrl.Emissive = e; mtrl.Power = p; return mtrl; } d3d::BoundingBox::BoundingBox() { // infinite small _min.x = d3d::INFINITY0; _min.y = d3d::INFINITY0; _min.z = d3d::INFINITY0; _max.x = -d3d::INFINITY0; _max.y = -d3d::INFINITY0; _max.z = -d3d::INFINITY0; } bool d3d::BoundingBox::isPointInside(D3DXVECTOR3& p) { if( p.x >= _min.x && p.y >= _min.y && p.z >= _min.z && p.x <= _max.x && p.y <= _max.y && p.z <= _max.z ) { return true; } else { return false; } } d3d::BoundingSphere::BoundingSphere() { _radius = 0.0f; } bool d3d::DrawBasicScene(IDirect3DDevice9* device, float scale) { static IDirect3DVertexBuffer9* floor = 0; static IDirect3DTexture9* tex = 0; static ID3DXMesh* pillar = 0; HRESULT hr = 0; if( device == 0 ) { if( floor && tex && pillar ) { // they already exist, destroy them d3d::Release<IDirect3DVertexBuffer9*>(floor); d3d::Release<IDirect3DTexture9*>(tex); d3d::Release<ID3DXMesh*>(pillar); } } else if( !floor && !tex && !pillar ) { // they don't exist, create them device->CreateVertexBuffer( 6 * sizeof(d3d::Vertex), 0, d3d::Vertex::FVF, D3DPOOL_MANAGED, &floor, 0); Vertex* v = 0; floor->Lock(0, 0, (void**)&v, 0); v[0] = Vertex(-20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f); v[1] = Vertex(-20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); v[2] = Vertex( 20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[3] = Vertex(-20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f); v[4] = Vertex( 20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[5] = Vertex( 20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f); floor->Unlock(); D3DXCreateCylinder(device, 0.5f, 0.5f, 5.0f, 20, 20, &pillar, 0); D3DXCreateTextureFromFile( device, "desert.bmp", &tex); } else { // // Pre-Render Setup // device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); D3DXVECTOR3 dir(0.707f, -0.707f, 0.707f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); device->SetLight(0, &light); device->LightEnable(0, true); device->SetRenderState(D3DRS_NORMALIZENORMALS, true); device->SetRenderState(D3DRS_SPECULARENABLE, true); // // Render // D3DXMATRIX T, R, P, S; D3DXMatrixScaling(&S, scale, scale, scale); // used to rotate cylinders to be parallel with world's y-axis D3DXMatrixRotationX(&R, -D3DX_PI * 0.5f); // draw floor D3DXMatrixIdentity(&T); T = T * S; device->SetTransform(D3DTS_WORLD, &T); device->SetMaterial(&d3d::WHITE_MTRL); device->SetTexture(0, tex); device->SetStreamSource(0, floor, 0, sizeof(Vertex)); device->SetFVF(Vertex::FVF); device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); // draw pillars device->SetMaterial(&d3d::BLUE_MTRL); device->SetTexture(0, 0); for(int i = 0; i < 5; i++) { D3DXMatrixTranslation(&T, -5.0f, 0.0f, -15.0f + (i * 7.5f)); P = R * T * S; device->SetTransform(D3DTS_WORLD, &P); pillar->DrawSubset(0); D3DXMatrixTranslation(&T, 5.0f, 0.0f, -15.0f + (i * 7.5f)); P = R * T * S; device->SetTransform(D3DTS_WORLD, &P); pillar->DrawSubset(0); } } return true; } float d3d::GetRandomFloat(float lowBound, float highBound) { if( lowBound >= highBound ) // bad input return lowBound; // get random float in [0, 1] interval float f = (rand() % 10000) * 0.0001f; // return float in [lowBound, highBound] interval. return (f * (highBound - lowBound)) + lowBound; } void d3d::GetRandomVector( D3DXVECTOR3* out, D3DXVECTOR3* min, D3DXVECTOR3* max) { out->x = GetRandomFloat(min->x, max->x); out->y = GetRandomFloat(min->y, max->y); out->z = GetRandomFloat(min->z, max->z); } DWORD d3d::FtoDw(float f) { return *((DWORD*)&f); }
調用:dom
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: ps_multitex.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Deomstrates multi-texturing using a pixel shader. You will have // to switch to the REF device to run this sample if your hardware // doesn't support pixel shaders. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUtility.h" // // Globals // IDirect3DDevice9* Device = 0; const int Width = 320; const int Height = 180; IDirect3DPixelShader9* MultiTexPS = 0; ID3DXConstantTable* MultiTexCT = 0; IDirect3DVertexBuffer9* QuadVB = 0; IDirect3DTexture9* YTex = 0; IDirect3DTexture9* UTex = 0; IDirect3DTexture9* VTex = 0; D3DXHANDLE YTexHandle = 0; D3DXHANDLE UTexHandle = 0; D3DXHANDLE VTexHandle = 0; D3DXCONSTANT_DESC YTexDesc; D3DXCONSTANT_DESC UTexDesc; D3DXCONSTANT_DESC VTexDesc; //YUV file FILE *infile = NULL; unsigned char buf[Width*Height*3/2]; unsigned char *plane[3]; // // Structs // struct MultiTexVertex { MultiTexVertex(float x, float y, float z, float u0, float v0, float u1, float v1, float u2, float v2) { _x = x; _y = y; _z = z; _u0 = u0; _v0 = v0; _u1 = u1; _v1 = v1; _u2 = u2, _v2 = v2; } float _x, _y, _z; float _u0, _v0; float _u1, _v1; float _u2, _v2; static const DWORD FVF; }; const DWORD MultiTexVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX3; // // Framework functions // bool Setup() { HRESULT hr = 0; // // Create geometry. // Device->CreateVertexBuffer( 6 * sizeof(MultiTexVertex), D3DUSAGE_WRITEONLY, MultiTexVertex::FVF, D3DPOOL_MANAGED, &QuadVB, 0); MultiTexVertex* v = 0; QuadVB->Lock(0, 0, (void**)&v, 0); v[0] = MultiTexVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); v[1] = MultiTexVertex(-10.0f, 10.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); v[2] = MultiTexVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[3] = MultiTexVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); v[4] = MultiTexVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f); v[5] = MultiTexVertex( 10.0f, -10.0f, 5.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); QuadVB->Unlock(); // // Compile shader // ID3DXBuffer* shader = 0; ID3DXBuffer* errorBuffer = 0; hr = D3DXCompileShaderFromFile( "ps_multitex.txt", 0, 0, "Main", // entry point function name "ps_2_0", D3DXSHADER_DEBUG | D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, &shader, &errorBuffer, &MultiTexCT); // output any error messages if( errorBuffer ) { ::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0); d3d::Release<ID3DXBuffer*>(errorBuffer); } if(FAILED(hr)) { ::MessageBox(0, "D3DXCompileShaderFromFile() - FAILED", 0, 0); return false; } // // Create Pixel Shader // hr = Device->CreatePixelShader( (DWORD*)shader->GetBufferPointer(), &MultiTexPS); if(FAILED(hr)) { ::MessageBox(0, "CreateVertexShader - FAILED", 0, 0); return false; } d3d::Release<ID3DXBuffer*>(shader); // // Create textures. // Device->CreateTexture ( Width, Height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &YTex, NULL ) ; Device->CreateTexture ( Width / 2, Height / 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &UTex, NULL ) ; Device->CreateTexture ( Width / 2, Height / 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &VTex, NULL ) ; if((infile=fopen("test_yuv420p_320x180.yuv", "rb"))==NULL){ printf("cannot open this file\n"); return false; } // // Set Projection Matrix // D3DXMATRIX P; D3DXMatrixPerspectiveFovLH( &P, D3DX_PI * 0.25f, (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &P); // // Disable lighting. // Device->SetRenderState(D3DRS_LIGHTING, false); // // Get Handles // YTexHandle = MultiTexCT->GetConstantByName(0, "YTex"); UTexHandle = MultiTexCT->GetConstantByName(0, "UTex"); VTexHandle = MultiTexCT->GetConstantByName(0, "VTex"); // // Set constant descriptions: // UINT count; MultiTexCT->GetConstantDesc(YTexHandle, &YTexDesc, &count); MultiTexCT->GetConstantDesc(UTexHandle, &UTexDesc, &count); MultiTexCT->GetConstantDesc(VTexHandle, &VTexDesc, &count); MultiTexCT->SetDefaults(Device); return true; } void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(QuadVB); d3d::Release<IDirect3DTexture9*>(YTex); d3d::Release<IDirect3DTexture9*>(UTex); d3d::Release<IDirect3DTexture9*>(VTex); d3d::Release<IDirect3DPixelShader9*>(MultiTexPS); d3d::Release<ID3DXConstantTable*>(MultiTexCT); } bool Display(float timeDelta) { if (fread(buf, 1, Width*Height*3/2, infile) != Width*Height*3/2){ // Loop fseek(infile, 0, SEEK_SET); fread(buf, 1, Width*Height*3/2, infile); } if( buf != NULL && Device ) { // // Update the scene: Allow user to rotate around scene. // static float angle = (3.0f * D3DX_PI) / 2.0f; static float radius = 20.0f; if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f ) angle -= 0.5f * timeDelta; if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f ) angle += 0.5f * timeDelta; if( ::GetAsyncKeyState(VK_UP) & 0x8000f ) radius -= 2.0f * timeDelta; if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f ) radius += 2.0f * timeDelta; D3DXVECTOR3 position( cosf(angle) * radius, 0.0f, sinf(angle) * radius ); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // // Render // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); plane[0] = buf; plane[1] = plane[0] + Width*Height; plane[2] = plane[1] + Width*Height/4; D3DLOCKED_RECT d3d_rect; byte *pSrc = buf; //Locks a rectangle on a texture resource. //And then we can manipulate pixel data in it. LRESULT lRet = YTex->LockRect(0, &d3d_rect, 0, 0); if (FAILED(lRet)){ return false; } // Copy pixel data to texture byte *pDest = (byte *)d3d_rect.pBits; int stride = d3d_rect.Pitch; for(int i = 0;i < Height;i ++){ memcpy(pDest + i * stride,plane[0] + i * Width, Width); } YTex->UnlockRect(0); D3DLOCKED_RECT d3d_rect1; lRet = UTex->LockRect(0, &d3d_rect1, 0, 0); if (FAILED(lRet)){ return false; } // Copy pixel data to texture byte *pDest1 = (byte *)d3d_rect1.pBits; int stride1 = d3d_rect1.Pitch; for(int i = 0;i < Height/2;i ++){ memcpy(pDest1 + i * stride1,plane[1] + i * Width / 2, Width / 2); } UTex->UnlockRect(0); D3DLOCKED_RECT d3d_rect2; lRet = VTex->LockRect(0, &d3d_rect2, 0, 0); if (FAILED(lRet)){ return false; } // Copy pixel data to texture byte *pDest2 = (byte *)d3d_rect2.pBits; int stride2 = d3d_rect2.Pitch; for(int i = 0;i < Height/2;i ++){ memcpy(pDest2 + i * stride2,plane[2] + i * Width / 2, Width / 2); } VTex->UnlockRect(0); Device->BeginScene(); Device->SetPixelShader(MultiTexPS); Device->SetFVF(MultiTexVertex::FVF); Device->SetStreamSource(0, QuadVB, 0, sizeof(MultiTexVertex)); // Y tex Device->SetTexture( YTexDesc.RegisterIndex, YTex); Device->SetSamplerState(YTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(YTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(YTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(YTexDesc.RegisterIndex, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); Device->SetSamplerState(YTexDesc.RegisterIndex, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); // U tex Device->SetTexture( UTexDesc.RegisterIndex, UTex); Device->SetSamplerState(UTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(UTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(UTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(UTexDesc.RegisterIndex, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); Device->SetSamplerState(UTexDesc.RegisterIndex, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); // string tex Device->SetTexture( VTexDesc.RegisterIndex, VTex); Device->SetSamplerState(VTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(VTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(VTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(VTexDesc.RegisterIndex, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); Device->SetSamplerState(VTexDesc.RegisterIndex, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }
這裏我提示一下:在運行項目時,D3DXCompileShaderFromFile
會返回失敗,甚至會崩潰報錯,這裏你們注意一下它的第一個參數ps_multitex.txt
的目錄,你能夠先把它寫成絕對目錄試試。
這裏還有一個問題是:顯示沒有拉伸,我沒找到拉伸的方式。ide
這裏代碼參考雷神的代碼:
最簡單的視音頻播放示例4:Direct3D播放RGB(經過Texture)svg
/** * 最簡單的Direct3D播放視頻的例子(Direct3D播放RGB)[Texture] * Simplest Video Play Direct3D (Direct3D play RGB)[Texture] * * 雷霄驊 Lei Xiaohua * leixiaohua1020@126.com * 中國傳媒大學/數字電視技術 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程序使用Direct3D播放RGB/YUV視頻像素數據。使用D3D中的Texture渲染數據。 * 相對於使用Surface渲染視頻數據來講,使用Texture渲染視頻數據功能更加靈活, * 可是學習起來也會相對複雜一些。 * * 函數調用步驟以下: * * [初始化] * Direct3DCreate9():得到IDirect3D9 * IDirect3D9->CreateDevice():經過IDirect3D9建立Device(設備) * IDirect3DDevice9->CreateTexture():經過Device建立一個Texture(紋理)。 * IDirect3DDevice9->CreateVertexBuffer():經過Device建立一個VertexBuffer(頂點緩存)。 * IDirect3DVertexBuffer9->Lock():鎖定頂點緩存。 * memcpy():填充頂點緩存。 * IDirect3DVertexBuffer9->Unlock():解鎖頂點緩存。 * * [循環渲染數據] * IDirect3DTexture9->LockRect():鎖定紋理。 * memcpy():填充紋理數據 * IDirect3DTexture9->UnLockRect():解鎖紋理。 * IDirect3DDevice9->BeginScene():開始繪製。 * IDirect3DDevice9->SetTexture():設置當前要渲染的紋理。 * IDirect3DDevice9->SetStreamSource():綁定VertexBuffer。 * IDirect3DDevice9->SetFVF():設置Vertex格式。 * IDirect3DDevice9->DrawPrimitive():渲染。 * IDirect3DDevice9->EndScene():結束繪製。 * IDirect3DDevice9->Present():顯示出來。 * * This software plays RGB/YUV raw video data using Direct3D. * It uses Texture in D3D to render the pixel data. * Compared to another method (use Surface), it's more flexible * but a little difficult. * * The process is shown as follows: * * [Init] * Direct3DCreate9():Get IDirect3D9. * IDirect3D9->CreateDevice():Create a Device. * IDirect3DDevice9->CreateTexture():Create a Texture. * IDirect3DDevice9->CreateVertexBuffer():Create a VertexBuffer. * IDirect3DVertexBuffer9->Lock():Lock VertexBuffer. * memcpy():Fill VertexBuffer. * IDirect3DVertexBuffer9->Unlock():UnLock VertexBuffer. * * [Loop to Render data] * IDirect3DTexture9->LockRect():Lock Texture. * memcpy():Fill pixel data... * IDirect3DTexture9->UnLockRect():UnLock Texture. * IDirect3DDevice9->BeginScene():Begin to draw. * IDirect3DDevice9->SetTexture():Set current Texture. * IDirect3DDevice9->SetStreamSource():Bind VertexBuffer. * IDirect3DDevice9->SetFVF():Set Vertex Format. * IDirect3DDevice9->DrawPrimitive():Render. * IDirect3DDevice9->EndScene():End drawing. * IDirect3DDevice9->Present():Show on the screen. */ #include <stdio.h> #include <tchar.h> #include <d3d9.h> //Flexible Vertex Format, FVF typedef struct { FLOAT x,y,z; // vertex untransformed position FLOAT rhw; // eye distance D3DCOLOR diffuse; // diffuse color FLOAT tu, tv; // texture relative coordinates } CUSTOMVERTEX; CRITICAL_SECTION m_critial; HWND m_hVideoWnd; // 視頻窗口 IDirect3D9 *m_pDirect3D9= NULL; IDirect3DDevice9 *m_pDirect3DDevice= NULL; IDirect3DTexture9 *m_pDirect3DTexture= NULL; IDirect3DVertexBuffer9 *m_pDirect3DVertexBuffer= NULL; // Custom flexible vertex format (FVF), which describes custom vertex structure #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) //Select one of the Texture mode (Set '1'): #define TEXTURE_DEFAULT 1 //Rotate the texture #define TEXTURE_ROTATE 0 //Show half of the Texture #define TEXTURE_HALF 0 //Width, Height const int screen_w=500,screen_h=500; const int pixel_w=320,pixel_h=180; FILE *fp=NULL; //Bit per Pixel const int bpp=32; unsigned char buffer[pixel_w*pixel_h*bpp/8]; void Cleanup() { EnterCriticalSection(&m_critial); if(m_pDirect3DVertexBuffer) m_pDirect3DVertexBuffer->Release(); if(m_pDirect3DTexture) m_pDirect3DTexture->Release(); if(m_pDirect3DDevice) m_pDirect3DDevice->Release(); if(m_pDirect3D9) m_pDirect3D9->Release(); LeaveCriticalSection(&m_critial); } int InitD3D( HWND hwnd, unsigned long lWidth, unsigned long lHeight ) { HRESULT lRet; InitializeCriticalSection(&m_critial); Cleanup(); EnterCriticalSection(&m_critial); // Create IDirect3D m_pDirect3D9 = Direct3DCreate9( D3D_SDK_VERSION ); if ( m_pDirect3D9 == NULL ){ LeaveCriticalSection(&m_critial); return -1; } if ( lWidth == 0 || lHeight == 0 ){ RECT rt; GetClientRect( hwnd, &rt ); lWidth = rt.right-rt.left; lHeight = rt.bottom-rt.top; } /* //Get Some Info //Retrieves device-specific information about a device. D3DCAPS9 d3dcaps; lRet=m_pDirect3D9->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&d3dcaps); int hal_vp = 0; if( d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ){ //save in hal_vp the fact that hardware vertex processing is supported. hal_vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; } // get D3DDISPLAYMODE D3DDISPLAYMODE d3dDisplayMode; lRet = m_pDirect3D9->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3dDisplayMode ); if ( FAILED(lRet) ){ LeaveCriticalSection(&m_critial); return -1; } */ //D3DPRESENT_PARAMETERS Describes the presentation parameters. D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.BackBufferWidth = lWidth; d3dpp.BackBufferHeight = lHeight; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; //d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; d3dpp.BackBufferCount = 1; d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; d3dpp.SwapEffect = D3DSWAPEFFECT_COPY; d3dpp.hDeviceWindow = hwnd; d3dpp.Windowed = TRUE; d3dpp.EnableAutoDepthStencil = FALSE; d3dpp.Flags = D3DPRESENTFLAG_VIDEO; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; m_hVideoWnd = hwnd; //Creates a device to represent the display adapter. //Adapter: Ordinal number that denotes the display adapter. D3DADAPTER_DEFAULT is always the primary display //D3DDEVTYPE: D3DDEVTYPE_HAL((Hardware Accelerator), or D3DDEVTYPE_SW(SoftWare) //BehaviorFlags:D3DCREATE_SOFTWARE_VERTEXPROCESSING, or D3DCREATE_HARDWARE_VERTEXPROCESSING lRet = m_pDirect3D9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, &d3dpp, &m_pDirect3DDevice ); /* //Set some property //SetSamplerState() // Texture coordinates outside the range [0.0, 1.0] are set // to the texture color at 0.0 or 1.0, respectively. IDirect3DDevice9_SetSamplerState(m_pDirect3DDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); IDirect3DDevice9_SetSamplerState(m_pDirect3DDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); // Set linear filtering quality IDirect3DDevice9_SetSamplerState(m_pDirect3DDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); IDirect3DDevice9_SetSamplerState(m_pDirect3DDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); //SetRenderState() //set maximum ambient light IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,0)); // Turn off culling IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_CULLMODE, D3DCULL_NONE); // Turn off the zbuffer IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_ZENABLE, D3DZB_FALSE); // Turn off lights IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_LIGHTING, FALSE); // Enable dithering IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_DITHERENABLE, TRUE); // disable stencil IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_STENCILENABLE, FALSE); // manage blending IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_ALPHABLENDENABLE, TRUE); IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_ALPHATESTENABLE,TRUE); IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_ALPHAREF, 0x10); IDirect3DDevice9_SetRenderState(m_pDirect3DDevice, D3DRS_ALPHAFUNC,D3DCMP_GREATER); // Set texture states IDirect3DDevice9_SetTextureStageState(m_pDirect3DDevice, 0, D3DTSS_COLOROP,D3DTOP_MODULATE); IDirect3DDevice9_SetTextureStageState(m_pDirect3DDevice, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(m_pDirect3DDevice, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE); // turn off alpha operation IDirect3DDevice9_SetTextureStageState(m_pDirect3DDevice, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); */ //Creates a texture resource. //Usage: //D3DUSAGE_SOFTWAREPROCESSING: If this flag is used, vertex processing is done in software. // If this flag is not used, vertex processing is done in hardware. //D3DPool: //D3D3POOL_DEFAULT: Resources are placed in the hardware memory (Such as video memory) //D3D3POOL_MANAGED: Resources are placed automatically to device-accessible memory as needed. //D3DPOOL_SYSTEMMEM: Resources are placed in system memory. lRet = m_pDirect3DDevice->CreateTexture(lWidth, lHeight, 1, D3DUSAGE_SOFTWAREPROCESSING, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &m_pDirect3DTexture, NULL ); if ( FAILED(lRet) ){ LeaveCriticalSection(&m_critial); return -1; } // Create Vertex Buffer lRet = m_pDirect3DDevice->CreateVertexBuffer( 4 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &m_pDirect3DVertexBuffer, NULL ); if ( FAILED(lRet) ){ LeaveCriticalSection(&m_critial); return -1; } /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */ #if TEXTURE_HALF CUSTOMVERTEX vertices[] ={ {-0.5f, -0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,0.0f}, {lWidth-0.5f, -0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.5f,0.0f}, {lWidth - 0.5f, lHeight-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.5f,1.0f}, {-0.5f, lHeight-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,1.0f} }; #elif TEXTURE_ROTATE //Rotate Texture? CUSTOMVERTEX vertices[] ={ {lWidth/4-0.5f, -0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,0.0f}, {lWidth-0.5f, lHeight/4-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),1.0f,0.0f}, {lWidth*3/4-0.5f, lHeight-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),1.0f,1.0f}, {-0.5f, lHeight*3/4-0.5f,0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,1.0f} }; #else CUSTOMVERTEX vertices[] ={ {-0.5f, -0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,0.0f}, {lWidth-0.5f, -0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),1.0f,0.0f}, {lWidth - 0.5f, lHeight-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),1.0f,1.0f}, {-0.5f, lHeight-0.5f, 0.0f, 1.0f,D3DCOLOR_ARGB(255, 255, 255, 255),0.0f,1.0f} }; #endif // Fill Vertex Buffer CUSTOMVERTEX *pVertex; lRet = m_pDirect3DVertexBuffer->Lock( 0, 4 * sizeof(CUSTOMVERTEX), (void**)&pVertex, 0 ); if ( FAILED(lRet) ){ LeaveCriticalSection(&m_critial); return -1; } memcpy(pVertex, vertices, sizeof(vertices)); m_pDirect3DVertexBuffer->Unlock(); LeaveCriticalSection(&m_critial); return 0; } bool Render() { LRESULT lRet; //Read Data //RGB if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){ // Loop fseek(fp, 0, SEEK_SET); fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp); } if(buffer == NULL || m_pDirect3DDevice == NULL) return false; //Clears one or more surfaces lRet = m_pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0); D3DLOCKED_RECT d3d_rect; //Locks a rectangle on a texture resource. //And then we can manipulate pixel data in it. lRet = m_pDirect3DTexture->LockRect( 0, &d3d_rect, 0, 0 ); if ( FAILED(lRet) ){ return false; } // Copy pixel data to texture byte *pSrc = buffer; byte *pDest = (byte *)d3d_rect.pBits; int stride = d3d_rect.Pitch; unsigned long i = 0; int pixel_w_size=pixel_w*bpp/8; for(unsigned long i=0; i< pixel_h; i++){ memcpy( pDest, pSrc, pixel_w_size ); pDest += stride; pSrc += pixel_w_size; } m_pDirect3DTexture->UnlockRect( 0 ); //Begin the scene if ( FAILED(m_pDirect3DDevice->BeginScene()) ){ return false; } lRet = m_pDirect3DDevice->SetTexture( 0, m_pDirect3DTexture ); //Binds a vertex buffer to a device data stream. m_pDirect3DDevice->SetStreamSource( 0, m_pDirect3DVertexBuffer, 0, sizeof(CUSTOMVERTEX) ); //Sets the current vertex stream declaration. lRet = m_pDirect3DDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); //Renders a sequence of nonindexed, geometric primitives of the //specified type from the current set of data input streams. m_pDirect3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 ); m_pDirect3DDevice->EndScene(); //Presents the contents of the next buffer in the sequence of back //buffers owned by the device. m_pDirect3DDevice->Present( NULL, NULL, NULL, NULL ); return true; } LRESULT WINAPI MyWndProc(HWND hwnd, UINT msg, WPARAM wparma, LPARAM lparam) { switch(msg){ case WM_DESTROY: Cleanup(); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wparma, lparam); } int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd ) { WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpfnWndProc = (WNDPROC)MyWndProc; wc.lpszClassName = L"D3D"; wc.style = CS_HREDRAW | CS_VREDRAW; RegisterClassEx(&wc); HWND hwnd = NULL; hwnd = CreateWindow(L"D3D", L"Simplest Video Play Direct3D (Texture)", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, NULL); if (hwnd==NULL){ return -1; } if(InitD3D( hwnd, pixel_w, pixel_h)==E_FAIL){ return -1; } ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); fp=fopen("../test_bgra_320x180.rgb","rb+"); if(fp==NULL){ printf("Cannot open this file.\n"); return -1; } MSG msg; ZeroMemory(&msg, sizeof(msg)); while (msg.message != WM_QUIT){ //PeekMessage, not GetMessage if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ TranslateMessage(&msg); DispatchMessage(&msg); } else{ Sleep(40); Render(); } } UnregisterClass(L"D3D", hInstance); return 0; }
首先咱們看看網上的方式:參考連接使用D3D渲染YUV_RGB
這裏就不貼代碼了,這裏主要有一個問題就是,在播放窗口變大後,圖片拉伸是模糊的,沒有按照分辨率去拉伸,我下面貼出個人代碼:頭文件d3dDispaly.h
函數
#pragma once #include <stdio.h> #include <tchar.h> #include <d3d9.h> class d3dDispaly{ public: d3dDispaly(); ~d3dDispaly(); public: bool init(HWND hwnd); void uninit(); bool inputYUVData(LPBYTE pBuffer, long nwidth, long nheight); private: bool __setVideoSize(long lWidth, long lHeight); void __drawImage(); private: HWND m_hwnd; int m_nImgWidth; int m_nImgHeight; IDirect3D9* m_pD3D; IDirect3DDevice9* m_pd3dDevice; IDirect3DSurface9* m_pd3dSurface; IDirect3DSurface9* m_pBackBuffer; RECT m_rtViewport; };
cpp文件:d3dDispaly.cpp
//#include "stdafx.h" #include "d3dDispaly.h" d3dDispaly::d3dDispaly() : m_nImgWidth(0), m_nImgHeight(0), m_pD3D(NULL), m_pd3dDevice(NULL), m_pd3dSurface(NULL), m_hwnd(NULL), m_pBackBuffer(NULL) { } d3dDispaly::~d3dDispaly() { } bool d3dDispaly::init(HWND hwnd) { m_hwnd = hwnd; m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (m_pD3D == NULL) { OutputDebugStringA("D3D****************Direct3DCreate9 Fail*******\n"); return false; } D3DDISPLAYMODE d3dDisplayMode; m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3dDisplayMode); D3DCAPS9 d3dcaps; m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps); int hal_vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; if (d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) hal_vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3dDisplayMode.Format;//D3DFMT_UNKNOWN; d3dpp.BackBufferWidth = d3dDisplayMode.Width; d3dpp.BackBufferHeight = d3dDisplayMode.Height; d3dpp.Flags = D3DPRESENTFLAG_VIDEO; d3dpp.hDeviceWindow = m_hwnd; HRESULT result = m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hwnd, hal_vp, &d3dpp, &m_pd3dDevice); if (FAILED(result)) { D3DERR_OUTOFVIDEOMEMORY; char buf[100] = { 0 }; sprintf_s(buf, 100, "D3D****************CreateDevice-1 Fail[%d]*******\n", result); OutputDebugStringA(buf); if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hwnd, hal_vp, &d3dpp, &m_pd3dDevice))) { OutputDebugStringA("D3D****************CreateDevice-2 Fail*******\n"); return false; } } m_rtViewport.left = 0; m_rtViewport.right = d3dDisplayMode.Width; m_rtViewport.top = 0; m_rtViewport.bottom = d3dDisplayMode.Height; return 0; } void d3dDispaly::uninit() { if (m_pD3D != NULL) { m_pD3D->Release(); m_pD3D = NULL; } if (m_pd3dDevice != NULL) { m_pd3dDevice->Release(); m_pd3dDevice = NULL; } if (m_pd3dSurface != NULL) { m_pd3dSurface->Release(); m_pd3dSurface = NULL; } if (m_pBackBuffer != NULL) { m_pBackBuffer->Release(); m_pBackBuffer = NULL; } m_nImgWidth = 0; m_nImgHeight = 0; } bool d3dDispaly::inputYUVData(LPBYTE pBuffer, long nwidth, long nheight) { if (NULL == m_pd3dDevice) { return false; } if (m_nImgWidth != nwidth || m_nImgHeight != nheight) { if (!__setVideoSize(nwidth, nheight)) return false; } if (m_pd3dSurface == NULL) return false; D3DLOCKED_RECT d3d_rect; if (FAILED(m_pd3dSurface->LockRect(&d3d_rect, NULL, D3DLOCK_DONOTWAIT))) { //OutputDebugStringA("D3D****************LockRect Fail*******\n"); return false; } const int w = m_nImgWidth, h = m_nImgHeight; BYTE* const p = (BYTE *)d3d_rect.pBits; const int stride = d3d_rect.Pitch; int i = 0; for (i = 0; i < h; i++) memcpy(p + i * stride, pBuffer + i * w, w); for (i = 0; i < h / 2; i++) memcpy(p + stride * h + i * stride / 2, pBuffer + w * h + w * h / 4 + i * w / 2, w / 2); for (i = 0; i < h / 2; i++) memcpy(p + stride * h + stride * h / 4 + i * stride / 2, pBuffer + w * h + i * w / 2, w / 2); if (FAILED(m_pd3dSurface->UnlockRect())) { //OutputDebugStringA("D3D****************UnlockRect Fail*******\n"); return false; } __drawImage(); return true; } bool d3dDispaly::__setVideoSize(long lWidth, long lHeight) { if (FAILED(m_pd3dDevice->CreateOffscreenPlainSurface(lWidth, lHeight, (D3DFORMAT)MAKEFOURCC('Y', 'V', '1', '2'), D3DPOOL_DEFAULT, &m_pd3dSurface, NULL))) { OutputDebugStringA("D3D****************CreateOffscreenPlainSurface Fail*******\n"); return false; } m_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); if (!m_pBackBuffer) { OutputDebugStringA("D3D****************GetBackBuffer Fail*******\n"); return false; } m_nImgWidth = lWidth; m_nImgHeight = lHeight; return true; } void d3dDispaly::__drawImage() { if (m_pd3dDevice != NULL) { //m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); if (SUCCEEDED(m_pd3dDevice->BeginScene())) { m_pd3dDevice->StretchRect(m_pd3dSurface/*NULL*/, NULL, m_pBackBuffer, &m_rtViewport, D3DTEXF_LINEAR); m_pd3dDevice->EndScene(); } m_pd3dDevice->Present(NULL, NULL, NULL, NULL); } }
這裏須要指出的是init
函數中的代碼,不能放在__setVideoSize
函數中,由於D3D初始化較耗性能,若是在初始化的同時就壓數據,很容易引發卡頓問題。