Work with QOpenGLWidget in multiThread



  • Hi

    So i know that we can only have one openGLcontext per thread, and i need only one. With my window, i have two buttons, each create a QThread, the capture need a QOpenGLContext, the other doesn't.
    0_1500986770482_Sans titre.png

    Here is the code when i push the capture button:

    void MainWindow::capture(QWidget *widget)
    {
        if(!launch){
            QOpenGLWidget* OWidget = reinterpret_cast<QOpenGLWidget*> (widget);
            OWidget->context()->create();
            OWidget->makeCurrent();
            c = new C_anccap();
            c->CaptureCall(OWidget);
            launch = true;
        }
    }
    
    
    int C_anccap::CaptureCall (QOpenGLWidget* widget)
    {
    	// Debug console.
    	//SetupConsole();
        this->m_SDIin.m_videoDC = GetDC((HWND)widget->effectiveWinId());
        if(this->Configure() == E_FAIL)
    		return FALSE;
    
        if(this->SetupSDIDevices() == E_FAIL)
    		return FALSE;
    
    
    	// Calculate the window size based on the incoming and outgoing video signals
        this->CalcWindowSize();
        this->SetupGL();
    	
        if(this->StartSDIPipeline() == E_FAIL)
    		return FALSE;
    
        widget->context()->doneCurrent();
    
        thread = new QThread(this);
        widget->context()->moveToThread(thread);
        QSignalMapper* signalMapper = new QSignalMapper(this);
        QObject::connect(thread,SIGNAL(started()),signalMapper,SLOT(map()));
        signalMapper->setMapping(thread, widget);
        QObject::connect(signalMapper, SIGNAL(mapped(QWidget*)),this, SLOT(LoopAnimation(QWidget*)));
        this->moveToThread(thread);
        thread->start();
    
    }
    
    

    I'm trying to display gltexture continuously thanks to this QThread but i can't managed to display anything. Moreover, i think i didn't get something with the QOpenGLContext because as soon i start capturing, I can't touch any other windows without having an exception
    "Cannot make QOpenGLContext current in a different thread" from qopenglcontext.cpp line 952.
    I don't know if i did something wrong (probably) or if I didn't get something.
    Can you help me?


  • Moderators

    @Miyoku Why do you need more than one thread?



  • This post is deleted!

  • Moderators

    @Miyoku I don't think you need a loop to capture video from a camera. How do you capture the video? Using http://doc.qt.io/qt-5/qcamera.html ? You should use the asynchronous nature of Qt as much as possible to avoid using multithreading.



  • This post is deleted!


  • @jsulm sorry for the double post, i'm deleting one of them.
    For your answer, in fact i'm using a specific hardware, the SDI Quadro input to get 4 SDI input and capture them thanks to the GPU.
    I don't know how the QCamera work, but do you think it's working with SDI input?


  • Moderators

    @Miyoku I don't know whether it works with your camera, but you can try.
    If not, then maybe you can capture the video in an extra thread but hen send the frames via a signal to main thread where you show the frames then. The problem is: in Qt you are only allow to access UI directly from main thread.



  • @jsulm Ok, so here I'm quite stuck, if i want to use an OpenGLWidget, it's because my driver capture the video stream in GLTexture, so the frame are in the GPU not in the CPU. But in order to capture them, i need an OpenGLContext active (which i've succeed to pass to my thread with movetothread) but if i have to make the display in the main thread, it will create a conflict.


  • Moderators

    @Miyoku Maybe you can get rid of the loop using a QTimer in main thread?



  • @jsulm That could work indeed! didn't think about that, I'm going to try that thanks



  • @jsulm I've changed my way of doing, i'm now using a QTimer to capture the frame. But i still have no feedback from the display. I'm wondering if my way of using the QOpenGLWidget is right.

    int C_anccap::LoopAnimation()
    {
        Owidget->makeCurrent();
    
        if (this->CaptureVideo() != GL_FAILURE_NV)
        {
            if (this->rec[0].isStarted) {
                glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->rec[0].pixels.get());
            }
        }
        if (C_anccap::exit) {
            this->Shutdown();
            return FALSE;
        }
        return TRUE;
    }
    
    
    void MyOpenGLWidget::initializeGL()
    {
        initializeOpenGLFunctions();
        glClearColor(1.0f,1.0f,1.0f,1.0f);
        context()->create();
        makeCurrent();
        c = new C_anccap();
        c->CaptureCall(this);
    }
    
    void MyOpenGLWidget::resizeGL(int w, int h)
    {
        if(h==0)
            h =1;
        glViewport(0,0,w,h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        perspectiveGL(45.0f,w/h,0.1f,100.0f);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
    }
    
    void MyOpenGLWidget::paintGL()
    {
        //QPainter p(this);
        // p.beginNativePainting();
         c->DisplayVideo();
        // p.endNativePainting();
    }
    void MyOpenGLWidget::perspectiveGL(GLdouble fovY, GLdouble aspect, GLdouble zNear, GLdouble zFar){
        const GLdouble pi = 3.1415926535897932384626433832795;
        GLdouble fW, fH;
        fH = tan( fovY / 360 * pi) * zNear;
        fW = fH * aspect;
        glFrustum( -fW,fW,-fH,fH,zNear,zFar);
    }
    
    GLboolean C_anccap::DisplayVideo()
    {
    	//
    	// Draw texture contents to graphics window.
    	//
        //widget->makeCurrent();
    	// Reset view parameters
    	glViewport(0, 0, m_windowWidth, m_windowHeight);
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
        glOrtho(0.0, (GLdouble) m_windowWidth, 0.0, (GLdouble) m_windowHeight, -1, 1);
    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();
    
    	// Draw contents of each video texture
    	glEnable(GL_TEXTURE_RECTANGLE_NV);  
    
    	// Set draw color
    	glColor3f(1.0f, 1.0f, 1.0f);
    
    	// Draw captured streams to graphics window.
    	switch(m_SDIin.GetNumVideoObjects()) {
    		case 1:
    		drawOne();
    		break;
    		case 2:
    		drawTwo();
    		break;
    		case 3:
    		drawThree();
    		break;
    		case 4:
    		drawFour();
    		break;
    		default:
    		drawOne();
    	};
    
    GLvoid C_anccap::drawOne()
    {
    	// Enable texture
    	glEnable(GL_TEXTURE_RECTANGLE_NV);  
    	
    	// Bind texture object for first video stream
    	glBindTexture(GL_TEXTURE_RECTANGLE_NV, m_SDIin.GetTextureObjectHandle(0));  
    
    	// Draw textured quad in lower left quadrant of graphics window.
    	glBegin(GL_QUADS);
    	glTexCoord2f(0.0, 0.0); glVertex2f(-1, -1); 
    	glTexCoord2f(0.0, (GLfloat)m_videoHeight); glVertex2f(-1, 1); 
    	glTexCoord2f((GLfloat)m_videoWidth, (GLfloat)m_videoHeight); glVertex2f(1, 1); 
    	glTexCoord2f((GLfloat)m_videoWidth, 0.0); glVertex2f(1, -1); 
    	glEnd();
    	GLenum g = glGetError();
    	assert(glGetError() == GL_NO_ERROR);
    
    	// Disable texture
    	glDisable(GL_TEXTURE_RECTANGLE_NV);
    }
    

    I'm dropping all the code required for the display. Maybe you'll see some errors in the way i'm using it.
    To precise, MyOpenGLWidget inherit QOpenGLWidget.
    I'm quite sure that i'm capturing the frame because the nvidia driver send no error, i just can't manage to display them



  • @Miyoku NeverMind i succeed to make it appears thanks, a lot, i just need to make it refresh every frame. I will do it with a timer.
    Thanks a lot for your time


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.