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.pngHere 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? -
@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.
-
@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? -
@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.
-
@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