ReceiveImage is black

Hello,
I’ve got a working Sender (as tested with the sample receiver application) in the Spout plugin for OBS.
My own receiver, however, only spits out black pixels. I’m using the Spout library for c++, compiling with msvc2017 and QtCreator, using Qt QML as a framework for window creation.

My initial code had all Qt related stuff commented out and looked a little something like this:

    receiver = GetSpout();
    if (!receiver) {
        return;
    }
    receiver->EnableSpoutLog();
    receiver->CreateOpenGL();
    receiver->SetSpoutLogLevel(LibLogLevel::SPOUT_LOG_VERBOSE);

    //get sender name... => char senderName[256]
    receiver->SetActiveSender(senderName);
    receiver->SetReceiverName();
    //this returns true, width and height are correct.
    qDebug() << "receive: " << receiver->ReceiveTexture();
    int width = receiver->GetSenderWidth();
    int height = receiver->GetSenderHeight();

    QImage img(QSize(width, height), QImage::Format_RGBA8888);
    unsigned char* pixels;
    pixels = new unsigned char[width * height * 4];
    //both return true:
    qDebug() << "receive image: " << receiver->ReceiveImage(pixels, GL_RGBA, false, 0);
    qDebug() << "receive image: " << receiver->ReceiveImage(img.bits(), GL_RGBA, false, 0);

At the end of this code, both img and pixels only contain values of 0. I get no errors through the spout log, I don’t see anything out of place…:

[notice] spoutGL::CreateOpenGL()
[notice]     OpenGL window created OK

[notice] spoutGL::OpenSpout - 64bit 2.007 - this 0x2F1C9890
[notice] spoutGL::OpenDirectX
[notice] spoutDirectX::OpenDirectX11
[notice] spoutDirectX::CreateDX11device - pAdapter (0x0000000)
[notice]     Device (0x2F5010B8) - Context (0x2F523E00)
[notice] spoutGL::LoadGLextensions - all extensions available
[notice] spoutGL::OpenSpout - GL extensions loaded sucessfully
[notice] spoutGL::GLDXready - testing for GL/DX interop compatibility
[notice]     GL/DX interop extensions available
[notice] spoutDirectX::CreateSharedDX11Texture
[notice]     pDevice = 0x2F5010B8, width = 256, height = 256, format = 87
[notice]     pTexture = 0x2F447AF8 : dxShareHandle = 0x0000F02
[notice]     Linking test - OpenGL texture (0x0000001) DX11 texture (0x2F447AF8)
[notice] spoutGL::CleanupInterop
[notice] spoutDirectX::ReleaseDX11Texture (0x2F447AF8)
[notice]     Test OpenGL and DX11 textures created and linked OK
[notice]     GL/DX interop compatible
[notice]     Using GPU OpenGL GL/DX methods
[notice] Spout::InitReceiver(Spout_OBS_Filter, 1280 x 1024)
[notice] spoutFrameCount::CreateAccessMutex - texture access mutex [Spout_OBS_Filter_SpoutAccessMutex] exists
[notice]     Handle for access [0x0000810]
[notice] SpoutFrameCount::EnableFrameCount : setting not enabled
[notice] spoutGL::CreateInterop
[notice] spoutGL::CreateInterop - m_pSharedTexture [0x2F40F178] m_dxShareHandle [0x0003DC2]
[notice]     m_hInteropObject = 0x0002752

Am I doing something obvious wrong? And, what format is GL_RGBA exactly? The OpenGL documentation only lists it as a pixel format, it doesn’t say what type the values are. float, byte, etc…?
Should I be using ReceiveTexture instead? Can I do that with QOpenGLTexture rather than trying to set up yet another framework such as openframeworks?

I understand not everyone works with Qt, but this code produced the same result even when no Qt code was being run (qDebug being replaced with std::cout, no QApplication created etc).

Side note, can I use Qt’s OpenGL context somehow? I’m pretty sure QtQuick renders in OpenGL but Spout can’t seem to access that.

Hi JayEff,

You don’t need :

ReceiveTexture();
receiver->SetActiveSender(senderName);
receiver->SetReceiverName();

Just create an image of any size.

QImage img(QSize(256, 256), QImage::Format_RGBA8888);

Then receive to that image.

receiver->ReceiveImage(img.bits(), GL_RGBA, false, 0);

No data will be received on the first frame until you call IsUpdated()

if (receiver->IsUpdated()) {
	// Re-allocate the receiving image to 
	// receiver->GetSenderWidth(), receiver->GetSenderHeight()
}

The next frame will contain data.

You can use ReceiveTexture which is more efficient. The same applies with IsUpdated().

OpenGL GL_RGBA is a four byte pixel format with order R,G,B,A and used extensively throughout the Spout SDK.

I investigated QT OpenGL only briefly and seem to recall that the QOpenGLContext class is necessary.

Thank you very much, I will give this a try very soon. I left out the isUpdated because I thought it was just a getter function and wasn’t hiding any important mechanics. Good to know! It would be great if this works, spout seems like a fantastic tool for what I want to do. my alternative was using a websocket plugin, roundtrip from request to image is 200 ms ;D

Once again, thank you very much. It works! Here’s what I’ve got:

if (!receiver) {
        receiver = GetSpout();
        if (!receiver) {
            qDebug() << "creating the receiver failed";
            return;
        }
        receiver->EnableSpoutLog();
        receiver->CreateOpenGL();
        receiver->SetSpoutLogLevel(LibLogLevel::SPOUT_LOG_VERBOSE);
        receiver->SetReceiverName("Spout_OBS_Filter");
        receiver->SetActiveSender("Spout_OBS_Filter");
        receiver->SetReceiverName();
        qDebug() << "first receive: " << receiver->ReceiveTexture();
    }

    if (receiver->IsUpdated()) {
        mSpoutWidth = receiver->GetSenderWidth();
        mSpoutHeight = receiver->GetSenderHeight();
        mImage = QImage(QSize(mSpoutWidth, mSpoutHeight), QImage::Format_RGB888);
    }

    qDebug() << "receive image: " << receiver->ReceiveImage(mImage.bits(), GL_RGB, false, 0);

As this will run repeatedly, pretty much as fast as I can get it, I hope there’s no obvious mistakes. It also seems to run easily fast enough for my purposes.

As you said, only the second run of the code will produce an image, but that’s not an issue. I’ve noticed the trend continues: If I click the button that runs this code, a snapshot is made, but the previous snapshot is received, so the received image always lags behind by a frame - perhaps due to some kind of double buffering? That’s also no problem for me, though.

You can leave out :

// receiver->SetActiveSender(“Spout_OBS_Filter”);
// receiver->SetReceiverName();

SetReceiverName(“Spout_OBS_Filter”) is enough to lock onto that sender.

Yes there is buffering with ReceiveImage, depending on the number of PBO’s you choose in SpoutSettings. This speeds up data transfer from GPU to CPU.

If ReceiveImage is fast enough for you that’s fine. Just watch the CPU load for larger images. If necessary, ReceiveTexture is approximately 0.5 msec regardless of size.