Reject vfr timecodes which are all identical

This commit is contained in:
Thomas Goyne 2014-07-15 07:37:08 -07:00
parent 1835d5e2d8
commit 584284aa79
3 changed files with 31 additions and 32 deletions

View file

@ -38,9 +38,11 @@ using namespace agi::vfr;
/// @param timecodes List of timecodes to check
void validate_timecodes(std::vector<int> const& timecodes) {
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()))
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
@ -71,15 +73,15 @@ TimecodeRange v1_parse_line(std::string const& str) {
if (ss.fail() || comma1 != ',' || comma2 != ',' || !ss.eof())
throw MalformedLine(str);
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)
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.)
throw BadFPS("FPS must be greater than zero");
throw InvalidFramerate("FPS must be greater than zero");
if (range.fps > 1000.)
// This is our limitation, not mkvmerge's
// mkvmerge uses nanoseconds internally
throw BadFPS("FPS must be at most 1000");
throw InvalidFramerate("FPS must be at most 1000");
return range;
}
@ -91,8 +93,8 @@ TimecodeRange v1_parse_line(std::string const& str) {
/// @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) {
double fps = atof(line.substr(7).c_str());
if (fps <= 0.) throw BadFPS("Assumed FPS must be greater than zero");
if (fps > 1000.) throw BadFPS("Assumed FPS must not be greater than 1000");
if (fps <= 0.) throw InvalidFramerate("Assumed FPS must be greater than zero");
if (fps > 1000.) throw InvalidFramerate("Assumed FPS must not be greater than 1000");
std::vector<TimecodeRange> ranges;
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) {
// mkvmerge allows overlapping timecode ranges, but does completely
// broken things with them
throw UnorderedTimecodes("Override ranges must not overlap");
throw InvalidFramerate("Override ranges must not overlap");
}
for (; frame < range.start; ++frame) {
timecodes.push_back(int(time + .5));
@ -133,8 +135,8 @@ Framerate::Framerate(double fps)
: denominator(default_denominator)
, numerator(int64_t(fps * denominator))
{
if (fps < 0.) throw BadFPS("FPS must be greater than zero");
if (fps > 1000.) throw BadFPS("FPS must not be greater than 1000");
if (fps < 0.) throw InvalidFramerate("FPS must be greater than zero");
if (fps > 1000.) throw InvalidFramerate("FPS must not be greater than 1000");
timecodes.push_back(0);
}
@ -144,8 +146,8 @@ Framerate::Framerate(int64_t numerator, int64_t denominator, bool drop)
, drop(drop && numerator % denominator != 0)
{
if (numerator <= 0 || denominator <= 0)
throw BadFPS("Numerator and denominator must both be greater than zero");
if (numerator / denominator > 1000) throw BadFPS("FPS must not be greater than 1000");
throw InvalidFramerate("Numerator and denominator must both be greater than zero");
if (numerator / denominator > 1000) throw InvalidFramerate("FPS must not be greater than 1000");
timecodes.push_back(0);
}

View file

@ -41,15 +41,11 @@ enum Time {
DEFINE_EXCEPTION(Error, Exception);
/// FPS specified is not a valid frame rate
DEFINE_EXCEPTION(BadFPS, Error);
DEFINE_EXCEPTION(InvalidFramerate, Error);
/// Unknown timecode file format
DEFINE_EXCEPTION(UnknownFormat, Error);
/// Invalid line encountered in a timecode file
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
/// @brief Class for managing everything related to converting frames to times

View file

@ -43,14 +43,15 @@ TEST(lagi_vfr, constructors_good) {
}
TEST(lagi_vfr, constructors_bad_cfr) {
EXPECT_THROW(Framerate(-1.), BadFPS);
EXPECT_THROW(Framerate(1000.1), BadFPS);
EXPECT_THROW(Framerate(-1.), InvalidFramerate);
EXPECT_THROW(Framerate(1000.1), InvalidFramerate);
}
TEST(lagi_vfr, constructors_bad_timecodes) {
EXPECT_THROW(Framerate(std::initializer_list<int>{}), TooFewTimecodes);
EXPECT_THROW(Framerate({ 0 }), TooFewTimecodes);
EXPECT_THROW(Framerate({ 10, 0 }), UnorderedTimecodes);
EXPECT_THROW(Framerate(std::initializer_list<int>{}), InvalidFramerate);
EXPECT_THROW(Framerate({0}), InvalidFramerate);
EXPECT_THROW(Framerate({10, 0}), InvalidFramerate);
EXPECT_THROW(Framerate({0, 0}), InvalidFramerate);
}
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_many_parts.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_fully_contained.txt"), UnorderedTimecodes);
EXPECT_THROW(Framerate("data/vfr/in/v1_assume_over_1000.txt"), BadFPS);
EXPECT_THROW(Framerate("data/vfr/in/v1_override_over_1000.txt"), BadFPS);
EXPECT_THROW(Framerate("data/vfr/in/v1_override_zero.txt"), BadFPS);
EXPECT_THROW(Framerate("data/vfr/in/v1_negative_start_of_range.txt"), UnorderedTimecodes);
EXPECT_THROW(Framerate("data/vfr/in/v1_end_less_than_start.txt"), UnorderedTimecodes);
EXPECT_THROW(Framerate("data/vfr/in/v1_start_end_overlap.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/v1_fully_contained.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/v1_assume_over_1000.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/v1_override_over_1000.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/v1_override_zero.txt"), InvalidFramerate);
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"), InvalidFramerate);
}
TEST(lagi_vfr, constructors_bad_v2) {
EXPECT_THROW(Framerate("data/vfr/in/v2_empty.txt"), TooFewTimecodes);
EXPECT_THROW(Framerate("data/vfr/in/v2_out_of_order.txt"), UnorderedTimecodes);
EXPECT_THROW(Framerate("data/vfr/in/v2_empty.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/v2_out_of_order.txt"), InvalidFramerate);
EXPECT_THROW(Framerate("data/vfr/in/empty.txt"), UnknownFormat);
}