iOS|iOS YUV数据与RGBA数据互转
在iOS视频开发的时候,我们会遇到YUV与RGBA数据转换的需求,解决这个需求我们有许多方法,我们可以自己根据公式写转换函数,可以使用第三方,也可以使用系统库实现。后附demo。
1、自己实现转换函数
一般情况下是遍历YUV数据生成RGBA数据,或者遍历RGBA数据生成YUV数据。普通函数是由CPU执行,执行时间和数据的大小成正相关。如果不是专家级人物,性能是没有第三方和系统的快的。
转换公式如下:
1.小数形式,未量化(U~[-0.5-0.5],R~[0,1])
R = Y + 1.4075 * V;
G = Y - 0.3455 * U - 0.7169*V;
B = Y + 1.779 * U;
Y = 0.299*R + 0.587*G + 0.114*B;
U = (B-Y)/1.772;
V = (R-Y)/1.402;
或写为:Y =0.299*R + 0.587*G + 0.114*B;
U = -0.169*R - 0.331*G + 0.5*B ;
V =0.5*R - 0.419*G - 0.081*B;
相关详细资料参考如下博客:
https://www.cnblogs.com/luoyinjie/p/7219319.html
2、第三方库 第三方库有比较多的库,我们熟悉的ffmpeg可以做yuv和rgba的数据转换,另外还有一个比较出名的libyuv库也可以做各种像素格式转换。这里我们介绍libyuv库。
Libyuv库在文章末尾的demo里面已经编译好,可以直接使用,需要的朋友可以直接下载。
Libyuv使用比较简单,引入头文件直接调用函数即可,比如YUV转RGBA的函数如下:
#import "libyuv.h"int I420ToRGBA(const uint8* src_y,
int src_stride_y,
const uint8* src_u,
int src_stride_u,
const uint8* src_v,
int src_stride_v,
uint8* dst_rgba,
int dst_stride_rgba,
int width,
int height);
前面几个数据为yuv数据源,后面两个参数为RGBA数据地址,最后面填写的是图像的宽高。RGBA转YUV函数如下:
#import "libyuv.h"int RGBAToI420(const uint8* src_frame,
int src_stride_frame,
uint8* dst_y,
int dst_stride_y,
uint8* dst_u,
int dst_stride_u,
uint8* dst_v,
int dst_stride_v,
int width,
int height);
参数同上。需要注意的是,目标数据的指针需要提前分配好内存空间,转换函数不进行空间分配。
Ffmpeg数据转换的这里不说了,可以参考:https://github.com/XMSECODE/FFMPEG_STUDY
3、系统库转换 系统库转换是速度最快的,消耗性能最少的。如可以满足需求,建议使用系统库进行转换。
iOS系统提供了Accelerate库进行复杂计算操作,可以大量提高计算性能。提供的计算功能比较多,其中有一项功能就是提供图像数据格式转换。过程如下:
初始化缓存区-》创建转换器对象-》转换数据
a、初始化缓存区 我们这里示例YUV转换RGBA,RGBA转换YUV过程也是一样的,demo里有详细代码。
buffer结构体如下:
typedef struct vImage_Buffer
{
void*data;
/* Pointer to the top left pixel of the buffer.*/
vImagePixelCountheight;
/* The height (in pixels) of the buffer*/
vImagePixelCountwidth;
/* The width (in pixels) of the buffer*/
size_trowBytes;
/* The number of bytes in a pixel row, including any unused space between one row and the next. */
}vImage_Buffer;
Buffer初始化函数如下,对于需要转换的数据可以直接对结构体赋值,对于存储目标数据的结构体才需要使用初始化函数进行初始化。
VIMAGE_PF vImage_ErrorvImageBuffer_Init( vImage_Buffer *buf,
vImagePixelCountheight,
vImagePixelCountwidth,
uint32_tpixelBits,
vImage_Flagsflags)
b、创建转换器对象 创建转换器的函数如下:
VIMAGE_PF vImage_Error vImageConvert_YpCbCrToARGB_GenerateConversion(const vImage_YpCbCrToARGBMatrix *matrix, const vImage_YpCbCrPixelRange *pixelRange, vImage_YpCbCrToARGB *outInfo, vImageYpCbCrType inYpCbCrType, vImageARGBType outARGBType, vImage_Flags flags) VIMAGE_NON_NULL(1,2,3) API_AVAILABLE(macos(10.10), ios(8.0), watchos(1.0), tvos(8.0));
我们的代码调用过程如下:
vImage_YpCbCrToARGB infoyuvoargb;
vImage_YpCbCrPixelRange range;
range.Yp_bias = 16;
range.CbCr_bias = 128;
range.YpRangeMax = 235;
range.CbCrRangeMax = 240;
range.YpMax = 235;
range.YpMin = 16;
range.CbCrMax = 240;
range.CbCrMin = 16;
vImageConvert_YpCbCrToARGB_GenerateConversion(kvImage_YpCbCrToARGBMatrix_ITU_R_601_4, &range, &infoyuvoargb, kvImage420Yp8_Cb8_Cr8, kvImageARGB8888, kvImageNoFlags);
c、转换数据 转换数据也为一个函数,如下:
VIMAGE_PF vImage_Error vImageConvert_420Yp8_Cb8_Cr8ToARGB8888(const vImage_Buffer *srcYp, const vImage_Buffer *srcCb, const vImage_Buffer *srcCr, const vImage_Buffer *dest, const vImage_YpCbCrToARGB *info, const uint8_t permuteMap[4], const uint8_t alpha, vImage_Flags flags) VIMAGE_NON_NULL(1,2,3,4,5) API_AVAILABLE(macos(10.10), ios(8.0), watchos(1.0), tvos(8.0));
我们调用如下:
vImage_Error result = vImageConvert_420Yp8_Cb8_Cr8ToARGB8888(&srcsBuff_y, &srcsBuff_v, &srcsBuff_u, &argbBuff, &infoyuvoargb, NULL, 255, kvImagePrintDiagnosticsToConsole);
【iOS|iOS YUV数据与RGBA数据互转】随后我们就可以从argbBuff中取出转换后的数据,到此转换完成。
demo地址:https://github.com/XMSECODE/ESCLibyuvDemo
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- 2020-04-07vue中Axios的封装和API接口的管理
- iOS中的Block
- 使用协程爬取网页,计算网页数据大小
- Java|Java基础——数组
- Python数据分析(一)(Matplotlib使用)
- Jsr303做前端数据校验
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片
- Spark|Spark 数据倾斜及其解决方案
- 数据库设计与优化