用DirectDraw显示YV12图像,离屏表面blt主表面

http://real.zdell.com/a/200512/818.html

这个问题在我初学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;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值