#include #include #define REFRESH_EVENT (SDL_USEREVENT + 1) #define QUIT_EVENT (SDL_USEREVENT + 1) #define YUV_WIDTH 320 #define YUV_HEIGHT 240 // SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */ #define YUV_FORMAT SDL_PIXELFORMAT_IYUV int nThreadExitFlag = 0; int refreshVideoThread(void *data) { while (!nThreadExitFlag) { SDL_Event event; event.type = REFRESH_EVENT; SDL_PushEvent(&event); SDL_Delay(40); } nThreadExitFlag = 0; SDL_Event eq; eq.type = QUIT_EVENT; SDL_PushEvent(&eq); return 0; } int main() { if (SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr, "SDL_Init(SDL_INIT_VIDEO) failed: %s\n", SDL_GetError()); return -1; } SDL_Event event; SDL_Rect rect; SDL_Window *window; SDL_Renderer *renderer = NULL; SDL_Texture *texture = NULL; SDL_Thread *t = NULL; uint32_t pixformat = YUV_FORMAT; int video_width = YUV_WIDTH; int video_height = YUV_HEIGHT; int win_width = YUV_WIDTH; int win_height = YUV_HEIGHT; FILE *video_fd = NULL; const char* yuv_path = "yuv420p_320x240.yuv"; size_t video_buff_len = 0; uint8_t *video_buf = NULL; uint32_t y_frame_len = video_width * video_height; uint32_t u_frame_len = video_width * video_height / 4; uint32_t v_frame_len = video_width * video_height / 4; uint32_t yuv_frame_size = y_frame_len + u_frame_len + v_frame_len; window = SDL_CreateWindow("YUV", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, win_width, win_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!window) { printf("SDL_CreateWindow() failed: %s\n", SDL_GetError()); goto fail; } // 基于窗口创建渲染器 renderer = SDL_CreateRenderer(window, -1, 0); // 基于渲染器创建纹理 texture = SDL_CreateTexture(renderer, pixformat, SDL_TEXTUREACCESS_STREAMING, video_width, video_height); video_buf = (uint8_t*)malloc(yuv_frame_size); if (!video_buf) { fprintf(stderr, "malloc video_buf failed\n"); } video_fd = fopen(yuv_path, "rb"); if (!video_fd) { fprintf(stderr, "fopen failed\n"); } t = SDL_CreateThread(refreshVideoThread, "refresh_video_thread", NULL); while (1) { SDL_WaitEvent(&event); if (event.type == REFRESH_EVENT) { video_buff_len = fread(video_buf, 1, yuv_frame_size, video_fd); if (video_buff_len <= 0) { fprintf(stderr, "fread from yuv file failed\n"); goto fail; } SDL_UpdateTexture(texture, NULL, video_buf, video_width); rect.x = 0; rect.y = 0; float w_ratio = win_width * 1.0 / video_width; float h_ratio = win_height * 1.0 / video_height; // 保持宽高比 rect.w = video_width * w_ratio; rect.h = video_height * h_ratio; // 清楚渲染器中的缓存 SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, &rect); SDL_RenderPresent(renderer); } else if (event.type == SDL_WINDOWEVENT) { SDL_GetWindowSize(window, &win_width, &win_height); } else if (event.type == SDL_QUIT) { nThreadExitFlag = 1; } else if (event.type == QUIT_EVENT) { break; } } fail: nThreadExitFlag = 1; if (t) { SDL_WaitThread(t, NULL); } if (video_buf) { free(video_buf); } if (video_fd) { fclose(video_fd); } if (texture) { SDL_DestroyTexture(texture); } if (renderer) { SDL_DestroyRenderer(renderer); } if (window) { SDL_DestroyWindow(window); } SDL_Quit(); return 0; }