0
点赞
收藏
分享

微信扫一扫

code-SDL2.0播放YUV文件


涉及的知识点:SDL事件 SDL线程,SDLwindow、渲染器,纹理,YUV在纹理(texture)上的显示。
代码比较简单直接~~

/*

制作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;
}


举报

相关推荐

0 条评论