织梦CMS - 轻松建站从此开始!

罗索

用DirectDraw显示YV12图像

罗索客 发布于 2005-12-28 11:05 点击:次 
这个问题在我初学DirectX是困惑了我很久,贴出来为初学者提供一个参考。 // yv12.cpp :seac@tom.com, caohai 2005.1 #define WIN32_LEAN_AND_MEAN// 从 Windows 头中排除极少使用的资料 #include windows.h #include stdlib.h #include stdio.h #include malloc.h #incl
TAG:

这个问题在我初学DirectX是困惑了我很久,贴出来为初学者提供一个参考。

// yv12.cpp :  seac@tom.com, caohai 2005.1

#define WIN32_LEAN_AND_MEAN        // 从 Windows 头中排除极少使用的资料
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

#include "resource.h"
#include "ddraw.h"
#pragma comment(lib,"ddraw.lib")


// 此代码模块中包含的函数的前向声明:
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM); // 窗口消息处理函数
BOOL                    DrawYV12(HWND hWnd);                // Draw YV12 图像

// 应用入口
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    MSG msg;
    WNDCLASSEX wcex;
    TCHAR szWindowClass[] = "Draw YV12";            // 主窗口类名
    HWND hWnd;

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = HBRUSH(COLOR_WINDOW + 1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = szWindowClass;
    wcex.hIconSm        = NULL;

    RegisterClassEx(&wcex);

    hWnd = CreateWindow(szWindowClass, szWindowClass,
            WS_OVERLAPPEDWINDOW,//WS_POPUP,
            0, 0,
            800,//GetSystemMetrics(SM_CXSCREEN),
            600,//GetSystemMetrics(SM_CYSCREEN),
            NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    
    // 主消息循环:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}



//
//  函数: WndProc(HWND, unsigned, WORD, LONG)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND    - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY    - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_KEYDOWN:
        switch( wParam )
        {
        case VK_ESCAPE:
        case VK_F12:
            PostMessage(hWnd, WM_CLOSE, 0, 0);
            break;
        case VK_TAB:
            if(!DrawYV12(hWnd))
                MessageBox(hWnd,"Draw yv12 image failed","DDraw error", MB_OK);
            break;
        }
    case WM_DESTROY:
        FreeDDraw();    // destroy again
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

#define FILE_HEIGHT            288
#define FILE_WIDTH            352

#define DRAW_TOP            0
#define DRAW_LEFT            0
#define DRAW_HEIGHT            288
#define DRAW_WIDHT            352

BOOL DrawYV12(HWND hWnd)
{
    LPDIRECTDRAW            lpDD;                // DirectDraw 对象指针
    LPDIRECTDRAWSURFACE     lpDDSPrimary;        // DirectDraw 主表面指针
    LPDIRECTDRAWSURFACE     lpDDSOffScr;        // DirectDraw 离屏表面指针
    DDSURFACEDESC            ddsd;                // DirectDraw 表面描述
    RECT                    rctDest;            // 目标区域
    RECT                    rctSour;            // 源区域
    HRESULT                    ddRval;                // DirectDraw 函数返回值

    // 创建DirectCraw对象
    if (DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK)
        return FALSE;
        
    // 设置协作层
    if (lpDD->SetCooperativeLevel(hWnd,
            DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES) != DD_OK)
        return FALSE;
        
    // 创建主表面
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    if (lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL) != DD_OK)
        return FALSE;
    
    // 创建离屏表面对象
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
    ddsd.dwWidth = DRAW_WIDHT;
    ddsd.dwHeight = DRAW_HEIGHT;
    ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
    ddsd.ddpfPixelFormat.dwFlags  = DDPF_FOURCC | DDPF_YUV ;
    ddsd.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','V','1','2');
    ddsd.ddpfPixelFormat.dwYUVBitCount = 8;
    if (lpDD->CreateSurface(&ddsd, &lpDDSOffScr, NULL) != DD_OK)
        return FALSE;

    // 加载yv12图像文件
    FILE * f = fopen("test.yv12","rb");
    LPBYTE lpYV12 = new BYTE[FILE_WIDTH * FILE_HEIGHT * 3 / 2];
    UINT iLen = fread(lpYV12, 1, FILE_WIDTH * FILE_HEIGHT * 3 / 2, f);
    fclose(f);
    LPBYTE lpY = lpYV12;
    LPBYTE lpV = lpYV12 + FILE_WIDTH * FILE_HEIGHT;
    LPBYTE lpU = lpYV12 + FILE_WIDTH * FILE_HEIGHT * 5 / 4;
    
    ddRval = lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL);
    while(ddRval == DDERR_WASSTILLDRAWING);
    if(ddRval != DD_OK)
        return FALSE;
    LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
    LPBYTE lpY1 = lpSurf;
    LPBYTE lpV1 = lpSurf + ddsd.lPitch * FILE_HEIGHT;
    LPBYTE lpU1 = lpV1 + ddsd.lPitch  * FILE_HEIGHT / 4;
    int nOffset = DRAW_TOP*FILE_WIDTH+DRAW_LEFT;
    
    // 填充离屏表面
    if(lpSurf)
    {
        int i = 0;
        
        // fill Y data
        lpY += nOffset;
        for(i=0; i<ddsd.dwHeight; i++)
        {
            memcpy(lpSurf, lpY, ddsd.dwWidth);
            lpY += FILE_WIDTH;
            lpSurf += ddsd.lPitch;
        }
        
        // fill V data
        lpV += DRAW_TOP * FILE_WIDTH / 4 + DRAW_LEFT / 2;
        for(i=0; i<ddsd.dwHeight/2; i++)
        {
            memcpy(lpSurf, lpV, ddsd.dwWidth / 2);
            lpV += FILE_WIDTH / 2;
            lpSurf += ddsd.lPitch / 2;
        }
        
        // fill U data
        lpU += DRAW_TOP * FILE_WIDTH / 4 + DRAW_LEFT / 2;
        for(i=0; i<ddsd.dwHeight/2; i++)
        {
            memcpy(lpSurf, lpU, ddsd.dwWidth / 2);
            lpU += FILE_WIDTH / 2;
            lpSurf += ddsd.lPitch / 2;
        }
    }
    
    lpDDSOffScr->Unlock(NULL);
    
    delete lpYV12;

    // Blt到主表面上
    rctSour.left = 0;
    rctSour.top = 0;
    rctSour.right = ddsd.dwWidth;
    rctSour.bottom = ddsd.dwHeight;
    GetClientRect(hWnd,&rctDest);
    ClientToScreen(hWnd, (LPPOINT)&rctDest.left);
    ClientToScreen(hWnd, (LPPOINT)&rctDest.right);

    ddRval = lpDDSPrimary->Blt(&rctDest, lpDDSOffScr, &rctSour, DDBLT_WAIT, NULL);
    while(ddRval == DDERR_WASSTILLDRAWING);
    if(ddRval != DD_OK)
        return FALSE;
        
    // 释放DirectDraw对象
    if(lpDD != NULL)
    {
        if(lpDDSPrimary != NULL)
        {
            lpDDSPrimary->Release();
            lpDDSPrimary = NULL;
        }
        if(lpDDSOffScr != NULL)
        {
            lpDDSOffScr->Release();
            lpDDSOffScr = NULL;
        }
        lpDD->Release();
        lpDD = NULL;
    }

    return TRUE;
}
(iwgh)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/200512/818.html]
本文出处: 作者:iwgh
顶一下
(3)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容