使用SDL播放RGB24文件
一、概述
在音视频处理领域,SDL(Simple DirectMedia Layer)是一个功能强大且跨平台的多媒体开发库,能轻松实现视频播放、渲染等功能。本文聚焦于使用 SDL 播放 RGB24 文件,详细阐述从文件准备、SDL 初始化、窗口与渲染器创建,到 RGB24 数据读取、纹理生成与渲染的完整流程。并给出在实际测试中遇到的问题与解决方案。
注意事项:
在用SDL做渲染的时候像素格式一定要对的上。例如:你的文件xxx.rgb是rgb24格式的,那么SDL在创建材质的时候也必须指定SDL_PIXELFORMAT_RGB24。如果这两者不对应则会出现视频画面无法显示或者黑白图的问题。
二、代码实例
1.使用ffmpeg工具生成rgb数据,命令如下:
ffmpeg -i original1080.mp4 -s 400x300 -pix_fmt rgb24 output400_300.rgb
使用ffmpeg测试生成的数据是否正常,命令如下:
ffplay -f rawvideo -video_size 400x300 -pixel_format rgb24 -framerate 30 output400_300.rgb
2.封装文件读取类BinaryFileReader.h
class BinaryFileReader { public: //视频的宽高 int width = 400; int height = 300; //文件名 string filename; // ifstream in; public: bool Init() { Close(); in.open(filename, std::ios::binary); if (!in.is_open()) { qDebug() << "无法打开文件"; return false; } return true; } bool Close() { if (in) { in.close(); } return true; } //空间需要外部申请 bool ReadRGB24(char* data) { int dataSize = width * height * 3; in.read(data, dataSize); if (in.gcount() == 0) { // 未读取任何字节:可能已到文件结尾或出现错误 if (in.eof()) { qDebug() << "已到达文件结尾"; return false; } else if (in.fail()) { qDebug() << "读取失败(非EOF原因)"; return false; } } return true; } static BinaryFileReader* Get() { static BinaryFileReader reader; return &reader; } protected: BinaryFileReader() {}; ~BinaryFileReader() {} };
3.封装SDL工具类
class SDLRenderUtil { private: SDL_Window* sdlWindow; SDL_Renderer* sdlRender; SDL_Texture* sdlTexture; public: int width = 400; int height = 300; public: void Init() { Close(); //初始化SDL库 if (SDL_Init(SDL_INIT_VIDEO)) { qDebug() << "SDL初始化失败->" << SDL_GetError(); return; } //2 生成SDL 窗口 sdlWindow = SDL_CreateWindow("SDL窗口", SDL_WINDOWPOS_CENTERED,//窗口位置 SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE ); if (!sdlWindow) { qDebug() << "SDL窗口创建失败->" << SDL_GetError(); return; } //3 生成渲染器 sdlRender = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); if (!sdlRender) { qDebug() << "SDL渲染器创建失败->" << SDL_GetError(); return; } //4 生成材质 //SDL_PIXELFORMAT_ARGB8888 sdlTexture = SDL_CreateTexture(sdlRender, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING,// 可加锁 width, height ); if (!sdlTexture) { qDebug() << "SDL材质创建失败->" << SDL_GetError() << endl; return; } } void Render(char* data) { //5 内存数据写入材质 SDL_UpdateTexture(sdlTexture, NULL, data, width * 3); //6 清理屏幕 SDL_RenderClear(sdlRender); SDL_Rect sdl_rect; sdl_rect.x = 0; sdl_rect.y = 0; sdl_rect.w = width; sdl_rect.h = height; //7 复制材质到渲染器 SDL_RenderCopy(sdlRender, sdlTexture, NULL,//原图位置和尺寸 &sdl_rect//目标位置和尺寸 ); //8 渲染 SDL_RenderPresent(sdlRender); } //初始化SDL事件 bool isEventQuit() { //判断退出 SDL_Event ev; SDL_WaitEventTimeout(&ev, 10); if (ev.type == SDL_QUIT) { Close(); return true; } return false; } void Close() { if (sdlTexture) { SDL_DestroyTexture(sdlTexture); sdlTexture = NULL; } if (sdlRender) { SDL_DestroyRenderer(sdlRender); sdlRender = NULL; } if (sdlWindow) { SDL_DestroyWindow(sdlWindow); sdlWindow = NULL; } } static SDLRenderUtil* Get() { static SDLRenderUtil sdlRenderUtil; return &sdlRenderUtil; } };
4.使用工具类读取文件并渲染窗口
BinaryFileReader::Get()->filename = filePath.toStdString(); BinaryFileReader::Get()->width = mWidth; BinaryFileReader::Get()->height = mHeight; BinaryFileReader::Get()->Init(); SDLRenderUtil::Get()->width = mWidth; SDLRenderUtil::Get()->height = mHeight; SDLRenderUtil::Get()->Init(); std::thread renderThread([=] { char* data = new char[mWidth * mHeight * 3]; for (;;) { SDLRenderUtil::Get()->isEventQuit(); bool ret = BinaryFileReader::Get()->ReadRGB24(data); if (!ret) { break; } SDLRenderUtil::Get()->Render(data); std::this_thread::sleep_for(33ms); } delete data; }); renderThread.detach();//线程分离
5.测试效果

浙公网安备 33010602011771号