Recursive Screen Recording Solution for desktop feedback loop!


#1

Hi!

I am desperately trying to create a program that captures the entire screen and displays that back into the window, hopefully creating a feedback loop with the intention of making a really good music video with my other windowing software

http://markfingerhut.com/index.php/computer/about/

I know this is possible in general, and I was wondering how you would go about converting the HBITMAP you get from this method :

http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen ( number 1)

into an ofImage for easy drawing / positioning?

I can supply much, much more of my code / methods / things I’ve tried if anyone sees this and wants to help.

Thanks!!! :slight_smile:

EDIT: THIS HAS BEEN SOLVED! SEE BELOW…


#2

I’ve also gotten the desktop image stored in a HDC device context object, I just don’t knoe the best way to load the pixels from it into an ofPixels object or an ofImage.

HDC hdc = GetDC(GetDesktopWindow()); // get the desktop device context

HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself

int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);

int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);

// create a bitmap
HBITMAP hbDesktop = CreateCompatibleBitmap(hdc, width, height);

// use the previously created device context with the bitmap
SelectObject(hDest, hbDesktop);

// copy from the desktop device context to the bitmap device context
// call this once per 'frame'
BitBlt(hDest, 0, 0, width, height, hdc, 0, 0, SRCCOPY);

//This is where I need to save it to an ofImage...

// after the recording is done, release the desktop context you got..
ReleaseDC(NULL, hdc);

// ..and delete the context you created
DeleteDC(hDest);

#3

I’m very surprised no one else is excited about getting this working… Imagine all the stuff you could do.


#4

I would guess you can also use syphon on osx and spout on windows to do this.


#5

Spout… Tell me about spout. I’m very familiar with syphon, but does spout have the ability to monitor the entire screen?


#6

Hi,
I’m not sure this can help you, because I wrote it a long time ago and I don’t remenber the details.
This is a part of a short program I used to capture the content of a window:

int captureScreen(AVFrame *pict, int width, int height) {

    HDC hSourceDC = GetDC(hSourceWindowWnd);
    HDC hCaptureDC = CreateCompatibleDC(hSourceDC);
    HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hSourceDC, sourceWidth, sourceHeight);
    SelectObject(hCaptureDC,hCaptureBitmap);
    StretchBlt(hCaptureDC, 0, height, width, - height, hSourceDC, 0, 0, width, height, SRCCOPY|CAPTUREBLT);

    BITMAPINFO bmi = {0};
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biWidth = sourceWidth;
    bmi.bmiHeader.biHeight = sourceHeight;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;

    int success = 0;
    // Here's the part that can interest you
    if ( GetDIBits(hCaptureDC, hCaptureBitmap, 0, height, pict->data[0], &bmi, DIB_RGB_COLORS) == 0) success = -1;
    if (success) {
        cout << "error: copy pixels failed" << flush;
    }

    ReleaseDC(hSourceWindowWnd,hSourceDC);
    DeleteDC(hCaptureDC);
    DeleteObject(hCaptureBitmap);

    return success;

}

This fonction copy the pixels from a window to an AVFrame, which is the struct holding an image for ffmpeg.
pict->data[0] is the first element of the pixels array, RGBRGBRGBRGB…

In your case, perhaps you can do the same thing, with an ofImage instead of an AVFrame.
Allocate an ofImage to the right dimension, call GetDIBits with your ofImage.getPixels(), or something like that?
Don’t forget to call the ofImage.update() method after this copy if you want to display it.


#7

wow! awesome suggestion!

So i gave it a shot this afternoon, however the resulting ofImage is all black, no matter how many times i call the capture function. How can I verify the buffers actually contain the pixels I want? Or how can I verify that all the copying went through ok?

This is what I’m running at the moment:

Let me know what you think!

ScreenCaptureWindow::ScreenCaptureWindow(WindowParameters * _p) : BaseWindow(_p)
{
transform->SetWindowSize(transform->SCR().x - 1, transform->SCR().y - 1);
ofSetEscapeQuitsApp(false);
}

