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.    */
    vImagePixelCount    height;       /* The height (in pixels) of the buffer        */
    vImagePixelCount    width;        /* The width (in pixels) of the buffer         */
    size_t              rowBytes;     /* The number of bytes in a pixel row, including any unused space between one row and the next. */
}vImage_Buffer;

Buffer初始化函数如下,对于需要转换的数据可以直接对结构体赋值,对于存储目标数据的结构体才需要使用初始化函数进行初始化。

VIMAGE_PF vImage_Error  vImageBuffer_Init( vImage_Buffer *         buf,
                                          vImagePixelCount        height,
                                          vImagePixelCount        width,
                                          uint32_t                pixelBits,
                                          vImage_Flags            flags)
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);

随后我们就可以从argbBuff中取出转换后的数据,到此转换完成。
demo地址:https://github.com/XMSECODE/ESCLibyuvDemo

你可能感兴趣的:(iOS YUV数据与RGBA数据互转)