我正在为我自己的问题添加一个答案。
希望能看到更好的答案...
我找到了使用两个 IPP 功能的解决方案:
我选择了使用定点数学的函数,以获得更好的性能。
- 缩放的定点实现
0.859
是通过扩展、缩放和移位来实现的。示例:b = (a*scale + (1<<7)) >> 8;
[当scale
= (0.859)*2^8
]。
val
参数ippsMulC_8u_Sfs
设置为round(0.859*2^8)
= 220
。要设置的
scaleFactor
参数(将缩放结果除以)。ippsMulC_8u_Sfs
8
2^8
代码示例:
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);
}
题外话:
有一种方法可以将视频流标记为“全范围”(其中Y
范围是 [0, 255] 而不是 [ 16
, 235
],并且U
范围V
也是 [0, 255])。
使用“全范围”标准可以I
代替Y
(即Y = I)。
使用 Intel Media SDK 将流标记为“全范围”是可能的(但没有很好的记录)。
将 H.264 流标记为“全范围”需要添加指向mfxExtBuffer **ExtParam
列表的指针(在结构中mfxVideoParam
):
指向结构类型的指针mfxExtVideoSignalInfo
应添加以下值:
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
是设置“全范围”视频的唯一相关参数,但我们必须填充整个结构。