From 5a23ae35c8ce51741d13175314e38c92846dfe1e Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Wed, 15 Jul 2020 13:04:39 -0600 Subject: [PATCH] Added file extensions for session recording files --- .../openspace/interaction/sessionrecording.h | 13 +- src/interaction/sessionrecording.cpp | 120 ++++++++++++------ .../tasks/convertrecformattask.cpp | 32 +++++ 3 files changed, 123 insertions(+), 42 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 5fb72268a4..23635a7780 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -41,10 +41,13 @@ static const std::string SessionRecordingFileHeaderTitle = "OpenSpace_record/pla static const std::string SessionRecordingHeaderCameraAscii = "camera"; static const std::string SessionRecordingHeaderTimeAscii = "time"; static const std::string SessionRecordingHeaderScriptAscii = "script"; +static const std::string SessionRecordingFileExtensionBinary = ".osrec"; +static const std::string SessionRecordingFileExtensionAscii = ".osrectxt"; static const char SessionRecordingHeaderCameraBinary = 'c'; static const char SessionRecordingHeaderTimeBinary = 't'; static const char SessionRecordingHeaderScriptBinary = 's'; + class SessionRecording : public properties::PropertyOwner { public: enum class SessionState { @@ -415,6 +418,14 @@ public: */ static void saveKeyframeToFile(std::string entry, std::ofstream& file); + /** + * Checks if a specified recording file ends with a particular file extension + * + * \param filename the name of the file to record to + * \param extension the file extension to check for + */ + static bool hasFileExtension(std::string filename, std::string extension); + private: enum class RecordedType { Camera = 0, @@ -436,7 +447,7 @@ private: double appropriateTimestamp(double timeOs, double timeRec, double timeSim); double equivalentSimulationTime(double timeOs, double timeRec, double timeSim); double equivalentApplicationTime(double timeOs, double timeRec, double timeSim); - + bool handleRecordingFile(std::string filenameIn); bool playbackCamera(); bool playbackTimeChange(); bool playbackScript(); diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 4a545275b7..a39e059351 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -77,18 +77,41 @@ void SessionRecording::setRecordDataFormat(SessionRecordingDataMode dataMode) { _recordingDataMode = dataMode; } -bool SessionRecording::startRecording(const std::string& filename) { - if (filename.find("/") != std::string::npos) { +bool SessionRecording::hasFileExtension(std::string filename, std::string extension) { + if (filename.length() <= extension.length()) { + return false; + } + else { + return (filename.substr(filename.length() - extension.length()) == extension); + } +} + +bool SessionRecording::handleRecordingFile(std::string filenameIn) { + if (filenameIn.find("/") != std::string::npos) { LERROR("Recording filename must not contain path (/) elements"); return false; } - if (!FileSys.directoryExists(absPath("${RECORDINGS}"))) { - FileSys.createDirectory( - absPath("${RECORDINGS}"), - ghoul::filesystem::FileSystem::Recursive::Yes - ); + + if (_recordingDataMode == SessionRecordingDataMode::Binary) { + if (hasFileExtension(filenameIn, SessionRecordingFileExtensionAscii)) { + LERROR("Specified filename for binary recording has ascii file extension"); + return false; + } + else if (!hasFileExtension(filenameIn, SessionRecordingFileExtensionBinary)) { + filenameIn += SessionRecordingFileExtensionBinary; + } } - const std::string absFilename = absPath("${RECORDINGS}/" + filename); + else if (_recordingDataMode == SessionRecordingDataMode::Ascii) { + if (hasFileExtension(filenameIn, SessionRecordingFileExtensionBinary)) { + LERROR("Specified filename for ascii recording has binary file extension"); + return false; + } + else if (!hasFileExtension(filenameIn, SessionRecordingFileExtensionAscii)) { + filenameIn += SessionRecordingFileExtensionAscii; + } + } + + std::string absFilename = absPath("${RECORDINGS}/" + filenameIn); if (FileSys.fileExists(absFilename)) { LERROR(fmt::format( @@ -96,19 +119,6 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - if (_state == SessionState::Recording) { - LERROR("Unable to start recording while already in recording mode"); - return false; - } - else if (_state == SessionState::Playback) { - LERROR("Unable to start recording while in session playback mode"); - return false; - } - - _state = SessionState::Recording; - _playbackActive_camera = false; - _playbackActive_time = false; - _playbackActive_script = false; if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile.open(absFilename, std::ios::binary); } @@ -122,29 +132,57 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - _recordFile << SessionRecordingFileHeaderTitle; - _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); - if (_recordingDataMode == SessionRecordingDataMode::Binary) { - _recordFile << DataFormatBinaryTag; - } - else { - _recordFile << DataFormatAsciiTag; - } - _recordFile << '\n'; - - _timestampRecordStarted = global::windowDelegate.applicationTime(); - - //Record the current delta time so this is preserved in recording - double currentDeltaTime = global::timeManager.deltaTime(); - std::string scriptCommandForInitializingDeltaTime = - "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ")"; - saveScriptKeyframe(scriptCommandForInitializingDeltaTime); - - LINFO("Session recording started"); - return true; } +bool SessionRecording::startRecording(const std::string& filename) { + if (_state == SessionState::Recording) { + LERROR("Unable to start recording while already in recording mode"); + return false; + } + else if (_state == SessionState::Playback) { + LERROR("Unable to start recording while in session playback mode"); + return false; + } + if (!FileSys.directoryExists(absPath("${RECORDINGS}"))) { + FileSys.createDirectory( + absPath("${RECORDINGS}"), + ghoul::filesystem::FileSystem::Recursive::Yes + ); + } + + bool recordingFileOK = handleRecordingFile(filename); + + if (recordingFileOK) { + _state = SessionState::Recording; + _playbackActive_camera = false; + _playbackActive_time = false; + _playbackActive_script = false; + + _recordFile << SessionRecordingFileHeaderTitle; + _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); + if (_recordingDataMode == SessionRecordingDataMode::Binary) { + _recordFile << DataFormatBinaryTag; + } + else { + _recordFile << DataFormatAsciiTag; + } + _recordFile << '\n'; + + _timestampRecordStarted = global::windowDelegate.applicationTime(); + + //Record the current delta time so this is preserved in recording + double currentDeltaTime = global::timeManager.deltaTime(); + std::string scriptCommandForInitializingDeltaTime = + "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ")"; + saveScriptKeyframe(scriptCommandForInitializingDeltaTime); + + LINFO("Session recording started"); + } + + return recordingFileOK; +} + void SessionRecording::stopRecording() { if (_state == SessionState::Recording) { _state = SessionState::Idle; diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 6cbe5257db..de938626ec 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -83,6 +83,38 @@ void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallbac } void ConvertRecFormatTask::convert() { + std::string expectedFileExtension_in, expectedFileExtension_out; + std::string currentFormat; + if (_fileFormatType == SessionRecordingDataMode::Binary) { + currentFormat = "binary"; + expectedFileExtension_in = SessionRecordingFileExtensionBinary; + expectedFileExtension_out = SessionRecordingFileExtensionAscii; + } + else if (_fileFormatType == SessionRecordingDataMode::Ascii) { + currentFormat = "ascii"; + expectedFileExtension_in = SessionRecordingFileExtensionAscii; + expectedFileExtension_out = SessionRecordingFileExtensionBinary; + } + + if (!SessionRecording::hasFileExtension(_inFilePath, expectedFileExtension_in)) { + LWARNING(fmt::format( + "Input filename doesn't have expected {} " + "format file extension", + currentFormat) + ); + } + if (SessionRecording::hasFileExtension(_outFilePath, expectedFileExtension_in)) { + LERROR(fmt::format( + "Output filename has {} file extension, but is conversion from {}", + currentFormat, + currentFormat) + ); + return; + } + else if (!SessionRecording::hasFileExtension(_outFilePath, expectedFileExtension_out)) { + _outFilePath += expectedFileExtension_out; + } + if (_fileFormatType == SessionRecordingDataMode::Ascii) { _oFile.open(_outFilePath); }