=====================================================

SDL源码分析系列文章列表:

SDL2源码分析1:初始化(SDL_Init())

SDL2源码分析2:窗体(SDL_Window)

SDL2源码分析3:渲染器(SDL_Renderer)

SDL2源码分析4:纹理(SDL_Texture)

SDL2源码分析5:更新纹理(SDL_UpdateTexture())

SDL2源码分析6:拷贝到渲染器(SDL_RenderCopy())

SDL2源码分析7:显示(SDL_RenderPresent())

SDL2源码分析8:视频显示总结

=====================================================

上一篇文章分析了SDL的创建纹理函数SDL_CreateTexture()。这篇文章继续分析SDL的源码。本文分析SDL更新纹理数据函数SDL_UpdateTexture()。

SDL播放视频的代码流程例如以下所看到的。
初始化: 

SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 创建窗体(Window)。 
SDL_CreateRenderer(): 基于窗体创建渲染器(Render)。 
SDL_CreateTexture(): 创建纹理(Texture)。

循环渲染数据: 

SDL_UpdateTexture(): 设置纹理的数据。

SDL_RenderCopy(): 纹理复制给渲染器。

SDL_RenderPresent(): 显示。

上篇文章分析了该流程中的第4个函数SDL_CreateTexture()。本文继续分析该流程中的第5个函数SDL_UpdateTexture()。

SDL_UpdateTexture()

函数简单介绍

SDL使用SDL_UpdateTexture()设置纹理的像素数据。

SDL_UpdateTexture()的原型例如以下。

int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,
const SDL_Rect * rect,
const void *pixels, int pitch);

參数的含义例如以下。

texture:目标纹理。

rect:更新像素的矩形区域。设置为NULL的时候更新整个区域。

pixels:像素数据。

pitch:一行像素数据的字节数。

成功的话返回0,失败的话返回-1。

函数调用关系图

SDL_UpdateTexture()关键函数的调用关系能够用下图表示。

上面的图片不太清晰。更清晰的图片上传到了相冊里面:

http://my.csdn.net/leixiaohua1020/album/detail/1793769

把相冊里面的图片保存下来就能够得到清晰的图片。

源码分析

SDL_UpdateTexture()的源码位于render\SDL_render.c中。例如以下所看到的。

int SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
const void *pixels, int pitch)
{
SDL_Renderer *renderer;
SDL_Rect full_rect; CHECK_TEXTURE_MAGIC(texture, -1); if (!pixels) {
return SDL_InvalidParamError("pixels");
}
if (!pitch) {
return SDL_InvalidParamError("pitch");
} if (!rect) {
full_rect.x = 0;
full_rect.y = 0;
full_rect.w = texture->w;
full_rect.h = texture->h;
rect = &full_rect;
} if (texture->yuv) {
return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);
} else if (texture->native) {
return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
} else {
renderer = texture->renderer;
return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
}
}

从源码中能够看出,SDL_UpdateTexture()的大致流程例如以下。

1. 检查输入參数的合理性。比如像素格式是否支持,宽和高是否小于等于0等等。
2. 假设是一些特殊的格式,进行一定的处理:

a) 假设输入的像素数据是YUV格式的,则会调用SDL_UpdateTextureYUV()进行处理。

b) 假设输入的像素数据的像素格式不是渲染器支持的格式,则会调用SDL_UpdateTextureNative()进行处理。

3. 调用SDL_Render的UpdateTexture()方法更新纹理。

这一步是整个函数的核心。
以下我们具体看一下几种不同的渲染器的UpdateTexture ()的方法。

1. Direct3D

Direct3D 渲染器中相应UpdateTexture ()的函数是D3D_UpdateTexture(),它的源码例如以下所看到的(位于render\direct3d\SDL_render_d3d.c)。

