Beginning SDL 2.0(3) SDL介绍及BMP渲染

SDL是一个跨平台的多媒体库。为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface、SDL_Texture、SDL_Renderer用于处理画面刷新及基本的图形绘制,提供各种事件(鼠标、键盘、游戏手柄等)输入事件、窗口消息事件用于模拟基于消息的事件处理机制。同时也提供了线程创建、销毁以及同步的机制,在此基础上上也提供了文件访问、字体渲染、多格式图片加载、混音器等扩展功能。

正是由于SDL的跨平台特性,如果你仅仅是希望知道SDL的功能,并能够应用SDL做简单的开发,那这篇文件不适合你,建议去SDL官网上看看Lazy Foo的教程或者Beginning SDL 2.0(1) SDL功能简介

撰写本文的主要目的在于,我希望可以在window框架下使用SDL渲染YUV数据,仅仅调用视频渲染有关的函数,其他跨平台的机制不需要,windows平台下都提供了对应的机制。或者你现有基于window框架的程序,希望使用SDL渲染视频,这也是一篇不错的介绍文章。

一、准备工作

我使用的开发环境是VS2010,SDL使用V2.0.0.3的发布版本,并且安装在C:\dev-tools\SDL2-2.0.3目录下。请按照其他任何SDL的开发环境配置号vs的包含路径和库路径。

同时创建一个Win32的工程,命名为0_Win32_bmp_render。

编译并运行,会有如下窗口显示:

二、SDLVideoRender基类

为了实现抽象化的概念,我们先设定下SDL视频渲染类的对外接口,并给出基本的框架。

#include <SDL.h>
//#include <SDL_main.h>
#pragma comment(lib, "SDL2.lib")

class SDLVideoRender
{
public:
    SDLVideoRender();
    virtual ~SDLVideoRender();

    virtual bool Init(HWND show_wnd, RECT show_rect);
    virtual void Deinit();

    // width x height resolution
    // data[] for Y\U\V, stride is linesize of each raw
    virtual void Update(int width, int height, unsigned char *data[3], int stride[3]) = 0;
    virtual bool Render() = 0;

protected:
    SDL_Window * m_sdl_window;
    SDL_Rect m_show_rect;
};

其中调用Init函数时需要指定绘制的窗口句柄及显示区域(相对于窗口的客户区坐标)。

如果需要刷新窗口(给定YUV)数据,调用Update接口。

Render接口用于实现画面的显示。

m_sdl_window指针是SDL提供的窗口抽象句柄。

SDL_Rect是SDL给出的矩形定义形式,其定义如下:

typedef struct SDL_Rect
{
    int x, y;
    int w, h;
} SDL_Rect;

那么初始化Init函数需要完成哪些功能呢?创建SDL_Window并保存显示区域,其实现代码如下:

bool SDLVideoRender::Init(HWND show_wnd, RECT show_rect)
{
    // 初始化窗口句柄为空或者显示区域为空
    if (nullptr == show_wnd || IsRectEmpty(&show_rect))
    {
        return false;
    }

    if (nullptr != m_sdl_window)
    {
        return true;
    }

    if (SDL_WasInit(SDL_INIT_VIDEO))
    {
        SDL_InitSubSystem(SDL_INIT_VIDEO);
    }

    m_sdl_window = SDL_CreateWindowFrom(show_wnd);
    if (nullptr == m_sdl_window)
    {
        return false;
    }

    m_show_rect.x = show_rect.left;
    m_show_rect.y = show_rect.top;
    m_show_rect.w = show_rect.right - show_rect.left;
    m_show_rect.h = show_rect.bottom - show_rect.top;

    return true;
}

Deinit函数功能正好相反,代码如下:

void SDLVideoRender::Deinit()
{
    if (nullptr != m_sdl_window)
    {
        SDL_DestroyWindow(m_sdl_window);
        m_sdl_window = nullptr;
    }
}

OK,到此我们的SDLVideoRender基类功能基本完善,任何需要绘制渲染视频的程序都可以通过这个基类接口刷新。

三、BMP渲染实现

我们第一个实现的功能可能不是直接加载YUV数据,而是通过加载BMP位图,并渲染显示,来简单了解SDL提供的视频渲染机制。

