Beginning SDL 2.0(4) YUV加载及渲染
本文主要内容是基于的“Beginning SDL 2.0(3) SDL介绍及BMP渲染”(以下简称BS3)基础上,将BMP加载及渲染修改为YUV420或I420的原始视频格式。阅读完本部分内容相信你可以对SDL2.0中的Renderer机制(支持硬件加速)有一定了解,并可以直接加载显示YUV数据。
SDL 2.0新的支持硬件加速的视频渲染技术——Render
SDL 1.x的版本的视频渲染技术是基于纯软件实现的,效率相对较差,通常很难满足实时渲染的需求。SDL 2.0之后针对这个问题,提供了新的2D加速渲染方案——Renderer。并提供了基于以下类型的机制:
- 单个像素点(point)
- 直线(line)
- 填充矩形(rectangle)
- 纹理图像(texture image)
为了应用新的渲染技术,我们需要修改下BS3中提供的SDLVideoRender基类,主要是添加SDL_Renderer成员函数:
SDL_Renderer * m_sdl_renderer;
在实现文件中修改SDLVideoRender::Init函数中添加初始化代码,用于创建SDL_Renderer对象
m_sdl_renderer = SDL_CreateRenderer(m_sdl_window, -, SDL_RENDERER_ACCELERATED);
if (nullptr == m_sdl_renderer)
{
return false;
}
参数具体函数可以参考SDL_CreateRenderer。(SDL官网上的函数介绍)。
同时在void SDLVideoRender::Deinit()函数中添加反初始化代码,用于销毁SDL_Renderer对象
if (nullptr != m_sdl_renderer)
{
SDL_DestroyRenderer(m_sdl_renderer);
m_sdl_renderer = nullptr;
}
YUV图像渲染
首先我们使用YuvRender类来说明,如何实现YUV图像加载及渲染的方法。其定义如下:
#pragma once
#include "sdlvideorender.h" class YuvRender :public SDLVideoRender
{
public:
YuvRender(void);
~YuvRender(void); bool Init(HWND show_wnd, RECT show_rect);
void Deinit(); // width x height resolution
// data[] for Y\U\V, stride is linesize of each raw
void Update(int width, int height, unsigned char *data[], int stride[]){}
bool Render(); private:
void FillTexture1();
void FillTexture2(); private:
int m_yuv_width;
int m_yuv_height;
int m_yuv_frame_size;
unsigned char * m_yuv_data; SDL_Texture * m_show_texture;
};
这里假定要加载的YUV图像分辨率为720x576,构造函数代码如下:
YuvRender::YuvRender(void)
: SDLVideoRender()
, m_yuv_width(), m_yuv_height()
, m_yuv_frame_size()
, m_yuv_data(nullptr)
, m_show_texture(nullptr)
{}
Init函数的实现是,先创建SDL_Texture,之后从创建YUV缓冲,并从文件中加载图像数据。代码如下
bool YuvRender::Init(HWND show_wnd, RECT show_rect)
{
if (!SDLVideoRender::Init(show_wnd, show_rect))
return false; // create texture
m_show_texture = SDL_CreateTexture(m_sdl_renderer, SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING, m_yuv_width, m_yuv_height);
if (nullptr == m_show_texture)
{
return false;
} // alloc buffer and read yuv file
m_yuv_frame_size = m_yuv_width * m_yuv_height * >> ;
m_yuv_data = new unsigned char[m_yuv_frame_size];
FILE * fin = NULL;
if ( != fopen_s(&fin, "test_720x576.yuv", "rb"))
{
return false;
} fread(m_yuv_data, , m_yuv_frame_size, fin); fclose(fin); return true;
}
注意创建SDL_Texture时使用SDL_TEXTUREACCESS_STREAMING表示我们希望创建的Texture可以频繁的更新,数据能够放到内存和缓存都可以访问的地方。
Deinit函数需要将Init创建的额外资源释放掉。
void YuvRender::Deinit()
{
if (nullptr != m_yuv_data)
{
delete [] m_yuv_data;
m_yuv_data = nullptr;
} if (nullptr != m_show_texture)
{
SDL_DestroyTexture(m_show_texture);
m_show_texture = NULL;
} SDLVideoRender::Deinit();
}
Render渲染函数实现很简单,先填充Texture,之后将Texture渲染到renderer中,就可以提交系统刷新了。代码如下:
bool YuvRender::Render()
{
if (NULL != m_show_texture)
{
//FillTexture1();
FillTexture2(); SDL_RenderCopy(m_sdl_renderer, m_show_texture, NULL, &m_show_rect);
SDL_RenderPresent(m_sdl_renderer);
} return true;
}
YUV数据拷贝及SDL_Texture的更新
上一节中没有说明FillTexture函数的实现。这个函数主要实现将内存中的YUV数据填充到SDL_Texture中。SDL_Texture中的数据存储形式是由创建时第二个参数决定的,SDL_PIXELFORMAT_IYUV(表示I420,常用的planer YUV420格式之一,Y、1/4U、1/4V)。
先看下FillTexture1函数的实现
void YuvRender::FillTexture1()
{
// This is a fairly slow function, intended for use with static textures that do not change often
SDL_UpdateTexture(m_show_texture, NULL, m_yuv_data, m_yuv_width);
}
从SDL官网上可以看到SDL_UpdateTexture可以直接刷新Texture,但是效率上很难保证。
所以FillTexture2应该是我们在常规视频渲染中使用的机制,其代码如下
void YuvRender::FillTexture2()
{
void * pixel = NULL;
int pitch = ;
if( == SDL_LockTexture(m_show_texture, NULL, &pixel, &pitch))
{
// 如果不考虑数据对齐,直接拷贝YUV数据是没有问题的
if (pitch == m_yuv_width)
{
memcpy(pixel, m_yuv_data, m_yuv_frame_size);
}
else // 可能发生pitch > width的情况
{
// 如果有数据对齐的情况,单独拷贝每一行数据
// for Y
int h = m_yuv_height;
int w = m_yuv_width;
unsigned char * dst = reinterpret_cast<unsigned char *>(pixel);
unsigned char * src = m_yuv_data;
for (int i = ; i < h; ++i)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
} h >>= ;
w >>= ;
pitch >>= ;
// for U
for (int i = ; i < h; ++i)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
} // for V
for (int i = ; i < h; ++i)
{
memcpy(dst, src, w);
dst += pitch;
src += w;
}
} SDL_UnlockTexture(m_show_texture);
}
}
这里使用了LockTexture/UnlockTexture的机制。至于SDL_texture的实际内存布局跟Direct 3D的surface类似。
YUV图像渲染验证
我们用vs2010创建基于win32的工程1_Win32_yuv_render,并按照BS3中的修改,将YuvRender提供的接口添加到工程中。
YUV的原图如下:

