add source code
This commit is contained in:
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(sdl-yuv LANGUAGES C)
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
add_executable(sdl-yuv main.c)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS sdl-yuv
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE SDL2::SDL2)
|
||||||
141
main.c
Normal file
141
main.c
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user