5

英特尔® Media SDK 等视频编码器需要 NV12 视频输入格式。

NV12 格式是在内存中排序的 YUV 4:2:0 格式,首先是 Y 平面,然后是交错 UV 平面中的打包色度样本。

例子:
YYYYYY
YYYYYY
UVUVUV

在此处输入图像描述

RGB 颜色格式,指 Pixel-Order RGB(每像素字节,低字节为红色):
RGBRGBRGBRGBRGB
RGBRGBRGBRGBRGB

在此处输入图像描述

我做了一些网络研究,发现关于 NV12,YUV被定义为 YCbCr 颜色空间。目前至少有 2 种可能的 YCbCr 格式适用于 NV12:

  • BT.601 - 适用于标清电视
  • BT.709 - 适用于高清电视

我的问题是:是否有将 RGB 颜色空间转换为 NV12的IPP功能?

4

1 回答 1

12

我发现存在IPP功能:

ippiRGBToYCbCr420_8u_C3P2R

很难找到,因为函数名称或描述没有提到 NV12。
该功能使用BT.601标准。

以下是BT.601标准 中将RGB转换为NV12的代码示例:

void Rgb2NV12(const unsigned char I[], int image_width, int image_height, unsigned char J[])
{
    IppStatus ipp_status;
    int srcStep = image_width*3;
    int dstYStep = image_width;
    int dstCbCrStep = image_width;
    IppiSize roiSize = {image_width, image_height};

    const Ipp8u* pSrc = (Ipp8u*)I;

    Ipp8u *pDstY    = (Ipp8u*)J;                            //Y color plane is the first image_width*image_height pixels of J.
    Ipp8u *pDstCbCr = (Ipp8u*)&J[image_width*image_height]; //In NV12 format, UV plane starts below Y.

    ipp_status = ippiRGBToYCbCr420_8u_C3P2R(pSrc, srcStep, pDstY, dstYStep, pDstCbCr, dstCbCrStep, roiSize);

    //if (ipp_status != ippStsNoErr), Handle errors...          
}



使用 BT.709 标准将 RGB 转换为 NV12:

至于 2019 年,BT.709(HDTV)标准可能比 BT.601(SDTV)更相关。

IPP 在 BT.709 标准中缺少将 RGB 直接转换为 NV12 的功能。
有一个函数可以将BGR转换为NV12
解决方案包括两个阶段:

  1. RGB转换为BGR(交换通道)。
    代码示例ippiSwapChannels_8u_C3R用于RGBBGR的转换。
  2. BGR转换为NV12
    代码示例ippiBGRToYCbCr420_709CSC_8u_C3P2R用于BGRNV12 的转换。

示例函数需要一些额外的内存空间来存储中间 BGR 图像。
指向草图内存的指针被传递给函数(内存应该在函数外部分配)。

以下是BT.709标准 中将RGB转换为NV12的代码示例:

//sketch_buff - Temporary buffer for storing image in BGR format.
//              Size of sketch_buff must be at least image_width*image_height*3 bytes.
void Rgb2NV12_709(const unsigned char I[],
                  const int image_width, 
                  const int image_height,
                  unsigned char sketch_buff[],
                  unsigned char J[])
{
    IppStatus ipp_status;    
    int srcStep = image_width*3;
    int dstBgrStep = image_width*3;
    int dstYStep = image_width;
    int dstCbCrStep = image_width;
    IppiSize roiSize = {image_width, image_height};

    const Ipp8u* pRGB = (Ipp8u*)I;
    Ipp8u* pBGR = (Ipp8u*)sketch_buff; //BGR image is stored in sketch_buff
    Ipp8u *pDstY    = (Ipp8u*)J;                            //Y color plane is the first image_width*image_height pixels of J.
    Ipp8u *pDstCbCr = (Ipp8u*)&J[image_width*image_height]; //In NV12 format, UV plane starts below Y.

    const int bgrOrder[3] = {2, 1, 0};

    //Swap Red and Blue color channels - convert from RGB to BGR
    //Store the result into sketch_buff (sketch buffer is allocated outside the function)
    ipp_status = ippiSwapChannels_8u_C3R(pRGB, srcStep, pBGR, dstBgrStep, roiSize, bgrOrder);

    //if (ipp_status != ippStsNoErr), Handle errors...

    //Convert BGR to NV12 in BT.709 standard
    ipp_status = ippiBGRToYCbCr420_709CSC_8u_C3P2R(pBGR, srcStep, pDstY, dstYStep, pDstCbCr, dstCbCrStep, roiSize);

    //if (ipp_status != ippStsNoErr), Handle errors...
}
于 2016-06-11T21:41:15.877 回答