SDL入门
本篇主要用于记录SDL2.0.22的基本用法,参考别人的代码,并加了注释方便理解这些api
以下两个demo可以在VS中编译并运行,代码参考 SDL视频显示_奋斗吧!骚年!的博客-CSDN博客
1、SimpleSDL
这个demo使用SDL api来播放yuv视频,运行可以发现窗口并不能移动或者缩放
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> extern "C" { #include "SDL.h" } int main(int argc, char* argv[]) { // 窗口大小 int screen_w = 1000; int screen_h = 1000; // 视频大小 const int pixel_w = 352, pixel_h = 288; const int bpp = 12; // 这里buffer大小为 1 帧数据 width * height * 3 / 2,主要是因为YUV420这种采样方式 unsigned char buffer[pixel_w * pixel_h * bpp / 8]; // 初始化SDL if (SDL_Init(SDL_INIT_VIDEO)) { printf("could not initialize SDL: %s\n", SDL_GetError()); return -1; } // 创建一个SDL_Window // 第二个参数、第三个参数是相对于显示器左上角的坐标 // 第四个参数、第五个参数是窗口大小 // 最后一个参数为窗口选项 SDL_Window *screen = SDL_CreateWindow("SimpleSDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!screen) { printf("could not create window: %s\n", SDL_GetError()); return -1; } // 创建一个SDL_Render对象,第一个参数为SDL_Window,第二个参数为图层序号、第三个参数为flags SDL_Renderer *sdlRenderer = SDL_CreateRenderer(screen, -1, 0); // 数据的存储格式 Uint32 pixformat = SDL_PIXELFORMAT_IYUV; // 创建一个SDL_Texture对象 // 第一个参数为SDL_Render // 第二个参数为数据格式 // // 第四第五个为视频的宽高 SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); FILE *fp = fopen("E:\\Videos\\YUV\\352_288.yuv", "rb+"); if (fp == NULL) { printf("cannot open this file\n"); return -1; } // 这个sdlRect表示渲染的视频相对窗口的位置 SDL_Rect sdlRect; sdlRect.x = 20; sdlRect.y = 50; sdlRect.w = screen_w; sdlRect.h = screen_h; int i = 0; while (1) { if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8) { // Loop fseek(fp, 0, SEEK_SET); fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp); } // 更新SDL_Texture // 最后一个参数为 pitch SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w); // 清除Render中的数据 SDL_RenderClear(sdlRenderer); // 将sdltexture中的数据拷贝给render // 第三个参数SDL_Rect表示拷贝的数据范围 // 第四个参数SDL_Rect表示渲染的大小以及相对渲染窗口的位置 SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); // 渲染 SDL_RenderPresent(sdlRenderer); //Delay 40ms SDL_Delay(40); } SDL_Quit(); return 0; }
2、advanced SDL
主要用了消息事件机制来做视频播放,这时候窗口可以自由移动并且缩放
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> extern "C" { #include "SDL.h" } // 自定义事件 //Refresh Event #define REFRESH_EVENT (SDL_USEREVENT + 1) //Break #define BREAK_EVENT (SDL_USEREVENT + 2) int thread_exit = 0; int refresh_video(void* opaque) { thread_exit = 0; while (thread_exit == 0) { // 每隔40ms发送一个Refresh SDL_Event event; event.type = REFRESH_EVENT; SDL_PushEvent(&event); SDL_Delay(4000); } thread_exit = 0; //Break SDL_Event event; event.type = BREAK_EVENT; SDL_PushEvent(&event); return 0; } int main(int argc, char* argv[]) { const int bpp = 12; int screen_w = 500, screen_h = 500; const int pixel_w = 352, pixel_h = 288; unsigned char buffer[pixel_w * pixel_h * bpp / 8]; if (SDL_Init(SDL_INIT_VIDEO)) { printf("Could not initialize SDL - %s\n", SDL_GetError()); return -1; } SDL_Window* screen = SDL_CreateWindow("Advanced SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!screen) { printf("SDL: could not create window - exiting:%s\n", SDL_GetError()); return -1; } SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0); Uint32 pixformat = SDL_PIXELFORMAT_IYUV; SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); FILE *fp = fopen("E:\\Videos\\YUV\\352_288.yuv", "rb+"); if (fp == NULL) { printf("cannot open this file\n"); return -1; } SDL_Rect sdlRect; // 创建一个SDL线程 SDL_Thread* refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL); SDL_Event event; while (1) { // Wait 阻塞等待事件 SDL_WaitEvent(&event); if (event.type == REFRESH_EVENT) { //如果是刷新事件 if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8) { // Loop fseek(fp, 0, SEEK_SET); fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp); } SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w); //FIX: If window is resize // 重新设置渲染区域 sdlRect.x = 0; sdlRect.y = 0; sdlRect.w = screen_w; sdlRect.h = screen_h; SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); SDL_RenderPresent(sdlRenderer); } else if (event.type == SDL_WINDOWEVENT) { //If Resize // 如果窗口发生改变,那么就获取窗口大小 SDL_GetWindowSize(screen, &screen_w, &screen_h); } else if (event.type == SDL_QUIT) {//如果退出 thread_exit = 1; //让线程安全退出 } else if (event.type == BREAK_EVENT) { break; } } SDL_Quit(); return 0; }