0

I am struggling with writing a video player which uses OpenCV to read a frame from video and display it in a QWidget.

This is my code:

// video caputre is opened here
...

void VideoPlayer::run()
{
    int sleep = 1000 / static_cast<unsigned long>(video_capture_.get(CV_CAP_PROP_FPS));
    forever
    {
            QScopedPointer<cv::Mat> frame(new cv::Mat);
            if(!video_capture_.read(*frame))
                break;

            cv::resize(*frame, *frame, cv::Size(640, 360), 0, 0, cv::INTER_CUBIC);
            cv::cvtColor(*frame, *frame, CV_BGR2RGB);

            QImage image(frame->data, frame->cols, frame->rows, QImage::Format_RGB888);

            emit signalFrame(image); // notifying QWidget to draw an image

            msleep(sleep); // wait before we read another frame
    }
}

and on the QWidget side, I am just using this image and drawing it in paintEvent.

It just looks to me that parameter sleep doesn't play important role here. As much as I decrease it (to get more FPS) the video is just not smooth.

The only thing here left for me is that I gave up on that approach because it doesn't work, but I wanted to ask here one more time, just to be sure - am I doing something wrong here?

carobnodrvo
  • 1,021
  • 1
  • 9
  • 32
  • 1
    You seem to assume each iteration will take same amount of real time -- it won't. In fact, you assume that the rest of the loop body other than `msleep` will take zero time -- reading, decoding, resizing, color conversion,... definitely not instantaneous. You don't buffer frames ahead, so any kind of hiccup in the read/decode will be visible. `QScopedPointer` seems a bit pointless due to how `cv::Mat` works. It also seems to me that `image` uses the data buffer from `frame`, which may get destroyed while [some shallow copy of] `image` is still in use (due to the signal). – Dan Mašek Dec 07 '16 at 15:02
  • Besides video decoding, is your VideoPlayer::run() in another thread? If not, it will probably freeze your GUI. – Yancey Dec 07 '16 at 15:12
  • Oh wow, first two statements are right in the target! I need to calculate how much time does other calculation take (reading, resizing...) and based on that set msleep. Buffering of frames ahead is also amazing idea. `QScopePointer` is there to assure that pointer witch is emitted is drawn before new frame is red. Check out [this](https://stackoverflow.com/questions/21246766/how-to-efficiently-display-opencv-video-in-qt) topic for more details on that. @DanMašek I will try to re-implement this and if it functions you can write answer and I will accept it. – carobnodrvo Dec 07 '16 at 15:13
  • @Yancey Yes, it's another thread. – carobnodrvo Dec 07 '16 at 15:14
  • 1
    @carobnodrvo Ok, in that case your QImage instance should take ownership of that pointer. See that answer you referred to. – Dan Mašek Dec 07 '16 at 15:36
  • Oops, I've overlooked it, yes it has to take ownership - Thanks. – carobnodrvo Dec 07 '16 at 15:38
  • @DanMašek feel free to write your answer, I will gladly accept it! One stupid question - does VLC (for example) use GPU in order to get all frames? My CPU usage is a bit high when I play video like this, but when I play it with VLC for example its much lower... – carobnodrvo Dec 08 '16 at 12:20
  • @carobnodrvo Looks like it can: https://wiki.videolan.org/VLC_GPU_Decoding/ – Dan Mašek Dec 08 '16 at 13:24

0 Answers0