说明
QAbstractVideoSurface类是一个抽象基类,通过实现它的派生类可以获取来自QMediaPlayer或QCamera视频的帧。原理是视频数据的帧流会被引入到QAbstractVideoSurface类的present()函数中,通过该类可获取视频中的所有的帧,因此可以在读取或编辑这些帧,然后再输出到视图中。
QAbstractVideoSurface类下的有两个纯虚函数supportedPixelFormats()和present(),前者用于向Qt返回帧流的图像类型,后者可获取到每一帧。
函数
-
virtual QList<QVideoFrame::PixelFormat> QAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const = 0
-
virtual bool QAbstractVideoSurface::present(const QVideoFrame & frame) = 0
释义
- 返回支持的像素格式,格式由枚举类型QVideoFrame::PixelFormat指定。
- 当前帧。视频每加载一帧都会调用一次该函数,形参frame存储有当前帧的数据。
示例
为抽象基类QAbstractVideoSurface设计派生类。
首先必须重写两个纯虚函数supportedPixelFormats()和present(),之后需要将QVideoFrame类型的帧转化为QImage类型。
示例并没有在派生类的present()函数中直接将QVideoFrame转化为QImage类型,而是把前者作为信号发送了出去。
class VideoSurface : public QAbstractVideoSurface
{
Q_OBJECT
public:
VideoSurface(QObject * parent = Q_NULLPTR);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const;
private slots:
bool present(const QVideoFrame & frame);
signals:
void presentframe_(const QVideoFrame & frame);
};
QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(
QAbstractVideoBuffer::HandleType type) const
{
if(type == QAbstractVideoBuffer::NoHandle)
{
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB32;
}
else
return QList<QVideoFrame::PixelFormat>();
}
bool VideoSurface::present(const QVideoFrame & frame)
{
if(frame.isValid())
{
emit presentframe_(frame);
return true;
}
stop();
return false;
}
presentframe_()信号的接收槽需要转换QVideoFrame类型:
void Widget::_presentframe(const QVideoFrame & frame)
{
QVideoFrame frametodraw(frame);
if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
return;
img = QImage(frame.bits(),
frame.width(),
frame.height(),
frame.bytesPerLine(),
QVideoFrame::imageFormatFromPixelFormat(frametodraw.pixelFormat())
//QImage::Format_RGB32
);
img = img.mirrored(false, true);//图像垂直翻转(图像是倒置的,调用该函数可正置。同时该函数也解决了频繁的内存错误引起的崩溃, 原因不明)
//这里可以分析或编辑图像后再输出显示视频
//视频的显示则利用重写paintEvent()函数来绘制实现。还可以直接将图像设置到label控件中,也会形成视频。
update(); //通知Qt重绘
frametodraw.unmap();
}
paintEvent()函数的重绘则是直接用drawImage()函数绘制。