void ScreenCaptureWindow::captureScreen(ofImage *pict, int width, int height) {

HDC hFromDC = GetDC(GetDesktopWindow());
HDC hToDC = CreateCompatibleDC(hFromDC);

HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hFromDC, sourceWidth, sourceHeight);
SelectObject(hToDC, hCaptureBitmap);
if(StretchBlt(hToDC, 0, 0, width, height, hFromDC, 0, 0, width, height, SRCCOPY | CAPTUREBLT) == 0) printf("stretch blt failed!\n");

BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = sourceWidth;
bmi.bmiHeader.biHeight = sourceHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

if (GetDIBits(hToDC, hCaptureBitmap, 0, height, (LPVOID)pict->getPixels()[0], &bmi, DIB_RGB_COLORS) == 0) cout << "error: copy pixels failed" << std::endl;

pict->update();

ReleaseDC(GetDesktopWindow(), hFromDC);
DeleteDC(hToDC);
DeleteObject(hCaptureBitmap);
}

ScreenCaptureWindow::~ScreenCaptureWindow()
{

}

void ScreenCaptureWindow::setup()
{
if (!InitializeTransparency()) std::cout << "Failed transparency!" << std::endl;
 sourceWidth = ofGetScreenWidth();
 sourceHeight = ofGetScreenHeight();

screenimg = new ofImage();
screenimg->allocate(sourceWidth, sourceHeight, OF_IMAGE_COLOR);

}

void ScreenCaptureWindow::update()
{
if (ofGetKeyPressed('q'))captureScreen(screenimg, sourceWidth, sourceHeight);
}

void ScreenCaptureWindow::draw()
{
screenimg->draw(20, 20);
ofSetColor(ofColor::aquamarine);
ofCircle(120, 120, 20, 20);
}

bool ScreenCaptureWindow::InitializeTransparency()
{

ofSetBackgroundColor(0, 0, 0, 0);
ofSetBackgroundAuto(true);
glEnable(GL_MULTISAMPLE);

#define MWT_MIN_FACTOR (0)
#define MWT_MAX_FACTOR (0xFF)

int fWidth = SCR().x;
int fHeight = SCR().y;
MARGINS margins = { -1 };
HWND hwnd = myWindow->getWin32Window();

SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLong(hwnd, -20, 524288 | 32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes(hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
DwmExtendFrameIntoClientArea(hwnd, &margins);

glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

glEnable(GL_BLEND);
glClearColor(0, 0, 0, 0);

DWM_BLURBEHIND bb = { 0 };
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hwnd, &bb);


return true;
}


void ScreenCaptureWindow::keyPressed(ofKeyEventArgs & _e)
{

}

#9

I used GDI once in my life, it’s far.
But are you sure about
HDC hFromDC = GetDC(GetDesktopWindow());
?

I read
GetDC(NULL);
in some screenshots samples, and that perhaps GetDesktopWindow() is not what you need.


#10

It didn’t work still. However that is most certainly a step closer. I still believe the problem lies in the dumping of the data from the DC into the ofPixels object.

Thank you SO much for your help with this.

Here is what my code looks like now:

ofImage* screenimg;

ScreenCaptureWindow::ScreenCaptureWindow(WindowParameters * _p) : BaseWindow(_p)
{
transform->SetWindowSize(transform->SCR().x - 100, transform->SCR().y - 100);

ofSetEscapeQuitsApp(false);
}

ScreenCaptureWindow::~ScreenCaptureWindow()
{

}

void ScreenCaptureWindow::setup()
{
//if (!InitializeTransparency()) std::cout << "Failed transparency!" << std::endl;
 sourceWidth = ofGetScreenWidth();
 sourceHeight = ofGetScreenHeight();

screenimg = new ofImage();
screenimg->allocate(sourceWidth, sourceHeight, OF_IMAGE_COLOR);

}

void ScreenCaptureWindow::keyPressed(ofKeyEventArgs & _e)
{
if (_e.key == 'q')
	captureScreen(screenimg, myWindow->getWidth(), myWindow->getHeight());
}

void ScreenCaptureWindow::captureScreen(ofImage *pict, int width, int height) {

HDC hFromDC = GetDC(NULL);
HDC hToDC = CreateCompatibleDC(hFromDC);

HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hFromDC, sourceWidth, sourceHeight);
SelectObject(hToDC, hCaptureBitmap);
if (StretchBlt(hToDC, 0, 0, width, height, hFromDC, 0, 0, sourceWidth, sourceHeight, SRCCOPY | CAPTUREBLT) == 0) printf("stretch blt failed!\n");

BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = sourceWidth;
bmi.bmiHeader.biHeight = sourceHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

if (GetDIBits(hToDC, hCaptureBitmap, 0, height, (LPVOID)pict->getPixels()[0], &bmi, DIB_RGB_COLORS) == 0) cout << "error: copy pixels failed" << std::endl;

pict->update();
printf("screen cap ok\n");

ReleaseDC(GetDesktopWindow(), hFromDC);
DeleteDC(hToDC);
DeleteObject(hCaptureBitmap);
}

