Skip to content

Commit

Permalink
Shift timecodes so that frame 0 always starts at time 0, as nothing r…
Browse files Browse the repository at this point in the history
…elated to audio supports non-zero start times

Originally committed to SVN as r4791.
  • Loading branch information
tgoyne committed Sep 23, 2010
1 parent 7586f28 commit 1dedfb1
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
20 changes: 15 additions & 5 deletions aegisub/libaegisub/common/vfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ static void validate_timecodes(std::vector<int> const& timecodes) {
std::accumulate(timecodes.begin()+1, timecodes.end(), timecodes.front(), is_increasing);
}

/// @brief Shift timecodes so that frame 0 starts at time 0
/// @param timecodes List of timecodes to normalize
static void normalize_timecodes(std::vector<int> &timecodes) {
if (int front = timecodes.front()) {
std::transform(timecodes.begin(), timecodes.end(), timecodes.begin(), std::bind2nd(std::minus<int>(), front));
}
}

// A "start,end,fps" line in a v1 timecode file
struct TimecodeRange {
int start;
Expand Down Expand Up @@ -183,7 +191,8 @@ Framerate::Framerate(std::vector<int> const& timecodes)
: timecodes(timecodes)
{
validate_timecodes(timecodes);
fps = (timecodes.size() - 1) * 1000. / (timecodes.back() - timecodes.front());
normalize_timecodes(this->timecodes);
fps = (timecodes.size() - 1) * 1000. / timecodes.back();
last = timecodes.back();
}

Expand Down Expand Up @@ -212,7 +221,8 @@ Framerate::Framerate(std::string const& filename) : fps(0.) {
if (line == "# timecode format v2") {
copy(line_iterator<int>(*file, encoding), line_iterator<int>(), back_inserter(timecodes));
validate_timecodes(timecodes);
fps = (timecodes.size() - 1) * 1000. / (timecodes.back() - timecodes.front());
normalize_timecodes(timecodes);
fps = (timecodes.size() - 1) * 1000. / timecodes.back();
last = timecodes.back();
return;
}
Expand Down Expand Up @@ -266,8 +276,8 @@ int Framerate::FrameAtTime(int ms, Time type) const {
if (timecodes.empty()) {
return (int)floor(ms * fps / 1000.);
}
if (ms < timecodes.front()) {
return (int)floor((ms - timecodes.front()) * fps / 1000.);
if (ms < 0) {
return (int)floor(ms * fps / 1000.);
}
if (ms > timecodes.back()) {
return round((ms - timecodes.back()) * fps / 1000.) + (int)timecodes.size() - 1;
Expand All @@ -294,7 +304,7 @@ int Framerate::TimeAtFrame(int frame, Time type) const {
}

if (frame < 0) {
return (int)ceil(frame / fps * 1000.) + timecodes.front();
return (int)ceil(frame / fps * 1000.);
}
if (frame >= (signed)timecodes.size()) {
return round((frame - timecodes.size() + 1) * 1000. / fps + last);
Expand Down
18 changes: 18 additions & 0 deletions aegisub/tests/libaegisub_vfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,21 @@ TEST(lagi_vfr, load_v1_save_v2_ovr) {
ASSERT_NO_THROW(fps.Save("data/vfr/out/v2_100_frames_30_with_override.txt", 100));
EXPECT_TRUE(validate_save("data/vfr/in/v2_100_frames_30_with_override.txt", "data/vfr/out/v2_100_frames_30_with_override.txt"));
}

TEST(lagi_vfr, nonzero_start_time) {
Framerate fps;

ASSERT_NO_THROW(fps = Framerate(make_vector<int>(5, 10, 20, 30, 40, 50)));
EXPECT_EQ(0, fps.TimeAtFrame(0, EXACT));
EXPECT_EQ(10, fps.TimeAtFrame(1, EXACT));
EXPECT_EQ(20, fps.TimeAtFrame(2, EXACT));
EXPECT_EQ(30, fps.TimeAtFrame(3, EXACT));
EXPECT_EQ(40, fps.TimeAtFrame(4, EXACT));

ASSERT_NO_THROW(fps = Framerate(make_vector<int>(5, -10, 20, 30, 40, 50)));
EXPECT_EQ(0, fps.TimeAtFrame(0, EXACT));
EXPECT_EQ(30, fps.TimeAtFrame(1, EXACT));
EXPECT_EQ(40, fps.TimeAtFrame(2, EXACT));
EXPECT_EQ(50, fps.TimeAtFrame(3, EXACT));
EXPECT_EQ(60, fps.TimeAtFrame(4, EXACT));
}

0 comments on commit 1dedfb1

Please sign in to comment.