1.视频播放的大致流程如下:
初始化—>创建窗口—>创建渲染器—>创建纹理—>读取一帧数据—>设置纹理数据—->将纹理数据拷贝给渲染器—>显示—>退出
2.代码分析:
//自定义的刷新事件
#define REFRESH_EVENT (SDL_USEREVENT + 1)
//自定义的结束事件
#define BREAK_EVENT (SDL_USEREVENT + 2)
int thread_exit = 0;
int screen_w = 640;
int screen_h = 360;
int refresh_video(void *opaque);
int main()
{
SDL_Window* Window = NULL;
const int pixel_w = 640;
const int pixel_h = 360;
const int bpp = 12;
Uint32 pixformat = SDL_PIXELFORMAT_IYUV;
unsigned char buffer[pixel_w*pixel_h*bpp/8];
//打开用于测试的yuv格式的视频文件
FILE *fp = fopen("./sintel_640_360.yuv","rb");
if(fp == NULL)
{
perror("open");
}
//SDL初始化
if(SDL_Init(SDL_INIT_VIDEO)<0)
{
printf( "Could not init SDL: %s\n", SDL_GetError());
return -1;
}
//创建窗口
Window = SDL_CreateWindow("YUV播放器",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
screen_w,
screen_h,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if(Window == NULL)
{
printf("Could not create window: %s\n", SDL_GetError());
}
//创建渲染器
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(Window,-1,0);
//创建纹理(表示一帧或者一张图片)
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat,SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);
SDL_Rect sdlRect;
//创建刷新线程
SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);
SDL_Event event;
while(1)
{
SDL_WaitEvent(&event); //查询是否有事件发生,方便后续处理
//while(SDL_PollEvent(&event)){} 这种写法也是可以的
if(event.type == REFRESH_EVENT)
{
//表示读取一帧数据
//Y = pixel_w*pixel_h
//U = V = pixel_w*pixel_h/4
//因此加起来就是1.5倍pixel_w*pixel_h,也就是bpp(12)/8 = 1.5
if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8)
{
fseek(fp, 0, SEEK_SET);
fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);
}
SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);
//表示要显示的内容的左上角顶点相较于显示框左上角顶点的坐标
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) //窗口事件,拉伸窗口
{
//获得放大后的窗口的尺寸,最终传递给sdlRect结构体,改变下一次刷新时的显示效果
SDL_GetWindowSize(Window,&screen_w,&screen_h);
}
//点击窗口上的X触发事件
else if(event.type == SDL_QUIT)
{
thread_exit = 1;
}
else if(event.type == BREAK_EVENT)
{
break;
}
SDL_Delay(5); //减少cpu使用
}
SDL_DestroyTexture(sdlTexture);
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
int refresh_video(void *opaque)
{
SDL_Event event;
//触发SDL_QUIT事件的时候将thread_exit置1,停止刷新
while (thread_exit == 0)
{
//触发刷新事件,执行主线程中的相应代码,实现刷新的循环执行
event.type = REFRESH_EVENT;
//将事件添加到事件队列中
SDL_PushEvent(&event);
SDL_Delay(40);
}
thread_exit = 0;
event.type = BREAK_EVENT;
SDL_PushEvent(&event);
return 0;
}
3.程序的框架简介:
SDL_Texture用于显示YUV数据,一个SDL_Texture对应一帧YUV数据。
SDL_Renderer用于渲染SDL_Texture至SDL_Window。
SDL_Rect用于确定SDL_Texture显示的位置。
4.官方文档:https://wiki.libsdl.org/FrontPage