Skip to content

Commit

Permalink
Add mirror, flip, swap options
Browse files Browse the repository at this point in the history
Add options for image mirror, flip and swap (RGB <> BGR)
Requires SpoutCamSettings - Version 2.005 or greater
Verson 2.017
  • Loading branch information
leadedge committed Oct 6, 2020
1 parent f14c8e6 commit 2cf47fb
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 27 deletions.
61 changes: 48 additions & 13 deletions SpoutDX/source/SpoutCopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
07.09.20 - experimental SSE RGBA to RGB not working
19.09.20 - Removed experimental SSE RGBA to RGB function
23.09.20 - CheckSSE - initialize CPUInfo
06.10.20 - Modifications to rgba2rgb and rgba2rgbResample for SpoutCam mirror and swap red/blue
*/
#include "SpoutCopy.h"
Expand Down Expand Up @@ -588,7 +589,7 @@ void spoutCopy::bgr2bgra(const void *bgr_source, void *bgra_dest, unsigned int w

void spoutCopy::rgba2rgb(const void *rgba_source, void *rgb_dest,
unsigned int width, unsigned int height,
unsigned int rgba_pitch, bool bInvert) const
unsigned int rgba_pitch, bool bInvert, bool bMirror, bool bSwapRB) const
{
// RGB dest does not have padding
const unsigned long rgbsize = width * height * 3;
Expand All @@ -606,14 +607,30 @@ void spoutCopy::rgba2rgb(const void *rgba_source, void *rgb_dest,
rgb -= rgbpitch; // beginning of the last rgb line
}

// Swap red and blue option
int ir = 0; int ig = 1; int ib = 2;
if(bSwapRB) {
ir = 2; ib = 0;
}

unsigned int z = 0;
for (unsigned int y = 0; y < height; y++) {
for (unsigned int x = 0; x < width; x++) {
*(rgb + 0) = *(rgba + 0); // red
*(rgb + 1) = *(rgba + 1); // grn
*(rgb + 2) = *(rgba + 2); // blu
rgb += 3;
if (bMirror) {
z = (width - x - 1)*3;
*(rgb + z + ir) = *(rgba + 0); // red
*(rgb + z + ig) = *(rgba + 1); // grn
*(rgb + z + ib) = *(rgba + 2); // blu
}
else {
z = x * 3;
*(rgb + z + ir) = *(rgba + 0); // red
*(rgb + z + ig) = *(rgba + 1); // grn
*(rgb + z + ib) = *(rgba + 2); // blu
}
rgba += 4;
}
rgb += width * 3;
rgba += rgba_padding;

if (bInvert)
Expand Down Expand Up @@ -828,28 +845,46 @@ void spoutCopy::rgba2rgbaResample(const void* source, void* dest,

void spoutCopy::rgba2rgbResample(const void* source, void* dest,
unsigned int sourceWidth, unsigned int sourceHeight, unsigned int sourcePitch,
unsigned int destWidth, unsigned int destHeight, bool bInvert) const
unsigned int destWidth, unsigned int destHeight, bool bInvert, bool bMirror, bool bSwapRB) const
{
unsigned char *srcBuffer = (unsigned char *)source; // bgra source
unsigned char *dstBuffer = (unsigned char *)dest; // bgr dest

float x_ratio = (float)sourceWidth / (float)destWidth;
float y_ratio = (float)sourceHeight / (float)destHeight;

// Swap red and blue option
int ir = 0; int ig = 1; int ib = 2;
if (bSwapRB) {
ir = 2; ib = 0;
}

float px, py;
unsigned int i, j;
unsigned int pixel, nearestMatch;
for (i = 0; i < destHeight; i++) {
for (j = 0; j < destWidth; j++) {
px = floor((float)j*x_ratio);
py = floor((float)i*y_ratio);
if (bInvert)
pixel = (destHeight - i - 1)*destWidth * 3 + j * 3; // flip vertically
else
pixel = i * destWidth * 3 + j * 3;

if (bMirror) {
if (bInvert)
pixel = (destHeight - i - 1)*destWidth * 3 + (destWidth - j - 1) * 3; // flip vertically
else
pixel = i * destWidth * 3 + (destWidth - j - 1) * 3;
}
else {
if (bInvert)
pixel = (destHeight - i - 1)*destWidth * 3 + j * 3; // flip vertically
else
pixel = i * destWidth * 3 + j * 3;
}

nearestMatch = (unsigned int)(py*sourcePitch + px * 4);
dstBuffer[pixel + 0] = srcBuffer[nearestMatch + 0];
dstBuffer[pixel + 1] = srcBuffer[nearestMatch + 1];
dstBuffer[pixel + 2] = srcBuffer[nearestMatch + 2];

dstBuffer[pixel + ir] = srcBuffer[nearestMatch + 0];
dstBuffer[pixel + ig] = srcBuffer[nearestMatch + 1];
dstBuffer[pixel + ib] = srcBuffer[nearestMatch + 2];
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions SpoutDX/source/SpoutCopy.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ class SPOUT_DLLEXP spoutCopy {

// Copy RGBA to RGB allowing for source line pitch
void rgba2rgb (const void* rgba_source, void *rgb_dest, unsigned int width, unsigned int height,
unsigned int sourcePitch, bool bInvert = false) const;
unsigned int sourcePitch, bool bInvert = false, bool bMirror = false, bool bSwapRB = false) const;
// Copy RGBA to RGB allowing for source and destination pitch
void rgba2rgbResample(const void* source,void* dest,
void rgba2rgbResample(const void* source, void* dest,
unsigned int sourceWidth, unsigned int sourceHeight, unsigned int sourcePitch,
unsigned int destWidth, unsigned int destHeight, bool bInvert = false) const;
unsigned int destWidth, unsigned int destHeight,
bool bInvert = false, bool bMirror = false, bool bSwapRB = false) const;
// Copy RGBA to BGR allowing for source line pitch
void rgba2bgr(const void* rgba_source, void *rgb_dest, unsigned int width, unsigned int height,
unsigned int sourcePitch, bool bInvert = false) const;
Expand Down
20 changes: 16 additions & 4 deletions SpoutDX/source/SpoutDX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
// - Replace ReadRGBAimage, ReadRGBimage, ReadRGBApixels, ReadRGBpixels
// with ReadPixelData and rgb flag
// 06.10.20 - Allow for DX9 shared textures by creating receiving texture with compatible format
// - Mirror and swap red/blue options for SpoutCam via class flags m_bMirror, and m_bSwapRB
// Modifications to SpoutCopy rgba2rgb and rgba2rgbResample
//
// ====================================================================================
/*
Expand Down Expand Up @@ -128,6 +130,8 @@ spoutDX::spoutDX()
m_bSpoutPanelOpened = false;
m_bSpoutPanelActive = false;
m_bClassDevice = false;
m_bMirror = false;
m_bSwapRB = false;
ZeroMemory(&m_SenderInfo, sizeof(SharedTextureInfo));
ZeroMemory(&m_ShExecInfo, sizeof(m_ShExecInfo));

Expand Down Expand Up @@ -544,7 +548,8 @@ bool spoutDX::ReceiveTexture(ID3D11Texture2D** ppTexture)

// Receive from a sender via DX11 staging textures to an rgba or rgb buffer of variable size
// A new shared texture pointer (m_pSharedTexture) is retrieved if the sender changed
bool spoutDX::ReceiveImage(unsigned char * pixels, unsigned int width, unsigned int height, bool bRGB, bool bInvert)
bool spoutDX::ReceiveImage(unsigned char * pixels,
unsigned int width, unsigned int height, bool bRGB, bool bInvert)
{
// Make sure DirectX is initialized
if (!OpenDirectX11())
Expand Down Expand Up @@ -960,7 +965,13 @@ bool spoutDX::ReadPixelData(ID3D11Texture2D* pStagingTexture, unsigned char* pix
// Copy the staging texture pixels to the user buffer
if (!bRGB) {
// RGBA buffer
spoutcopy.rgba2rgba(mappedSubResource.pData, pixels, width, height, mappedSubResource.RowPitch, bInvert);
// TODO : test rgba-rgba resample
if (width != m_Width || height != m_Height) {
spoutcopy.rgba2rgbaResample(mappedSubResource.pData, pixels, m_Width, m_Height, mappedSubResource.RowPitch, width, height, bInvert);
}
else {
spoutcopy.rgba2rgba(mappedSubResource.pData, pixels, width, height, mappedSubResource.RowPitch, bInvert);
}
}
else if (m_dwFormat == 28) {
// RGB buffer
Expand All @@ -973,12 +984,13 @@ bool spoutDX::ReadPixelData(ID3D11Texture2D* pStagingTexture, unsigned char* pix
}
}
else {
// Used for SpoutCam to receive RGB images
if (width != m_Width || height != m_Height) {
spoutcopy.rgba2rgbResample(mappedSubResource.pData, pixels, m_Width, m_Height, mappedSubResource.RowPitch, width, height, bInvert);
spoutcopy.rgba2rgbResample(mappedSubResource.pData, pixels, m_Width, m_Height, mappedSubResource.RowPitch, width, height, bInvert, m_bMirror, m_bSwapRB);
}
else {
// Approx 5 msec at 1920x1080
spoutcopy.rgba2rgb(mappedSubResource.pData, pixels, m_Width, m_Height, mappedSubResource.RowPitch, bInvert);
spoutcopy.rgba2rgb(mappedSubResource.pData, pixels, m_Width, m_Height, mappedSubResource.RowPitch, bInvert, m_bMirror, m_bSwapRB);
}
}

Expand Down
4 changes: 4 additions & 0 deletions SpoutDX/source/SpoutDX.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ class SPOUT_DLLEXP spoutDX {
spoutDirectX spoutdx;
spoutCopy spoutcopy;

// Options used for SpoutCam
bool m_bMirror; // Mirror image
bool m_bSwapRB; // RGB <> BGR

protected :

ID3D11Device* m_pd3dDevice;
Expand Down
Binary file modified release/win32/SpoutCam32.ax
Binary file not shown.
Binary file modified release/x64/SpoutCam64.ax
Binary file not shown.
40 changes: 33 additions & 7 deletions source/cam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@
06.10.20 Add "public IAMDroppedFrames" to the declaration of CVCamStream in "cam.h"
to prevent problems due to missing property dialog. Thanks to Valentin Schmidt.
Allow for receiving from DX9 senders in SpoutDX
Add options for image mirror, flip and swap (RGB <> BGR)
Requires SpoutCamSettings - Version 2.005 or greater
Verson 2.017
*/
Expand Down Expand Up @@ -514,6 +516,35 @@ CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
// (Memoryshare is not supported by DirectX)
bMemoryMode = receiver.GetMemoryShareMode();

//
// Options in SpoutCamSettings
//

DWORD dwMode = 0;
// Mirror image
ReadDwordFromRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "mirror", &dwMode);
if(dwMode > 0)
receiver.m_bMirror = true;
else
receiver.m_bMirror = false;

// RGB <> BGR
ReadDwordFromRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "swap", &dwMode);
if (dwMode > 0)
receiver.m_bSwapRB = true;
else
receiver.m_bSwapRB = false;

// Flip image
// Default is flipped due to upside down Windows bitmap
// If set false, the result comes out inverted
// bInvert = false;
ReadDwordFromRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "flip", &dwMode);
if (dwMode > 0)
bInvert = false;
else
bInvert = true;

m_Fps = dwFps;
m_Resolution = dwResolution;

Expand Down Expand Up @@ -727,12 +758,6 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms)
if(width == 0 || height == 0)
return NOERROR;

// LJ DEBUG
// DX9 mode not supported for SpoutCam DX11 version
// LJ DEBUG
// if (receiver.GetDX9())
// return NOERROR;

// Don't do anything if disconnected because it will already have connected
// previously and something has changed. It can only disconnect after it has connected.
if(!bDisconnected) {
Expand Down Expand Up @@ -767,7 +792,8 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms)

// Get bgr pixels from the sender bgra shared texture
// ReceiveImage handles sender detection, connection and copy of pixels
if (receiver.ReceiveImage(pData, g_Width, g_Height, true, true)) { // rgb = true (not rgba), invert = true
if (receiver.ReceiveImage(pData, g_Width, g_Height, true, bInvert)) {
// rgb(not rgba) = true, invert = true
// If IsUpdated() returns true, the sender has changed
if (receiver.IsUpdated()) {
if (strcmp(g_SenderName, receiver.GetSenderName()) != 0) {
Expand Down

0 comments on commit 2cf47fb

Please sign in to comment.