zoukankan      html  css  js  c++  java
  • 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
    ");
    		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.
    ");
    		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*******
    ");
    		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]*******
    ", result);
    		OutputDebugStringA(buf);
    		if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hwnd, hal_vp, &d3dpp, &m_pd3dDevice)))
    		{
    			OutputDebugStringA("D3D****************CreateDevice-2 Fail*******
    ");
    			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*******
    ");
    		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*******
    ");
    		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*******
    ");
    		return false;
    	}
    
    	m_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
    	if (!m_pBackBuffer)
    	{
    		OutputDebugStringA("D3D****************GetBackBuffer Fail*******
    ");
    		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初始化较耗性能,如果在初始化的同时就压数据,很容易引起卡顿问题。

  • 相关阅读:
    wordPress屏蔽中国境内的IP
    中国IP地址大全
    WebGL之点精灵的旋转(Rotation Sprite)
    WebGL之点上添加图片(using texture on point)
    potree--加载二进制格式文件
    potree--如何控制八叉树子节点的显示?
    重启tomcat后,访问登陆接口响应慢--Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [27,572] milliseconds.
    Unirest
    配置规范
    函数编写建议
  • 原文地址:https://www.cnblogs.com/SunkingYang/p/11049088.html
Copyright © 2011-2022 走看看