这里我们添加一个BmpRender类,继承自SDLVideoRender,并重写Init、Deinit、Render三个函数。类头文件如下:

class BmpVideoRender: SDLVideoRender
{
public:
    BmpVideoRender();
    ~BmpVideoRender();

    bool Init(HWND show_wnd, RECT show_rect);
    void Deinit();

    // width x height resolution
    // data[] for Y\U\V, stride is linesize of each raw
    void Update(int width, int height, unsigned char *data[3], int stride[3]){}
    bool Render();

private:
    SDL_Surface * m_bmp_surface;

};

Init函数添加了Bmp文件加载到SDL_Surface的代码。Deinit中添加了销毁SDL_Surface的代码。其实现如下:

bool BmpVideoRender::Init(HWND show_wnd, RECT show_rect)
{
    if (!SDLVideoRender::Init(show_wnd, show_rect))
    {
        return false;
    }

    m_bmp_surface = SDL_LoadBMP("hello_world.bmp");
    if (nullptr == m_bmp_surface)
    {
        return false;
    }

    return true;
}
void BmpVideoRender::Deinit()
{
    if (nullptr != m_bmp_surface)
    {
        SDL_FreeSurface(m_bmp_surface);
        m_bmp_surface = nullptr;
    }

    SDLVideoRender::Deinit();
}

Render给出了如何将SDL_Surface渲染到SDL_Window上的机制。

bool BmpVideoRender::Render()
{
    if (nullptr != m_bmp_surface)
    {
        SDL_Surface * window_surface = SDL_GetWindowSurface(m_sdl_window);
        SDL_BlitScaled(m_bmp_surface, NULL, window_surface,  &m_show_rect);

        SDL_UpdateWindowSurfaceRects(m_sdl_window, &m_show_rect, 1);
    }

    return true;
}

原理很简单,先获取窗口的surface,直接通过SDL_BlitScaled函数将BMP位图Surface渲染到我们事先指定的区域。

四、集成到window程序中

既然BmpRender已经完成了,那么怎么在Window程序中调用呢?

以win32的测试程序为例(第一步vs自动生成的代码)。

首先在0_Win32_bmp_render.cpp文件开头添加

HWND hMainWnd;
BmpVideoRender bmpRender;

并在_tWinMain的主消息循环之前添加:(注意InvalidateRect是必须的,否则你可以去掉试试。)

    if (0 != SDL_Init(SDL_INIT_VIDEO))
    {
        return FALSE;
    }

    RECT show_rect = {0};
    GetClientRect(hMainWnd, &show_rect);
    show_rect.right/=2;
    show_rect.bottom/=2;
    bmpRender.Init(hMainWnd, show_rect);
    InvalidateRect(hMainWnd, &show_rect, TRUE);

在消息循环结束的时候添加:

    bmpRender.Deinit();
    SDL_Quit();

在InitInstance中添加

hMainWnd = hWnd;

最后在WndProc消息处理函数的WM_PAINT的EndPaint函数之后添加

bmpRender.Render();

编译运行,就会得到下面效果图:(我们将图片缩放到客户区的左上角的1/4的区域)

总结

这是一篇很简单的SDL绘制位图的demo。基本概念涉及到SDL_Window、SDL_Rect、SDL_Surface、BMP位图加载、Surface缩放、窗口绘制区域获取和刷新。

这里说明一点,据SDL官网介绍,SDL_Surface的实现是纯软件实现的,不支持硬件加速。如果对性能要求比较苛刻,建议不要过多依赖SDL_Surface。

相关代码可以从我的git下载,url如下:https://git.oschina.net/Tocy/SampleCode.git,位于TocySDL2VisualTutorial目录下。

----------------------------------------------------------------------------------------------------------------------------

本文作者:Tocy  e-mail: [email protected]

版权所有@2015,请勿用于商业用途,转载请注明原文地址。本人保留所有权利

时间: 2024-10-11 18:08:24

Beginning SDL 2.0(3) SDL介绍及BMP渲染的相关文章

Beginning SDL 2.0(1) SDL功能简介

