5

Video encoders like Intel® Media SDK require NV12 video input format.

NV12 format is YUV 4:2:0 format ordered in memory with a Y plane first, followed by packed chroma samples in interleaved UV plane.

Example:
YYYYYY
YYYYYY
UVUVUV

enter image description here

RGB color format, refers to Pixel-Order RGB (byte per pixel, lower byte is Red):
RGBRGBRGBRGBRGB
RGBRGBRGBRGBRGB

enter image description here

I did some Web research, and found out that regarding NV12, YUV is defined as YCbCr color space. There are currently at least 2 possible YCbCr formats apply NV12:

My question is: Is there as IPP function that converts RGB color space to NV12?

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • @Rotem: please clarify whether you're looking for matlab answers, and if not, please make another edit to change the last sentence I added. (And remove the `[matlab]` tag) – Peter Cordes Jun 17 '16 at 23:38
  • Should I split the question into 3 different questions: 1. Using IPP, 2. Pain C Code, 3. SSE optimized code? – Rotem Jun 19 '16 at 16:48
  • 1
    If you wrote a highly specialised toolbox, GitHub is probably the better place for that. Self-Q/A works on Stack Overflow only if your question is on-topic. Yours are, as evident by the closure, much too broad. Either try and write it as a narrow-shaped question with properly explained answer (as opposed to a pure code dump) or create a GitHub page with your toolbox. – Adriaan Jun 19 '16 at 17:52
  • 3
    See it like this: you made one of the world's finest bicycles. If you want to promote it, a car show would be a bad place. Both are transportation vehicles, but of different kinds. For a great example of how a self-Q/A should look like on Stack Overflow I recommend you take a look at this one:http://stackoverflow.com/questions/32379805/linear-indexing-logical-indexing-and-all-that – Adriaan Jun 19 '16 at 18:08
  • OK, I gave the focus for the IPP solution. – Rotem Jun 19 '16 at 22:39
  • 3
    Looks like a decent self-answered question now - voting to re-open. – Paul R Jun 22 '16 at 14:51

1 Answers1

13

I found out that IPP function exists:

ippiRGBToYCbCr420_8u_C3P2R

It was hard to find, because the function name or description does not mention NV12.
The function uses BT.601 standard.

Here is a code sample for converting RGB to NV12 in BT.601 standard:

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...          
}



Converting RGB to NV12 with BT.709 standard:

As for 2019, BT.709 (HDTV) standard is probably more relevant than BT.601 (SDTV).

IPP lacks a function for direct conversion from RGB to NV12 in BT.709 standard.
There is a function that converts BGR to NV12.
The solution includes two stages:

  1. Convert from RGB to BGR (swap channels).
    Code sample uses ippiSwapChannels_8u_C3R for RGB to BGR conversion.
  2. Convert from BGR to NV12.
    Code sample uses ippiBGRToYCbCr420_709CSC_8u_C3P2R for BGR to NV12 conversion.

The sample function requires some extra memory space for storing the intermediate BGR image.
A pointer to the sketch memory is passed to the function (the memory should be allocated outside the function).

Here is a code sample for converting RGB to NV12 in BT.709 standard:

//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...
}
Rotem
  • 30,366
  • 4
  • 32
  • 65
  • 1
    My optimized implementation in C (vectorized using SSE intrinsics) can be found here: [https://github.com/cohenrotem/Rgb2NV12](https://github.com/cohenrotem/Rgb2NV12). – Rotem Sep 26 '16 at 21:22