mirror of https://github.com/odrling/Aegisub
Reject vfr timecodes which are all identical
This commit is contained in:
parent
1835d5e2d8
commit
584284aa79
|
@ -38,9 +38,11 @@ using namespace agi::vfr;
|
||||||
/// @param timecodes List of timecodes to check
|
/// @param timecodes List of timecodes to check
|
||||||
void validate_timecodes(std::vector<int> const& timecodes) {
|
void validate_timecodes(std::vector<int> const& timecodes) {
|
||||||
if (timecodes.size() <= 1)
|
if (timecodes.size() <= 1)
|
||||||
throw TooFewTimecodes("Must have at least two timecodes to do anything useful");
|
throw InvalidFramerate("Must have at least two timecodes to do anything useful");
|
||||||
if (!is_sorted(timecodes.begin(), timecodes.end()))
|
if (!is_sorted(timecodes.begin(), timecodes.end()))
|
||||||
throw UnorderedTimecodes("Timecodes are out of order");
|
throw InvalidFramerate("Timecodes are out of order");
|
||||||
|
if (timecodes.front() == timecodes.back())
|
||||||
|
throw InvalidFramerate("Timecodes are all identical");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Shift timecodes so that frame 0 starts at time 0
|
/// @brief Shift timecodes so that frame 0 starts at time 0
|
||||||
|
@ -71,15 +73,15 @@ TimecodeRange v1_parse_line(std::string const& str) {
|
||||||
if (ss.fail() || comma1 != ',' || comma2 != ',' || !ss.eof())
|
if (ss.fail() || comma1 != ',' || comma2 != ',' || !ss.eof())
|
||||||
throw MalformedLine(str);
|
throw MalformedLine(str);
|
||||||
if (range.start < 0 || range.end < 0)
|
if (range.start < 0 || range.end < 0)
|
||||||
throw UnorderedTimecodes("Cannot specify frame rate for negative frames.");
|
throw InvalidFramerate("Cannot specify frame rate for negative frames.");
|
||||||
if (range.end < range.start)
|
if (range.end < range.start)
|
||||||
throw UnorderedTimecodes("End frame must be greater than or equal to start frame");
|
throw InvalidFramerate("End frame must be greater than or equal to start frame");
|
||||||
if (range.fps <= 0.)
|
if (range.fps <= 0.)
|
||||||
throw BadFPS("FPS must be greater than zero");
|
throw InvalidFramerate("FPS must be greater than zero");
|
||||||
if (range.fps > 1000.)
|
if (range.fps > 1000.)
|
||||||
// This is our limitation, not mkvmerge's
|
// This is our limitation, not mkvmerge's
|
||||||
// mkvmerge uses nanoseconds internally
|
// mkvmerge uses nanoseconds internally
|
||||||
throw BadFPS("FPS must be at most 1000");
|
throw InvalidFramerate("FPS must be at most 1000");
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +93,8 @@ TimecodeRange v1_parse_line(std::string const& str) {
|
||||||
/// @return Assumed fps times one million
|
/// @return Assumed fps times one million
|
||||||
int64_t v1_parse(line_iterator<std::string> file, std::string line, std::vector<int> &timecodes, int64_t &last) {
|
int64_t v1_parse(line_iterator<std::string> file, std::string line, std::vector<int> &timecodes, int64_t &last) {
|
||||||
double fps = atof(line.substr(7).c_str());
|
double fps = atof(line.substr(7).c_str());
|
||||||
if (fps <= 0.) throw BadFPS("Assumed FPS must be greater than zero");
|
if (fps <= 0.) throw InvalidFramerate("Assumed FPS must be greater than zero");
|
||||||
if (fps > 1000.) throw BadFPS("Assumed FPS must not be greater than 1000");
|
if (fps > 1000.) throw InvalidFramerate("Assumed FPS must not be greater than 1000");
|
||||||
|
|
||||||
std::vector<TimecodeRange> ranges;
|
std::vector<TimecodeRange> ranges;
|
||||||
for (auto const& line : file) {
|
for (auto const& line : file) {
|
||||||
|
@ -111,7 +113,7 @@ int64_t v1_parse(line_iterator<std::string> file, std::string line, std::vector<
|
||||||
if (frame > range.start) {
|
if (frame > range.start) {
|
||||||
// mkvmerge allows overlapping timecode ranges, but does completely
|
// mkvmerge allows overlapping timecode ranges, but does completely
|
||||||
// broken things with them
|
// broken things with them
|
||||||
throw UnorderedTimecodes("Override ranges must not overlap");
|
throw InvalidFramerate("Override ranges must not overlap");
|
||||||
}
|
}
|
||||||
for (; frame < range.start; ++frame) {
|
for (; frame < range.start; ++frame) {
|
||||||
timecodes.push_back(int(time + .5));
|
timecodes.push_back(int(time + .5));
|
||||||
|
@ -133,8 +135,8 @@ Framerate::Framerate(double fps)
|
||||||
: denominator(default_denominator)
|
: denominator(default_denominator)
|
||||||
, numerator(int64_t(fps * denominator))
|
, numerator(int64_t(fps * denominator))
|
||||||
{
|
{
|
||||||
if (fps < 0.) throw BadFPS("FPS must be greater than zero");
|
if (fps < 0.) throw InvalidFramerate("FPS must be greater than zero");
|
||||||
if (fps > 1000.) throw BadFPS("FPS must not be greater than 1000");
|
if (fps > 1000.) throw InvalidFramerate("FPS must not be greater than 1000");
|
||||||
timecodes.push_back(0);
|
timecodes.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +146,8 @@ Framerate::Framerate(int64_t numerator, int64_t denominator, bool drop)
|
||||||
, drop(drop && numerator % denominator != 0)
|
, drop(drop && numerator % denominator != 0)
|
||||||
{
|
{
|
||||||
if (numerator <= 0 || denominator <= 0)
|
if (numerator <= 0 || denominator <= 0)
|
||||||
throw BadFPS("Numerator and denominator must both be greater than zero");
|
throw InvalidFramerate("Numerator and denominator must both be greater than zero");
|
||||||
if (numerator / denominator > 1000) throw BadFPS("FPS must not be greater than 1000");
|
if (numerator / denominator > 1000) throw InvalidFramerate("FPS must not be greater than 1000");
|
||||||
timecodes.push_back(0);
|
timecodes.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,15 +41,11 @@ enum Time {
|
||||||
|
|
||||||
DEFINE_EXCEPTION(Error, Exception);
|
DEFINE_EXCEPTION(Error, Exception);
|
||||||
/// FPS specified is not a valid frame rate
|
/// FPS specified is not a valid frame rate
|
||||||
DEFINE_EXCEPTION(BadFPS, Error);
|
DEFINE_EXCEPTION(InvalidFramerate, Error);
|
||||||
/// Unknown timecode file format
|
/// Unknown timecode file format
|
||||||
DEFINE_EXCEPTION(UnknownFormat, Error);
|
DEFINE_EXCEPTION(UnknownFormat, Error);
|
||||||
/// Invalid line encountered in a timecode file
|
/// Invalid line encountered in a timecode file
|
||||||
DEFINE_EXCEPTION(MalformedLine, Error);
|
DEFINE_EXCEPTION(MalformedLine, Error);
|
||||||
/// Timecode file or vector has too few timecodes to be usable
|
|
||||||
DEFINE_EXCEPTION(TooFewTimecodes, Error);
|
|
||||||
/// Timecode file or vector has timecodes that are not monotonically increasing
|
|
||||||
DEFINE_EXCEPTION(UnorderedTimecodes, Error);
|
|
||||||
|
|
||||||
/// @class Framerate
|
/// @class Framerate
|
||||||
/// @brief Class for managing everything related to converting frames to times
|
/// @brief Class for managing everything related to converting frames to times
|
||||||
|
|
|
@ -43,14 +43,15 @@ TEST(lagi_vfr, constructors_good) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, constructors_bad_cfr) {
|
TEST(lagi_vfr, constructors_bad_cfr) {
|
||||||
EXPECT_THROW(Framerate(-1.), BadFPS);
|
EXPECT_THROW(Framerate(-1.), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate(1000.1), BadFPS);
|
EXPECT_THROW(Framerate(1000.1), InvalidFramerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, constructors_bad_timecodes) {
|
TEST(lagi_vfr, constructors_bad_timecodes) {
|
||||||
EXPECT_THROW(Framerate(std::initializer_list<int>{}), TooFewTimecodes);
|
EXPECT_THROW(Framerate(std::initializer_list<int>{}), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate({ 0 }), TooFewTimecodes);
|
EXPECT_THROW(Framerate({0}), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate({ 10, 0 }), UnorderedTimecodes);
|
EXPECT_THROW(Framerate({10, 0}), InvalidFramerate);
|
||||||
|
EXPECT_THROW(Framerate({0, 0}), InvalidFramerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, constructors_bad_v1) {
|
TEST(lagi_vfr, constructors_bad_v1) {
|
||||||
|
@ -58,18 +59,18 @@ TEST(lagi_vfr, constructors_bad_v1) {
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_too_few_parts.txt"), MalformedLine);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_too_few_parts.txt"), MalformedLine);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_too_many_parts.txt"), MalformedLine);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_too_many_parts.txt"), MalformedLine);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_float_frame_number.txt"), MalformedLine);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_float_frame_number.txt"), MalformedLine);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_start_end_overlap.txt"), UnorderedTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_start_end_overlap.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_fully_contained.txt"), UnorderedTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_fully_contained.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_assume_over_1000.txt"), BadFPS);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_assume_over_1000.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_override_over_1000.txt"), BadFPS);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_override_over_1000.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_override_zero.txt"), BadFPS);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_override_zero.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_negative_start_of_range.txt"), UnorderedTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_negative_start_of_range.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v1_end_less_than_start.txt"), UnorderedTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v1_end_less_than_start.txt"), InvalidFramerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, constructors_bad_v2) {
|
TEST(lagi_vfr, constructors_bad_v2) {
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v2_empty.txt"), TooFewTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v2_empty.txt"), InvalidFramerate);
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/v2_out_of_order.txt"), UnorderedTimecodes);
|
EXPECT_THROW(Framerate("data/vfr/in/v2_out_of_order.txt"), InvalidFramerate);
|
||||||
|
|
||||||
EXPECT_THROW(Framerate("data/vfr/in/empty.txt"), UnknownFormat);
|
EXPECT_THROW(Framerate("data/vfr/in/empty.txt"), UnknownFormat);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue