DirectDraw 显示 YUV

在网上找了一段代码,能工作,但是颜色不对,红的变成蓝色的,黄的变青色了,有时间找找问题。

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

 

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

#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;
}

时间: 2025-01-21 14:49:46

DirectDraw 显示 YUV的相关文章

使用DirectDraw直接显示YUV视频数据

最近在编写一个进行视频播放的ActiveX控件,工作已经接近尾声,现将其中显示YUV数据的使用DirectDraw的一些经验总结如下:(解码部分不是我编写的,我负责从网络接收数据,将数据传给解码器,并将解码得到的YUV数据进行显示,最初在显示部分我是先将YUV数据转换为RGB数据,再以位图的形式显示到屏幕上,但发现CPU占用率比较高,后来改用DirectDraw直接显示YUV数据) 1.在DirectDraw中创建YUV表面   与一般表面不同的是,创建YUV表面时需要指定象素格式,并指定YUV

yuv-关于OpenGL ES20显示YUV数据在不同手机要使用不同坐标系的问题,求教各位大虾

问题描述 关于OpenGL ES20显示YUV数据在不同手机要使用不同坐标系的问题,求教各位大虾 现在做OpenGL ES20在JNI层直接显示H264解码出来的YUV视频数据.参考的是这个链接,里面的坐标系问题至今也还没能解决掉,在不同手机上一定要用不同坐标系才能在正确的位置显示完整图像,如下: #if 0 // 红米.台电pad.kindle pad 等 GLfloat squareVertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,

【转载】SDL2.0在mfc窗口中显示yuv的一种方法

DWORD ThreadFun(){    //用mfc窗口句柄创建一个sdl window    SDL_Window * pWindow = SDL_CreateWindowFrom( (void *)( GetDlgItem(IDC_STATIC1)->GetSafeHwnd() ) );     SDL_Rect sdlRT;    sdlRT.h = 288;    sdlRT.w = 352;    sdlRT.x = 0;    sdlRT.y = 0;     SDL_Rect

directdraw显示yuv420(YV12)

height=width=widthBytes=0;  m_screen.SetWindowPos(&CWnd::wndBottom,0,0,720,576, SWP_NOMOVE | SWP_SHOWWINDOW);  UpdateWindow();  main_window_handle = m_screen.GetSafeHwnd();  if(DD_OK!=(DirectDrawCreateEx(NULL, (void **)&lpdd7, IID_IDirectDraw7, NU

directdraw显示yuv422(yuy2)

#include <mmsystem.h> void CshowpicDlg::OnBnClickedButton3() {  // TODO: 在此添加控件通知处理程序代码     height=width=widthBytes=0;  m_screen.SetWindowPos(&CWnd::wndBottom,0,0,720,576, SWP_NOMOVE | SWP_SHOWWINDOW);  UpdateWindow();  main_window_handle = m_sc

directdraw显示rgb565

// TODO: 在此添加控件通知处理程序代码  height=width=widthBytes=0;  m_screen.SetWindowPos(&CWnd::wndBottom,0,0,720,576, SWP_NOMOVE | SWP_SHOWWINDOW);  UpdateWindow();  main_window_handle = m_screen.GetSafeHwnd();  if(DD_OK!=(DirectDrawCreateEx(NULL, (void **)&lp

directdraw显示rgb555

// TODO: 在此添加控件通知处理程序代码  height=width=widthBytes=0;  m_screen.SetWindowPos(&CWnd::wndBottom,0,0,720,576, SWP_NOMOVE | SWP_SHOWWINDOW);  UpdateWindow();  main_window_handle = m_screen.GetSafeHwnd();  if(DD_OK!=(DirectDrawCreateEx(NULL, (void **)&lp

最简单的视音频播放示例7:SDL2播放RGB/YUV

本文记录SDL播放视频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API用于播放视频:封装了DirectSound这类的API用于播放音频.因为SDL的编写目的就是简化视音频播放的开发难度,所以使用SDL播放视频(YUV/RGB)和音频(PCM)数据非常的容易.下文记录一下使用SDL播放视频数据的技术.   SDL简介 SDL(Simple DirectMedia La

最简单的视音频播放示例3:Direct3D播放YUV,RGB(通过Surface)

上一篇文章记录了GDI播放视频的技术.打算接下来写两篇文章记录Direct3D(简称D3D)播放视频的技术.Direct3D应该Windows下最常用的播放视频的技术.实际上视频播放只是Direct3D的"副业",它主要用于3D游戏制作.当前主流的游戏几乎都是使用Direct3D制作的,例如<地下城与勇士>,<穿越火线>,<英雄联盟>,<魔兽世界>,<QQ飞车>等等.使用Direct3D可以用两种方式渲染视频:Surface和