H264解码之D3D显示YUV
概述
备注:本文主要针对DirectX 9.0版本来讨论的。
在开始这篇文章之前,我们先阐述一下一些名词:DX、DDraw、DirectShow、D3D、DirectX、DirectDraw
等。
关系
首先我们理一理他们之间的关系,这些关键词统称DirectX,简称DX,它有一下成员:
- DirectX Graphics: 集成了以前的
DirectDraw
(简称DDraw
) 和Direct3D
(简称D3D
)技术。DirectDraw
主要负责2D加速,以实现对显卡内存和系统内存的直接操作;Direct3D
主要提供三维绘图硬件接口,它是开发三维DirectX游戏的基础。
- DirectInput: 主要支持输入服务(包括鼠标、键盘、游戏杆等),同时支持输出设备。
- DirectPlay: 主要提供多人网络游戏的通信、组织功能。
- DirectSetup: 主要提供自动安装
DirectX
组件的API功能。 - DirectMusic: 主要支持MIDI音乐合成和播放功能。
- DirectSound: 主要提供音频捕捉、回放、音效处理、硬件加速、直接设备访问等功能。
- DirectShow: 为Windows平台上处理各种格式的媒体文件的回放、音视频采集等高性能要求的多媒体应用,提供了完整的解决方案。
- DirectX Media Objects:
DirectShow Filter
的简化模型,提供更方便的流数据处理方案。
参考
链接DirectX和DirectShow介绍和区别
链接DirectShow和DirectX有什么区别
接口介绍
显示方式
D3D显示YUV方式有两种:纹理(Texture)方式和表面(Surface)方式。而Texture方式又可以包含使用Shader及不使用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
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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);
}
调用:
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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
的目录,你可以先把它写成绝对目录试试。
这里还有一个问题是:显示没有拉伸,我没找到拉伸的方式。
不使用shader的纹理方式
这里代码参考雷神的代码:
最简单的视音频播放示例4:Direct3D播放RGB(通过Texture)
/**
* 最简单的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;
}
表面(Surface)方式
首先我们看看网上的方式:参考链接使用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初始化较耗性能,如果在初始化的同时就压数据,很容易引起卡顿问题。