使用Direct3D 9在硬件中将RGB表面转换为YUV

时间:2018-07-20 03:50:47

标签: c++ c windows directx direct3d

我有一个ARGB Direct3D9曲面,需要将其扫成相同尺寸的UYVY曲面。两个表面都在系统内存中。我该怎么做?

  

UpdateSurface和StretchRect失败。

如果需要,我愿意使用纹理代替表面。

这必须在GPU中完成,即使用硬件加速。

1 个答案:

答案 0 :(得分:0)

DirectXTex中有执行所有这些转换的代码,您可以参考这些代码。传统的Direct3D 9 D3DFMT_UYVY格式与DXGI_FORMAT_YUY2相同,但有一些通道混乱。

这些格式在每个图像像素中编码两个可见像素:

struct XMUBYTEN4 { // DirectXMath data type
  uint8_t x;
  uint8_t y;
  uint8_t z;
  uint8_t w;
};

XMUBYTEN4 rgb1, rgb2 = // Input pixel pair

int y0 = ((66 * rgb1.x + 129 * rgb1.y + 25 * rgb1.z + 128) >> 8) + 16;
int u0 = ((-38 * rgb1.x - 74 * rgb1.y + 112 * rgb1.z + 128) >> 8) + 128;
int v0 = ((112 * rgb1.x - 94 * rgb1.y - 18 * rgb1.z + 128) >> 8) + 128;

int y1 = ((66 * rgb2.x + 129 * rgb2.y + 25 * rgb2.z + 128) >> 8) + 16;
int u1 = ((-38 * rgb2.x - 74 * rgb2.y + 112 * rgb2.z + 128) >> 8) + 128;
int v1 = ((112 * rgb2.x - 94 * rgb2.y - 18 * rgb2.z + 128) >> 8) + 128;

对于DXGI_FORMAT_YUY2,您可以使用:

XMUBYTEN4 *dPtr = // Output pixel pair

dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));
dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));

对于D3DFMT_UYVY,您可以使用:

dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));
dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));