文章目录
-
1. 基本流程
-
2. `API`介绍
-
3. Demo
1. 基本流程
-
初始化
-
初始化SDL
-
创建窗口
-
创建渲染器
-
创建纹理
2.渲染
-
设置纹理的数据
-
绘制要显示的内容
-
将缓冲区的内容渲染到窗口,显示
3.清理
-
销毁渲染器
-
销毁窗口
-
退出SDL
2. API介绍
-
SDL_Init 初始化
int SDL_Init(Uint32 flags)
flags:
SDL_INIT_TIMER: 定时器
SDL_INIT_AUDIO: 音频
SDL_INIT_VIDEO: 视频
SDL_INIT_JOYSTICK: 摇杆
SDL_INIT_HAPTIC: 触摸屏
SDL_INIT_GAMECONTROLLER:游戏控制器
SDL_INIT_EVENTS: 事件
SDL_INIT_NOPARACHUTE: 不捕获关键信号(这个不理解)
SDL_INIT_EVERYTHING: 包含上述所有选项
SDL_CreateWindow
创建视频播放的窗口
SDL_Window* SDL_CreateWindow(const char *title,
int x, int y, int w,
int h, Uint32 flags);
title:窗口标题
x,y:窗口x,y坐标,可以设置为SDL_WINDOWPOS_UNDEFINED
w,h:窗口宽高
flags:
SDL_WINDOW_FULLSCREEN, //全屏
SDL_WINDOW_OPENGL, //使用OpenGL上下文
SDL_WINDOW_HIDDEN, //窗口不可见
SDL_WINDOW_BORDERLESS, //无边框
SDL_WINDOW_RESIZABLE, //窗口大小可变
SDL_WINDOW_MAXIMIZED, //窗口最大化
SDL_WINDOW_MINIMIZED, //窗口最小化
SDL_WINDOW_INPUT_GRABBED, //输入捕获
SDL_CreateRenderer
基于窗口创建渲染器
SDL_Renderer* SDL_CreateRenderer(SDL_Window* window,
int index,
Uint32 flags)
window: 指明在哪个窗口里进行渲染
index: 指定渲染驱动的索引号。-1:初始化默认的渲染设备
flags:
SDL_RENDERER_SOFTWARE //使用软件渲染
SDL_RENDERER_ACCELERATED //硬件加速
SDL_RENDERER_PRESENTVSYNC //和显示器的刷新率同步
SDL_RENDERER_TARGETTEXTURE //支持渲染纹理
返回值:返回创建完成的渲染器的ID。如果创建失败则返回NULL。
SDL_CreateTexture基于渲染器创建一个纹理
SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,
Uint32 format,
int access,
int w,
int h);
renderer:目标渲染器
format:纹理的格式
access:
SDL_TEXTUREACCESS_STATIC : 变化极少
SDL_TEXTUREACCESS_STREAMING : 变化频繁
SDL_TEXTUREACCESS_TARGET : ???
SDL_UpdateTexture
设置纹理数据
int SDLCALL SDL_UpdateTexture( SDL_Texture * texture,
const SDL_Rect * rect,
const void *pixels, int pitch);
texture 目标纹理
rec 更新像素的矩阵区域,NULL:更新整个区域
pixels 像素数据
返回值:成功返回0,失败返回-1
SDL_RenderCopy
将纹理数据复制给渲染目标
int SDLCALL SDL_RenderCopy(
SDL_Renderer * renderer,
SDL_Texture * texture,
const SDL_Rect * srcrect,
const SDL_Rect * dstrect);
renderer 渲染目标
texture 输入纹理
srcrect 选择输入纹理的块矩形区域作为输入,NULL:整个纹理作为输入
dstrect 选择渲染目标的块矩形区域作为输出,NULL:整个渲染目标作为输出
返回值:成功返回0,失败返回-1
SDL_RenderPresent
显示纹理到窗口
void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
renderer 指定渲染器
本文福利,免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部↓↓
3. Demo
#include "SDLHeader.h"
#include <string>
#include <fstream>
#include <iostream>
#include <memory>
#include <iostream>
//生成yuv数据
//ffmpeg.exe -i zgr.flv -f rawvideo -video_size 852x480 -pixel_format yuv420p -y zgr_852x480_yuv420p.yuv
//ffplay播放
//ffplay.exe -i zgr_852x480_yuv420p.yuv -video_size 852x480 -pixel_format yuv420p
const static std::string yuv_path = "D:\\vod\\testvideo\\zgr_852x480_yuv420p.yuv";
const static int width = 852;
const static int height = 480;
const static Uint32 pix_fmt = SDL_PIXELFORMAT_IYUV; //YUV420
const static uint32_t frame_size = width * height * 3 / 2;
int ReadYUV(std::fstream& yuv);
void RenderYUV(SDL_Texture* texture, SDL_Renderer* renderer);
void TextureYUV(SDL_Texture* texture, std::shared_ptr<char> yuv_data_sp);
int main(int argc, char** argv)
{
bool quit = false;
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture* texture = nullptr;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) //init
return -1;
window = SDL_CreateWindow(
"Show YUV",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
);
if (!window)
return -1;
renderer = SDL_CreateRenderer(window, -1, 0);
if (!renderer)
return -1;
texture = SDL_CreateTexture(
renderer,
pix_fmt,
SDL_TEXTUREACCESS_STREAMING,
width,
height
);
if (!texture)
return -1;
RenderYUV(texture, renderer);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
int ReadYUV(std::fstream& yuv)
{
if (yuv.is_open())
yuv.close();
yuv.open(yuv_path.c_str(), std::ios::in | std::ios::binary);
if (!yuv.is_open())
{
throw std::logic_error("Open file error " + yuv_path);
return -1;
}
return 0;
}
void RenderYUV(SDL_Texture* texture, SDL_Renderer* renderer)
{
std::fstream yuv;
if (ReadYUV(yuv) != 0)
return;
//用于存放YUV数据
std::shared_ptr<char> yuv_data_sp(new char[frame_size],
[](char* p)
{
std::cout << "Delete frame data" << std::endl;
delete[] p;
}
);
bool quit = false;
SDL_Event event;
SDL_Rect rect;
while (!quit && !yuv.eof())
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
SDL_Log("quit");
quit = true;
break;
}
//读取一帧图像
yuv.read(yuv_data_sp.get(), frame_size);
if (yuv.bad())
{
throw std::runtime_error("Read yuv data");
break;
}
//要绘制的区域
rect.x = 0;
rect.y = 0;
rect.w = width;
rect.h = height;
//直接渲染数据
SDL_UpdateTexture(texture, NULL, yuv_data_sp.get(), width);
//自己填充texture
//TextureYUV(texture, yuv_data_sp);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, &rect);
SDL_RenderPresent(renderer); //输出到目标窗口
SDL_Delay(40);
}
}
void TextureYUV(SDL_Texture* texture, std::shared_ptr<char> yuv_data_sp)
{
void* pixel = nullptr;
int pitch = 0;
if (SDL_LockTexture(texture, nullptr, &pixel, &pitch) == 0)
{
if (pitch == width)
memcpy(pixel, yuv_data_sp.get(), frame_size);
else
{
int h = height;
int w = width;
//Copy all data to dst
uint8_t* dst = reinterpret_cast<uint8_t*>(pixel);
uint8_t* src = reinterpret_cast<uint8_t*>(yuv_data_sp.get());
//Copy Y
for (int i = 0; i < h; i++)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
}
h >>= 1;
w >>= 1;
pitch >>= 1;
//Copy U
for (int i = 0; i < h; i++)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
}
//Copy V
for (int i = 0; i < h; i++)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
}
}
}
SDL_UnlockTexture(texture);
}
原文链接:SDL2.0-播放YUV文件 - 资料 - 我爱音视频网 - 构建全国最权威的音视频技术交流分享论坛
本文福利,免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部↓↓