使用 QSCreen::grabWindow() 函数在 qt 中制作 window 预览
Making window previews in qt using QSCreen::grabWindow() function
我想制作一个屏幕投射应用程序,将 window 或屏幕直接捕获到 QQuickImage。为此,我制作了这个 header,它有一个线程 object,它在收到信号时经常更新屏幕截图(抱歉,文件是用糟糕的语言编写的)
class OtherThread : public QThread
{
Q_OBJECT
QString oldWritingFile = "filename.png";
bool loaded = true;
public:
int winId = 0;
OtherThread(QObject *parent = nullptr):QThread(parent){};
~OtherThread(){
if(isRunning()){
requestInterruption();
wait();
}
};
void setParams(int id){
winId = id;
}
void knowLoaded(){
loaded =true;
}
signals:
void fileCacheChanged(QString);
protected:
void run() override{
while (!isInterruptionRequested()) {
if(winId != 0 && loaded){
bool success;
loaded = false;
if(oldWritingFile == QString::number(winId)+".png"){
if(qApp->primaryScreen()->grabWindow(winId).save(QString::number(winId)+"file.png")){
oldWritingFile = QString::number(winId)+"file.png";
success = true;
}else{success=false;}
}else{
if(qApp->primaryScreen()->grabWindow(winId).save(QString::number(winId)+".png")){
oldWritingFile = QString::number(winId)+".png";
success = true;
}else{success = false;}
}
emit fileCacheChanged(oldWritingFile);
}
}
};
};
class Controller : public QObject
{
Q_OBJECT
QString oldWritingFile;
public:
Controller(QObject *parent = nullptr):QObject(parent) {}
virtual ~Controller() {}
void changeFile(QString message){
oldWritingFile = message;
emit newFile(message);
};
public slots:
void startThread(){
OtherThread *thread =new OtherThread;
connect(thread, &OtherThread::fileCacheChanged, this, &Controller::changeFile);
connect(this, &Controller::stop, thread, &OtherThread::requestInterruption);
connect(this, &Controller::changePrint, thread, &OtherThread::setParams);
connect(this, &Controller::loaded, thread, &OtherThread::knowLoaded);
thread->start();
}
QString getLoadedFile(){
if(oldWritingFile != NULL){
return "file:./"+oldWritingFile;
}else{
return "file:./index.png";
}
}
signals:
void stop();
void changePrint(int id);
void newFile(QString);
void loaded();
};
我用我的 qml 图像做了这个
Image {
id: image
anchors.fill: parent
source: "images/kalaripayattu.svg"
fillMode: Image.PreserveAspectFit
cache:false
Component.onCompleted: {
justThread.newFile.connect(updateFunction)
}
function updateFunction(filename){
source = "file:./"+filename;
justThread.loaded()
}
}
JustThread{
signal stopThread
id:justThread
onStopThread: {
stop()
}
Component.onCompleted: {
startThread()
changePrint(id)
}
}
Component.onCompleted:{
applicationWindow.closing.connect(justThread.stopThread)
}
但它的 fps 真的很糟糕。
可以做些什么来增加 fps 吗?
有什么简单的方法可以做到这一点吗?
Image
并不是真正为显示频繁变化的图像而设计的。你要的是VideoOutput
.
这是我会做的:
您需要创建一个 QObject 派生的 class 实例并将其设置为 VideoOutput 的源:http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html#source-prop
您的 class 需要 Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY videoSurfaceChanged)
在你的 setVideoSurface
方法中,你需要以正确的格式调用 QAbstractVideoSurface 的启动方法(你的大小和像素格式,我猜桌面的像素格式应该是 QVideoFrame::Format_ARGB32)。
然后,当您想要更新 VideoOutput(例如通过 QTimer)时,您可以使用从 QScreen::grabWindow.[=19= 中获得的 QPixmap 构造的 QVideoFrame 调用 QAbstractVideoSurface 的当前方法]
为此,您可以使用 toImage
and then convert it to QVideoFrame with theQVideoFrame::QVideoFrame(const QImage &image)
constructor.
将 QPixmap 转换为 QImage
我想制作一个屏幕投射应用程序,将 window 或屏幕直接捕获到 QQuickImage。为此,我制作了这个 header,它有一个线程 object,它在收到信号时经常更新屏幕截图(抱歉,文件是用糟糕的语言编写的)
class OtherThread : public QThread
{
Q_OBJECT
QString oldWritingFile = "filename.png";
bool loaded = true;
public:
int winId = 0;
OtherThread(QObject *parent = nullptr):QThread(parent){};
~OtherThread(){
if(isRunning()){
requestInterruption();
wait();
}
};
void setParams(int id){
winId = id;
}
void knowLoaded(){
loaded =true;
}
signals:
void fileCacheChanged(QString);
protected:
void run() override{
while (!isInterruptionRequested()) {
if(winId != 0 && loaded){
bool success;
loaded = false;
if(oldWritingFile == QString::number(winId)+".png"){
if(qApp->primaryScreen()->grabWindow(winId).save(QString::number(winId)+"file.png")){
oldWritingFile = QString::number(winId)+"file.png";
success = true;
}else{success=false;}
}else{
if(qApp->primaryScreen()->grabWindow(winId).save(QString::number(winId)+".png")){
oldWritingFile = QString::number(winId)+".png";
success = true;
}else{success = false;}
}
emit fileCacheChanged(oldWritingFile);
}
}
};
};
class Controller : public QObject
{
Q_OBJECT
QString oldWritingFile;
public:
Controller(QObject *parent = nullptr):QObject(parent) {}
virtual ~Controller() {}
void changeFile(QString message){
oldWritingFile = message;
emit newFile(message);
};
public slots:
void startThread(){
OtherThread *thread =new OtherThread;
connect(thread, &OtherThread::fileCacheChanged, this, &Controller::changeFile);
connect(this, &Controller::stop, thread, &OtherThread::requestInterruption);
connect(this, &Controller::changePrint, thread, &OtherThread::setParams);
connect(this, &Controller::loaded, thread, &OtherThread::knowLoaded);
thread->start();
}
QString getLoadedFile(){
if(oldWritingFile != NULL){
return "file:./"+oldWritingFile;
}else{
return "file:./index.png";
}
}
signals:
void stop();
void changePrint(int id);
void newFile(QString);
void loaded();
};
我用我的 qml 图像做了这个
Image {
id: image
anchors.fill: parent
source: "images/kalaripayattu.svg"
fillMode: Image.PreserveAspectFit
cache:false
Component.onCompleted: {
justThread.newFile.connect(updateFunction)
}
function updateFunction(filename){
source = "file:./"+filename;
justThread.loaded()
}
}
JustThread{
signal stopThread
id:justThread
onStopThread: {
stop()
}
Component.onCompleted: {
startThread()
changePrint(id)
}
}
Component.onCompleted:{
applicationWindow.closing.connect(justThread.stopThread)
}
但它的 fps 真的很糟糕。 可以做些什么来增加 fps 吗? 有什么简单的方法可以做到这一点吗?
Image
并不是真正为显示频繁变化的图像而设计的。你要的是VideoOutput
.
这是我会做的:
您需要创建一个 QObject 派生的 class 实例并将其设置为 VideoOutput 的源:http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html#source-prop
您的 class 需要 Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY videoSurfaceChanged)
在你的 setVideoSurface
方法中,你需要以正确的格式调用 QAbstractVideoSurface 的启动方法(你的大小和像素格式,我猜桌面的像素格式应该是 QVideoFrame::Format_ARGB32)。
然后,当您想要更新 VideoOutput(例如通过 QTimer)时,您可以使用从 QScreen::grabWindow.[=19= 中获得的 QPixmap 构造的 QVideoFrame 调用 QAbstractVideoSurface 的当前方法]
为此,您可以使用 toImage
and then convert it to QVideoFrame with theQVideoFrame::QVideoFrame(const QImage &image)
constructor.