美文网首页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