diff --git a/libaegisub/common/keyframe.cpp b/libaegisub/common/keyframe.cpp index 50e537338..b2855bd11 100644 --- a/libaegisub/common/keyframe.cpp +++ b/libaegisub/common/keyframe.cpp @@ -19,6 +19,8 @@ #include "libaegisub/keyframe.h" +#include + #include "libaegisub/io.h" #include "libaegisub/line_iterator.h" @@ -35,10 +37,9 @@ std::vector agi_keyframes(std::istream &file) { return std::vector(agi::line_iterator(file), agi::line_iterator()); } -std::vector other_keyframes(std::istream &file, char (*func)(std::string const&)) { +std::vector enumerated_keyframes(std::istream &file, char (*func)(std::string const&)) { int count = 0; std::vector ret; - agi::line_iterator end; for (auto line : agi::line_iterator(file)) { char c = tolower(func(line)); if (c == 'i') @@ -49,6 +50,16 @@ std::vector other_keyframes(std::istream &file, char (*func)(std::string co return ret; } +std::vector indexed_keyframes(std::istream &file, int (*func)(std::string const&)) { + std::vector ret; + for (auto line : agi::line_iterator(file)) { + int frame_no = func(line); + if (frame_no >= 0) + ret.push_back(frame_no); + } + return ret; +} + char xvid(std::string const& line) { return line.empty() ? 0 : line[0]; } @@ -68,6 +79,20 @@ char x264(std::string const& line) { if (pos == line.npos || pos + 5 >= line.size()) return 0; return line[pos + 5]; } + +int wwxd(std::string const& line) { + if (line.empty() || line[0] == '#') + return -1; + std::istringstream ss(line); + int frame_no; + char frame_type; + ss >> frame_no >> frame_type; + if (ss.fail()) + throw agi::keyframe::KeyframeFormatParseError("WWXD keyframe file not in qpfile format"); + if (frame_type == 'I') + return frame_no; + return -1; +} } namespace agi { namespace keyframe { @@ -87,13 +112,14 @@ std::vector Load(agi::fs::path const& filename) { getline(is, header); if (header == "# keyframe format v1") return agi_keyframes(is); - if (boost::starts_with(header, "# XviD 2pass stat file")) return other_keyframes(is, xvid); - if (boost::starts_with(header, "# ffmpeg 2-pass log file, using xvid codec")) return other_keyframes(is, xvid); - if (boost::starts_with(header, "# avconv 2-pass log file, using xvid codec")) return other_keyframes(is, xvid); - if (boost::starts_with(header, "##map version")) return other_keyframes(is, divx); - if (boost::starts_with(header, "#options:")) return other_keyframes(is, x264); + if (boost::starts_with(header, "# XviD 2pass stat file")) return enumerated_keyframes(is, xvid); + if (boost::starts_with(header, "# ffmpeg 2-pass log file, using xvid codec")) return enumerated_keyframes(is, xvid); + if (boost::starts_with(header, "# avconv 2-pass log file, using xvid codec")) return enumerated_keyframes(is, xvid); + if (boost::starts_with(header, "##map version")) return enumerated_keyframes(is, divx); + if (boost::starts_with(header, "#options:")) return enumerated_keyframes(is, x264); + if (boost::starts_with(header, "# WWXD log file, using qpfile format")) return indexed_keyframes(is, wwxd); - throw Error("Unknown keyframe format"); + throw UnknownKeyframeFormatError("File header does not match any known formats"); } } } diff --git a/libaegisub/include/libaegisub/keyframe.h b/libaegisub/include/libaegisub/keyframe.h index 43fb9333f..6fc82ff49 100644 --- a/libaegisub/include/libaegisub/keyframe.h +++ b/libaegisub/include/libaegisub/keyframe.h @@ -29,6 +29,7 @@ namespace agi { /// @param keyframes List of keyframes to save void Save(agi::fs::path const& filename, std::vector const& keyframes); - DEFINE_EXCEPTION(Error, Exception); + DEFINE_EXCEPTION(KeyframeFormatParseError, agi::InvalidInputException); + DEFINE_EXCEPTION(UnknownKeyframeFormatError, agi::InvalidInputException); } } diff --git a/src/project.cpp b/src/project.cpp index 312f86fe8..633a526b7 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -391,10 +391,14 @@ void Project::LoadKeyframes(agi::fs::path path) { ShowError(e.GetMessage()); config::mru->Remove("Keyframes", path); } - catch (agi::keyframe::Error const& e) { + catch (agi::keyframe::KeyframeFormatParseError const& e) { ShowError("Failed to parse keyframes file: " + e.GetMessage()); config::mru->Remove("Keyframes", path); } + catch (agi::keyframe::UnknownKeyframeFormatError const& e) { + ShowError("Keyframes file in unknown format: " + e.GetMessage()); + config::mru->Remove("Keyframes", path); + } } void Project::CloseKeyframes() {