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) |