Russian Qt Forum
Октябрь 02, 2024, 09:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Сделать скрин экрана максимально эффективно!  (Прочитано 11114 раз)
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« : Август 13, 2013, 14:02 »

Доброго дня! Как добиться максимальной эффективности при сохранении картинки, не останавливая основоное приложение на 0.5-1 сек. Хотелось разместить код
Код:
QPixmap px = QPixmap::grabWindow(QApplication::desktop()->winId()); 
px.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");  

в отдельном потоке с минимальным приоритетом, но он не работает в отдельном потоке видимо из-за непотокобезопасности QPixmap, софт вылетает.. программа под Linux. Должна делать скриншоты периодически раз в 10-20 сек (в режиме автомата), либо вручную.
« Последнее редактирование: Август 14, 2013, 10:46 от Vladimir » Записан
Bepec
Гость
« Ответ #1 : Август 13, 2013, 14:14 »

Платформо-ориентированным кодом будет наиболее быстро.
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #2 : Август 13, 2013, 14:21 »

А примеров под Linux случаем нет?))
Записан
Bepec
Гость
« Ответ #3 : Август 13, 2013, 14:30 »

Не работаю. Нехватает цели для использования linux.
Записан
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #4 : Август 13, 2013, 15:23 »

Я делал так:
Запускаем функцию в потоке, а из нее делаем блокирующий вызов функции из главного потока через
Код:
QMetaObject::invokeMethod(this, "your_function", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));

Таким образом никакого торможения гуи нет.

Посмотреть код можно тут: https://github.com/kibsoft/QtMEL/blob/master/src/grabbers/image/screengrabber.cpp
Функция captureFrame работает в отдельном потоке(сделано с помощью QtConcurrent), а функция currentFrame(к которой мы делаем блокирующий вызов) находится в главном.
Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #5 : Август 13, 2013, 15:28 »

Цитировать
Платформо-ориентированным кодом будет наиболее быстро.
А разве grabWindow не реализована платформо-зависимым кодом внутри? Я думаю других вариантов нет. В начале пробовал изобретать велосипед и делать скриншоты через WinAPI, но скорость та же самая, что и у grabWindow.
Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
Bepec
Гость
« Ответ #6 : Август 13, 2013, 15:35 »

В реализации Qt происходит много преобразований. Один уж QPixmap::fromWinHBITMAP чего стоит.

 Зачем преобразовывать, если нужно просто сохранить на диск winApi-шными функциями.
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #7 : Август 13, 2013, 15:39 »

Я делал так:
Запускаем функцию в потоке, а из нее делаем блокирующий вызов функции из главного потока через
Код:
QMetaObject::invokeMethod(this, "your_function", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));

Таким образом никакого торможения гуи нет.

Посмотреть код можно тут: https://github.com/kibsoft/QtMEL/blob/master/src/grabbers/image/screengrabber.cpp
Функция captureFrame работает в отдельном потоке(сделано с помощью QtConcurrent), а функция currentFrame(к которой мы делаем блокирующий вызов) находится в главном.

что-то не совсем понятно, как этот код работает.. как картинка сохраняется на жесткий диск? тут ведь и есть самая большая потеря времени.. из-за которого и рубиться приложение. если картинка на экране с минимум цветов, то сохранение относительно без тормозов проходит.. но если много цветов на экране, приложение просто замирает!
Записан
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #8 : Август 13, 2013, 15:46 »

Код:
QImage frame;
QMetaObject::invokeMethod(this, "your_function", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");

Этот код должен выполняться в отдельном потоке. По этой причине никаких тормозов и нет, т.к. главный(гуи) поток не занят.

Код:
QImage your_function() {
   return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
}

А эта функция должна находится в главном потоке.
« Последнее редактирование: Август 13, 2013, 15:48 от kibsoft » Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #9 : Август 13, 2013, 15:51 »

Код:
QImage frame;
QMetaObject::invokeMethod(this, "your_function", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");

Этот код должен выполняться в отдельном потоке. По этой причине никаких тормозов и нет, т.к. главный(гуи) поток не занят.

Код:
QImage your_function() {
   return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
}

А эта функция должна находится в главном потоке.

о как! сейчас буду пробовать..
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #10 : Август 13, 2013, 16:20 »

При вызове функции создания скрина на консоль выдает:
QMetaObject::invokeMethod: No such method CThreadSaveScreen::getScreenShot()

Я так понимаю надо зарегить объект CThreadSaveScreen, как мета тип
qRegisterMetaType< CThreadSaveScreen >( "CThreadSaveScreen" ); т.о.?

на это ругается ошибкой: 'QObject::QObject(const QObject&)' is private

класс CThreadSaveScreen:
Код:
class CThreadSaveScreen : public QThread
{
    Q_OBJECT

    private:
    QString pathScreen;

    public:
        CThreadSaveScreen() : QThread()
        {
            pathScreen = "";
        }

    protected:
        void run();

    private slots:
        void setPathScreen(QString path);
};
Записан
_OLEGator_
Гость
« Ответ #11 : Август 13, 2013, 16:33 »

А где у класса CThreadSaveScreen метод getScreenShot?
Записан
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #12 : Август 13, 2013, 16:41 »

Код:
[quote author=kibsoft link=topic=25451.msg182211#msg182211 date=1376397980]
[code]QImage frame;
QMetaObject::invokeMethod(this, "your_function", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");

Этот код должен выполняться в отдельном потоке. По этой причине никаких тормозов и нет, т.к. главный(гуи) поток не занят.

Код:
QImage your_function() {
   return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
}

А эта функция должна находится в главном потоке.
[/quote]

так я так понял, что your_function() - это функция класса основного потока?
А
Код:
QImage frame;
QMetaObject::invokeMethod(this, "[b]your_function[/b]", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");
[/code]
делаем в run() другого потока..
Записан
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #13 : Август 13, 2013, 19:58 »

Стоит почитать документацию. Код, который в run() выполняется в отдельном потоке, а все остальные члены класса QThread находятся в главном потоке(если объект CThreadSaveScreen создан там и не перемещен в другой поток). Таким образом, в run вы выполняете это:

Код:
QImage frame;
QMetaObject::invokeMethod(this, "your_slot", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");

И объявляете приватный слот в CThreadSaveScreen под название your_slot:
Код:
private slots:
QImage your_slot()
{
   return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
}
Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
Vladimir
Крякер
****
Offline Offline

Сообщений: 305



Просмотр профиля
« Ответ #14 : Август 14, 2013, 10:43 »

Стоит почитать документацию. Код, который в run() выполняется в отдельном потоке, а все остальные члены класса QThread находятся в главном потоке(если объект CThreadSaveScreen создан там и не перемещен в другой поток). Таким образом, в run вы выполняете это:

Код:
QImage frame;
QMetaObject::invokeMethod(this, "your_slot", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QImage, frame));
frame.save(currentFile.at(0) + "/" + currentFile.at(1) + ".png");

И объявляете приватный слот в CThreadSaveScreen под название your_slot:
Код:
private slots:
QImage your_slot()
{
   return QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
}

Спасибо kibsoft! Все получилось и работает шустро! Правда на слот QImage your_slot() он заругался
QMetaMethod::invoke: Unable to invoke methods with return values in queued connections почему-то.. поставил ему void!
Работает все как и хотелось!  Смеющийся





Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.052 секунд. Запросов: 23.