From cd7be9b87045f731a5a4b7dec0653e398bcf40d3 Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Tue, 14 Jul 2020 17:19:24 -0600 Subject: [PATCH] Conversion task working for both directions --- data/tasks/sessionRecordConvertExample1.task | 7 + .../openspace/interaction/sessionrecording.h | 80 +++++++---- .../interaction/tasks/convertrecformattask.h | 5 +- include/openspace/network/messagestructures.h | 8 ++ src/CMakeLists.txt | 2 + src/interaction/sessionrecording.cpp | 100 +++++++------- src/interaction/sessionrecording_lua.inl | 4 +- .../tasks/convertrecformattask.cpp | 124 ++++++++++++------ 8 files changed, 211 insertions(+), 119 deletions(-) create mode 100644 data/tasks/sessionRecordConvertExample1.task diff --git a/data/tasks/sessionRecordConvertExample1.task b/data/tasks/sessionRecordConvertExample1.task new file mode 100644 index 0000000000..2237c462e8 --- /dev/null +++ b/data/tasks/sessionRecordConvertExample1.task @@ -0,0 +1,7 @@ +return { + { + Type = "ConvertRecFormatTask", + InputFilePath = "../../recordings/input", + OutputFilePath = "../../recordings/output" + } +} diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index bcfedcd918..fbfc1b5c9c 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -32,13 +32,21 @@ namespace openspace::interaction { +enum class SessionRecordingDataMode { + Ascii = 0, + Binary, + Unknown +}; +static const std::string SessionRecordingFileHeaderTitle = "OpenSpace_record/playback"; +static const std::string SessionRecordingHeaderCameraAscii = "camera"; +static const std::string SessionRecordingHeaderTimeAscii = "time"; +static const std::string SessionRecordingHeaderScriptAscii = "script"; +static const char SessionRecordingHeaderCameraBinary = 'c'; +static const char SessionRecordingHeaderTimeBinary = 't'; +static const char SessionRecordingHeaderScriptBinary = 's'; + class SessionRecording : public properties::PropertyOwner { public: - enum class RecordedDataMode { - Ascii = 0, - Binary - }; - enum class SessionState { Idle = 0, Recording, @@ -51,14 +59,12 @@ public: double timeSim; }; - const std::string FileHeaderTitle = "OpenSpace_record/playback"; static const size_t FileHeaderVersionLength = 5; - const char FileHeaderVersion[FileHeaderVersionLength] = { + static constexpr char FileHeaderVersion[FileHeaderVersionLength] = { '0', '0', '.', '8', '5' }; - const char DataFormatAsciiTag = 'A'; - const char DataFormatBinaryTag = 'B'; - + static const char DataFormatAsciiTag = 'A'; + static const char DataFormatBinaryTag = 'B'; static const size_t keyframeHeaderSize_bytes = 33; static const size_t saveBufferCameraSize_min = 82; static const size_t saveBufferStringSize_max = 500; @@ -114,7 +120,7 @@ public: * * \return \c true if recording to file starts without errors */ - void setRecordDataFormat(RecordedDataMode dataMode); + void setRecordDataFormat(SessionRecordingDataMode dataMode); /** * Used to stop a recording in progress. If open, the recording file will be closed, @@ -246,11 +252,12 @@ public: * * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a camera keyframe which contains camera details - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readCameraKeyframeAscii(timestamps& times, - datamessagestructures::CameraKeyframe& kf, std::string filenameRead, int lineN); + datamessagestructures::CameraKeyframe& kf, std::string currentParsingLine, + int lineN); /** * Reads a time keyframe from a binary format playback file, and populates input @@ -270,11 +277,12 @@ public: * * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a time keyframe which contains time details - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readTimeKeyframeAscii(timestamps& times, - datamessagestructures::TimeKeyframe& kf, std::string filenameRead, int lineN); + datamessagestructures::TimeKeyframe& kf, std::string currentParsingLine, + int lineN); /** * Reads a script keyframe from a binary format playback file, and populates input @@ -296,11 +304,12 @@ public: * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a script keyframe which contains the size of the script * (in chars) and the text itself - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readScriptKeyframeAscii(timestamps& times, - datamessagestructures::ScriptMessage& kf, std::string filenameRead, int lineN); + datamessagestructures::ScriptMessage& kf, std::string currentParsingLine, + int lineN); /** * Writes a camera keyframe to a binary format recording file using a CameraKeyframe @@ -377,6 +386,35 @@ public: */ static std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars); + /** + * Writes a header to a binary recording file buffer + * + * \param times reference to a timestamps structure which contains recorded times + * \param type single character signifying the keyframe type + * \param kfBuffer the char buffer holding the recording info to be written + * \param idx index into write buffer (this is updated with the num of chars written) + */ + static void saveHeaderBinary(timestamps times, char type, unsigned char* kfBuffer, + size_t& idx); + + /** + * Writes a header to an ascii recording file buffer + * + * \param times reference to a timestamps structure which contains recorded times + * \param type string signifying the keyframe type + * \param line the stringstream buffer being written to + */ + static void saveHeaderAscii(timestamps times, const std::string& type, + std::stringstream& line); + + /** + * Saves a keyframe to an ascii recording file + * + * \param entry the ascii string version of the keyframe (any type) + * \param file ofstream object to write to + */ + static void saveKeyframeToFile(std::string entry, std::ofstream& file); + private: enum class RecordedType { Camera = 0, @@ -409,7 +447,6 @@ private: std::ofstream& file); static void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, std::ofstream& file); - static void saveKeyframeToFile(std::string entry, std::ofstream& file); void addKeyframe(double timestamp, interaction::KeyframeNavigator::CameraPose keyframe); @@ -439,12 +476,7 @@ private: static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c); static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b); - static void saveHeaderBinary(timestamps times, char type, - unsigned char* kfBuffer, size_t& idx); - static void saveHeaderAscii(timestamps times, const std::string& type, - std::stringstream& line); - - RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; + SessionRecordingDataMode _recordingDataMode = SessionRecordingDataMode::Binary; SessionState _state = SessionState::Idle; SessionState _lastState = SessionState::Idle; std::string _playbackFilename; diff --git a/include/openspace/interaction/tasks/convertrecformattask.h b/include/openspace/interaction/tasks/convertrecformattask.h index fab8dfab51..d084bec2a6 100644 --- a/include/openspace/interaction/tasks/convertrecformattask.h +++ b/include/openspace/interaction/tasks/convertrecformattask.h @@ -53,20 +53,19 @@ public: void perform(const Task::ProgressCallback& progressCallback) override; static documentation::Documentation documentation(); void convert(); - SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType(); private: void convertToAscii(); void convertToBinary(); + void determineFormatType(); std::string addFileSuffix(const std::string& filePath, const std::string& suffix); std::string _inFilePath; std::string _outFilePath; std::ifstream _iFile; std::ofstream _oFile; + SessionRecordingDataMode _fileFormatType; std::string _valueFunctionLua; - - SessionRecording sr; }; } // namespace openspace::interaction diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index bad251b66f..0131383ebe 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -429,6 +429,12 @@ struct ScriptMessage { double _timestamp; void serialize(std::vector &buffer) const { + size_t strLen = _script.size(); + size_t writeSize_bytes = sizeof(size_t); + + unsigned char const *p = reinterpret_cast(&strLen); + buffer.insert(buffer.end(), p, p + writeSize_bytes); + buffer.insert(buffer.end(), _script.begin(), _script.end()); }; @@ -486,6 +492,8 @@ struct ScriptMessage { _script.erase(); for (int i = 0; i < numScriptLines; ++i) { std::getline(iss, tmpReadbackScript); + size_t start = tmpReadbackScript.find_first_not_of(" "); + tmpReadbackScript = tmpReadbackScript.substr(start); _script.append(tmpReadbackScript); if (i < (numScriptLines - 1)) { _script.append("\n"); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5642e724a..ae2315ffc6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl ${OPENSPACE_BASE_DIR}/src/interaction/websocketinputstate.cpp ${OPENSPACE_BASE_DIR}/src/interaction/websocketcamerastates.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/tasks/convertrecformattask.cpp ${OPENSPACE_BASE_DIR}/src/mission/mission.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl @@ -245,6 +246,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketinputstate.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketcamerastates.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/tasks/convertrecformattask.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index eba6a4313a..8e26877d3d 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -57,7 +60,11 @@ namespace openspace::interaction { SessionRecording::SessionRecording() : properties::PropertyOwner({ "SessionRecording", "Session Recording" }) -{} +{ + auto fTask = FactoryManager::ref().factory(); + ghoul_assert(fRenderable, "No task factory existed"); + fTask->registerClass("ConvertRecFormatTask"); +} SessionRecording::~SessionRecording() {} // NOLINT @@ -66,7 +73,7 @@ void SessionRecording::deinitialize() { stopPlayback(); } -void SessionRecording::setRecordDataFormat(RecordedDataMode dataMode) { +void SessionRecording::setRecordDataFormat(SessionRecordingDataMode dataMode) { _recordingDataMode = dataMode; } @@ -102,7 +109,7 @@ bool SessionRecording::startRecording(const std::string& filename) { _playbackActive_camera = false; _playbackActive_time = false; _playbackActive_script = false; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile.open(absFilename, std::ios::binary); } else { @@ -115,9 +122,9 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - _recordFile << FileHeaderTitle; + _recordFile << SessionRecordingFileHeaderTitle; _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile << DataFormatBinaryTag; } else { @@ -180,9 +187,9 @@ bool SessionRecording::startPlayback(const std::string& filename, // Read header std::string readBackHeaderString = readHeaderElement( _playbackFile, - FileHeaderTitle.length() + SessionRecordingFileHeaderTitle.length() ); - if (readBackHeaderString != FileHeaderTitle) { + if (readBackHeaderString != SessionRecordingFileHeaderTitle) { LERROR("Specified playback file does not contain expected header."); cleanUpPlayback(); return false; @@ -190,10 +197,10 @@ bool SessionRecording::startPlayback(const std::string& filename, readHeaderElement(_playbackFile, FileHeaderVersionLength); std::string readDataMode = readHeaderElement(_playbackFile, 1); if (readDataMode[0] == DataFormatAsciiTag) { - _recordingDataMode = RecordedDataMode::Ascii; + _recordingDataMode = SessionRecordingDataMode::Ascii; } else if (readDataMode[0] == DataFormatBinaryTag) { - _recordingDataMode = RecordedDataMode::Binary; + _recordingDataMode = SessionRecordingDataMode::Binary; } else { LERROR("Unknown data type in header (should be Ascii or Binary)"); @@ -201,13 +208,14 @@ bool SessionRecording::startPlayback(const std::string& filename, } std::string throwawayNewlineChar = readHeaderElement(_playbackFile, 1); - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { //Close & re-open the file, starting from the beginning, and do dummy read // past the header, version, and data type _playbackFile.close(); _playbackFile.open(_playbackFilename, std::ifstream::in | std::ios::binary); - size_t headerSize = FileHeaderTitle.length() + FileHeaderVersionLength + - sizeof(DataFormatBinaryTag) + sizeof('\n'); + size_t headerSize = SessionRecordingFileHeaderTitle.length() + + FileHeaderVersionLength + + sizeof(DataFormatBinaryTag) + sizeof('\n'); _playbackFile.read(reinterpret_cast(&_keyframeBuffer), headerSize); } @@ -443,7 +451,7 @@ void SessionRecording::saveCameraKeyframe() { kf._timestamp - _timestampRecordStarted, global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveCameraKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { @@ -479,7 +487,7 @@ void SessionRecording::saveCameraKeyframeBinary(timestamps times, { // Writing to a binary session recording file size_t idx = 0; - saveHeaderBinary(times, 'c', kfBuffer, idx); + saveHeaderBinary(times, SessionRecordingHeaderCameraBinary, kfBuffer, idx); // Writing to internal buffer, and then to file, for performance reasons std::vector writeBuffer; kf.serialize(writeBuffer); @@ -492,7 +500,7 @@ void SessionRecording::saveCameraKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "camera", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderCameraAscii, keyframeLine); kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -510,7 +518,7 @@ void SessionRecording::saveTimeKeyframe() { kf._timestamp - _timestampRecordStarted, global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveTimeKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { saveTimeKeyframeAscii(times, kf, _recordFile); @@ -523,7 +531,7 @@ void SessionRecording::saveTimeKeyframeBinary(timestamps times, std::ofstream& file) { size_t idx = 0; - saveHeaderBinary(times, 't', kfBuffer, idx); + saveHeaderBinary(times, SessionRecordingHeaderTimeBinary, kfBuffer, idx); std::vector writeBuffer; kf.serialize(writeBuffer); writeToFileBuffer(kfBuffer, idx, writeBuffer); @@ -535,7 +543,7 @@ void SessionRecording::saveTimeKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "time", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderTimeAscii, keyframeLine); kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -554,7 +562,7 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveScriptKeyframeBinary(times, sm, _keyframeBuffer, _recordFile); } else { @@ -568,11 +576,12 @@ void SessionRecording::saveScriptKeyframeBinary(timestamps times, std::ofstream& file) { size_t idx = 0; - saveHeaderBinary(times, 's', smBuffer, idx); - //Write script header to file + saveHeaderBinary(times, SessionRecordingHeaderScriptBinary, smBuffer, idx); + // Writing to internal buffer, and then to file, for performance reasons + std::vector writeBuffer; + sm.serialize(writeBuffer); + writeToFileBuffer(smBuffer, idx, writeBuffer); saveKeyframeToFileBinary(smBuffer, idx, file); - //Write script data to file - sm.write(smBuffer, idx, file); } void SessionRecording::saveScriptKeyframeAscii(timestamps times, @@ -581,7 +590,7 @@ void SessionRecording::saveScriptKeyframeAscii(timestamps times, { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "script", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderScriptAscii, keyframeLine); sm.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -632,7 +641,7 @@ SessionRecording::SessionState SessionRecording::state() const { bool SessionRecording::playbackAddEntriesToTimeline() { bool parsingErrorsFound = false; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { unsigned char frameType; bool fileReadOk = true; @@ -647,13 +656,13 @@ bool SessionRecording::playbackAddEntriesToTimeline() { fileReadOk = false; break; } - if (frameType == 'c') { + if (frameType == SessionRecordingHeaderCameraBinary) { playbackCamera(); } - else if (frameType == 't') { + else if (frameType == SessionRecordingHeaderTimeBinary) { playbackTimeChange(); } - else if (frameType == 's') { + else if (frameType == SessionRecordingHeaderScriptBinary) { playbackScript(); } else { @@ -682,13 +691,13 @@ bool SessionRecording::playbackAddEntriesToTimeline() { break; } - if (entryType == "camera") { + if (entryType == SessionRecordingHeaderCameraAscii) { playbackCamera(); } - else if (entryType == "time") { + else if (entryType == SessionRecordingHeaderTimeAscii) { playbackTimeChange(); } - else if (entryType == "script") { + else if (entryType == SessionRecordingHeaderScriptAscii) { playbackScript(); } else { @@ -788,7 +797,7 @@ void SessionRecording::playbackCamera() { timestamps times; datamessagestructures::CameraKeyframe kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readCameraKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { @@ -843,16 +852,18 @@ void SessionRecording::readCameraKeyframeBinary(timestamps& times, void SessionRecording::readCameraKeyframeAscii(timestamps& times, datamessagestructures::CameraKeyframe& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string rotationFollowing; std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); + //ASCII format does not contain trailing timestamp so add it here + kf._timestamp = times.timeOs; if (iss.fail() || !iss.eof()) { LERROR(fmt::format("Error parsing camera line {} of playback file", lineN)); @@ -864,7 +875,7 @@ void SessionRecording::playbackTimeChange() { timestamps times; datamessagestructures::TimeKeyframe kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readTimeKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { readTimeKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); @@ -913,12 +924,12 @@ void SessionRecording::readTimeKeyframeBinary(timestamps& times, void SessionRecording::readTimeKeyframeAscii(timestamps& times, datamessagestructures::TimeKeyframe& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); @@ -931,8 +942,8 @@ void SessionRecording::readTimeKeyframeAscii(timestamps& times, } } -static std::string SessionRecording::readHeaderElement(std::ifstream& stream, - size_t readLen_chars) +std::string SessionRecording::readHeaderElement(std::ifstream& stream, + size_t readLen_chars) { std::vector readTemp(readLen_chars); stream.read(&readTemp[0], readLen_chars); @@ -943,7 +954,7 @@ void SessionRecording::playbackScript() { timestamps times; datamessagestructures::ScriptMessage kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readScriptKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { readScriptKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); @@ -990,11 +1001,11 @@ void SessionRecording::readScriptKeyframeBinary(timestamps& times, void SessionRecording::readScriptKeyframeAscii(timestamps& times, datamessagestructures::ScriptMessage& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); @@ -1156,11 +1167,6 @@ bool SessionRecording::doesTimelineEntryContainCamera(unsigned int index) const } bool SessionRecording::processNextNonCameraKeyframeAheadInTime() { - //LINFO(fmt::format( - // "Keyframe at {} frame={} timelineIndex={}", - // now, global::renderEngine._frameNumber, _idxTimeline - //)); - switch (getNextKeyframeType()) { case RecordedType::Camera: // Just return true since this function no longer handles camera keyframes diff --git a/src/interaction/sessionrecording_lua.inl b/src/interaction/sessionrecording_lua.inl index 8a1c2409b4..8e4761295b 100644 --- a/src/interaction/sessionrecording_lua.inl +++ b/src/interaction/sessionrecording_lua.inl @@ -40,7 +40,7 @@ int startRecording(lua_State* L) { return luaL_error(L, "filepath string is empty"); } global::sessionRecording.setRecordDataFormat( - openspace::interaction::SessionRecording::RecordedDataMode::Binary + openspace::interaction::SessionRecordingDataMode::Binary ); global::sessionRecording.startRecording(recordFilePath); @@ -63,7 +63,7 @@ int startRecordingAscii(lua_State* L) { return luaL_error(L, "filepath string is empty"); } global::sessionRecording.setRecordDataFormat( - openspace::interaction::SessionRecording::RecordedDataMode::Ascii + openspace::interaction::SessionRecordingDataMode::Ascii ); global::sessionRecording.startRecording(recordFilePath); diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 8b79e4477e..6cbe5257db 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -51,11 +51,11 @@ ConvertRecFormatTask::ConvertRecFormatTask(const ghoul::Dictionary& dictionary) ghoul_assert(FileSys.fileExists(_inFilePath), "The filename must exist"); if (!FileSys.fileExists(_inFilePath)) { LERROR(fmt::format("Failed to load session recording file: {}", _inFilePath)); - //throw ghoul::FileNotFoundError(_inFilePath); } - - _iFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); - _iFile.open(_inFilePath); + else { + _iFile.open(_inFilePath, std::ifstream::in); + determineFormatType(); + } } ConvertRecFormatTask::~ConvertRecFormatTask() { @@ -63,17 +63,42 @@ ConvertRecFormatTask::~ConvertRecFormatTask() { _oFile.close(); } -void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { +std::string ConvertRecFormatTask::description() { + std::string description = "Convert session recording file '" + _inFilePath + "' "; + if (_fileFormatType == SessionRecordingDataMode::Ascii) { + description += "(ascii format) "; + } + else if (_fileFormatType == SessionRecordingDataMode::Binary) { + description += "(binary format) "; + } + else { + description += "(UNKNOWN format) "; + } + description += "conversion to file '" + _outFilePath + "'."; + return description; +} +void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { + convert(); } void ConvertRecFormatTask::convert() { - SessionRecording::RecordedDataMode type = formatType(); + if (_fileFormatType == SessionRecordingDataMode::Ascii) { + _oFile.open(_outFilePath); + } + else if (_fileFormatType == SessionRecordingDataMode::Binary) { + _oFile.open(_outFilePath, std::ios::binary); + } + _oFile.write(SessionRecordingFileHeaderTitle.c_str(), + SessionRecordingFileHeaderTitle.length()); + _oFile.write(SessionRecording::FileHeaderVersion, + SessionRecording::FileHeaderVersionLength); + _oFile.close(); - if (type == SessionRecording::RecordedDataMode::Ascii) { + if (_fileFormatType == SessionRecordingDataMode::Ascii) { convertToBinary(); } - else if (type == SessionRecording::RecordedDataMode::Binary) { + else if (_fileFormatType == SessionRecordingDataMode::Binary) { convertToAscii(); } else { @@ -82,27 +107,31 @@ void ConvertRecFormatTask::convert() { } } -SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType() { - const std::string expectedHeader = "OpenSpace_record/playback"; +void ConvertRecFormatTask::determineFormatType() { + _fileFormatType = SessionRecordingDataMode::Unknown; std::string line; - //Get first line, which is ASCII regardless of format - std::getline(_iFile, line); - if (line.substr(0, SessionRecording::FileHeaderTitle.length()) - != SessionRecording::FileHeaderTitle) + line = SessionRecording::readHeaderElement(_iFile, + SessionRecordingFileHeaderTitle.length()); + + if (line.substr(0, SessionRecordingFileHeaderTitle.length()) + != SessionRecordingFileHeaderTitle) { - LERROR(fmt::format("Session recording file {} does not have expected header.", _inFilePath)); - return SessionRecording::RecordedDataMode::Binary + 1; + LERROR(fmt::format("Session recording file {} does not have expected header.", + _inFilePath)); } else { - if (line.back() == SessionRecording::DataFormatAsciiTag) { - return SessionRecording::RecordedDataMode::Ascii; + //Read version string and throw it away (and also line feed character at end) + SessionRecording::readHeaderElement(_iFile, + SessionRecording::FileHeaderVersionLength); + line = SessionRecording::readHeaderElement(_iFile, 1); + SessionRecording::readHeaderElement(_iFile, 1); + + if (line.at(0) == SessionRecording::DataFormatAsciiTag) { + _fileFormatType = SessionRecordingDataMode::Ascii; } - else if (line.back() == SessionRecording::DataFormatBinaryTag) { - return SessionRecording::RecordedDataMode::Binary; - } - else { - return SessionRecording::RecordedDataMode::Binary + 1; + else if (line.at(0) == SessionRecording::DataFormatBinaryTag) { + _fileFormatType = SessionRecordingDataMode::Binary; } } } @@ -114,8 +143,10 @@ void ConvertRecFormatTask::convertToAscii() { datamessagestructures::ScriptMessage skf; int lineNum = 1; unsigned char frameType; - _outFilePath = addFileSuffix(_inFilePath, "_ascii"); - std::stringstream keyframeLine = std::stringstream(); + _oFile.open(_outFilePath, std::ifstream::app); + char tmpType = SessionRecording::DataFormatAsciiTag; + _oFile.write(&tmpType, 1); + _oFile.write("\n", 1); bool fileReadOk = true; while (fileReadOk) { @@ -130,20 +161,24 @@ void ConvertRecFormatTask::convertToAscii() { break; } + std::stringstream keyframeLine = std::stringstream(); keyframeLine.str(std::string()); - if (frameType == 'c') { + if (frameType == SessionRecordingHeaderCameraBinary) { SessionRecording::readCameraKeyframeBinary(times, ckf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "camera", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderCameraAscii, + keyframeLine); ckf.write(keyframeLine); } - else if (frameType == 't') { + else if (frameType == SessionRecordingHeaderTimeBinary) { SessionRecording::readTimeKeyframeBinary(times, tkf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "time", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderTimeAscii, + keyframeLine); tkf.write(keyframeLine); } - else if (frameType == 's') { + else if (frameType == SessionRecordingHeaderScriptBinary) { SessionRecording::readScriptKeyframeBinary(times, skf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "script", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderScriptAscii, + keyframeLine); skf.write(keyframeLine); } else { @@ -156,6 +191,7 @@ void ConvertRecFormatTask::convertToAscii() { SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); lineNum++; } + _oFile.close(); } void ConvertRecFormatTask::convertToBinary() { @@ -166,8 +202,10 @@ void ConvertRecFormatTask::convertToBinary() { int lineNum = 1; std::string lineContents; unsigned char keyframeBuffer[SessionRecording::_saveBufferMaxSize_bytes]; - std::ofstream saveFile; - saveFile.open(_outFilePath, std::ios::binary); + _oFile.open(_outFilePath, std::ifstream::app | std::ios::binary); + char tmpType = SessionRecording::DataFormatBinaryTag; + _oFile.write(&tmpType, 1); + _oFile.write("\n", 1); size_t idx = 0; while (std::getline(_iFile, lineContents)) { @@ -183,20 +221,20 @@ void ConvertRecFormatTask::convertToBinary() { break; } - if (entryType == "camera") { - SessionRecording::readCameraKeyframeAscii(times, ckf, _inFilePath, lineNum); + if (entryType == SessionRecordingHeaderCameraAscii) { + SessionRecording::readCameraKeyframeAscii(times, ckf, lineContents, lineNum); SessionRecording::saveCameraKeyframeBinary(times, ckf, keyframeBuffer, - saveFile); + _oFile); } - else if (entryType == "time") { - SessionRecording::readTimeKeyframeAscii(times, tkf, _inFilePath, lineNum); + else if (entryType == SessionRecordingHeaderTimeAscii) { + SessionRecording::readTimeKeyframeAscii(times, tkf, lineContents, lineNum); SessionRecording::saveTimeKeyframeBinary(times, tkf, keyframeBuffer, - saveFile); + _oFile); } - else if (entryType == "script") { - SessionRecording::readScriptKeyframeAscii(times, skf, _inFilePath, lineNum); + else if (entryType == SessionRecordingHeaderScriptAscii) { + SessionRecording::readScriptKeyframeAscii(times, skf, lineContents, lineNum); SessionRecording::saveScriptKeyframeBinary(times, skf, keyframeBuffer, - saveFile); + _oFile); } else { LERROR(fmt::format( @@ -206,7 +244,7 @@ void ConvertRecFormatTask::convertToBinary() { break; } } - saveFile.close(); + _oFile.close(); LINFO(fmt::format( "Finished converting {} entries from file {}", lineNum, _inFilePath