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[], int stride[]) = ;
virtual bool Render() = ; 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[], int stride[]){}
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, );
} return true;
}

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

四、集成到window程序中

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

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

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

HWND hMainWnd;
BmpVideoRender bmpRender;

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

    if ( != SDL_Init(SDL_INIT_VIDEO))
{
return FALSE;
} RECT show_rect = {};
GetClientRect(hMainWnd, &show_rect);
show_rect.right/=;
show_rect.bottom/=;
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: zyvj@qq.com

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

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

  1. Beginning SDL 2.0(4) YUV加载及渲染

    本文主要内容是基于的“Beginning SDL 2.0(3) SDL介绍及BMP渲染”(以下简称BS3)基础上,将BMP加载及渲染修改为YUV420或I420的原始视频格式.阅读完本部分内容相信你可 ...

  2. Beginning SDL 2.0(1) SDL功能简介

    原文链接为 http://wiki.libsdl.org/Introduction. 由于近期整理音视频可视化的技术,发现好久不更新的SDL发布了2.0版本,以前也没有过于关注,这里准备尝试下.了解S ...

  3. Beginning SDL 2.0(5) 基于MFC和SDL的YuvPlayer

    本文是在“Beginning SDL 2.0(4) YUV加载及渲染”(以下简称BS4)基础上做的功能完善,如果你对之间介绍的内容了解不多,麻烦先阅读之前的内容. 本文主要介绍如何完成一个基于MFC和 ...

  4. Beginning SDL 2.0(2) TwinklebearDev SDL 2.0 Tutorial

    本文整理并简要介绍了TwinklebearDev SDL 2.0 Tutorial相关内容(以下简称TDSDLTutorial). 这是作为我学习并了解SDL2.0功能一篇学习总结. TDSDLTut ...

  5. SDL 开发实战(二):SDL 2.0 核心 API 解析

    在上一篇文章 SDL 开发实战(一):SDL介绍及开发环境配置 中,我们配置好了SDL的开发环境,并成功运行了SDL的Hello World 代码.但是可能大部分人还是读不太明白具体Hello Wol ...

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

    http://blog.csdn.net/visioncat/article/details/1596576 GCC for Win32 开发环境介绍(5) 第四章 跨平台图像显示库——SDL 第一节 ...

  7. Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性

    Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性 Apache hadoop 项目组最新消息,hadoop3.x以后将会调整方案架构,将Mapreduce 基于内存+io+ ...

  8. Hbase 0.95.2介绍及下载地址

    HBase是一个分布式的.面向列的开源数据库,该技术来源于Google论文“Bigtable:一个结构化数据的分布式存储系统”.就像Bigtable利用了Google文件系统(File System) ...

  9. webpack 4.0.0-beta.0 新特性介绍

    webpack 可以看做是模块打包机.它做的事情是:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式 ...

随机推荐

  1. C语言中的随意跳转

    C语言中有一个很不常用的头文件:setjmp.h. 这个头文件是C语言底层实现的,不像math.h里面的函数都是纯C语言实现的. setjmp.h包含两个函数: longjmp 跳转到某个位置 set ...

  2. Spring 3.0 AOP 之 AOP 术语 (一)

    关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...

  3. VirtualBox虚拟机增加CentOS根目录容量 LVM扩容

    对于目前的网络开发者来说,比较好的搭档就是Win7+VirtualBox+CentOS的组合,既可以发挥Linux强大的网络服务功能,也可以有效的隔离各项服务拖慢系统,影响系统的运行,对于新手来说可以 ...

  4. spring-data-redis读写分离

    在对Redis进行性能优化时,一直想对Redis进行读写分离.但由于项目底层采用spring-data-redis对redis进行操作,参考spring官网却发现spring-data-redis目前 ...

  5. Docker 的技术组件

    Docker可以运行于任何安装了现代Linux内核的x64主机上.推荐的内核版本是3.8或者更高.Docker的开销比较低,可用于服务器.台式机或者笔记本.它包括以下几个部分. 一个原生的Linux容 ...

  6. 【转载并整理】Linux - centOS 6 SVN服务器安装、配置及开机启动

    以前在windows上安装svn服务器,用的是VisualSVN-Server用起来还不错,但只能用在windows,在linux上部署使用是 subversion,具体说明如下 参考原文:http: ...

  7. webstorm 设置js或者html文件自动缩进为4个空格不生效

    设置 tab 和自动缩进为4个空格不生效,解决办法如下 设置代码缩进 1. 依次打开files —- settings —- Editor —- Code Style —- JavaScript 2. ...

  8. MySQL通过Explain查看select语句的执行计划结果触发写操作

    [背景] 某某同学执行了一下Explain结果结果发现数据库有了一条写入操作,恭喜这位同学你的锅到货了,你签收一下: 对! 你没有听错,在一种场景下就算是Explain也会引发数据的写操作,就这是外层 ...

  9. MySQL存储过程相互调用

    什么都不说了上代码: 方式一: 第一个存储过程:test1,参数如下:IN `user_name` VARCHAR(50),OUT `uid`  bigint(20) BEGIN #Routine b ...

  10. Tcp超时修改

    Linux 建立 TCP 连接的超时时间分析 tags: linux | network Linux 系统默认的建立 TCP 连接的超时时间为 127 秒,对于许多客户端来说,这个时间都太长了, 特别 ...