Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Display a videoframe with graphic overlay
Forum Updated to NodeBB v4.3 + New Features

Display a videoframe with graphic overlay

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 1.5k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SGaistS Offline
    SGaistS Offline
    SGaist
    Lifetime Qt Champion
    wrote on last edited by
    #2

    Hi,

    Are you going to show your video frame by frame or as a continuous stream ?

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    M 1 Reply Last reply
    0
    • SGaistS SGaist

      Hi,

      Are you going to show your video frame by frame or as a continuous stream ?

      M Offline
      M Offline
      makopo
      wrote on last edited by
      #3

      @SGaist

      I want to show a single frame of the stream. For normal video playback I think the QOpenGLWidget should be the best.

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #4

        Well for the single frame you can paint on top of it before setting it on your QLabel.

        That said, you could also implement that through OpenGL.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        M 1 Reply Last reply
        1
        • SGaistS SGaist

          Well for the single frame you can paint on top of it before setting it on your QLabel.

          That said, you could also implement that through OpenGL.

          M Offline
          M Offline
          makopo
          wrote on last edited by
          #5

          I have a further question. I create a QImage with given Data from an API. The class where I construct the image is derived from QOpenGLWidget and I override paintEvent(QPaintEvent*) to draw the function. There QPainter calls painter->drawImage(this->rect(), *m_image). But all I get is an empty widget. I have a Data class where I get the data of a current frame and where I emit a signal that send this data to Render class. As I can see on the console, transmitting the data works fine.

          void RenderClass::receiveData(uchar* bufData, int outWidth, int outHeight, int bytesPerRow)
          {
          	m_image = new QImage(bufData, outWidth, outHeight, bytesPerRow, QImage::Format_RGB444);
          }
          
          
          void RenderClass::paintEvent(QPaintEvent*)
          {
          	QPainter* painter = new QPainter(this);
          	if (m_image == nullptr) {
          		qDebug() << "Image not loaded.";
          	}
          	else {
          		painter->drawImage(this->rect(), *m_image);
          		qDebug() << "paintEvent called.";
          		QWidget::update();
          	}
          	painter->end();
          }
          

          It is possible to draw primitives with QPainter into the widget. Also loading images from disk works. I'am not shure if I construct the QImage correct.
          Did someone have an advice for me?

          1 Reply Last reply
          0
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #6

            @makopo said in Display a videoframe with graphic overlay:

            m_image = new QImage(bufData, outWidth, outHeight, bytesPerRow, QImage::Format_RGB444);

            Please read the docs: "The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed."

            QPainter* painter = new QPainter(this);#

            Thsi creates a memleak for no reason - create the QPainter on the stack (and while you're at it also don't create ther QImage on the heap since there is also a memleak)

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            M 1 Reply Last reply
            1
            • Christian EhrlicherC Christian Ehrlicher

              @makopo said in Display a videoframe with graphic overlay:

              m_image = new QImage(bufData, outWidth, outHeight, bytesPerRow, QImage::Format_RGB444);

              Please read the docs: "The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed."

              QPainter* painter = new QPainter(this);#

              Thsi creates a memleak for no reason - create the QPainter on the stack (and while you're at it also don't create ther QImage on the heap since there is also a memleak)

              M Offline
              M Offline
              makopo
              wrote on last edited by makopo
              #7

              @Christian-Ehrlicher

              Thanks for your advice. I found that the value of m_image in paintEvent() method is null. m_image is the initalized in the constructor. For me it look like that paintEvent can only work with local variables and not with class member variables.

              void RenderClass::paintEvent(QPaintEvent*)
              {
              	QImage image(m_bufferData, m_frameWidth, m_frameHeight, m_bytesPerRow, QImage::Format_RGB444);
              	QPainter painter(this);
              	painter.drawImage(this->rect(), image);
              	painter.end();
              
              	qDebug() << "paintEvent called." << image;
              	QWidget::update();
              }
              

              As decribed in the code I paste member variables to the QImage. That members get there values in in the receiveData function

              Christian EhrlicherC 1 Reply Last reply
              0
              • M makopo

                @Christian-Ehrlicher

                Thanks for your advice. I found that the value of m_image in paintEvent() method is null. m_image is the initalized in the constructor. For me it look like that paintEvent can only work with local variables and not with class member variables.

                void RenderClass::paintEvent(QPaintEvent*)
                {
                	QImage image(m_bufferData, m_frameWidth, m_frameHeight, m_bytesPerRow, QImage::Format_RGB444);
                	QPainter painter(this);
                	painter.drawImage(this->rect(), image);
                	painter.end();
                
                	qDebug() << "paintEvent called." << image;
                	QWidget::update();
                }
                

                As decribed in the code I paste member variables to the QImage. That members get there values in in the receiveData function

                Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @makopo said in Display a videoframe with graphic overlay:

                For me it look like that paintEvent can only work with local variables and not with class member variables.

                For sure not except you use some custom c++ variant :D

                When it's a nullptr then receiveData() is not called.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                M 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  @makopo said in Display a videoframe with graphic overlay:

                  For me it look like that paintEvent can only work with local variables and not with class member variables.

                  For sure not except you use some custom c++ variant :D

                  When it's a nullptr then receiveData() is not called.

                  M Offline
                  M Offline
                  makopo
                  wrote on last edited by makopo
                  #9

                  @Christian-Ehrlicher

                  Actually I go back to my older code where I construct a QImage in the receiveData() method.

                  void RenderClass::receiveData(uchar* pData, int outWidth, int outHeight, int bytesPerRow)
                  {
                  	m_image = QImage(pData, outWidth, outHeight, bytesPerRow, QImage::Format_RGB444);
                  
                  	//qDebug() << "Receive Video Data" << bufData << "-" << outWidth << "-" << outHeight << "-" << bytesPerRow;
                  	qDebug() << "QImage" << m_image;
                  }
                  
                  
                  void RenderClass::paintEvent(QPaintEvent*)
                  {
                  	QPainter painter(this);
                  	painter.drawImage(this->rect(), m_image);
                  	painter.end();
                  	
                  	qDebug() << "paintEvent called." << m_image;
                  	QWidget::update();
                  }
                  

                  If I print the value of m_image to the console I got the following:

                  paintEvent called. QImage(null)
                  QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                  paintEvent called. QImage(null)
                  paintEvent called. QImage(null)
                  QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                  paintEvent called. QImage(null)
                  paintEvent called. QImage(null)
                  paintEvent called. QImage(null)
                  QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                  paintEvent called. QImage(null)
                  ....
                  // and so on
                  

                  If the program starts the paint event is called and the value is null. Thats ok because I have a button in my program that do an API-Call and that start a callback function to get the data of the video. If the button is clicked the data is received by the slot, m_image get the value of QImage. As you can see the value of m_image in paintEvent() remains QImage(null).

                  Christian EhrlicherC 1 Reply Last reply
                  0
                  • M makopo

                    @Christian-Ehrlicher

                    Actually I go back to my older code where I construct a QImage in the receiveData() method.

                    void RenderClass::receiveData(uchar* pData, int outWidth, int outHeight, int bytesPerRow)
                    {
                    	m_image = QImage(pData, outWidth, outHeight, bytesPerRow, QImage::Format_RGB444);
                    
                    	//qDebug() << "Receive Video Data" << bufData << "-" << outWidth << "-" << outHeight << "-" << bytesPerRow;
                    	qDebug() << "QImage" << m_image;
                    }
                    
                    
                    void RenderClass::paintEvent(QPaintEvent*)
                    {
                    	QPainter painter(this);
                    	painter.drawImage(this->rect(), m_image);
                    	painter.end();
                    	
                    	qDebug() << "paintEvent called." << m_image;
                    	QWidget::update();
                    }
                    

                    If I print the value of m_image to the console I got the following:

                    paintEvent called. QImage(null)
                    QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                    paintEvent called. QImage(null)
                    paintEvent called. QImage(null)
                    QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                    paintEvent called. QImage(null)
                    paintEvent called. QImage(null)
                    paintEvent called. QImage(null)
                    QImage QImage(QSize(1280, 720),format=QImage::Format_RGB444,depth=16,devicePixelRatio=1,bytesPerLine=3200,sizeInBytes=2304000)
                    paintEvent called. QImage(null)
                    ....
                    // and so on
                    

                    If the program starts the paint event is called and the value is null. Thats ok because I have a button in my program that do an API-Call and that start a callback function to get the data of the video. If the button is clicked the data is received by the slot, m_image get the value of QImage. As you can see the value of m_image in paintEvent() remains QImage(null).

                    Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #10

                    @makopo said in Display a videoframe with graphic overlay:

                    Actually I go back to my older code where I construct a QImage in the receiveData() method.

                    Which is still wrong as stated in my first post...

                    Please read the docs: "The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed."

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #11

                      Beside the point of @Christian-Ehrlicher about the lifetime of the data you use to build your QImage. It would be simpler to create on QImage of the right size and then memcopy the data to it.

                      That said, the wait you do it, you are modifying your m_image object from two different threads without any protection.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved