void IndexBuilder::writeSnapshots(Reader &reader, KZip &zip) { static const qint64 SNAPSHOT_INTERVAL_MS = 1000; // snapshot interval in milliseconds static const int SNAPSHOT_MIN_ACTIONS = 200; // minimum number of actions between snapshots paintcore::LayerStack image; net::LayerListModel layermodel; canvas::StateTracker statetracker(&image, &layermodel, 1); MessageRecord msg; int snapshotCounter = 0; QElapsedTimer timer; timer.start(); while(true) { if(_abortflag.load()) return; msg = reader.readNext(); if(msg.status == MessageRecord::END_OF_RECORDING) break; else if(msg.status == MessageRecord::INVALID) continue; protocol::MessagePtr m(msg.message); if(m->isCommand()) { statetracker.receiveCommand(m); ++snapshotCounter; } // Save a snapshot every SNAPSHOT_INTERVAL or at every marker. (But no more often than SNAPSHOT_MIN_ACTIONS) // Note. We use the actual elapsed rendering time to decide when to snapshot. This means that (ideally), // the time it takes to jump to a snapshot is at most SNAPSHOT_INTERVAL milliseconds (+ the time it takes to load the snapshot) if(m_index.snapshots().isEmpty() || ((timer.hasExpired(SNAPSHOT_INTERVAL_MS) || m->type() == protocol::MSG_MARKER) && snapshotCounter>=SNAPSHOT_MIN_ACTIONS)) { qint64 streampos = reader.filePosition(); emit progress(streampos); canvas::StateSavepoint sp = statetracker.createSavepoint(-1); QBuffer buf; buf.open(QBuffer::ReadWrite); { QDataStream ds(&buf); sp.toDatastream(ds); } int snapshotIdx = m_index.m_snapshots.size(); zip.writeFile(QString("snapshot-%1").arg(snapshotIdx), buf.data()); m_index.m_snapshots.append(SnapshotEntry(streampos, reader.currentIndex())); snapshotCounter = 0; timer.restart(); } } }