Reputation: 337
I want to make a screen caster application that captures a window or a screen directly to QQuickImage. To do so I made this header which has a thread object which frequently updates screen shots when signal received (sorry file was written in a poor language)
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();
};
and with my qml image i did this
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)
}
but it has a really horrible fps. can anything be done to increase fps? Is there any easy way to do this?
Upvotes: 0
Views: 615
Reputation: 7160
Image
is not really made for displaying frequently changing images. What you want is VideoOutput
.
Here's what I would do :
You need to create a QObject derived class instance and set it as the source of the VideoOutput : http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html#source-prop
Your class needs to have a Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY videoSurfaceChanged)
In your setVideoSurface
method, you need to call the start method of QAbstractVideoSurface with a correct format (your size and the pixelformat, pixelformat should be QVideoFrame::Format_ARGB32 for desktop I guess).
And then when you want to update the VideoOutput (via a QTimer for example), you call the present method of QAbstractVideoSurface with a QVideoFrame you constructed from the QPixmap you got in QScreen::grabWindow.
For that, you could convert the QPixmap to QImage with toImage
and then convert it to QVideoFrame with theQVideoFrame::QVideoFrame(const QImage &image)
constructor.
Upvotes: 1