diff --git a/src/timestamp.cpp b/src/timestamp.cpp index ae9478c8..a8cf741a 100644 --- a/src/timestamp.cpp +++ b/src/timestamp.cpp @@ -89,14 +89,12 @@ Timestamp::operator bool() const noexcept Timestamp operator+(const Timestamp &left, const Timestamp &right) noexcept { - // Use more good precision - if (left.timebase() < right.timebase()) { - auto ts = av_add_stable(left.timebase(), left.timestamp(), - right.timebase(), right.timestamp()); + // av_add_stable() required that rhs value less than lhs + if (left >= right) { + auto const ts = av_add_stable(left.timebase(), left.timestamp(), right.timebase(), right.timestamp()); return {ts, left.timebase()}; } else { - auto ts = av_add_stable(right.timebase(), right.timestamp(), - left.timebase(), left.timestamp()); + auto ts = av_add_stable(right.timebase(), right.timestamp(), left.timebase(), left.timestamp()); return {ts, right.timebase()}; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d1e20d8b..69b8d96f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,7 +14,8 @@ add_executable(test_executor AvDeleter.cpp Packet.cpp Format.cpp - Rational.cpp) + Rational.cpp + Timestamp.cpp) target_link_libraries(test_executor PUBLIC Catch2::Catch2 test_main avcpp::avcpp) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../catch2/contrib") diff --git a/tests/Timestamp.cpp b/tests/Timestamp.cpp new file mode 100644 index 00000000..8ead45ae --- /dev/null +++ b/tests/Timestamp.cpp @@ -0,0 +1,57 @@ +#include + +#include + +#include "rational.h" +#include "timestamp.h" + +#ifdef _MSC_VER +# pragma warning(disable : 4702) // Disable warning: unreachable code +#endif + + +using namespace std; + +TEST_CASE("Core", "[Overflow]") +{ + SECTION("Overflow operator+(a,b)") + { + { + auto const tsLimit = std::numeric_limits::max() / 48000; + + av::Timestamp t { + tsLimit, av::Rational {1, 48000} + }; + av::Timestamp inc {48000, t.timebase()}; // 1s + + auto v1 = t; + v1 += inc; + + auto v2 = t + inc; + auto v3 = inc + t; + + CHECK(v1 == v2); + CHECK(v1 == v3); + } + +#if 0 + av::Timestamp t1(48000, av::Rational {1, 48000}); // 1s + av::Timestamp t2 = t1; + av::Timestamp t3 = t1; + for (int64_t i = 0; i < 4194258; ++i) { + t1 = t1 + av::Timestamp {1024, t1.timebase()}; // fail case + t2 += av::Timestamp {1024, t2.timebase()}; // good + t3 = av::Timestamp {1024, t1.timebase()} + t3; + + CHECK(t3 == t2); + CHECK(t1 == t2); + CHECK(t1.seconds() >= 1.0); + + if (t1 != t2 || t2 != t3 || t1.seconds() < 1.0) { + CHECK(i < 0); // always fail, just for report + break; + } + } +#endif + } +}