原文链接为 http://wiki.libsdl.org/Introduction. 由于近期整理音视频可视化的技术,发现好久不更新的SDL发布了2.0版本,以前也没有过于关注,这里准备尝试下.了解SDL到底支持哪些功能. 本文部分内容为翻译内容.有任何不当支持请联系我. SDL全名Simple DirectMedia Layer (SDL).官网:http://www.libsdl.org/ What can SDL do? SDL功能简介 Read ahead for an overview

Beginning SDL 2.0(2) TwinklebearDev SDL 2.0 Tutorial

本文整理并简要介绍了TwinklebearDev SDL 2.0 Tutorial相关内容(以下简称TDSDLTutorial). 这是作为我学习并了解SDL2.0功能一篇学习总结. TDSDLTutorial包含7个lesson.lesson 0主要是关于SDL2.0开发环境的配置(visual studio.mingw.linux gcc等). lesson 1和lesson 2介绍了bmp图片的加载.SDL中视频渲染的基本原理以及SDL初始化销毁的方式,其中主要涉及window.rende

第四章 跨平台图像显示库——SDL 第一节 与SDL第一次亲密接触

http://blog.csdn.net/visioncat/article/details/1596576 GCC for Win32 开发环境介绍(5) 第四章 跨平台图像显示库——SDL 第一节 与SDL第一次亲密接触 SDL,也就是 Simple DirectMedia Layer 是一个针对 声音,键盘,鼠标,遥杆,通过OpenGL的3D以及2D处理的底层跨平台函数库.她主要支持的平台有Linux, Windows, Windows CE, BeOS, MacOS, Mac OS X,

Hadoop 2.4.0新特性介绍

在2014年4月7日,Apache发布了Hadoop 2.4.0 .相比于hadoop 2.3.0,这个版本有了一定的改进,突出的变化可以总结为下列几点(官方文档说明): 1 支持HDFS访问控制列表(ACL,Access Control Lists) 这个特性解决了在一定情况下,文件权限访问的权限问题.其机制是基于Linux文件访问权限的特征,如果你熟悉Linux的文件访问机制,你就不用再去理解HDFS文件访问的特性了. 有了ACL特性后,对HDFS文件系统就具有了良性的扩展特性.HDFS-4

开源yYmVc项目 v 0.2 版本介绍

项目地址:https://code.csdn.net/hacke2/yymvc 本版本主要实现以下几点功能: 1.框架入口基于过滤器统一实现,action后缀动态配置 2.action配置模仿struts 3.增加action的辅助类 4.完成模型与视图的分离 ----------- 开源yYmVc项目 v 0.2 版本介绍,布布扣,bubuko.com

Spring 2.0 的AOP介绍及其通知类型

Spring 2.0的AOP 在Spring 2.0中最激动人心的增强之一是关于Spring AOP,它变得更加便于使用而且更加强大,主要是通过复杂而成熟的AspectJ语言的支持功能来实现,而同时保留纯的基于代理的Java运行时.Spring 2.0的AOP提供给我们一种新的思考程序结构的方法,能够解决很多纯OOP无法解决的问题--让我们能够在一个模块中实现某些需求,而不是以发散的方式实现.Spring 2.0允许用户选择使用基于模式或@AspectJ注解的方式来自定义切面.这两种风格都支持所

Hbase 0.95.2介绍及下载地址

HBase是一个分布式的.面向列的开源数据库,该技术来源于Google论文“Bigtable:一个结构化数据的分布式存储系统”.就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力.HBase是Apache的Hadoop项目的子项目.HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库.另一个不同的是HBase基于列的而不是基于行的模式.www.169it.com H

手思3.0 第三方库介绍

手思3.0第三方库介绍 AFNetworking https://github.com/AFNetworking/AFNetworking MBProgressHUD    https://github.com/jdg/MBProgressHUD SVProgressHUD https://github.com/TransitApp/SVProgressHUD SDWebImage   https://github.com/rs/SDWebImage FMDB          https://

vSphere 6.0 新功能介绍 系列 前言

最近准备写个系列:vSphere 6.0 新功能介绍 希望大家关注 希望自己坚持下来 vSphere 6.0 新功能介绍 系列 前言