void PlaybackController::nextSequence() { if(waitForExporter()) return; // Play back until either an undopoint or end-of-file is reached bool loop=true; while(loop) { MessageRecord next = m_reader->readNext(); switch(next.status) { case MessageRecord::OK: if(next.message->type() == protocol::MSG_INTERVAL) { // skip intervals delete next.message; } else { emit commandRead(protocol::MessagePtr(next.message)); if(next.message->type() == protocol::MSG_UNDOPOINT) loop = false; } break; case MessageRecord::INVALID: qWarning() << "Unrecognized command " << next.error.type << "of length" << next.error.len; break; case MessageRecord::END_OF_RECORDING: emit endOfFileReached(); loop = false; break; } } if(m_exporter && m_autosave) exportFrame(); updateIndexPosition(); }
void PlaybackController::jumpTo(int pos) { Q_ASSERT(m_indexloader); if(pos == m_reader->currentIndex()) return; if(waitForExporter()) return; // If the target position is behind current position or sufficiently far ahead, jump // to the closest snapshot point first if(pos < m_reader->currentIndex() || pos - m_reader->currentIndex() > 500) { int seIdx=0; const Index &index = m_indexloader->index(); for(int i=1;i<index.snapshots().size();++i) { const SnapshotEntry &next = index.snapshots().at(i); if(int(next.pos) > pos) break; seIdx = i; } // When jumping forward, don't restore the snapshot if the snapshot is behind // the current position if(pos < m_reader->currentIndex() || index.snapshots().at(seIdx).pos > quint32(m_reader->currentIndex())) jumptToSnapshot(seIdx); } // Now the current position is somewhere before the target position: replay commands while(m_reader->currentIndex() < pos && !m_reader->isEof()) { MessageRecord next = m_reader->readNext(); switch(next.status) { case MessageRecord::OK: if(next.message->type() == protocol::MSG_INTERVAL) { // skip intervals delete next.message; } else { emit commandRead(protocol::MessagePtr(next.message)); } break; case MessageRecord::INVALID: qWarning() << "Unrecognized command " << next.error.type << "of length" << next.error.len; break; case MessageRecord::END_OF_RECORDING: emit endOfFileReached(); break; } } if(m_exporter && m_autosave) exportFrame(); updateIndexPosition(); }
void PlaybackController::jumpTo(int pos) { if(!m_indexloader) { qWarning("jumpTo(%d): index not loaded!", pos); return; } if(pos == m_reader->currentIndex()) return; if(waitForExporter()) return; // If the target position is behind current position or sufficiently far ahead, jump // to the closest snapshot point first if(pos < m_reader->currentIndex() || pos - m_reader->currentIndex() > 500) { const Index &index = m_indexloader->index(); int snap = index.findClosestSnapshot(pos); // When jumping forward, don't restore the snapshot if the snapshot is behind // the current position if(pos < m_reader->currentIndex() || index.entries().at(snap).pos > quint32(m_reader->currentIndex())) jumpToSnapshot(snap); } // Now the current position is somewhere before the target position: replay commands while(m_reader->currentIndex() < pos && !m_reader->isEof()) { MessageRecord next = m_reader->readNext(); switch(next.status) { case MessageRecord::OK: if(next.message->type() == protocol::MSG_INTERVAL) { // skip intervals delete next.message; } else { emit commandRead(protocol::MessagePtr(next.message)); } break; case MessageRecord::INVALID: qWarning("Unrecognized command %d of length %d", next.error.type, next.error.len); break; case MessageRecord::END_OF_RECORDING: emit endOfFileReached(); break; } } if(m_exporter && m_autosave) exportFrame(); updateIndexPosition(); }
void PlaybackController::jumpToSnapshot(int idx) { Q_ASSERT(m_indexloader); StopEntry se = m_indexloader->index().entry(idx); canvas::StateSavepoint savepoint = m_indexloader->loadSavepoint(idx, m_canvas->stateTracker()); if(!savepoint) { qWarning("error loading savepoint"); return; } m_reader->seekTo(se.index, se.pos); m_canvas->stateTracker()->resetToSavepoint(savepoint); updateIndexPosition(); }
void PlaybackController::jumptToSnapshot(int idx) { Q_ASSERT(m_indexloader); SnapshotEntry se = m_indexloader->index().snapshots().at(idx); canvas::StateSavepoint savepoint = m_indexloader->loadSavepoint(idx, m_canvas->stateTracker()); if(!savepoint) { qWarning() << "error loading savepoint"; return; } m_reader->seekTo(se.pos, se.stream_offset); // TODO this needs more cooperation from the canvas thread: there may be // commands in the queue still which needs to be cleared. m_canvas->stateTracker()->resetToSavepoint(savepoint); updateIndexPosition(); }
void PlaybackController::nextCommands(int stepCount) { Q_ASSERT(stepCount>0); if(waitForExporter()) { m_waitedForExporter = true; return; } MessageRecord next = m_reader->readNext(); int writeFrames = 1; switch(next.status) { case MessageRecord::OK: { protocol::MessagePtr msg(next.message); if(msg->type() == protocol::MSG_INTERVAL) { if(m_play) { // Autoplay mode: pause for the given interval int interval = msg.cast<protocol::Interval>().milliseconds(); int maxinterval = m_maxInterval * 1000; m_timer->start(qMin(maxinterval, int(interval / m_speedFactor))); if(m_exporter && m_autosave) { int pauseframes = qRound(qMin(interval, maxinterval) / 1000.0 * m_exporter->fps()); if(pauseframes>0) writeFrames = pauseframes; } } else { // Manual mode: skip interval nextCommands(1); return; } } else { if(m_play) { if(msg->type() == protocol::MSG_MARKER && m_stopOnMarkers) { setPlaying(false); notification::playSound(notification::Event::MARKER); } else { if(stepCount==1) m_timer->start(int(qMax(1.0, 33.0 / m_speedFactor) + 0.5)); } } emit commandRead(msg); } break; } case MessageRecord::INVALID: qWarning() << "Unrecognized command " << next.error.type << "of length" << next.error.len; if(m_play) m_timer->start(1); break; case MessageRecord::END_OF_RECORDING: emit endOfFileReached(); break; } if(stepCount>1) { nextCommands(stepCount-1); } else { if(m_exporter && m_autosave) exportFrame(writeFrames); updateIndexPosition(); } }