void ScreenCaptureWindow::update()
{
}

void ScreenCaptureWindow::draw()
{
ofSetColor(255, 255, 255, 255);
screenimg->draw(20, 20);
ofSetColor(ofColor::aquamarine);
ofCircle(120, 120, 20, 20);
}

bool ScreenCaptureWindow::InitializeTransparency()
{

ofSetBackgroundColor(0, 0, 0, 0);
ofSetBackgroundAuto(true);
glEnable(GL_MULTISAMPLE);

#define MWT_MIN_FACTOR (0)
#define MWT_MAX_FACTOR (0xFF)

int fWidth = SCR().x;
int fHeight = SCR().y;
MARGINS margins = { -1 };
HWND hwnd = myWindow->getWin32Window();

SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLong(hwnd, -20, 524288 | 32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes(hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
DwmExtendFrameIntoClientArea(hwnd, &margins);

glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

glEnable(GL_BLEND);
glClearColor(0, 0, 0, 0);

DWM_BLURBEHIND bb = { 0 };
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hwnd, &bb);


return true;
return false;
}

#11

ALSO: Tbh, I dont even care if it gets put into an ofImage. I just want to draw it in my window. Becasue I have written a lot of wrapper code for the windows to give myself explicit control over them from one process. So if I can just Bitblt to my whole window, that would be fine too.


#12

BIG UPDATE: It works! kind of.

Now, it only works when the method is called by a key press… (???). Also, it is completely blocking, it seems that the background redraws over the data every frame, unless it stacks up by holding a key down to force the event method. interesting. This is why I’m in an of thread. It seems to be an issue with backgorund redraw of ofSetBackgroundAuto? I have it set to FALSE already. Here is the related code:

ofImage* screenimg;

ScreenCaptureWindow::ScreenCaptureWindow(WindowParameters * _p) : BaseWindow(_p)
{
transform->SetWindowSize(transform->SCR().x - 100, transform->SCR().y - 100);

ofSetEscapeQuitsApp(false);
}

void ScreenCaptureWindow::setup()
{
 sourceWidth = ofGetScreenWidth();
 sourceHeight = ofGetScreenHeight();

screenimg = new ofImage();
screenimg->allocate(sourceWidth, sourceHeight, OF_IMAGE_COLOR);

ofSetBackgroundAuto(false);
}

void ScreenCaptureWindow::update()
{
    //this gets called every frame but gets overwritten by the background draw....
    screenGrab();
}

void ScreenCaptureWindow::draw()
{
ofSetColor(255, 255, 255, 255);
screenimg->draw(0, 0);
}

void ScreenCaptureWindow::keyPressed(ofKeyEventArgs & _e)
{
captureScreen(screenimg, myWindow->getWidth(), myWindow->getHeight());
}

void ScreenCaptureWindow::captureScreen(ofImage *pict, int width, int height) {

HDC hFromDC = GetDC(NULL);
HDC hToDC = GetDC(myWindow->getWin32Window());

//HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hFromDC, sourceWidth, sourceHeight);
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hToDC, width, height);

SelectObject(hToDC, hCaptureBitmap);
if (StretchBlt(hToDC, 0, 0, width, height, hFromDC, 0, 0, sourceWidth, sourceHeight, SRCCOPY) == 0) printf("stretch blt failed!\n");

BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = sourceWidth;
bmi.bmiHeader.biHeight = sourceHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
int success = GetDIBits(hToDC, hCaptureBitmap, 0, height, (LPVOID)pict->getPixels()[0], &bmi, DIB_RGB_COLORS);

if (success == 0) cout << "error: copy pixels failed" << std::endl;
pict->update();
ReleaseDC(myWindow->getWin32Window(),hFromDC);
DeleteDC(hToDC);
DeleteObject(hCaptureBitmap);
}


