mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-07 22:29:10 +02:00
Massive performance improvements.
This commit is contained in:
parent
7f4613f136
commit
1e97a69b51
2 changed files with 106 additions and 67 deletions
|
@ -14,16 +14,22 @@
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
|
|
||||||
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
#include "SnapshotAnimated.h"
|
#include "SnapshotAnimated.h"
|
||||||
|
|
||||||
QTimer SnapshotAnimated::snapshotAnimatedTimer;
|
QTimer* SnapshotAnimated::snapshotAnimatedTimer = NULL;
|
||||||
GifWriter SnapshotAnimated::snapshotAnimatedGifWriter;
|
|
||||||
qint64 SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
qint64 SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
||||||
qint64 SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
qint64 SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
||||||
qint64 SnapshotAnimated::snapshotAnimatedLastWriteFrameDuration = 0;
|
|
||||||
bool SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
bool SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
||||||
QString SnapshotAnimated::snapshotAnimatedPath;
|
QString SnapshotAnimated::snapshotAnimatedPath;
|
||||||
QString SnapshotAnimated::snapshotStillPath;
|
QString SnapshotAnimated::snapshotStillPath;
|
||||||
|
QVector<QImage> SnapshotAnimated::snapshotAnimatedFrameVector;
|
||||||
|
QVector<qint64> SnapshotAnimated::snapshotAnimatedFrameDelayVector;
|
||||||
|
Application* SnapshotAnimated::app;
|
||||||
|
float SnapshotAnimated::aspectRatio;
|
||||||
|
QSharedPointer<WindowScriptingInterface> SnapshotAnimated::snapshotAnimatedDM;
|
||||||
|
GifWriter SnapshotAnimated::snapshotAnimatedGifWriter;
|
||||||
|
|
||||||
|
|
||||||
Setting::Handle<bool> SnapshotAnimated::alsoTakeAnimatedSnapshot("alsoTakeAnimatedSnapshot", true);
|
Setting::Handle<bool> SnapshotAnimated::alsoTakeAnimatedSnapshot("alsoTakeAnimatedSnapshot", true);
|
||||||
Setting::Handle<float> SnapshotAnimated::snapshotAnimatedDuration("snapshotAnimatedDuration", SNAPSNOT_ANIMATED_DURATION_SECS);
|
Setting::Handle<float> SnapshotAnimated::snapshotAnimatedDuration("snapshotAnimatedDuration", SNAPSNOT_ANIMATED_DURATION_SECS);
|
||||||
|
@ -31,77 +37,103 @@ Setting::Handle<float> SnapshotAnimated::snapshotAnimatedDuration("snapshotAnima
|
||||||
void SnapshotAnimated::saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer<WindowScriptingInterface> dm) {
|
void SnapshotAnimated::saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer<WindowScriptingInterface> dm) {
|
||||||
// If we're not in the middle of capturing an animated snapshot...
|
// If we're not in the middle of capturing an animated snapshot...
|
||||||
if (SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp == 0) {
|
if (SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp == 0) {
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimer = new QTimer();
|
||||||
|
SnapshotAnimated::aspectRatio = aspectRatio;
|
||||||
|
SnapshotAnimated::app = app;
|
||||||
|
SnapshotAnimated::snapshotAnimatedDM = dm;
|
||||||
// Define the output location of the still and animated snapshots.
|
// Define the output location of the still and animated snapshots.
|
||||||
SnapshotAnimated::snapshotStillPath = pathStill;
|
SnapshotAnimated::snapshotStillPath = pathStill;
|
||||||
SnapshotAnimated::snapshotAnimatedPath = pathStill;
|
SnapshotAnimated::snapshotAnimatedPath = pathStill;
|
||||||
SnapshotAnimated::snapshotAnimatedPath.replace("jpg", "gif");
|
SnapshotAnimated::snapshotAnimatedPath.replace("jpg", "gif");
|
||||||
// Reset the current animated snapshot last frame duration
|
|
||||||
SnapshotAnimated::snapshotAnimatedLastWriteFrameDuration = SNAPSNOT_ANIMATED_INITIAL_WRITE_DURATION_MSEC;
|
|
||||||
|
|
||||||
// Ensure the snapshot timer is Precise (attempted millisecond precision)
|
// Ensure the snapshot timer is Precise (attempted millisecond precision)
|
||||||
SnapshotAnimated::snapshotAnimatedTimer.setTimerType(Qt::PreciseTimer);
|
SnapshotAnimated::snapshotAnimatedTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
|
||||||
// Connect the snapshotAnimatedTimer QTimer to the lambda slot function
|
// Connect the snapshotAnimatedTimer QTimer to the lambda slot function
|
||||||
QObject::connect(&(SnapshotAnimated::snapshotAnimatedTimer), &QTimer::timeout, [=] {
|
QObject::connect((SnapshotAnimated::snapshotAnimatedTimer), &QTimer::timeout, captureFrames);
|
||||||
if (SnapshotAnimated::snapshotAnimatedTimerRunning) {
|
|
||||||
// Get a screenshot from the display, then scale the screenshot down,
|
|
||||||
// then convert it to the image format the GIF library needs,
|
|
||||||
// then save all that to the QImage named "frame"
|
|
||||||
QImage frame(app->getActiveDisplayPlugin()->getScreenshot(aspectRatio));
|
|
||||||
frame = frame.scaledToWidth(SNAPSNOT_ANIMATED_WIDTH).convertToFormat(QImage::Format_RGBA8888);
|
|
||||||
|
|
||||||
// If this is an intermediate or the final frame...
|
|
||||||
if (SnapshotAnimated::snapshotAnimatedTimestamp > 0) {
|
|
||||||
// Variable used to determine how long the current frame took to pack
|
|
||||||
qint64 framePackStartTime = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
// Write the frame to the gif
|
|
||||||
GifWriteFrame(&(SnapshotAnimated::snapshotAnimatedGifWriter),
|
|
||||||
(uint8_t*)frame.bits(),
|
|
||||||
frame.width(),
|
|
||||||
frame.height(),
|
|
||||||
round(((float)(framePackStartTime - SnapshotAnimated::snapshotAnimatedTimestamp + SnapshotAnimated::snapshotAnimatedLastWriteFrameDuration)) / 10));
|
|
||||||
// Record the current frame timestamp
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimestamp = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
// Record how long it took for the current frame to pack
|
|
||||||
SnapshotAnimated::snapshotAnimatedLastWriteFrameDuration = SnapshotAnimated::snapshotAnimatedTimestamp - framePackStartTime;
|
|
||||||
// If that was the last frame...
|
|
||||||
if ((SnapshotAnimated::snapshotAnimatedTimestamp - SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp) >= (SnapshotAnimated::snapshotAnimatedDuration.get() * MSECS_PER_SECOND)) {
|
|
||||||
// Stop the snapshot QTimer. This action by itself DOES NOT GUARANTEE
|
|
||||||
// that the slot will not be called again in the future.
|
|
||||||
// See: http://lists.qt-project.org/pipermail/qt-interest-old/2009-October/013926.html
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimer.stop();
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
|
||||||
// Reset the current frame timestamp
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
|
||||||
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
|
||||||
// Write out the end of the GIF
|
|
||||||
GifEnd(&(SnapshotAnimated::snapshotAnimatedGifWriter));
|
|
||||||
// Let the dependency manager know that the snapshots have been taken.
|
|
||||||
emit dm->snapshotTaken(SnapshotAnimated::snapshotStillPath, SnapshotAnimated::snapshotAnimatedPath, false);
|
|
||||||
}
|
|
||||||
// If that was the first frame...
|
|
||||||
} else {
|
|
||||||
// Write out the header and beginning of the GIF file
|
|
||||||
GifBegin(&(SnapshotAnimated::snapshotAnimatedGifWriter), qPrintable(SnapshotAnimated::snapshotAnimatedPath), frame.width(), frame.height(), SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC / 10);
|
|
||||||
// Write the first to the gif
|
|
||||||
GifWriteFrame(&(SnapshotAnimated::snapshotAnimatedGifWriter),
|
|
||||||
(uint8_t*)frame.bits(),
|
|
||||||
frame.width(),
|
|
||||||
frame.height(),
|
|
||||||
SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC / 10);
|
|
||||||
// Record the current frame timestamp
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimestamp = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = SnapshotAnimated::snapshotAnimatedTimestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start the snapshotAnimatedTimer QTimer - argument for this is in milliseconds
|
// Start the snapshotAnimatedTimer QTimer - argument for this is in milliseconds
|
||||||
SnapshotAnimated::snapshotAnimatedTimer.start(SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC);
|
|
||||||
SnapshotAnimated::snapshotAnimatedTimerRunning = true;
|
SnapshotAnimated::snapshotAnimatedTimerRunning = true;
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimer->start(SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC);
|
||||||
// If we're already in the middle of capturing an animated snapshot...
|
// If we're already in the middle of capturing an animated snapshot...
|
||||||
} else {
|
} else {
|
||||||
// Just tell the dependency manager that the capture of the still snapshot has taken place.
|
// Just tell the dependency manager that the capture of the still snapshot has taken place.
|
||||||
emit dm->snapshotTaken(pathStill, "", false);
|
emit dm->snapshotTaken(pathStill, "", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SnapshotAnimated::captureFrames() {
|
||||||
|
if (SnapshotAnimated::snapshotAnimatedTimerRunning) {
|
||||||
|
// Get a screenshot from the display, then scale the screenshot down,
|
||||||
|
// then convert it to the image format the GIF library needs,
|
||||||
|
// then save all that to the QImage named "frame"
|
||||||
|
QImage frame(SnapshotAnimated::app->getActiveDisplayPlugin()->getScreenshot(SnapshotAnimated::aspectRatio));
|
||||||
|
frame = frame.scaledToWidth(SNAPSNOT_ANIMATED_WIDTH);
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameVector.append(frame);
|
||||||
|
|
||||||
|
// If that was the first frame...
|
||||||
|
if (SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp == 0) {
|
||||||
|
// Record the current frame timestamp
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
// Record the first frame timestamp
|
||||||
|
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = SnapshotAnimated::snapshotAnimatedTimestamp;
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameDelayVector.append(SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC / 10);
|
||||||
|
// If this is an intermediate or the final frame...
|
||||||
|
} else {
|
||||||
|
// Push the current frame delay onto the vector
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameDelayVector.append(round(((float)(QDateTime::currentMSecsSinceEpoch() - SnapshotAnimated::snapshotAnimatedTimestamp)) / 10));
|
||||||
|
// Record the current frame timestamp
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
|
// If that was the last frame...
|
||||||
|
if ((SnapshotAnimated::snapshotAnimatedTimestamp - SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp) >= (SnapshotAnimated::snapshotAnimatedDuration.get() * MSECS_PER_SECOND)) {
|
||||||
|
// Stop the snapshot QTimer. This action by itself DOES NOT GUARANTEE
|
||||||
|
// that the slot will not be called again in the future.
|
||||||
|
// See: http://lists.qt-project.org/pipermail/qt-interest-old/2009-October/013926.html
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimer->stop();
|
||||||
|
delete SnapshotAnimated::snapshotAnimatedTimer;
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
||||||
|
// Reset the current frame timestamp
|
||||||
|
SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
||||||
|
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
||||||
|
|
||||||
|
// Kick off the thread that'll pack the frames into the GIF
|
||||||
|
QtConcurrent::run(processFrames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SnapshotAnimated::processFrames() {
|
||||||
|
uint32_t width = SnapshotAnimated::snapshotAnimatedFrameVector[0].width();
|
||||||
|
uint32_t height = SnapshotAnimated::snapshotAnimatedFrameVector[0].height();
|
||||||
|
|
||||||
|
// Create the GIF from the temporary files
|
||||||
|
// Write out the header and beginning of the GIF file
|
||||||
|
GifBegin(
|
||||||
|
&(SnapshotAnimated::snapshotAnimatedGifWriter),
|
||||||
|
qPrintable(SnapshotAnimated::snapshotAnimatedPath),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
1); // "1" means "yes there is a delay" with this GifCreator library.
|
||||||
|
for (int itr = 0; itr < SnapshotAnimated::snapshotAnimatedFrameVector.size(); itr++) {
|
||||||
|
// Write each frame to the GIF
|
||||||
|
GifWriteFrame(&(SnapshotAnimated::snapshotAnimatedGifWriter),
|
||||||
|
(uint8_t*)SnapshotAnimated::snapshotAnimatedFrameVector[itr].convertToFormat(QImage::Format_RGBA8888).bits(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameDelayVector[itr]);
|
||||||
|
}
|
||||||
|
// Write out the end of the GIF
|
||||||
|
GifEnd(&(SnapshotAnimated::snapshotAnimatedGifWriter));
|
||||||
|
|
||||||
|
// Clear out the frame and frame delay vectors.
|
||||||
|
// Also release the memory not required to store the items.
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameVector.clear();
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameVector.squeeze();
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameDelayVector.clear();
|
||||||
|
SnapshotAnimated::snapshotAnimatedFrameDelayVector.squeeze();
|
||||||
|
|
||||||
|
// Let the dependency manager know that the snapshots have been taken.
|
||||||
|
emit SnapshotAnimated::snapshotAnimatedDM->snapshotTaken(SnapshotAnimated::snapshotStillPath, SnapshotAnimated::snapshotAnimatedPath, false);
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_SnapshotAnimated_h
|
#ifndef hifi_SnapshotAnimated_h
|
||||||
#define hifi_SnapshotAnimated_h
|
#define hifi_SnapshotAnimated_h
|
||||||
|
|
||||||
|
#include <QtCore/QVector>
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <GifCreator.h>
|
#include <GifCreator.h>
|
||||||
|
@ -28,20 +29,26 @@
|
||||||
#define SNAPSNOT_ANIMATED_DURATION_MSEC (SNAPSNOT_ANIMATED_DURATION_SECS*1000)
|
#define SNAPSNOT_ANIMATED_DURATION_MSEC (SNAPSNOT_ANIMATED_DURATION_SECS*1000)
|
||||||
|
|
||||||
#define SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC (1000/SNAPSNOT_ANIMATED_TARGET_FRAMERATE)
|
#define SNAPSNOT_ANIMATED_FRAME_DELAY_MSEC (1000/SNAPSNOT_ANIMATED_TARGET_FRAMERATE)
|
||||||
// This is the fudge factor that we add to the *first* GIF frame's "delay" value
|
|
||||||
#define SNAPSNOT_ANIMATED_INITIAL_WRITE_DURATION_MSEC (20)
|
|
||||||
#define SNAPSNOT_ANIMATED_NUM_FRAMES (SNAPSNOT_ANIMATED_DURATION_SECS * SNAPSNOT_ANIMATED_TARGET_FRAMERATE)
|
|
||||||
|
|
||||||
class SnapshotAnimated {
|
class SnapshotAnimated {
|
||||||
private:
|
private:
|
||||||
static QTimer snapshotAnimatedTimer;
|
static QTimer* snapshotAnimatedTimer;
|
||||||
static GifWriter snapshotAnimatedGifWriter;
|
|
||||||
static qint64 snapshotAnimatedTimestamp;
|
static qint64 snapshotAnimatedTimestamp;
|
||||||
static qint64 snapshotAnimatedFirstFrameTimestamp;
|
static qint64 snapshotAnimatedFirstFrameTimestamp;
|
||||||
static qint64 snapshotAnimatedLastWriteFrameDuration;
|
|
||||||
static bool snapshotAnimatedTimerRunning;
|
static bool snapshotAnimatedTimerRunning;
|
||||||
static QString snapshotAnimatedPath;
|
|
||||||
static QString snapshotStillPath;
|
static QString snapshotStillPath;
|
||||||
|
|
||||||
|
static QString snapshotAnimatedPath;
|
||||||
|
static QVector<QImage> snapshotAnimatedFrameVector;
|
||||||
|
static QVector<qint64> snapshotAnimatedFrameDelayVector;
|
||||||
|
static QSharedPointer<WindowScriptingInterface> snapshotAnimatedDM;
|
||||||
|
static Application* app;
|
||||||
|
static float aspectRatio;
|
||||||
|
|
||||||
|
static GifWriter snapshotAnimatedGifWriter;
|
||||||
|
|
||||||
|
static void captureFrames();
|
||||||
|
static void processFrames();
|
||||||
public:
|
public:
|
||||||
static void saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer<WindowScriptingInterface> dm);
|
static void saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer<WindowScriptingInterface> dm);
|
||||||
static Setting::Handle<bool> alsoTakeAnimatedSnapshot;
|
static Setting::Handle<bool> alsoTakeAnimatedSnapshot;
|
||||||
|
|
Loading…
Reference in a new issue