SDL 学习笔记:从入门到理解核心原理
一、SDL 是什么?
SDL(Simple DirectMedia Layer) 是一个跨平台的硬件抽象层,提供统一的 API 来操作:
| 子系统 | 作用 |
|---|
| Video | 窗口创建、渲染(OpenGL/Vulkan/DirectX) |
| Audio | 音频播放、录制 |
| Input | 键盘、鼠标、游戏手柄事件 |
| Thread | 多线程、互斥锁、条件变量 |
| Timer | 高精度定时器 |
核心价值:一套代码,Windows/Linux/macOS/Android/iOS 全平台运行。
二、SDL 核心原理
2.1 架构图
你的应用程序
│
▼
SDL API(统一接口)
│
├─ Windows ─→ DirectX / Win32 API
├─ Linux ─→ X11 / Wayland / DRM / OpenGL
├─ macOS ─→ Metal / Cocoa
└─ Android ─→ SurfaceFlinger / OpenGL ES
2.2 核心概念:渲染管线
初始化 SDL
│
▼
创建窗口(Window)── 操作系统的"画框"
│
▼
创建渲染器(Renderer)── 决定用哪种 GPU API 画图
│
▼
创建纹理(Texture)── GPU 内存中的图像数据
│
▼
渲染循环:
├─ 处理事件(键盘、鼠标、关闭)
├─ 更新纹理数据(把解码后的 YUV/RGB 拷进去)
├─ 清空画布 → 绘制纹理 → 显示到屏幕
└─ 循环直到退出
│
▼
清理资源
2.3 为什么要区分 Renderer 和 Texture?
| 概念 | 作用 | 类比 |
|---|
| Window | 操作系统窗口 | 画框 |
| Renderer | GPU 渲染管线 | 画家 |
| Texture | GPU 内存中的图像 | 颜料 |
数据流:CPU 内存 → SDL_UpdateTexture → GPU 显存(Texture)→ SDL_RenderTexture → 屏幕。
三、常用 API 速查
3.1 初始化与清理
| API | 作用 | 参数说明 |
|---|
SDL_Init(flags) | 初始化 SDL 子系统 | SDL_INIT_VIDEO 视频,SDL_INIT_AUDIO 音频,SDL_INIT_EVENTS 事件 |
SDL_Quit() | 清理所有 SDL 资源 | 无 |
3.2 窗口
| API | 作用 | 参数说明 |
|---|
SDL_CreateWindow(title, w, h, flags) | 创建窗口 | flags:SDL_WINDOW_RESIZABLE(可调整大小)、SDL_WINDOW_OPENGL(支持 OpenGL) |
SDL_DestroyWindow(window) | 销毁窗口 | 窗口指针 |
3.3 渲染器
| API | 作用 | 参数说明 |
|---|
SDL_CreateRenderer(window, driver, flags) | 创建渲染器 | driver:NULL 自动选择;flags:SDL_RENDERER_ACCELERATED(硬件加速) |
SDL_DestroyRenderer(renderer) | 销毁渲染器 | 渲染器指针 |
3.4 纹理
| API | 作用 | 参数说明 |
|---|
SDL_CreateTexture(renderer, format, access, w, h) | 创建纹理 | format:像素格式;access:SDL_TEXTUREACCESS_STREAMING(频繁更新) |
SDL_UpdateYUVTexture(texture, rect, Y, Ypitch, U, Upitch, V, Vpitch) | 更新 YUV 纹理 | Y/U/V:数据指针;pitch:每行字节数 |
SDL_UpdateTexture(texture, rect, pixels, pitch) | 更新 RGB 纹理 | pixels:数据指针 |
SDL_DestroyTexture(texture) | 销毁纹理 | 纹理指针 |
3.5 渲染
| API | 作用 | 参数说明 |
|---|
SDL_RenderClear(renderer) | 清空画布 | 渲染器指针 |
SDL_RenderTexture(renderer, texture, srcRect, dstRect) | 绘制纹理 | srcRect:源区域(NULL=全部);dstRect:目标区域(NULL=全屏) |
SDL_RenderPresent(renderer) | 显示到屏幕 | 渲染器指针(交换缓冲区) |
3.6 事件
| API | 作用 | 参数说明 |
|---|
SDL_PollEvent(&event) | 非阻塞获取事件 | 有事件返回 1,无事件返回 0 |
SDL_WaitEvent(&event) | 阻塞等待事件 | 直到有事件才返回 |
事件类型:
| 事件 | 含义 |
|---|
SDL_EVENT_QUIT | 窗口关闭 |
SDL_EVENT_KEY_DOWN | 键盘按下 |
SDL_EVENT_MOUSE_BUTTON_DOWN | 鼠标按下 |
四、常用像素格式
| 格式常量 | 含义 | 典型用途 |
|---|
SDL_PIXELFORMAT_IYUV | YUV420P 平面格式 | FFmpeg 解码输出 |
SDL_PIXELFORMAT_NV12 | YUV420 半平面 | MPP 硬解码输出 |
SDL_PIXELFORMAT_RGB24 | 8 位 RGB 打包 | 通用显示 |
SDL_PIXELFORMAT_ARGB8888 | 带 Alpha 的 RGB | UI 叠加 |
五、标准代码模板
#include <SDL3/SDL.h>
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *win = SDL_CreateWindow("SDL Demo",
1920, 1080,
SDL_WINDOW_RESIZABLE);
SDL_Renderer *renderer = SDL_CreateRenderer(win, NULL,
SDL_RENDERER_ACCELERATED);
SDL_Texture *tex = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING,
1920, 1080);
int running = 1;
while (running) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_EVENT_QUIT) running = 0;
}
SDL_RenderClear(renderer);
SDL_RenderTexture(renderer, tex, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
六、与 FFmpeg 对接
AVFrame *frame = ;
SDL_UpdateYUVTexture(texture, NULL,
frame->data[0], frame->linesize[0],
frame->data[1], frame->linesize[1],
frame->data[2], frame->linesize[2]);