void ScreenCaptureWindow::screenGrab()
{
captureScreen(screenimg, myWindow->getWidth(), myWindow->getHeight());
}

#13

Here is what we’re working towards. This is while I’m holding down a key though! We are so close, I can smell it…


#14

Hi,
I don’t understand very well what you are trying to achieve, and how you obtain this cool result picture, but I gave it a shot.
Because I don’t know how OF (and OpenGL) can deal with GDI drawing at the same time, I made a version which redraw the desktop in an ofImage. Colors are weird. But it’s possible to capture the desktop in update().

(the OF window is maximized in the background, and I display two others desktop apps in front of it)

void ofApp::setup()
{
    captureImg.allocate( 1920, 1080, OF_IMAGE_COLOR );
}

//--------------------------------------------------------------
void ofApp::update()
{
    int width = 1920;
    int height = 1080;
    HDC hSourceDC = GetDC( NULL );
    HDC hCaptureDC = CreateCompatibleDC( hSourceDC );
    HBITMAP hCaptureBitmap = CreateCompatibleBitmap( hSourceDC, width, height );
    SelectObject( hCaptureDC, hCaptureBitmap );
    StretchBlt( hCaptureDC, 0, height, width, - height, hSourceDC, 0, 0, width, height, SRCCOPY | CAPTUREBLT );

    BITMAPINFO bmi = {0};
    bmi.bmiHeader.biSize = sizeof( bmi.bmiHeader );
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biCompression = BI_RGB;

    int success = 0;
    if( GetDIBits( hCaptureDC, hCaptureBitmap, 0, height, (void*)captureImg.getPixels(), &bmi, DIB_RGB_COLORS ) == 0 ) success = -1;
    if( success )
    {
        cout << "error:Echec de la copie des pixels" << flush;
    }
    captureImg.update();

    ReleaseDC( NULL, hSourceDC );
    DeleteDC( hCaptureDC );
    DeleteObject( hCaptureBitmap );
}

//--------------------------------------------------------------
void ofApp::draw()
{
    ofSetColor( 255 );
    ofPushMatrix();
    ofTranslate( ofGetWidth() / 2.f + 15.f, ofGetHeight() / 2.f - 15.f );
    ofScale( 1.01f, 1.01f );
    ofRotate(-3);
    ofTranslate( - captureImg.width / 2.f, - captureImg.height / 2.f );
    captureImg.draw( 0, 0 );
    ofPopMatrix();
}

src.zip (1.6 KB)


Programmatic screen capture?
#15

you’ve… you’ve done it…

how… oh… my… god…

what did you do? whats different?

you have no idea…

wow.


#16

Haha :smile:

I started by reading the GDI documentation. Then I felt tired. Then I gave up. A few hours later I just tried some random variations between