static int
D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
SDL_bool full_texture = SDL_FALSE; #ifdef USE_DYNAMIC_TEXTURE
if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
rect->x == 0 && rect->y == 0 &&
rect->w == texture->w && rect->h == texture->h) {
full_texture = SDL_TRUE;
}
#endif if (!data) {
SDL_SetError("Texture is not currently available");
return -1;
} if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
return -1;
} if (data->yuv) {
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->vtexture : data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
return -1;
} /* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->utexture : data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
return -1;
}
}
return 0;
}

从代码中能够看出,该函数调用了D3D_UpdateTextureInternal()函数。在这里须要注意,假设输入像素格式是YUV。就会使用3个纹理,对于多出的那2个纹理会单独进行处理。调用的函数D3D_UpdateTextureInternal()代码例如以下。

static int D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool full_texture, int x, int y, int w, int h, const void *pixels, int pitch)
{
RECT d3drect;
D3DLOCKED_RECT locked;
const Uint8 *src;
Uint8 *dst;
int row, length;
HRESULT result; if (full_texture) {
result = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD);
} else {
d3drect.left = x;
d3drect.right = x + w;
d3drect.top = y;
d3drect.bottom = y + h;
result = IDirect3DTexture9_LockRect(texture, 0, &locked, &d3drect, 0);
} if (FAILED(result)) {
return D3D_SetError("LockRect()", result);
} src = (const Uint8 *)pixels;
dst = locked.pBits;
length = w * SDL_BYTESPERPIXEL(format);
if (length == pitch && length == locked.Pitch) {
SDL_memcpy(dst, src, length*h);
} else {
if (length > pitch) {
length = pitch;
}
if (length > locked.Pitch) {
length = locked.Pitch;
}
for (row = 0; row < h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
dst += locked.Pitch;
}
}
IDirect3DTexture9_UnlockRect(texture, 0); return 0;
}

从代码中能够看出,该函数首先调用IDirect3DTexture9_LockRect()锁定纹理。然后使用SDL_memcpy()将新的像素数据拷贝至纹理(SDL_memcpy()实际上就是memcpy()), 最后使用IDirect3DTexture9_UnlockRect()解锁纹理。

2. OpenGL

OpenGL渲染器中相应UpdateTexture()的函数是GL_UpdateTexture()。它的源码例如以下所看到的(位于render\opengl\SDL_render_gl.c)。

static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
GL_TextureData *data = (GL_TextureData *) texture->driverdata; GL_ActivateRenderer(renderer); renderdata->glEnable(data->type);
renderdata->glBindTexture(data->type, data->texture);
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
(pitch / SDL_BYTESPERPIXEL(texture->format)));
renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
rect->h, data->format, data->formattype,
pixels);
if (data->yuv) {
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2)); /* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
if (texture->format == SDL_PIXELFORMAT_YV12) {
renderdata->glBindTexture(data->type, data->vtexture);
} else {
renderdata->glBindTexture(data->type, data->utexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
rect->w/2, rect->h/2,
data->format, data->formattype, pixels); /* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
if (texture->format == SDL_PIXELFORMAT_YV12) {
renderdata->glBindTexture(data->type, data->utexture);
} else {
renderdata->glBindTexture(data->type, data->vtexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
rect->w/2, rect->h/2,
data->format, data->formattype, pixels);
}
renderdata->glDisable(data->type); return GL_CheckError("glTexSubImage2D()", renderer);
}

从代码中能够看出。该函数调用了OpenGL的API函数glBindTexture (),glTexSubImage2D()等更新了一个纹理。
在这里有一点须要注意,假设输入像素格式是YUV,就会使用3个纹理,对于多出的那2个纹理会单独进行处理。

3. Software

Software渲染器中相应UpdateTexture()的函数是SW_UpdateTexture()。它的源码例如以下所看到的(位于render\software\SDL_render_sw.c)。

static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
Uint8 *src, *dst;
int row;
size_t length; if(SDL_MUSTLOCK(surface))
SDL_LockSurface(surface);
src = (Uint8 *) pixels;
dst = (Uint8 *) surface->pixels +
rect->y * surface->pitch +
rect->x * surface->format->BytesPerPixel;
length = rect->w * surface->format->BytesPerPixel;
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
dst += surface->pitch;
}
if(SDL_MUSTLOCK(surface))
SDL_UnlockSurface(surface);
return 0;
}

该函数的源码还没有具体分析。当中最关键的函数要数SDL_memcpy()了,正是这个函数更新了纹理的像素数据。可是Software渲染器纹理改动的时候是否须要Lock()和Unlock()呢?这一点一直也没太搞清。

SDL2源码分析5:更新纹理(SDL_UpdateTexture())的更多相关文章

  1. SDL2源码分析6:拷贝到渲染器(SDL_RenderCopy())

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  2. SDL2源码分析8:视频显示总结

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  3. SDL2源码分析2:窗体(SDL_Window)

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  4. SDL2源码分析1:初始化(SDL_Init())

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  5. 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  6. 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  7. jQuery1.6源码分析系列

    原文地址:http://www.cnblogs.com/nuysoft/archive/2011/11/14/2248023.html jQuery源码分析(版本1.6.1) 目录 00 前言开光 0 ...

  8. 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  9. jQuery1.6.1源码分析系列(作者:nuysoft/高云)

    作者:nuysoft/高云 QQ:47214707 Email:nuysoft@gmail.com jQuery源码分析(版本1.6.1) 00 前言开光 01 总体架构 02 正则表达式-RegEx ...

随机推荐

  1. 初识JAVA,对servlet的理解

    一.WEB开发的简单理解 Web开发是一个指代网页或站点编写过程的广义术语.网页使用 HTML.CSS 和 JavaScript编写.这些页面可能是类似于文档的简单文本和图形.页面也能够是交互式的,或 ...

  2. 谈论multistage text input(中国输入法)下一个UITextView内容长度的限制

    我以前写<如何更好地限制UITextField输入长度>.接使用 UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotifica ...

  3. Codeforces Round #256 (Div. 2) 题解

    Problem A: A. Rewards time limit per test 1 second memory limit per test 256 megabytes input standar ...

  4. Material Master

    02-03 03: 物料主的定义:相同的物料应该是同一个物料号. 在PP放面我们主要关心的是工厂 . 定义公司后在公司下面在定义工厂. spro配置的时候我们可以在.后勤.物料管理.物料.创建: 后勤 ...

  5. 监控apache虚拟主机进程

    mod_status模块能输出例如以下内容: 正在伺服请求的工作者(线程或进程)数量 空暇的工作者数量 每一个工作者的状态:已完毕的请求数.已发送的字节数.(*) 总訪问数和已发送的字节总数(*) s ...

  6. C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。

    在C语言操作中会用到大量的内存操作,当中非经常常使用的一个是realloc(). 由字面意思能够知道,该函数的作用是用于又一次分配内存. 使用方式例如以下: NewPtr=(数据类型*)realloc ...

  7. iOS Dev (60) 怎样实现 UITextView 中的 placeHolder

    iOS Dev (60) 怎样实现 UITextView 中的 placeHolder 作者:阿锐 地址:http://blog.csdn.net/prevention - 跟着你的 UITextVi ...

  8. 《转》在win7,boa-constructor 0.6.1 的palette面板中没有控件图标的解决方法

    原地址:http://blog.csdn.net/rickleo/article/details/6532595 在win7-64bit环境下,boa-constructor 0.6.1 的palet ...

  9. 访何红辉:谈谈Android源码中的设计模式

    最近Android 6.0版本的源代码开放下载,刚好分析Android源码的技术书籍<Android源码设计模式解析与实战>上市,我们邀请到它的作者何红辉,来谈谈Android源码中的设计 ...

  10. Java Web----Java Web的数据库操作(二)

    Java Web的数据库操作 三.JDBC操作数据库 上一篇介绍了JDBC API,之后就可以通过API来操作数据库,实现对数据库的CRUD操作了. http://blog.csdn.net/zhai ...