Results 1 to 16 of 16

Thread: How to display QPaint Images from other Threads

  1. #1
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default How to display QPaint Images from other Threads

    Hi,
    I am using 2 threads in my program. 1 is GUI thread and other one is created from main application. I am getting frames in other thread and painting and displaying Images in main thread.

    After getting frames from other thread I am calling main thread paint function to paint on the widget. Here I am facing problem. I am getting 3 errors

    1. "QPixmap: It is not safe to use pixmaps outside the GUI thread"
    2. "QPainter::begin: Paint device returned engine == 0, type: 2"
    3. "QPainter::end: Painter not active, aborted"

    Here is my sudo code
    connect(thr, SIGNAL(sDisplayOnWidget()), this, SLOT(convertImg2Pix()))
    void frameThread::run() {
    mPlayer.loadVideo("/tmp/stream.bin");
    while(1) {
    mPlayer.loadVideoGetFrame();
    printf("we r in thread func \n");
    emit sDisplayOnWidget();
    }
    }
    convertImg2Pix() {
    p = QPixmap(img.size());
    QPainter painter;
    painter.begin(&p);
    painter.drawImage(0,0,img);
    painter.end();
    mLabelWidget->setPixmap(p);
    }
    please help me to get out of this problem.

    Thanks in advance...
    VijayQt

  2. #2
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    QPixmap belongs to QtGui module, it's not safe to use it in threads other than gui. If you need to draw in other thread, use QImage and then send the result for display to gui thread.

  3. #3
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    Thanks for your quick reply... I am doing QPixmap in main thread only.

    in my above code "convertImg2Pix()" function is in gui thread.
    VijayQt

  4. #4
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    Are you sure about that ? This warning says different.
    Add this debug code in both methods:
    Qt Code:
    1. qDebug() << /*method name here*/ << QThread::currentThread();
    To copy to clipboard, switch view to plain text mode 
    in my above code "convertImg2Pix()" function is in gui thread
    If it is, then maybe you are using QPixmaps somewhere else in your second thread code.

  5. #5
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    Its not calling SLOT . Its always in the while loop and printing non-gui thread id .
    Non GUI thread frameThread(0x9ef78a8)
    why its not calling SLOT function?? Please guide me.
    VijayQt

  6. #6
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    It's some kind of video player, so I think you should consider the video file fps, setup a QTimer in order to query frames in regular intervals and send them to display.
    Now it looks like you want to play the video as fast as possible, it's definitely not the way to go.
    Something like this (a pseudo-code):
    Qt Code:
    1. void VideoThread::run(){
    2. player.loadVideo("video file path");
    3. //...
    4. if( fps > 0 ){ // video fps
    5. timer.setInterval( 1000.0 / fps ); //
    6. connect(timer, SIGNAL(timeout()), this, SLOT(grabFrame()));
    7. timer.start();
    8. } else{
    9. // some kind of error handling
    10. }
    11. }
    12.  
    13. void VideoThread::grabFrame(){
    14. QImage img = player.getFrame();
    15. emit newFrame(img); // signal connected to some object from the gui thread, with Qt::QueuedConnection
    16. }
    17.  
    18. //...
    19.  
    20. void MainGui::frameCallback( const QImage& img ){
    21. qDebug() << "got frame";
    22. QPixmap p = /*img to pixmap*/;
    23. displayWidget->setPixmap(p);
    24. }
    To copy to clipboard, switch view to plain text mode 
    I think you can work on the details yourself.

  7. #7
    Join Date
    Aug 2008
    Posts
    45
    Thanks
    1
    Thanked 6 Times in 6 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: How to display QPaint Images from other Threads

    Do your main thread have event loop running? It will not call the convertImg2Pix() slot if it is not running.
    Last edited by joyer83; 2nd June 2011 at 17:23.

  8. #8
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    Your guess is correct... I am working on video frames displaying on widget.

    void VideoThread::grabFrame(){
    QImage img = player.getFrame();
    emit newFrame(img); // signal connected to some object from the gui thread, with Qt::QueuedConnection
    }
    I can not emit from here because this peace of code is belong to MainGUI. What I am doing here is
    while(1) {
    gPlayer->nextFrame();
    QImage img = gPlayer->displayFrame();
    emit sDisplayOnWidget(img);
    qDebug() << "Non GUI thread" << QThread::currentThread();
    msleep(400);
    }
    but it's not emiting signal. what I am doing is wrong way or am I missing some thing??

    what is event loop??? I am using connect call to emit signal from other thread and slot to render the image.
    I don't know what it is??... Please can you give sudo code to run event loop.
    VijayQt

  9. #9
    Join Date
    Aug 2008
    Posts
    45
    Thanks
    1
    Thanked 6 Times in 6 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: How to display QPaint Images from other Threads

    The event loop is what calls the slots. Read Qt's documentation to find out more.
    The main event loop is started with QCoreApplication::exec();

    Try running your application inside a debugger, pause execution and check if main thread's call stack contains the exec() call.

    EDIT: Also do check that the object which contains the convertImg2Pix()-slot is living in main thread. You can get the object's thread with method QObject::thread().

    You should also check that the connect() call successes, like this:
    Qt Code:
    1. bool ok = connect( ... );
    2. Q_ASSERT( ok );
    To copy to clipboard, switch view to plain text mode 
    Last edited by joyer83; 2nd June 2011 at 17:46.

  10. #10
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    If you can use gui, you can be sure there is an event loop running.
    I can not emit from here because this peace of code is belong to MainGUI
    This piece of code does not belong to anything, it's just a pseudo-code, you've asked about advice and here it is - I suggest you to setup a timer to grab frames. Don't forget to call "exec()" in your thread's run() method as well.

  11. #11
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    Hi Stampede,
    I am talking about my code, not your pseudo-code. In comment#8 I pasted my code and that is from MainGUI.

    void thread::run() {
    while(1) {
    gPlayer->nextFrame(); // This function belong to MainGUI thread
    QImage img = gPlayer->displayFrame(); // This function belong to Main GUI thread
    emit sDisplayOnWidget(img); // from here I am calling SLOT function which is there in again MainGUI thread
    qDebug() << "Non GUI thread" << QThread::currentThread();
    msleep(400);
    }
    }

    Please let me know whether this is correct way of doing or not???

    If it is correct it's not uploading frame on the Label Widget...
    VijayQt

  12. #12
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    I don't get it:
    // This function belong to MainGUI thread
    // This function belong to Main GUI thread
    // from here I am calling SLOT function which is there in again MainGUI thread
    It looks like you don't need a capture thread at all, if everything you call is from Main thread
    Please let me know whether this is correct way of doing or not???
    The way it's done now, it's definitely not ok.
    Why do you want to stick with the "while(1) + sleep()" approach ? Why are you calling methods from gui thread in capture thread directly ?
    In my opinion, you need to *really* understand what's going on and how things are supposed to work before writing the code.
    If you really need separate thread, put the capture code in this thread (class) only, and make it emit the 'new frame' signal - make it the only way of communication between GUI and capture thread (plus, some signals for pause, stop etc.).
    Think about the interface first, how do you wish to use your player class ?
    I think it could be nice to have something like this:
    Qt Code:
    1. // gui thread:
    2. void MainGui::startVideo( const QString& file ){
    3. delete this->player;
    4. this->player = new VideoPlayer(file);
    5. connect( player, SIGNAL(frame(const QImage&)), this, SLOT(frameCallback(const QImage&)) );
    6. // few more connections, for stop, pause, reverse, fast forward, whatever...
    7. this->player->start();
    8. }
    9.  
    10. void MainGui::frameCallback( const QImage& img ){
    11. QPixmap p = QPixmap::fromImage(img);
    12. this->ui.display->setPixmap(img);
    13. }
    To copy to clipboard, switch view to plain text mode 
    As you can see, all video capture details are hidden from GUI, you dont need to worry how VideoPlayer grabs frames, it's enough to know that it emits a signal and connect to it.
    Try to do it this way - hide all video capture details in one class, separate it from gui. Then you can start thinking about how to run it in separate thread.

  13. #13
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    Hi stampede
    I changed my code little bit. I spawn one thread where I am doing decode frame and final Image will give it to Qt MainGUI thread. it's working fine.

    Now my problem is, If I call callback function and spawn decoder thread inside that, it's not working.

    Here is my decoder thread:
    void QVideoDecoder::run()
    {

    timer->setInterval(40);
    connect(timer, SIGNAL(timeout()), this, SLOT(vDecoderFrame()));
    timer->start();
    }

    void QVideoDecoder::vDecoderFrame()
    {
    seekNextFrame();
    emit vDEmitSignal(LastFrame);
    }
    Here is my normal working code:
    void videoPlayer:layAFile() {
    This SLOT belong to MainGUI thread
    loadVideo("/tmp/stream.bin");
    decoderThr->start();
    decoderThr->wait();
    }


    void videoPlayer::displayOnWidget(const QImage& img) {
    printf("We are in videoPlayer::displayOnWidget func()...\n");
    mLabelWidget->setPixmap(QPixmap::fromImage(img));
    }
    This part is working normal way. I am able to see the video on widget

    Problem code:
    void videoPlayer:auseAFile()
    {
    rtspInterface->startDesktopClient();
    This is my callback function (It calls only one time)
    }

    CALLBACK FUNCTION:
    void frameReturn(unsigned char* data, int dataSize, void* decoder) {
    loadVideo("/tmp/stream.bin");
    decoderThr->start();
    Here I am spawning decoder thread
    decoderThr->wait();
    }
    This part is not working...
    I put some debug logs here and It's going and hitting the decoder run function and not calling vDecoderFrame() SLOT from run function.

    Please can you let me know the what I am doing wrong here??
    VijayQt

  14. #14
    Join Date
    Sep 2009
    Location
    Wroclaw, Poland
    Posts
    1,394
    Thanked 342 Times in 324 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: How to display QPaint Images from other Threads

    Now my problem is, If I call callback function and spawn decoder thread inside that, it's not working.
    Again, I don't understand something - how are you supposed to capture frames ? With frame callback method launched by some kind of underlying video capture library, or manually, calling some getNextFrame() method yourself ?

  15. #15
    Join Date
    Aug 2008
    Posts
    45
    Thanks
    1
    Thanked 6 Times in 6 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: How to display QPaint Images from other Threads

    The QVideoDecoder object is created in main thread, so it it lives in that thread too. And as such, its slot vDecoderFrame() is also called by main thread's event loop.
    Or, it would be called if the main thread wouldn't be blocked in this call:
    decoderThr->wait();


    Added after 20 minutes:


    I changed my code little bit. I spawn one thread where I am doing decode frame and final Image will give it to Qt MainGUI thread. it's working fine.
    As explained above, if it is vDecoderFrame() where you decode it, then your assumption is wrong. You are actually decoding in the main thread.
    You need to make the QVideoDecoder to live the new thread you have just created.

    Starting the decoder should look something like this:
    Qt Code:
    1. QThread *decoderThr = new QThread; // just a plain QThread object, not any derived class
    2. QVideoDecoder *decoder = new QVideoDecoder;
    3. decoder->moveToThread( decoderThr ); // move decoder to decoder thread so that it lives in it
    4. bool ok = connect( decoderThr, SIGNAL(started()), decoder, SLOT(run()) ); // execute run()-slot from decoder thread's event loop when the thread has been started
    5. Q_ASSERT( ok );
    6. decoderThr->start(); // start decoder thread
    To copy to clipboard, switch view to plain text mode 
    You need to also change QVideoDecoder's base class to QObject and change the run() method to a slot.
    Last edited by joyer83; 3rd June 2011 at 13:41.

  16. #16
    Join Date
    May 2011
    Posts
    16
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60

    Default Re: How to display QPaint Images from other Threads

    How to resolve this issue?? I removed decoderThr->wait(), still I am facing the same problem ...
    And one more QA here... In back-end I am wrinting data to file and I am loading that same file to read. When callback function called, I am spawning thread to decode that file frame-by-frame and QImage I am emiting to maingui widget.

    This is what I am doing.

    1. opening file I am doing in maingui function.
    2. spawing thread to decode frame by frame.
    3. final Image I am emiting from decoder thread
    4. catch that Image in maingui widget function and rendering.


    Added after 22 minutes:


    Here is my pseudo-code:

    This is my videodecoder class.
    class QVideoDecoder: public QThread
    {
    public:
    void run();

    signals:
    void vDEmitSignal(QImage);

    public slots:
    void vDecoderFrame();

    }

    Here is my maingui class (videoPlayer) :
    #include "QVideoDecoder.h"

    class videoPlayer : public QMainWindow
    {
    public:
    QVideoDecoder *decoderThr;

    public slots:
    void openAFile();
    void playAFile();
    }

    Here is my main class:
    #include <QApplication>
    #include <QtCore>
    #include "../inc/videoplayer.h"

    int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    videoPlayer vp(argc, argv);
    vp.show();
    app.exec();
    return (0);
    }

    Here is my videoplayer.cpp file:
    videoPlayer::videoPlayer(int urlSize, char *url[], QWidget *parent) :
    QMainWindow(parent)
    {
    decoderThr = new QVideoDecoder(*this);
    connect(decoderThr, SIGNAL(vDEmitSignal(QImage)), this, SLOT(displayOnWidget(const QImage&)));
    }

    void frameReturn(unsigned char* data, int dataSize, void* decoder) {
    printf("*********************We are in CALLBACK func() . . . ******************\n");
    gPlayer->loadVideo("/tmp/stream.bin");
    gPlayer->decoderThr->start();
    gPlayer->decoderThr->wait();
    }
    Last edited by vijayQt; 3rd June 2011 at 14:11.
    VijayQt

Similar Threads

  1. How to display DDS images?
    By jamsession in forum Qt Programming
    Replies: 5
    Last Post: 12th June 2013, 22:18
  2. Display images and move them
    By AL in forum Qt Programming
    Replies: 5
    Last Post: 11th February 2010, 17:49
  3. How do I display a list of images?
    By Morea in forum Qt Programming
    Replies: 2
    Last Post: 23rd November 2007, 08:49
  4. Is there any way to synchronize the display of images
    By kiransu123 in forum General Programming
    Replies: 2
    Last Post: 17th March 2007, 20:50
  5. Display animated images
    By suresh in forum Qt Programming
    Replies: 1
    Last Post: 27th January 2007, 21:53

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.