captureImg.allocate( 1920, 1080, OF_IMAGE_COLOR );

and

captureImg.allocate( 1920, 1080, OF_IMAGE_COLOR_ALPHA );

and between differents values for

bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;

This combination seems to work (kind of), even if I don’t understand why the colors are changing.
With others values I’ve got a weird thing: only some toolbars icons were copied by GDI, all the rest was transparent!
I don’t think I will dig further into GDI, I wish you good luck with that :wink:


#17

The red and blue channels/bytes are reversed. The method ofImage_<PixelType>::setFromPixels has an argument bOrderIsRGB that will allow you to fix this ordering by setting it to false. Instead of telling GetDIBits to save the data to (void*)captureImg.getPixels(), create an unsigned char* array of size width*height*3, and pass in a (void *) cast of this array. Then do:

captureImg.setFromPixels( yourUnsignedCharArray, captureWidth, captureHeight, OF_IMAGE_COLOR, false ); captureImg.update();.

Documentation: http://openframeworks.cc/documentation/graphics/ofImage/#show_setFromPixels

However, as of v0.9.3, there’s a minor bug in this method that you will need to fix. In \libs\openFrameworks\graphics\ofPixels.cpp, you’ll need to find a method named void ofPixels_<PixelType>::swapRgb(). Change its code to be:

template<typename PixelType>
void ofPixels_<PixelType>::swapRgb(){
	switch(pixelFormat){
	case OF_PIXELS_RGB:
	case OF_PIXELS_RGBA: // **move case statement up**
		break;           // **insert break statement**
	case OF_PIXELS_BGR:
	case OF_PIXELS_BGRA:{
		for(auto pixel: getPixelsIter()){
			std::swap(pixel[0],pixel[2]);
		}
	}
	break;
	default:
		ofLogWarning("ofPixels") << "rgb swap not supported for this pixel format";
		break;
	}
	switch(pixelFormat){
	case OF_PIXELS_RGB:
		pixelFormat = OF_PIXELS_BGR;
		break;
	case OF_PIXELS_BGR:
		pixelFormat = OF_PIXELS_RGB;
		break;
	case OF_PIXELS_RGBA:
		pixelFormat = OF_PIXELS_BGRA;
		break;
	case OF_PIXELS_BGRA:
		pixelFormat = OF_PIXELS_RGBA;
		break;
	default:
		break;
	}
}

Colors are fine for me now.


#18

After playing around with it more, I’ve separated the code into a startup and update function. Also, the mouse was flickering or would disappear with the above code, so I fixed that by removing the CAPTUREBLT flag from the StretchBlt(...) function. I’m not an expert on these Windows screen capture functions, so I left some of those in, commented out, in the updateScreenGrab() function (compare this code to previously posted code).

My application was capturing the output from a window/emulator titled “Mario Kart 64 (U) - Project64 2.2.0.3”. Screen capture for the entire desktop is in the code comments. The emulator window was set to 320x240 pixels, and I was resizing that to 140x104 pixels for my application.

The screen capture coordinates, afaik, have 0,0 in the lower-left corner of the screen, as opposed to the upper-left corner of the screen with OF images/drawing functions. OF Shaders also have 0,0 in the lower-left corner. This is why the capture is flipped upside down (with the option available to leave it upside down). Also, I save the capture first to a char/byte array so that I can have captureImg.setFromPixels(...) swap the red and blue components as discussed earlier.

This code updates at ~60 fps, the latency is barely noticeable, uses a total of 4% CPU on my computer, and causes no flickering! :thumbsup:

Also, I found another weird bug, where if I try to call captureImg.setFromPixels(...) after calling GetDIBits(...), when the destination image is 138x104 pixels, OF0.9.3/VS2015 triggers a breakpoint at varying locations in the libraries. As discussed in the code comments, I believe this is because 138 contains the prime number ‘23’. I changed my destination resolution to 140x104 and it works now, so I haven’t investigated this bug further.

