First draft of file format conversion ready for testing

This commit is contained in:
Gene Payne
2020-11-15 18:41:18 -07:00
parent e23e5cf16f
commit 86140d753e
5 changed files with 269 additions and 155 deletions

View File

@@ -70,7 +70,7 @@ public:
};
static const size_t FileHeaderVersionLength = 5;
static constexpr char FileHeaderVersion[] = "00.85";
char FileHeaderVersion[FileHeaderVersionLength+1] = "01.00";
static const char DataFormatAsciiTag = 'A';
static const char DataFormatBinaryTag = 'B';
static const size_t keyframeHeaderSize_bytes = 33;
@@ -455,10 +455,21 @@ public:
* (will determine the file format conversion to convert from based on the file's
* header version number).
*
* \param filename name of the file to convert
* \param root (optional) the 5-character version string that represents the version
* of the original file to convert (before recursion started)
*/
static bool convertFile(std::string filename);
bool convertFile(std::string filename, std::string root = "root");
private:
/**
* Returns pointer to SessionRecording object that is the previous legacy version
* of the current version.
*
* \return Pointer to the previous version of the SessionRecording
*/
SessionRecording* getLegacy();
protected:
properties::BoolProperty _renderPlaybackInformation;
enum class RecordedType {
@@ -532,15 +543,18 @@ private:
double getNextTimestamp();
double getPrevTimestamp();
void cleanUpPlayback();
static bool convertEntries(std::string& inFilename, std::ifstream& inFile,
bool convertEntries(std::string& inFilename, std::ifstream& inFile,
DataMode mode, int lineNum, std::ofstream& outFile);
static bool convertCamera(std::ifstream& inFile, DataMode mode, int lineNum,
virtual bool convertCamera(std::ifstream& inFile, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
static bool convertTimeChange(std::ifstream& inFile, DataMode mode, int lineNum,
virtual bool convertTimeChange(std::ifstream& inFile, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
static bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
virtual bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buff);
static std::string determineConversionOutFilename(const std::string filename);
std::string determineConversionOutFilename(const std::string filename);
void readPlaybackFileHeader(const std::string filename,
std::string& conversionInFilename, std::ifstream& conversionInFile,
std::string& version, DataMode& mode);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, double src);
static void writeToFileBuffer(unsigned char* buf, size_t& idx, std::vector<char>& cv);
@@ -592,8 +606,10 @@ private:
int _conversionLineNum = 1;
};
class SessionRecording_legacy_0085 : SessionRecording {
struct ScriptMessage_legacy_0085 : datamessagestructures::ScriptMessage {
class SessionRecording_legacy_0085 : public SessionRecording {
char FileHeaderVersion[FileHeaderVersionLength+1] = "00.85";
struct ScriptMessage_legacy_0085 : public datamessagestructures::ScriptMessage {
void read(std::istream* in) {
size_t strLen;
//Read string length from file
@@ -608,9 +624,8 @@ class SessionRecording_legacy_0085 : SessionRecording {
};
};
void convertUp(std::string header, std::string fileToConvert);
static constexpr char FileHeaderVersion[] = "01.00";
bool convertScript(std::ifstream& inFile, DataMode mode, int lineNum,
std::string& inputLine, std::ofstream& outFile, unsigned char* buffer);
};
} // namespace openspace

View File

@@ -59,6 +59,7 @@ private:
std::ifstream _iFile;
std::ofstream _oFile;
SessionRecording::DataMode _fileFormatType;
std::string _version;
std::string _valueFunctionLua;
};

View File

@@ -67,6 +67,10 @@ namespace {
namespace openspace::interaction {
ConversionError::ConversionError(std::string msg)
: ghoul::RuntimeError(std::move(msg), "conversionError")
{}
SessionRecording::SessionRecording()
: properties::PropertyOwner({ "SessionRecording", "Session Recording" })
, _renderPlaybackInformation(RenderPlaybackInfo, false)
@@ -74,10 +78,15 @@ SessionRecording::SessionRecording()
auto fTask = FactoryManager::ref().factory<Task>();
ghoul_assert(fTask, "No task factory existed");
fTask->registerClass<ConvertRecFormatTask>("ConvertRecFormatTask");
fTask->registerClass<ConvertRecFormatTask>("ConvertRecFileVersionTask");
addProperty(_renderPlaybackInformation);
}
SessionRecording::~SessionRecording() {} // NOLINT
SessionRecording::~SessionRecording() { // NOLINT
if (legacyVersion != nullptr) {
delete legacyVersion;
}
}
void SessionRecording::deinitialize() {
stopRecording();
@@ -1619,7 +1628,7 @@ void SessionRecording::saveKeyframeToFileBinary(unsigned char* buffer,
size_t size,
std::ofstream& file)
{
file.write(reinterpret_cast<unsigned char*>(buffer), size);
file.write(reinterpret_cast<const char*>(buffer), size);
}
void SessionRecording::saveKeyframeToFile(std::string entry, std::ofstream& file) {
@@ -1664,140 +1673,82 @@ std::vector<std::string> SessionRecording::playbackList() const {
return fileList;
}
scripting::LuaLibrary SessionRecording::luaLibrary() {
return {
"sessionRecording",
{
{
"startRecording",
&luascriptfunctions::startRecording,
{},
"string",
"Starts a recording session. The string argument is the filename used "
"for the file where the recorded keyframes are saved. "
"The file data format is binary."
},
{
"startRecordingAscii",
&luascriptfunctions::startRecordingAscii,
{},
"string",
"Starts a recording session. The string argument is the filename used "
"for the file where the recorded keyframes are saved. "
"The file data format is ASCII."
},
{
"stopRecording",
&luascriptfunctions::stopRecording,
{},
"void",
"Stops a recording session"
},
{
"startPlayback",
&luascriptfunctions::startPlaybackDefault,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the time since the recording was started (the same relative time "
"applies to the playback). When playback starts, the simulation time "
"is automatically set to what it was at recording time. The string "
"argument is the filename to pull playback keyframes from."
},
{
"startPlaybackApplicationTime",
&luascriptfunctions::startPlaybackApplicationTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"application time (seconds since OpenSpace application started). "
"The string argument is the filename to pull playback keyframes from."
},
{
"startPlaybackRecordedTime",
&luascriptfunctions::startPlaybackRecordedTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the time since the recording was started (the same relative time "
"applies to the playback). The string argument is the filename to pull "
"playback keyframes from."
},
{
"startPlaybackSimulationTime",
&luascriptfunctions::startPlaybackSimulationTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the simulated date & time. The string argument is the filename to pull "
"playback keyframes from."
},
{
"stopPlayback",
&luascriptfunctions::stopPlayback,
{},
"void",
"Stops a playback session before playback of all keyframes is complete"
},
{
"enableTakeScreenShotDuringPlayback",
&luascriptfunctions::enableTakeScreenShotDuringPlayback,
{},
"[int]",
"Enables that rendered frames should be saved during playback. The "
"parameter determines the number of frames that are exported per second "
"if this value is not provided, 60 frames per second will be exported."
},
{
"disableTakeScreenShotDuringPlayback",
&luascriptfunctions::disableTakeScreenShotDuringPlayback,
{},
"void",
"Used to disable that renderings are saved during playback"
}
}
};
void SessionRecording::readPlaybackFileHeader(const std::string filename,
std::string& conversionInFilename,
std::ifstream& conversionInFile,
std::string& version,
DataMode& mode)
{
if (filename.find("/") != std::string::npos) {
throw ConversionError("Playback filename musn't contain path (/) elements");
}
conversionInFilename = absPath("${RECORDINGS}/" + filename);
if (!FileSys.fileExists(conversionInFilename)) {
throw ConversionError("Cannot find the specified playback file to convert.");
}
// Open in ASCII first
conversionInFile.open(conversionInFilename, std::ifstream::in);
// Read header
std::string readBackHeaderString = readHeaderElement(
conversionInFile,
FileHeaderTitle.length()
);
if (readBackHeaderString != FileHeaderTitle) {
throw ConversionError("File to convert does not contain expected header.");
}
version = readHeaderElement(conversionInFile, FileHeaderVersionLength);
std::string readDataMode = readHeaderElement(conversionInFile, 1);
if (readDataMode[0] == DataFormatAsciiTag) {
mode = DataMode::Ascii;
}
else if (readDataMode[0] == DataFormatBinaryTag) {
mode = DataMode::Binary;
}
else {
throw ConversionError("Unknown data type in header (needs Ascii or Binary)");
}
}
bool SessionRecording::convertFile(std::string filename) {
bool SessionRecording::convertFile(std::string filename, std::string version) {
bool success = true;
std::string conversionInFilename;
std::ifstream conversionInFile;
DataMode mode;
bool preRecursion = (version == "root") ? true : false;
std::string throwOut;
try {
if (filename.find("/") != std::string::npos) {
throw ConversionError("Playback filename musn't contain path (/) elements");
}
std::string conversionInFilename = absPath("${RECORDINGS}/" + filename);
if (!FileSys.fileExists(conversionInFilename)) {
throw ConversionError("Cannot find the specified playback file to convert.");
}
int conversionLineNum = 1;
// Open in ASCII first
std::ifstream conversionInFile;
conversionInFile.open(conversionInFilename, std::ifstream::in);
// Read header
std::string readBackHeaderString = readHeaderElement(
conversionInFile,
FileHeaderTitle.length()
readPlaybackFileHeader(
filename,
conversionInFilename,
conversionInFile,
preRecursion ? version : throwOut,
mode
);
int conversionLineNum = 1;
LINFO(fmt::format(
"Starting conversion on rec file {}, version {} in {} mode.",
filename, version, (mode == DataMode::Ascii) ? "ascii" : "binary"
));
if (readBackHeaderString != FileHeaderTitle) {
throw ConversionError("File to convert does not contain expected header.");
}
if (readBackHeaderString != FileHeaderTitle) {
throw ConversionError("File to convert does not contain expected header.");
}
readHeaderElement(conversionInFile, FileHeaderVersionLength);
std::string readDataMode = readHeaderElement(conversionInFile, 1);
DataMode mode;
if (readDataMode[0] == DataFormatAsciiTag) {
mode = DataMode::Ascii;
}
else if (readDataMode[0] == DataFormatBinaryTag) {
mode = DataMode::Binary;
}
else {
throw ConversionError("Unknown data type in header (needs Ascii or Binary)");
//If this instance of the SessionRecording class isn't the instance with the
// correct version of the file to be converted, then call getLegacy() to recurse
// to the next level down in the legacy subclasses until we get the right
// version, then proceed with conversion from there.
if (version.compare(FileHeaderVersion) != 0) {
conversionInFile.close();
SessionRecording* old = getLegacy();
old->convertFile(filename, version);
readPlaybackFileHeader(
filename,
conversionInFilename,
conversionInFile,
version,
mode
);
}
if (!conversionInFile.is_open() || !conversionInFile.good()) {
@@ -1829,6 +1780,8 @@ bool SessionRecording::convertFile(std::string filename) {
conversionLineNum,
conversionOutFile
);
conversionInFile.close();
conversionOutFile.close();
}
catch (ConversionError& c) {
LERROR(c.message);
@@ -1843,7 +1796,8 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
{
bool conversionStatusOk = true;
std::string lineParsing;
std::shared_ptr<char[]> buffer(new char[_saveBufferMaxSize_bytes]);
//std::shared_ptr<unsigned char[]> buffer(new unsigned char[_saveBufferMaxSize_bytes]);
unsigned char* buffer = new unsigned char[_saveBufferMaxSize_bytes];
if (mode == DataMode::Binary) {
unsigned char frameType;
@@ -1867,7 +1821,7 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
lineNum,
lineParsing,
outFile,
buffer
reinterpret_cast<unsigned char*>(buffer)
);
}
else if (frameType == HeaderTimeBinary) {
@@ -1962,9 +1916,16 @@ bool SessionRecording::convertEntries(std::string& inFilename, std::ifstream& in
lineNum, inFilename
));
}
if (buffer != nullptr) {
delete buffer;
}
return conversionStatusOk;
}
SessionRecording* SessionRecording::getLegacy() {
legacyVersion = new SessionRecording_legacy_0085();
}
std::string SessionRecording::determineConversionOutFilename(const std::string filename) {
std::string conversionOutFilename;
if (filename.substr(filename.find_last_of(".")) == FileExtensionBinary) {
@@ -1981,14 +1942,135 @@ std::string SessionRecording::determineConversionOutFilename(const std::string f
return absPath("${RECORDINGS}/convert/" + conversionOutFilename);
}
void SessionRecording_legacy_0085::convertUp(std::string header, std::string fileToConvert)
bool SessionRecording_legacy_0085::convertScript(std::ifstream& inFile, DataMode mode,
int lineNum, std::string& inputLine,
std::ofstream& outFile,
unsigned char* buffer)
{
if (strcmp(legacyVersion->FileHeaderVersion, FileHeaderVersion) == 0) {
convertFile(fileToConvert);
}
else {
//Oldest known version
Timestamps times;
ScriptMessage_legacy_0085 kf;
bool success = readSingleKeyframeScript(
kf,
times,
mode,
inFile,
inputLine,
lineNum
);
if (success) {
saveSingleKeyframeScript(
kf,
times,
mode,
outFile,
buffer
);
}
return success;
}
scripting::LuaLibrary SessionRecording::luaLibrary() {
return {
"sessionRecording",
{
{
"startRecording",
&luascriptfunctions::startRecording,
{},
"string",
"Starts a recording session. The string argument is the filename used "
"for the file where the recorded keyframes are saved. "
"The file data format is binary."
},
{
"startRecordingAscii",
&luascriptfunctions::startRecordingAscii,
{},
"string",
"Starts a recording session. The string argument is the filename used "
"for the file where the recorded keyframes are saved. "
"The file data format is ASCII."
},
{
"stopRecording",
&luascriptfunctions::stopRecording,
{},
"void",
"Stops a recording session"
},
{
"startPlayback",
&luascriptfunctions::startPlaybackDefault,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the time since the recording was started (the same relative time "
"applies to the playback). When playback starts, the simulation time "
"is automatically set to what it was at recording time. The string "
"argument is the filename to pull playback keyframes from."
},
{
"startPlaybackApplicationTime",
&luascriptfunctions::startPlaybackApplicationTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"application time (seconds since OpenSpace application started). "
"The string argument is the filename to pull playback keyframes from."
},
{
"startPlaybackRecordedTime",
&luascriptfunctions::startPlaybackRecordedTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the time since the recording was started (the same relative time "
"applies to the playback). The string argument is the filename to pull "
"playback keyframes from."
},
{
"startPlaybackSimulationTime",
&luascriptfunctions::startPlaybackSimulationTime,
{},
"string",
"Starts a playback session with keyframe times that are relative to "
"the simulated date & time. The string argument is the filename to pull "
"playback keyframes from."
},
{
"stopPlayback",
&luascriptfunctions::stopPlayback,
{},
"void",
"Stops a playback session before playback of all keyframes is complete"
},
{
"enableTakeScreenShotDuringPlayback",
&luascriptfunctions::enableTakeScreenShotDuringPlayback,
{},
"[int]",
"Enables that rendered frames should be saved during playback. The "
"parameter determines the number of frames that are exported per second "
"if this value is not provided, 60 frames per second will be exported."
},
{
"disableTakeScreenShotDuringPlayback",
&luascriptfunctions::disableTakeScreenShotDuringPlayback,
{},
"void",
"Used to disable that renderings are saved during playback"
},
{
"fileFormatConversion",
&luascriptfunctions::fileFormatConversion,
{},
"string",
"Performs a conversion of the specified file to the most most recent "
"file format, creating a copy of the recording file."
},
}
};
}
} // namespace openspace::interaction

View File

@@ -167,4 +167,23 @@ int disableTakeScreenShotDuringPlayback(lua_State* L) {
return 0;
}
int fileFormatConversion(lua_State* L) {
using ghoul::lua::luaTypeToString;
const std::string convertFilePath = ghoul::lua::value<std::string>(
L,
1,
ghoul::lua::PopValue::Yes
);
if (convertFilePath.empty()) {
return luaL_error(L, "filepath string is empty");
}
global::sessionRecording.convertFile(convertFilePath);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
} // namespace openspace::luascriptfunctions

View File

@@ -128,10 +128,7 @@ void ConvertRecFormatTask::convert() {
SessionRecording::FileHeaderTitle.c_str(),
SessionRecording::FileHeaderTitle.length()
);
_oFile.write(
SessionRecording::FileHeaderVersion,
SessionRecording::FileHeaderVersionLength
);
_oFile.write(_version.c_str(), SessionRecording::FileHeaderVersionLength);
_oFile.close();
if (_fileFormatType == SessionRecording::DataMode::Ascii) {
@@ -161,7 +158,7 @@ void ConvertRecFormatTask::determineFormatType() {
}
else {
//Read version string and throw it away (and also line feed character at end)
SessionRecording::readHeaderElement(_iFile,
_version = SessionRecording::readHeaderElement(_iFile,
SessionRecording::FileHeaderVersionLength);
line = SessionRecording::readHeaderElement(_iFile, 1);
SessionRecording::readHeaderElement(_iFile, 1);