I am adding an answer to my own question.
I hope to see a better answer...
I found a solution using two IPP functions:
I selected functions that uses fixed point math, for better performance.
- Fixed point implementation of
0.859
scaling is performed by expanding, scaling and shifting. Example: b = (a*scale + (1<<7)) >> 8;
[When scale
= (0.859)*2^8
].
val
parameter to ippsMulC_8u_Sfs
set to round(0.859*2^8)
= 220
.
scaleFactor
parameter to ippsMulC_8u_Sfs
set to 8
(divide the scaled result by 2^8
).
Code sample:
void GrayscaleToNV12(const unsigned char I[],
int image_width,
int image_height,
unsigned char J[])
{
IppStatus ipp_status;
const int image_size = image_width*image_height;
unsigned char *UV = &J[image_size]; //In NV12 format, UV plane starts below Y.
const Ipp8u expanded_scaling = (Ipp8u)(0.859 * 256.0 + 0.5);
//J[x] = (expanded_scaling * I[x] + 128u) >> 8u;
ipp_status = ippsMulC_8u_Sfs(I, //const Ipp8u* pSrc,
expanded_scaling, //Ipp8u val,
J, //Ipp8u* pDst,
image_size, //int len,
8); //int scaleFactor);
//Check ipp_status, and handle errors...
//J[x] += 16;
//ippsAddC_8u_ISfs is deprecated, I used it to keep the code simple.
ipp_status = ippsAddC_8u_ISfs(16, //Ipp8u val,
J, //Ipp8u* pSrcDst,
image_size, //int len,
0); //int scaleFactor);
//Check ipp_status, and handle errors...
//2. Fill all UV plane with 128 value - "gray color".
memset(UV, 128, image_width*image_height/2);
}
Out of topic note:
There is a way to mark a video stream as "full range" (where Y
range is [0, 255] instead of [16
, 235
], and U
,V
range is also [0, 255]).
Using the "full range" standard allows placing I
in place of Y
(i.e Y = I).
Marking the stream as "full range" using Intel Media SDK, is possible (but not well documented).
Marking H.264 stream as "full range" requires to add pointer to mfxExtBuffer **ExtParam
list (in structure mfxVideoParam
):
A pointer to structure of type mfxExtVideoSignalInfo
should be added with the following values:
typedef struct {
mfxExtBuffer Header; //MFX_EXTBUFF_VIDEO_SIGNAL_INFO and sizeof(mfxExtVideoSignalInfo)
mfxU16 VideoFormat; //Most likely 5 ("Unspecified video format")
mfxU16 VideoFullRange; //1 (video_full_range_flag is equal to 1)
mfxU16 ColourDescriptionPresent; //0 (description_present_flag equal to 0)
mfxU16 ColourPrimaries; //0 (no affect when ColourDescriptionPresent = 0)
mfxU16 TransferCharacteristics; //0 (no affect when ColourDescriptionPresent = 0)
mfxU16 MatrixCoefficients; //0 (no affect when ColourDescriptionPresent = 0)
} mfxExtVideoSignalInfo;
VideoFullRange = 1
is the only relevant parameter of setting "full range" video, but we must fill the entire structure.