/*
制作YUV
ffmpeg -i xiongmao.flv -s 540x380 xiongmao_540_380.mp4
ffmpeg -i xiongmao_540_380.mp4 -an -c:v rawvideo -ss 00:00:00 -t 00:00:05 -pix_fmt yuv420p xiongmao_540_380.yuv
關鍵點
1. 把texture初始化為YUV格式,
2. 把YUV資料更新到texture上-SDL_UpdateTexture(texture, NULL, yuv_buf, yuv_w);
3. 把texture更新到window上并顯示出來。
*/
#include <SDL2/SDL.h>
#define PATH_YUV "1.yuv"
#define SDL_EVENT_FRESH (SDL_USEREVENT + 1)
#define SDL_EVENT_EXIT (SDL_USEREVENT + 2)
int isTaskRun = 1;
/*
* 定時發送重新整理事件
* */
int task_fresh_video(void *param)
{
while (isTaskRun)
{
SDL_Event event;
event.type = SDL_EVENT_FRESH;
SDL_PushEvent(&event);
SDL_Delay(40);
}
SDL_Event event;
event.type = SDL_EVENT_EXIT;
SDL_PushEvent(&event);
return 0;
}
int main(int argc, char *argv[])
{
SDL_Window *window;
SDL_Renderer *render;
SDL_Texture *texture;
//LOAD_YUV420P
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
FILE *yuv_fp;
int yuv_w = 540;
int yuv_h = 380;
int yuv_frame_len = yuv_w * yuv_h * 1.5;
char *yuv_buf = malloc(yuv_frame_len);
if (!yuv_buf)
{
sprintf(stderr, "%s", "Failed to malloc buffer!\n");
return -1;
}
yuv_fp = fopen(PATH_YUV, "r");
if (!yuv_fp)
{
sprintf(stderr, "%s", "Failed to open yuv file!\n");
return -1;
}
// 初始化SDL
if (SDL_Init(SDL_INIT_VIDEO))
{
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
// 建立視窗
window = SDL_CreateWindow(
"YUV player",
200,
200,
yuv_w,
yuv_h,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window)
{
fprintf(stderr, "Failed to create window, %s\n", SDL_GetError());
goto __EXIT;
}
// 為視窗建立渲染器
render = SDL_CreateRenderer(window, -1, 0);
if (!render)
{
fprintf(stderr, "Failed to create render, %s\n", SDL_GetError());
goto __DESTROY_WINDOW;
}
// 為渲染器建立紋理
texture = SDL_CreateTexture(render,
SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING,
yuv_w,
yuv_h);
if (!texture)
{
fprintf(stderr, "Failed to create texture, %s\n", SDL_GetError());
goto __DESTROY_RENDER;
}
// 建立線程,發送事件
SDL_CreateThread(task_fresh_video, NULL, NULL); // 啟動線程 函數名,線程名,參數
// 等待事件,然後更新
while (1)
{
SDL_Event event;
SDL_WaitEvent(&event);
if (event.type == SDL_EVENT_FRESH)
{
// 讀取YUV資料
if (fread(yuv_buf, 1, yuv_frame_len, yuv_fp) < 0)
{
sprintf(stderr, "%s", "Failed to read yuv file\n");
goto __CLOSE_FILE;
}
// 更新紋理
SDL_UpdateTexture(texture, NULL, yuv_buf, yuv_w);
// 清空原來圖像
SDL_RenderClear(render);
SDL_RenderCopy(render, texture, NULL, NULL);
SDL_RenderPresent(render);
}
else if (event.type == SDL_QUIT)
{
isTaskRun = 0;
}
else if (event.type == SDL_EVENT_EXIT)
{
break;
}
}
free(yuv_buf);
__CLOSE_FILE:
fclose(yuv_fp);
__DESTROY_TEXTURE:
SDL_DestroyTexture(texture);
__DESTROY_RENDER:
SDL_DestroyRenderer(render);
__DESTROY_WINDOW:
SDL_DestroyWindow(window);
__EXIT:
SDL_Quit();
return 0;
}