I’m not calling this code perfect or done, nor guaranteeing it will work for others, but I’m pretty happy with it (feel free to make improvements and repost).

ofApp.h declarations:

ofImage captureImg;

int capture_src_width;
int capture_src_height;
int capture_dst_width;
int capture_dst_height;
HDC hSourceDC;
HDC hCaptureDC;
HBITMAP hCaptureBitmap;
HWND window_handle;
BITMAPINFO bmi = { 0 };

unsigned char* capturedPixelData;

ofApp.cpp functions:

//--------------------------------------------------------------
void ofApp::initScreenGrab()
{
  capture_src_width = 320;
  capture_src_height = 240;

  capture_dst_width = 140; // capture_src_width; // 
  capture_dst_height = 104; // capture_src_height; // 

  // tried scaling image down to 104 pixels tall using same aspect ratio:
  //capture_dst_width = ( capture_src_width * 104 ) / capture_src_height; // = 138
  //capture_dst_height = 104
  // in catpureImg.setFromPixels(...), OF breaks for some reason; I'm betting it's because 138 contains a 23 prime number factor
  // I changed the capture_dst_width to 140 and it works with the height remaining 104

  captureImg.allocate( capture_dst_width, capture_dst_height, OF_IMAGE_COLOR );

  window_handle = FindWindow( NULL, TEXT( "Mario Kart 64 (U) - Project64 2.2.0.3" ) );
  hSourceDC = GetDC( window_handle );//GetDC( NULL ); for entire desktop
  hCaptureDC = CreateCompatibleDC( hSourceDC );
  hCaptureBitmap = CreateCompatibleBitmap( hSourceDC, capture_dst_width, capture_dst_height );

  bmi.bmiHeader.biSize = sizeof( bmi.bmiHeader );
  bmi.bmiHeader.biWidth = capture_dst_width;
  bmi.bmiHeader.biHeight = capture_dst_height;
  bmi.bmiHeader.biPlanes = 1;
  bmi.bmiHeader.biBitCount = 24;
  bmi.bmiHeader.biCompression = BI_RGB;

  capturedPixelData = new unsigned char[capture_dst_width * capture_dst_height * 3];
}

//--------------------------------------------------------------
void ofApp::updateScreenGrab()
{
  //hSourceDC = GetDC( window_handle );
  //hCaptureDC = CreateCompatibleDC( hSourceDC );
  //hCaptureBitmap = CreateCompatibleBitmap( hSourceDC, capture_dst_width, capture_dst_height );


  SelectObject( hCaptureDC, hCaptureBitmap );


  // flip right-side up:
  StretchBlt( hCaptureDC, 0, capture_dst_height, capture_dst_width, -capture_dst_height, hSourceDC, 0, 0, capture_src_width, capture_src_height, SRCCOPY );
  // keep upside-down:
  ///StretchBlt( hCaptureDC, 0, 0, capture_dst_width, capture_dst_height, hSourceDC, 0, 0, capture_src_width, capture_src_height, SRCCOPY );


  //ReleaseDC( window_handle, hSourceDC );

  if( GetDIBits( hCaptureDC, hCaptureBitmap, 0, capture_dst_height, (void*) capturedPixelData, &bmi, DIB_RGB_COLORS ) == 0 )
  {
    cout << "Error: Failed to copy the pixels" << flush;
  }


  //DeleteDC( hCaptureDC );
  //DeleteObject( hCaptureBitmap );


  captureImg.setFromPixels( capturedPixelData, capture_dst_width, capture_dst_height, OF_IMAGE_COLOR, false );
  captureImg.update();
}

#19

To get a even faster solution I changed these lines:

captureImg.setFromPixels( capturedPixelData, capture_dst_width, capture_dst_height, OF_IMAGE_COLOR, false );
captureImg.update();

To:

captureImg.getTextureReference().loadData(capturedPixelData, capture_dst_width, capture_dst_height, GL_RGB);