美文网首页IT.技术分享
H264解码之D3D显示YUV

H264解码之D3D显示YUV

作者: 5de9e117f2fe | 来源:发表于2019-06-12 17:26 被阅读5次

概述

备注:本文主要针对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初始化较耗性能,如果在初始化的同时就压数据,很容易引起卡顿问题。

相关文章

网友评论

    本文标题:H264解码之D3D显示YUV

    本文链接:https://www.haomeiwen.com/subject/dmfrfctx.html