Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions libaegisub/common/vfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ void validate_timecodes(std::vector<int> const& timecodes) {
throw InvalidFramerate("Timecodes are all identical");
}

/// @brief Shift timecodes so that frame 0 starts at time 0
/// @param timecodes List of timecodes to normalize
void normalize_timecodes(std::vector<int> &timecodes) {
if (int front = timecodes.front())
boost::for_each(timecodes, [=](int &tc) { tc -= front; });
}

// A "start,end,fps" line in a v1 timecode file
struct TimecodeRange {
int start;
Expand Down Expand Up @@ -153,9 +146,8 @@ Framerate::Framerate(int64_t numerator, int64_t denominator, bool drop)

void Framerate::SetFromTimecodes() {
validate_timecodes(timecodes);
normalize_timecodes(timecodes);
denominator = default_denominator;
numerator = (timecodes.size() - 1) * denominator * 1000 / timecodes.back();
numerator = (timecodes.size() - 1) * denominator * 1000 / (timecodes.back() - timecodes.front());
last = (timecodes.size() - 1) * denominator * 1000;
}

Expand Down Expand Up @@ -221,8 +213,8 @@ int Framerate::FrameAtTime(int ms, Time type) const {
if (type == END)
return FrameAtTime(ms - 1);

if (ms < 0)
return int((ms * numerator / denominator - 999) / 1000);
if (ms < timecodes.front())
return int(((ms - timecodes.front()) * numerator / denominator - 999) / 1000);

if (ms > timecodes.back())
return ((ms + 1) * numerator - last - numerator / 2 + (1000 * denominator - 1)) / (1000 * denominator) + timecodes.size() - 2;
Expand All @@ -245,7 +237,7 @@ int Framerate::TimeAtFrame(int frame, Time type) const {
}

if (frame < 0)
return (int)(frame * denominator * 1000 / numerator);
return (int)(frame * denominator * 1000 / numerator) + timecodes.front();

if (frame >= (signed)timecodes.size()) {
int64_t frames_past_end = frame - (int)timecodes.size() + 1;
Expand Down
6 changes: 5 additions & 1 deletion src/video_provider_ffmpegsource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
Index = nullptr;
}

int64_t ContainerFirstTime = FFMS_GetContainerFirstTimeI(Indexer);

// moment of truth
if (!Index) {
auto TrackMask = TrackSelection::None;
Expand Down Expand Up @@ -281,6 +283,8 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
throw VideoOpenError("failed to get track time base");

// build list of keyframes and timecodes
double Offset = ContainerFirstTime / 1000000.0 * 1000.0;

std::vector<int> TimecodesVector;
for (int CurFrameNum = 0; CurFrameNum < VideoInfo->NumFrames; CurFrameNum++) {
const FFMS_FrameInfo *CurFrameData = FFMS_GetFrameInfo(FrameData, CurFrameNum);
Expand All @@ -292,7 +296,7 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
KeyFramesList.push_back(CurFrameNum);

// calculate timestamp and add to timecodes vector
int Timestamp = (int)((CurFrameData->PTS * TimeBase->Num) / TimeBase->Den);
int Timestamp = (int)((CurFrameData->PTS * TimeBase->Num) / TimeBase->Den - Offset);
TimecodesVector.push_back(Timestamp);
}
if (TimecodesVector.size() < 2)
Expand Down
4 changes: 2 additions & 2 deletions subprojects/ffms2.wrap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/FFMS/ffms2.git
revision = head
url = https://github.com/moi15moi/ffms2.git
revision = Add-FFMS_GetContainerFirstTimeI
patch_directory = ffms2

[provide]
Expand Down
18 changes: 0 additions & 18 deletions tests/tests/vfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,24 +394,6 @@ TEST(lagi_vfr, load_v1_save_v2_ovr) {
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({ 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({ -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));
}

TEST(lagi_vfr, rational_timebase) {
Framerate fps;

Expand Down
Loading