PDA

View Full Version : WPF supports only PBGRA format



Korhak
05-10-2018, 08:37 AM
Hello,

when working with WPF.SendContainer, you are not converting the format of the rendered bitmap. As we can see in this code


targetBitmap = new RenderTargetBitmap(xres, yres, 96, 96, PixelFormats.Pbgra32);
targetBitmap.Render(this.Child);
You can't render your UIElements (like grid or canvas) in other format than PGBRA32. Microsoft programmed it this way unfortunatelly. As long as you are receiving in WPF, it doesn't matter. But I haven't met a commeracial receiver made in c#.
Since the desired format for sending video is just BGRA, in WPF you gotta unmultiply it yourself. Like this


private void ToBgra(int xres, int yres, byte[] buffer)
{
for (int y = 0; y < yres; y++)
{
for (int x = 0; x < xres; x++)
{
// Calculate array offset for this pixel
int offset = y * _stride + x * 4;
int alpha = buffer[offset + 3];

//Optimizaion for fully transparent pixel
if (alpha == 255)
{
continue;
}

// Extract individual color channels from pixel value
int b = buffer[offset];
int g = buffer[offset + 1];
int r = buffer[offset + 2];


// Remove premultiplication
if (alpha > 0)
{
r = r * 255 / alpha;
g = g * 255 / alpha;
b = b * 255 / alpha;
}

// Write color channels in desired order
buffer[offset] = (byte)b;
buffer[offset + 1] = (byte)g;
buffer[offset + 2] = (byte)r;
}
}
}

It would be good to at least have this function in the SDK for others starting to avoid confusion. If possible, could you add some support to your c++ libraries for faster processing? Or am I missing something?

John Perkins
05-11-2018, 09:21 AM
You're 100% correct on this. I'll be changing the example to include something similar.

I've made it optional because there is overhead in changing so many pixels one at a time and I took a slightly different approach so that we might gain a bit of speed from Microsoft's implementation.

If you don't need the alpha or if you have no partially transparent areas, you could leave UnPremultiply set to false and save a few CPU cycles.


if (UnPremultiply)
{
FormatConvertedBitmap fmtConvertedBmp = new FormatConvertedBitmap();
fmtConvertedBmp.BeginInit();
fmtConvertedBmp.Source = targetBitmap;
fmtConvertedBmp.DestinationFormat = PixelFormats.Bgra32;
fmtConvertedBmp.EndInit();

fmtConvertedBmp.CopyPixels(new Int32Rect(0, 0, xres, yres), bufferPtr, bufferSize, stride);
}
else
{
// copy the pixels into the buffer
targetBitmap.CopyPixels(new Int32Rect(0, 0, xres, yres), bufferPtr, bufferSize, stride);
}

Thanks, that was a good find.