今天我们来学习一下怎么把YUV文件显示到屏幕上。
• 视频显示的流程
▫ 视频显示的流程,就是将像素数据“画”在屏幕上的过程。
▫ 例如显示YUV,就是将YUV“画”在系统的窗口中
下面是SDL的视频显示流程。
• SDL视频显示函数简介
▫ SDL_Init():初始化SDL系统
▫ SDL_CreateWindow():创建窗口SDL_Window
▫ SDL_CreateRenderer():创建渲染器SDL_Renderer
▫ SDL_CreateTexture():创建纹理SDL_Texture
▫ SDL_UpdateTexture():设置纹理的数据
▫ SDL_RenderCopy():将纹理的数据拷贝给渲染器
▫ SDL_RenderPresent():显示
▫ SDL_Delay():工具函数,用于延时。
▫ SDL_Quit():退出SDL系统
VC下SDL开发环境的搭建
• 新建控制台工程
▫ 打开VC++
▫ 文件->新建->项目->Win32控制台应用程序
• 拷贝SDL开发文件
▫ 头文件(.h)拷贝至项目文件夹的include子文件夹下
▫ 导入库文件(.lib)拷贝至项目文件夹的lib子文件夹下
▫ 动态库文件(*.dll)拷贝至项目文件夹下
• 配置开发文件
▫ 打开属性面板
解决方案资源管理器->右键单击项目->属性
▫ 头文件配置
配置属性->C/C+±>常规->附加包含目录,输入“include”(刚才拷贝
文件的目录)
▫ 导入库配置
配置属性->链接器->常规->附加库目录,输入“lib” (刚才拷贝文件
的目录)
配置属性->链接器->输入->附加依赖项,输入“SDL2.lib;
SDL2main.lib”(导入库的文件名)
▫ 动态库不用配置
下面是详细代码。
#include <stdio.h>
#define SDL_MAIN_HANDLED //这个宏很重要配置SDL不加上它会报错。产生这个问题的原因是SDL把main函数变成了自己的SDL_main,
extern "C"
{
#include "sdl/SDL.h"
}
//窗口宽高
int w_width = 640;
int w_height = 360;
//图像宽高
const int p_width = 640;
const int p_height = 360;
//读取文件到buff里面。buff大小:图片的宽x高*(Y + 1/4U + 1/4V)
unsigned char buf[p_width * p_height * 12 / 8];//申请buff空间
int main(int argc ,char *argv[])
{
SDL_Window* window; //窗口指针
SDL_Renderer* renderer; //渲染器指针
SDL_Texture* texture; //纹理指针
//初始化SDL
if (SDL_Init(SDL_INIT_VIDEO))
{
printf("SDL_INIT_VIDEO ERROR:%s\n", (char*)SDL_GetError);
return - 1;
}
//创建窗口
//SDL_WINDOWPOS_UNDEFINED默认位置,窗口中间
window = SDL_CreateWindow("SDL_WINDOWS", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w_width, w_height, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (!window)
{
printf("SDL_CreateWindow ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//创建渲染器
renderer = SDL_CreateRenderer(window,-1, 0);
if (!renderer)
{
printf("SDL_CreateRenderer ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//创建纹理
//纹理格式IYUV:SDL_PIXELFORMAT_IYUV
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, p_width, p_height);
if (!texture)
{
printf("SDL_CreateTexture ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//以只读方式打开文件
FILE *yuvfile;
yuvfile = fopen("sintel_640_360.yuv","rb+");
//yuvfile = fopen("test_yuv420p_320x180.yuv", "rb+");
if (!yuvfile)
{
printf("fopen file error\n");
return -1;
}
int ret;//判断返回结果
//定义矩形并初始化
SDL_Rect sdlRect;
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = w_width;
sdlRect.h = w_height;
while (1)
{
//读文件
ret = fread(buf,1, p_width * p_height * 12 / 8, yuvfile);
if (ret == 0)//循环播放
{
fseek(yuvfile, 0, SEEK_SET);
continue;
}
//把数据更新到纹理
ret = SDL_UpdateTexture(texture, NULL, buf, p_width);
if (ret == -1)
{
printf("SDL_UpdateTexture ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//清除整个渲染目标
ret = SDL_RenderClear(renderer);
if (ret == -1)
{
printf("SDL_RenderClear ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//将纹理的一部分复制到当前渲染目标。
ret = SDL_RenderCopy(renderer, texture,NULL, &sdlRect);
if (ret == -1)
{
printf("SDL_RenderCopy ERROR:%s\n", (char*)SDL_GetError);
return -1;
}
//执行渲染后更新屏幕。
SDL_RenderPresent(renderer);
SDL_Delay(40);//延时40ms
}
fclose(yuvfile);//关闭文件
SDL_Quit();//退出SDL
return 0;
}
下载链接:sdl视频显示源代码