I am trying to display camera picture on screen using a subclass of QAbstractVideoSurface, and I've no experience on this.
I'd appreciate if anyone can explain how to do it.
The QAbstractVideoSurface
is an interface between the producer and consumer of the video frames.
You only have two functions to implement to begin with:
QVideoFrame
Lets say you want to use a classic QWidget
for the display. In this case, you may choose to use a QImage
to draw on the widget.
First Qt is guaranteed to paint a QImage
which is RGB24 (or BGR24) on most platforms. So
QList<QVideoFrame::PixelFormat> LabelBasedVideoSurface::supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const
{
if (handleType == QAbstractVideoBuffer::NoHandle) {
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB24;
} else {
return QList<QVideoFrame::PixelFormat>();
}
}
Now to present the QVideoFrame, you map its data to a QImage, and paint the QImage to the widget. For simplicity I will use a QLabel
, that I access directly (no signal no slot).
bool LabelBasedVideoSurface::present(const QVideoFrame &frame)
{
if (notMyFormat(frame.pixelFormat())) {
setError(IncorrectFormatError);
return false;
} else {
QVideoFrame frametodraw(frame);
if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
{
setError(ResourceError);
return false;
}
//this is a shallow operation. it just refer the frame buffer
QImage image(
frametodraw.bits(),
frametodraw.width(),
frametodraw.height(),
frametodraw.bytesPerLine(),
QImage::Format_RGB444);
mylabel->resize(image.size());
//QPixmap::fromImage create a new buffer for the pixmap
mylabel->setPixmap(QPixmap::fromImage(image));
//we can release the data
frametodraw.unmap();
mylabel->update();
return true;
}
}
This example is obviously not optimal.
QVideoFrame
might be stored in video memory, because we are drawing using a pixmap.You can write your own widget, and implement a paintEvent for better performance. Also, you have several design liberties on how present()
behave. For instance :
mylabel->repaint()
instead of mylabel->update()