My app uses IDirect3DDevice9Ex_StretchRect
to copy image from NV12 surface into D3DFMT_X8R8G8B8 surface. But the result image has lower contrast than the original.
Test setup: My source image comes from USB webcam, completely covered – it gives me almost black.
- Test A: I run the Windows Camera app, take a screenshot and measure the black color in a image editor, I get exact RGB:(9,9,9).
- Test B: I open the cam in my cam, it captures YUY2, then converts into NV12. I get a sample of the NV12 image, and run my own conversion code (see below). This way, I get also almost black image, in the test case the pixel colors are again RGB: (9,9,9). So, I think my captured image is the same as from Camera app, and also that my YUV/RGB conversion is correct.
- Test C: The same as before, but instead of converting NV12 myself, my code is calling
IDirect3DDevice9Ex_StretchRect()
to copy the image into the RGB surface. There I access pixel data directly (LockRect) and there I find the pixels with color RGB: (24,24,24), so much brighter – and that I think is incorrect
Here is snipped of my own conversion code (this conversion is in C#):
// https://stackoverflow.com/questions/17678685/nv12-format-support-in-bitmapimage-c-sharp
//// https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx
//// https://en.wikipedia.org/wiki/YUV
var c = y - 16;
var d = v - 128;
var e = u - 128;
c = c < 0 ? 0 : c;
var r = ((298 * c) + (409 * e) + 128) >> 8;
var g = ((298 * c) - (100 * d) - (208 * e) + 128) >> 8;
var b = ((298 * c) + (516 * d) + 128) >> 8;
*destPtrR = clip(r);
*destPtrG = clip(g);
*destPtrB = clip(b);
The entire solution is very complex, there is a .NET/C#/WPF app, GStreamer running the multimedia pipeline is driven by C++ code, there is a custom rendering GST element based on D3D9. It copies the image frames into a swapchain's backbuffer and that is then presented into D3DImage. Anyway, my tests lead me into conclusion that IDirect3DDevice9Ex_StretchRect
does something I am not expecting. Like gamma correction? But the app is windowed (so gamma ramp should not be used) and I am not calling IDirect3DSwapChain9_Present()
at all...
Can I change the behavior by changing some flag etc?
Note: I am not author the code around D3D9 and I am a beginner in DirectX programming