forked from mia/Aegisub
Fix FrameAtTime computation for CFR
The new formula is just the inverse function of the CFR part of the TimeAtFrame function. To see how the previous implementation was faulty, see either the added tests, or - In Aegisub, open a dummy video with a frame rate of 23.976 - Make a subtitle event with start time 04:44.41 - Double-click the line to (supposedly) seek to its first frame - This will seek one frame earlier than it should, and the event will not be displayed on the resulting frame.
This commit is contained in:
parent
a394aefd1a
commit
245cc68afa
2 changed files with 19 additions and 1 deletions
|
@ -225,7 +225,7 @@ int Framerate::FrameAtTime(int ms, Time type) const {
|
||||||
return int((ms * numerator / denominator - 999) / 1000);
|
return int((ms * numerator / denominator - 999) / 1000);
|
||||||
|
|
||||||
if (ms > timecodes.back())
|
if (ms > timecodes.back())
|
||||||
return int((ms * numerator - last + denominator - 1) / denominator / 1000) + (int)timecodes.size() - 1;
|
return int((ms * numerator - numerator / 2 - last + numerator - 1) / denominator / 1000) + (int)timecodes.size() - 1;
|
||||||
|
|
||||||
return (int)distance(lower_bound(timecodes.rbegin(), timecodes.rend(), ms, std::greater<int>()), timecodes.rend()) - 1;
|
return (int)distance(lower_bound(timecodes.rbegin(), timecodes.rend(), ms, std::greater<int>()), timecodes.rend()) - 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,6 +149,12 @@ TEST(lagi_vfr, cfr_round_trip_exact) {
|
||||||
for (int i = -10; i < 11; i++) {
|
for (int i = -10; i < 11; i++) {
|
||||||
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i)));
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(fps = Framerate(24000, 1001));
|
||||||
|
int frames[] = {-100, -10, -1, 0, 1, 10, 100, 6820};
|
||||||
|
for (int i : frames) {
|
||||||
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, cfr_round_trip_start) {
|
TEST(lagi_vfr, cfr_round_trip_start) {
|
||||||
|
@ -157,6 +163,12 @@ TEST(lagi_vfr, cfr_round_trip_start) {
|
||||||
for (int i = -10; i < 11; i++) {
|
for (int i = -10; i < 11; i++) {
|
||||||
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, START), START));
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, START), START));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(fps = Framerate(24000, 1001));
|
||||||
|
int frames[] = {-100, -10, -1, 0, 1, 10, 100, 6820};
|
||||||
|
for (int i : frames) {
|
||||||
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, START), START));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, cfr_round_trip_end) {
|
TEST(lagi_vfr, cfr_round_trip_end) {
|
||||||
|
@ -165,6 +177,12 @@ TEST(lagi_vfr, cfr_round_trip_end) {
|
||||||
for (int i = -10; i < 11; i++) {
|
for (int i = -10; i < 11; i++) {
|
||||||
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, END), END));
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, END), END));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(fps = Framerate(24000, 1001));
|
||||||
|
int frames[] = {-100, -10, -1, 0, 1, 10, 100, 6820};
|
||||||
|
for (int i : frames) {
|
||||||
|
EXPECT_EQ(i, fps.FrameAtTime(fps.TimeAtFrame(i, END), END));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lagi_vfr, vfr_round_trip_exact) {
|
TEST(lagi_vfr, vfr_round_trip_exact) {
|
||||||
|
|
Loading…
Reference in a new issue