程序运行后的效果图如下:(注意YUV做了拉伸和显示区域缩减)

相关代码可以从我的git下载,url如下:https://git.oschina.net/Tocy/SampleCode.git,位于TocySDL2VisualTutorial目录下。
Beginning SDL 2.0(4) YUV加载及渲染的更多相关文章
- Beginning SDL 2.0(5) 基于MFC和SDL的YuvPlayer
本文是在“Beginning SDL 2.0(4) YUV加载及渲染”(以下简称BS4)基础上做的功能完善,如果你对之间介绍的内容了解不多,麻烦先阅读之前的内容. 本文主要介绍如何完成一个基于MFC和 ...
- Beginning SDL 2.0(3) SDL介绍及BMP渲染
SDL是一个跨平台的多媒体库.为了实现跨平台,SDL提供了一个简单的界面库抽象,比如提供了SDL_Window用于表示窗口句柄,SDL_Surface.SDL_Texture.SDL_Renderer ...
- 【转】Sqlite 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该...
开发环境: vs2010+.net framework 4.0+ System.Data.SQLite.DLL (2.0)今天在做Sqlite数据库测试,一运行程序在一处方法调用时报出了一个异常 混合 ...
- SQLite.dll混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
其他信息: V5.7.4.4 Can't find the System.Data.SQLite.dll more info : 混合模式程序集是针对"v2.0.50727"版的运 ...
- @vue/cli 3.0 使用 svg-sprite-loader 加载本地 SVG 文件
目录 @vue/cli 3.0 使用 svg-sprite-loader 加载本地 SVG 文件 运行 使用 配置 svg-sprite-loader 调用当前环境下的颜色 props @vue/cl ...
- <VS2010>混合模式程序集是针对“v2.0”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集
在把以前写的代码生成工具从原来的.NET3.5升级到.NET4.0时,将程序集都更新后,一运行程序在一处方法调用时报出了一个异常: 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有 ...
- VS报错之混合模式程序集是针对“v1.1.4322”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
看到一个kinect大牛编写的一个水果忍者的体感游戏版本,让我为自己一直以来只用现有的网页游戏来模拟kinect体感游戏控制感到惭愧,没办法,我还是菜鸟.学习一段后自己模仿星际大战这个游戏,自己写了一 ...
- C#连接Sqlite 出现:混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。的解决方案
C#连接Sqlite 出现: 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集.的解决方案 C#连接sqlite数据库代码 ...
- c# .netframwork 4.0 调用 2.0时报错 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
“System.IO.FileLoadException”类型的未经处理的异常在 XXX.dll 中发生 其他信息: 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的 ...
随机推荐
- Tensorflow结点打包和依赖控制
深度学习库能够充分发挥GPU并行计算的能力,但是有时我们却不得不需要串行.这时就需要用到依赖控制. import tensorflow as tf a = tf.Variable(1) b = tf. ...
- ThinkPHP学习(三)
我们已经将数据保存到了后台数据库,那接下来我们肯定要将数据显示出来看看了. 先建立一个要显示数据的模板formlist.html: <!DOCTYPE HTML PUBLIC "-// ...
- MM bound 与 Jensen's inequality
MM bound 与 Jensen's inequality 简森不等式 在使用最大似然估计方法求解模型最优解的时候,如果使用梯度下降(GD or SGD)或者梯度上升(GA or SGA),可能收敛 ...
- 图片标注工具LabelImg使用教程
1.进入labelImg-master文件夹,在空白处使用 “Shift+鼠标右键” ,选择在此处打开命令窗口,依次输入下面语句即可打开软件. pyrcc4 -o resources.py resou ...
- NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用
NET MVC全局异常处理(一) 目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...
- 企业内知识库wiki所存在的问题
相信很多公司都利用开源的wiki web app搭建了自家的内部wiki服务,比如使用media Wiki, Gollum, doku wiki, jsWiki等 但是,真正可用的企业wiki系统却没 ...
- php把采集内容中图片地址下载并替换成本地地址
把字符串中地址全部获取到一个数组我们利用preg_match_all函数 代码如下 复制代码 <?php$str='<p><img border="0" s ...
- [转]Github 简明教程
如果你是一枚Coder,但是你不知道Github,那么我觉的你就不是一个菜鸟级别的Coder,因为你压根不是真正Coder,你只是一个Code搬运工. 但是你如果已经在读这篇文章了,我觉的你已经知道G ...
- [转]同步对象Event的用法
同步对象Event的用法 首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,线程锁定方面. CreateEvent函数功能描述:创建或打开一个命名的或无名的事 ...
- JavaScript面向对象:类、方法、属性
JavaScript是一种基于对象的语言,与传统面向对象语言(C#.C++)相比,JavaScript中没有类的概念,其继承有两种基本形式:基于对象的继承和基于类型的继承(原型链继承).无论哪种形式的 ...