#include <stdio.h>
#include <string.h>
#include <SDL.h>
//自定义消息类型
#define REFRESH_EVENT (SDL_USEREVENT + 1) // 请求画面刷新事件
//定义分辨率
// YUV像素分辨率
#define YUV_WIDTH 320
#define YUV_HEIGHT 240
//定义YUV格式
#define YUV_FORMAT SDL_PIXELFORMAT_IYUV
int s_thread_exit = 0; // 退出标志 = 1则退出
int refresh_video_timer(void *data)
{
while (!s_thread_exit)
{
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(40);
}
return 0;
}
#undef main
int main(int argc, char* argv[])
{
// 1.初始化SDL
if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf( stderr, "SDL_Init error: %s\n", SDL_GetError());
return -1;
}
// 2.创建窗口
SDL_Window *window = SDL_CreateWindow("YUV Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, YUV_WIDTH, YUV_HEIGHT, SDL_WINDOW_RESIZABLE);
if (window == NULL) {
fprintf( stderr, "SDL_CreateWindow error: %s\n", SDL_GetError());
return -1;
}
// 3.创建渲染器
SDL_Renderer *render = SDL_CreateRenderer(window, -1, 0);
if (render == NULL) {
fprintf( stderr, "SDL_CreateRenderer error: %s\n", SDL_GetError());
return -1;
}
// 4.创建纹理
SDL_Texture * texture = SDL_CreateTexture(render,
SDL_PIXELFORMAT_IYUV, // planar mode: Y + U + V (3 planes)
SDL_TEXTUREACCESS_STREAMING, YUV_WIDTH, YUV_HEIGHT);
if (texture == NULL) {
fprintf( stderr, "SDL_CreateTexture error: %s\n", SDL_GetError());
return -1;
}
// 5.分配缓存空间
uint32_t yuvlen = YUV_WIDTH*YUV_HEIGHT // Y
+ YUV_WIDTH*YUV_HEIGHT/4 // U
+ YUV_WIDTH*YUV_HEIGHT/4;// V
uint8_t *videobuf = (uint8_t*)malloc(yuvlen);
if (videobuf == NULL) {
fprintf( stderr, "YUV buf malloc error.\n");
return -1;
}
// 6.打开yuv文件
FILE* videofd = fopen("yuv420p_320x240.yuv", "rb");
if (videofd == NULL) {
fprintf( stderr, "fopen yuv file error.\n");
return -1;
}
// 7.创建刷新线程
SDL_Thread * sdlThread = SDL_CreateThread(refresh_video_timer, NULL, NULL);
// 8.事件循环
SDL_Event event;
size_t video_buff_len = 0;
SDL_Rect rect;
int win_width = YUV_WIDTH;
int win_height = YUV_HEIGHT;
while (1) {
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT) {
// 读取yuv数据
video_buff_len = fread(videobuf, 1, yuvlen, videofd);
if (video_buff_len < 0) {
fprintf( stderr, "Failed to read data from yuv file!\n");
break;
}
// 设置纹理数据
SDL_UpdateTexture(texture, NULL, videobuf, YUV_WIDTH);
// 设置大小
if (win_width/win_height > YUV_WIDTH/YUV_HEIGHT) {
int width = win_height * YUV_WIDTH/YUV_HEIGHT;
rect.x = (win_width - width)/2;
rect.y = 0;
rect.w = width;
rect.h = win_height;
}else {
int height = win_width * YUV_HEIGHT / YUV_WIDTH;
rect.x = 0;
rect.y = (win_height - height)/2;
rect.w = win_width;
rect.h = height;
}
// 清除显示区域
SDL_RenderClear(render);
// 拷贝纹理到渲染器
SDL_RenderCopy(render, texture, NULL, &rect);
// 显示数据
SDL_RenderPresent(render);
}
else if (event.type == SDL_WINDOWEVENT) {
SDL_GetWindowSize(window, &win_width, &win_height);
printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n",win_width, win_height);
}
else if (event.type == SDL_QUIT) {
break;
}
}
// 9.推出
s_thread_exit = 1;
if (sdlThread) {
SDL_WaitThread(sdlThread, NULL);
}
if (videobuf) {
free(videobuf);
}
if (videofd) {
fclose(videofd);
}
if (texture) {
SDL_DestroyTexture(texture);
}
if (render) {
SDL_DestroyRenderer(render);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
return 0;
}