PDA

View Full Version : Render raw video on a fullscreen window



BBT
25th November 2010, 11:03
Hi,

I new to Qt, and I have an small app to do.
I need to show a video coming from a driver and draw it in a Qt window.
I read the video frame from the driver as RGB32 data and I'm looking for a efficient way to display each frame.

My first try was to use a QGraphicsScene and put a QPixMap in it created from a QImage.
But I think it will be slow and I need to draw 30fps video.

Anybody have another approach on this thing ?

high_flyer
25th November 2010, 11:26
What is the size of the frame?

BBT
25th November 2010, 14:18
There are 2 resolutions 1024x768 and 768x576, but for this one, it will be put in a 1024x768 buffer.

Added after 1 17 minutes:

http://doc.trolltech.com/4.4/threads-mandelbrot.html
I've just found the Mandelbrot example that implements 2 threads, one from compute and the other for drawing.
It might be a good foundation for my app, isn't it ?

high_flyer
25th November 2010, 14:22
I think direct painting will be the most performant, so not with QGraphicsView.
I don't know though, if 30fps can be reached ,probably, but it needs testing.
To test it quick, you can make a smal app with a widget, and in the painEvent() do something like:


QPainter painter(this);
QImage image(pData, iWidth, iHeight, QImage::Format_ARGB32);
panter.drawImage(rectImage,image,rectImage); //In this case make the widget as large as the Image 1:1


and time it.
See if you get 30fps.

Added after 4 minutes:


It might be a good foundation for my app, isn't it ?
In your case no, since you are not doing anything with the data you get except show it.
If you need to manipulate the data, then, threads MIGHT be of benefit.

BBT
25th November 2010, 14:31
But how can I refresh the data if it isn't done in another thread ?
I think I will not put this refresh in the paintEvent.

Sorry for dummy questions, I'm totally new to Qt. :)

high_flyer
25th November 2010, 15:15
But how can I refresh the data if it isn't done in another thread ?
Well, you know when the device is ready with new data right?
Then you call widget->repaint() - which will cause paintEvent() to be called.

NOTE: usually you should not use repaint() - but in this case you want an imitate repainting.

BBT
25th November 2010, 16:00
True, I'll use a select() on the device of the driver to know when new frame is available.


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();

return a.exec();
}

Here's my main(), and I saw that a.exec() is where all Qt messages are processed so I can not call w->repaint(); from the main() as a.exec() is blocking.
So I thought the only way was to use a thread.
Am I missing something ?

high_flyer
25th November 2010, 16:04
Am I missing something ?
Yes.
Basic C++ concepts, but that is outside the scope of this forum.

BBT
25th November 2010, 16:13
You're right, I didn't use C++ for years, but I understand basic C++ concepts.
Do you think that I need to create a class which extends QApplication or something else ?

high_flyer
25th November 2010, 16:17
no, you need to subclass QWidget, and overload the paintEvent() (at least).
But the very fact that this is not clear to you, is not a good sign to your ability to cope with the task you set for your self (Video player).

BBT
25th November 2010, 16:41
I've already created a subclass of QWidget and overloaded paintEvent().
With this code, my widget is refreshed whenever a paint event occurs (which is good) but my problem is that I want to know a frame arrived before the next paint event.

high_flyer
25th November 2010, 19:42
but my problem is that I want to know a frame arrived before the next paint event.
I didn't get that - can you please explain again?

franco.amato
25th November 2010, 20:55
I've already created a subclass of QWidget and overloaded paintEvent().
With this code, my widget is refreshed whenever a paint event occurs (which is good) but my problem is that I want to know a frame arrived before the next paint event.

Hi,
you can decide when the next paintEvent occours by calling the update ( or repaint in your case for an immediate repainting of your widget ) as told by high_flyer.
I think your driver has some routines/mechanism to inform you when a new frame is available ( in my case it use windows messages ). In such case repaint your widget
with the new frame data.

In my case I had to reimplement winEvent and did something like this:


bool CameraView::winEvent(MSG *m, long* result)
{
uint msgType = m->message; // test line

if(msgType != IS_UEYE_MESSAGE)
return false; // Let Qt handle other messages

switch ( m->wParam )
{
case IS_DEVICE_REMOVED:
qDebug("Device removed");
break;
case IS_DEVICE_RECONNECTED:
qDebug("Device reconnected");
break;
case IS_FRAME:
{
// a new frame is available from my camera driver
ui.camViewerLabel->setPixmap(QPixmap::fromImage(image));
ui.camViewerLabel->update(); // <-----REPAINT THE WIDGET
break;
}
default:
break;
}
return true;
}

I hope this code can help you.
Regards

BBT
26th November 2010, 08:23
My goal is to synchronize the repaint on arrival of new frames, like Franco said.
The driver provides a char device and my app do a select() on the file descriptor opened on this char device.
When the driver has a new frame, it changes char device state so the select() call returns and I can get my frame on a nmapped memory block.

Right now, I've made a QThread which do the select() and it send a signal to the widget. The slot in the widget update the image data and call repaint() method.

I've just read about update() method which seems to be more "elegant", I'll test the two methods.



void Widget::paintEvent(QPaintEvent *event)
{
QPainter Painter(this);
if (this->Image != NULL)
{
QImage resizedImage = this->Image->scaledToWidth(this->width());
Painter.drawImage(resizedImage.rect(), resizedImage);
}
else
{
QWidget::paintEvent(event);
}
}

void Widget::showPix(const QImage* pic)
{
this->Timer.start();

this->Image = pic;
//this->repaint();
this->update();
}