Add support for WWXD keyframes in qpfile format

This commit is contained in:
Ryan Lucia 2018-05-10 03:28:51 -04:00
parent 747525142a
commit a621072e7d
3 changed files with 41 additions and 10 deletions

View file

@ -19,6 +19,8 @@
#include "libaegisub/keyframe.h" #include "libaegisub/keyframe.h"
#include <sstream>
#include "libaegisub/io.h" #include "libaegisub/io.h"
#include "libaegisub/line_iterator.h" #include "libaegisub/line_iterator.h"
@ -35,10 +37,9 @@ std::vector<int> agi_keyframes(std::istream &file) {
return std::vector<int>(agi::line_iterator<int>(file), agi::line_iterator<int>()); return std::vector<int>(agi::line_iterator<int>(file), agi::line_iterator<int>());
} }
std::vector<int> other_keyframes(std::istream &file, char (*func)(std::string const&)) { std::vector<int> enumerated_keyframes(std::istream &file, char (*func)(std::string const&)) {
int count = 0; int count = 0;
std::vector<int> ret; std::vector<int> ret;
agi::line_iterator<std::string> end;
for (auto line : agi::line_iterator<std::string>(file)) { for (auto line : agi::line_iterator<std::string>(file)) {
char c = tolower(func(line)); char c = tolower(func(line));
if (c == 'i') if (c == 'i')
@ -49,6 +50,16 @@ std::vector<int> other_keyframes(std::istream &file, char (*func)(std::string co
return ret; return ret;
} }
std::vector<int> indexed_keyframes(std::istream &file, int (*func)(std::string const&)) {
std::vector<int> ret;
for (auto line : agi::line_iterator<std::string>(file)) {
int frame_no = func(line);
if (frame_no >= 0)
ret.push_back(frame_no);
}
return ret;
}
char xvid(std::string const& line) { char xvid(std::string const& line) {
return line.empty() ? 0 : line[0]; 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; if (pos == line.npos || pos + 5 >= line.size()) return 0;
return line[pos + 5]; 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 { namespace agi { namespace keyframe {
@ -87,13 +112,14 @@ std::vector<int> Load(agi::fs::path const& filename) {
getline(is, header); getline(is, header);
if (header == "# keyframe format v1") return agi_keyframes(is); 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, "# XviD 2pass stat file")) return enumerated_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, "# 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 other_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 other_keyframes(is, divx); if (boost::starts_with(header, "##map version")) return enumerated_keyframes(is, divx);
if (boost::starts_with(header, "#options:")) return other_keyframes(is, x264); 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");
} }
} } } }

View file

@ -29,6 +29,7 @@ namespace agi {
/// @param keyframes List of keyframes to save /// @param keyframes List of keyframes to save
void Save(agi::fs::path const& filename, std::vector<int> const& keyframes); void Save(agi::fs::path const& filename, std::vector<int> const& keyframes);
DEFINE_EXCEPTION(Error, Exception); DEFINE_EXCEPTION(KeyframeFormatParseError, agi::InvalidInputException);
DEFINE_EXCEPTION(UnknownKeyframeFormatError, agi::InvalidInputException);
} }
} }

View file

@ -391,10 +391,14 @@ void Project::LoadKeyframes(agi::fs::path path) {
ShowError(e.GetMessage()); ShowError(e.GetMessage());
config::mru->Remove("Keyframes", path); 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()); ShowError("Failed to parse keyframes file: " + e.GetMessage());
config::mru->Remove("Keyframes", path); 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() { void Project::CloseKeyframes() {