良许Linux教程网 干货合集 每日开源:嵌入式开发瑞士军刀 SDL2

每日开源:嵌入式开发瑞士军刀 SDL2

SDL 是什么?

SDL(Simple DirectMedia Layer)是一套跨平台的多媒体开发库,采用 C 语言编写。它广泛应用于嵌入式系统、游戏开发、模拟器、媒体播放器等多媒体应用领域。

SDL 提供了一系列的 API,包括图像绘制、声音播放、键盘输入等,使得多媒体应用的开发变得简单。开发者可以使用相同或相似的代码在 Linux、Windows、Mac OS X 等多个平台上开发应用程序。

在我们公司的众多产品中,SDL 是被广泛使用的。举例来说,我们的设备需要根据要求定制开机 Logo 的显示方式,包括单屏和双屏显示,有时还需要旋转 180 度显示。为了实现这一需求,我们开发了一个专门的应用程序,该应用程序基于 SDL2 编写,能够在 Linux 内核启动后灵活配置并显示 Logo。

**SDL 有两个常见版本:

**SDL1.2 和 SDL2.x。

在不支持 OpenGL ES2 的嵌入式平台上,只能使用 SDL1.2,SDL2.x 依赖 OpengGL ES2。

官网

https://www.libsdl.org/

Github

https://github.com/libsdl-org/SDL

本文基于 SDL2。

SDL2 用法

示例:显示图片

 void main()
 {
    SDL_Window *window = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
    
    /* Create a Render */
    SDL_Renderer *render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    
    /* Load bitmap image */
    SDL_Surface *bmp = SDL_LoadBMP("./hello.bmp");
    
    SDL_Texture *texture = SDL_CreateTextureFromSurface(render, bmp);
    SDL_FreeSurface(bmp);

    SDL_RenderClear(render);
    SDL_RenderCopy(render, texture, NULL, NULL); // Copy the texture into render
    SDL_RenderPresent(render); // Show render on window

    /* Free all objects*/
    [...]

    /* Quit program */
    SDL_Quit();
    return 0;
}

**
要快速上手 SDL,需要理解下面几个核心结构体和 API:**

对于这些结构体,网上有各种各样的解释,但是都比较晦涩生硬,下面是我理解。

**
SDL_Window**

想要显示东西,首先要有一个容器来容纳程序绘制的内容。

这个容器,最常见的就是窗口。

对于 PC 机,一般都会有窗口的支持。

但是即便是没有桌面环境的嵌入式平台,SDL_Window 也能兼容,只不过这个窗口没有最小化、最大化、拉伸的功能罢了,都是纯软件的概念,和硬件无关。

一般只需要关注 x、y、w、h 4个成员变量,即窗口的原点坐标和宽高。

通过 SDL_CreateWindow() 可以创建一个窗口。

**
SDL_Renderer**

当描述用 GPU 来进行绘画图像时,就用术语渲染。

渲染器,你可以认为就是画笔。

现实世界里,你可以用圆珠笔来画画,也可以用铅笔来画画,所以渲染器也有多种类型,不同的渲染器就好比不同的笔。

SDL2 支持的渲染器:

image-20240101185733839
image-20240101185733839

在嵌入式平台上,一般就只支持 OpengGL ES2 这种渲染器类型。

通过 SDL_CreateRenderer() 可以创建一个渲染器。

**
SDL_Texture**

渲染器有了之后,就轮到要渲染的内容了。

Texture 负责描述渲染的内容。

既然是要显示图像,自然需要像素数据、像素格式、宽度、高度、渲染器类型等信息,这些都包含在 Texture 里。

最常见的情况是调用 SDL_CreateTextureFromSurface(SDL_Surface) 基于某个 Surface 来创建 Texture。

Surface 用于描述像素数据。

**
SDL_RenderCopy() 和 SDL_RenderPresent()**

我们把内存想象成是一块备用的画布,而此时屏幕正在显示另一块画布的内容。

你可以不断地调用 SDL_RenderCopy() 来往备用画布上画东西,无论你画多少次都可以。

