mirror of https://github.com/odrling/Aegisub
Shift timecodes so that frame 0 always starts at time 0, as nothing related to audio supports non-zero start times
Originally committed to SVN as r4791.
This commit is contained in:
parent
7586f28ffe
commit
1dedfb18cd
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue