在linux不带X window的系统中运行Qt程序,无法使用一般的录屏程序。
利用远程协议连接到终端也无法正确读取Qt界面。
本方法采用的思路为:利用qml的ApplicationWindow 提供的QImage image = rootWindow->grabWindow();来获取图片,再用opencv将图片压缩成视频即可。
以下为代码:
screenrecord.h
#include <opencv2/videoio.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
class ScreenRecord : public QObject
{
Q_OBJECT
public:
ScreenRecord(QObject *parent = 0);
Q_INVOKABLE bool record(QQuickWindow *rootWindow);
Q_INVOKABLE void endRecord();
private:
cv::VideoWriter writer; //opencv写视频的类
bool isRecording;
};
screenrecord.cpp
#include "screenopt.h"
#include <QDateTime>
#include <QDir>
#include <QImage>
ScreenRecord::ScreenRecord(QObject *parent): QObject(parent)
{
isRecording = false;
}
bool ScreenRecord::record(QQuickWindow *rootWindow)
{
QDir dir;
//创建存储视频目录
if (false == dir.exists("/myPath/"))
{
dir.mkpath("/myPath/");
}
if (isRecording == false)
{
QString filePathName = "/myPath/";
filePathName += QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss-zzz");
filePathName += QString(".avi");
writer.open(filePathName.toStdString(), cv::VideoWriter::fourcc('M','J','P','G'), 10, cv::Size(1280, 800), true);
isRecording = true;
}
QImage image = rootWindow->grabWindow();
image = image.convertToFormat(QImage::Format_RGB888);
//QImage转换为mat
cv:: Mat mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
cv::cvtColor(mat, mat, CV_RGB2BGR); //opencv储存为BGR,故需要进行转化
if (writer.isOpened())
{
//写入一张图片
writer.write(mat);
}
return true;
}
void ScreenRecord::endRecord()
{
isRecording = false;
writer.release();
}
将ScreenRecord 的实例注册到qml中,可以在qml中直接调用,一般在main函数中注册:
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QQmlApplicationEngine engine;
ScreenRecord screenrecord;
engine.rootContext()->setContextProperty("screenrecordObj", &screenrecord);
...
return app.exec();
}
main .qml
ApplicationWindow {
id:rootWindow
visible: true
Timer{
id:recordTimer
interval: 100
running: false
repeat: true
onTriggered: {
if (false === screenrecordObj.record(rootWindow))
{
recordTimer.stop();
screenrecordObj.endRecord();
}
}
Button{
id: startbutton
width: 1280
height: 800
onClicked:
{
//利用定时器不停的将图片写入到视频文件
recordTimer.start()
}
}
Button{
id: endbutton
width: 1280
height: 800
onClicked:
{
recordTimer.end()
screenrecordObj.endRecord();
}
}
...
}