只有当你调用 SDL_RenderPresent() 时,备用画布才会真正第切换到屏幕上。

**
实践应用**

在上一篇文章《五分钟拆解流媒体入门项目 MJPG-Streamer》里,我介绍了 MJPG-Streamer 将每一种输入或输出是都抽象为一个插件。

例如采集摄像头的功能被实现为一个输入插件, 而 http 视频流被实现为一个输出插件。

我们可以为 MJPG-Streamer 添加一个 SDL2 输出插件。

这样就可以在本地显示屏上查看到浏览器的图像了,效果如下:

$ ./mjpg_streamer -i "input_uvc.so /dev/video0 -r 640x480 -f 30" -o "output_sdl2.so"
image-20240101185738422
image-20240101185738422

点击查看大图

代码很简单,核心内容就是使用 SDL2 显示 JPG 图片,代码就不贴了。

SDL2 的实现

显示模块

SDL2 是个功能很丰富的库,最核心的 3 个模块是显示、音频、输入。

这里我们以显示模块为例。

SDL2 将底层显示封装为 video driver:

image-20240101185743043
image-20240101185743043

每一个 bootstrap 变量就实现了一种显示接口,我们比较熟悉的包括:Wayland、X11、KMSDRM。

以 KMSDRM 这个 video driver 为例,为了支持这个显示驱动,需要实现这么多 API:

image-20240101185752718
image-20240101185752718

如果你想了解 SDL2 是如何实现屏幕显示的,可以尝试阅读这些 API。需要你对 KMSDRM 的接口有一定的了解。

**
KMSDRM_VideoInit() 如何初始化显示:**

int KMSDRM_VideoInit(_THIS)
{
    KMSDRM_InitDisplays(_this)
        // 打开设备节点
        viddata->drm_fd = open(viddata->devpath, O_RDWR | O_CLOEXEC);

        // 获取到 DRM resources
        KMSDRM_drmModeGetResources(viddata->drm_fd);

        // 枚举出所有显示设备
        for (i = 0; i count_connectors; i++) {
            KMSDRM_AddDisplay(_this, connector, resources);
        }
}

最开始我们用 SDL2 开发 Logo 显示程序的时候,就遇到了无法双屏显示的问题。最后我们是通过阅读分析 KMSDRM_AddDisplay() 相关等相关代码定位出是 SDL2 自身的 bug,最新版本的 SDL2 已修复。双屏异显示这种需求 SDL2 都能满足,真是考虑得很到位。

**
其他功能模块**

除了核心的显示、音频、输入模块外,还有如 power、hid、joystick 等功能:

$ ls
atomic  cpuinfo  file        hidapi    loadso  misc    SDL_assert.c    SDL_dataqueue.c  SDL_error_c.h  SDL_internal.h  SDL_log.c  test    video
audio   dynapi   filesystem  joystick  locale  power   SDL_assert_c.h  SDL_dataqueue.h  SDL_hints.c    SDL_list.c      sensor     thread
core    events   haptic      libm      main    render  SDL.c           SDL_error.c      SDL_hints_c.h  SDL_list.h      stdlib     timer

你挑出自己感兴趣模块,看看人家是怎么对一个类型的功能进行抽象的。

SDL2 的源码较多,因此本文仅能到抛砖引玉的作用。

总结

SDL(Simple DirectMedia Layer)是一套开源的跨平台多媒体开发库,C 语言编写,多用于嵌入式、游戏、模拟器、媒体播放器等多媒体应用领域。

它提供了绘制图像、播放声音、获取键盘输入等相关的 API,大大降低多媒体应用开发难度的同时,也让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。

如果你想在板子进行多媒体开发,例如显示一些东西,或者简单地播放一段音频,又不想用 Qt 那么庞大的图形框架,可以考虑基于 SDL2 进行开发。

更重要的是,SDL2 代码质量很高,虽然代码量比较大,但是各个功能模块结构很清晰,阅读起来很舒服,。如果你想提高自己的 C 语言编码水平,无论你是不是做嵌入式开发,都可以将整个 SDL2 的源码反复翻几遍,绝对大有裨益。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部