diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index 5f1f82f2accd1204fc66bcdbf4416b371a7db25f..3a1e658d3c59cd86894ec5cace8534f99e634c0c 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -21,6 +21,8 @@ #include "config.h" +#include "rational.h" + #ifdef RING_VIDEO #include "video/video_base.h" #include "video/video_scaler.h" diff --git a/src/rational.h b/src/rational.h index 4544c23add947d8ca1b9af36e1ccedbd7de00a51..db37357c5e8443b263c1b5150f95cd737e6a9b6f 100644 --- a/src/rational.h +++ b/src/rational.h @@ -23,6 +23,7 @@ #include <utility> // std::swap #include <cstdlib> // std::abs #include <iostream> +#include <cmath> // std::fmod extern "C" { #include <libavutil/rational.h> // specify conversions for AVRational @@ -33,7 +34,6 @@ namespace ring { /** * Naive implementation of the boost::rational interface, described here: * http://www.boost.org/doc/libs/1_57_0/libs/rational/rational.html - * No form of normalisation or overflow prevention is implemented. */ template<typename I> class rational { @@ -41,7 +41,9 @@ public: // Constructors rational() {}; // Zero rational(I n) : num_(n) {}; // Equal to n/1 - rational(I n, I d) : num_(n), den_(d) {}; // General case (n/d) + rational(I n, I d) : num_(n), den_(d) { + reduce(); + }; // General case (n/d) // Define conversions to and from AVRational (equivalent) rational(AVRational r) : num_(r.num), den_(r.den) {}; @@ -53,7 +55,7 @@ public: rational& operator=(I n) { num_ = n; den_ = 1; return *this; } // Assign in place - rational& assign(I n, I d) { num_ = n; den_ = d; return *this; } + rational& assign(I n, I d) { num_ = n; den_ = d; reduce(); return *this; } // Representation I numerator() const { return num_; }; @@ -88,19 +90,21 @@ public: rational& operator*= (const rational& r) { num_ *= r.num_; den_ *= r.den_; + reduce(); return *this; } rational& operator/= (const rational& r) { num_ *= r.den_; den_ *= r.num_; + reduce(); return *this; } // Arithmetic with integers rational& operator+= (I i) { num_ += i * den_; return *this; } rational& operator-= (I i) { num_ -= i * den_; return *this; } - rational& operator*= (I i) { num_ *= i; return *this; } - rational& operator/= (I i) { den_ *= i; return *this; }; + rational& operator*= (I i) { num_ *= i; reduce(); return *this; } + rational& operator/= (I i) { den_ *= i; reduce(); return *this; } // Increment and decrement const rational& operator++() { num_ += den_; return *this; } @@ -132,6 +136,21 @@ public: private: I num_ {0}; I den_ {1}; + + static constexpr I gcd ( I a, I b ) { + return b == (I)0 ? a : gcd(b, std::modulus<I>()(a, b)); + } + void reduce() { + if (std::is_integral<I>::value) { + if (num_ and den_) { + auto g = gcd(num_ >= 0 ? num_ : -num_, den_ >= 0 ? den_ : -den_); + if (g > (I)1) { + num_ /= g; + den_ /= g; + } + } + } + } }; // Unary operators @@ -165,3 +184,12 @@ template <typename I> std::ostream& operator<< (std::ostream& os, const rational template <typename T, typename I> T rational_cast (const rational<I>& r); } + +namespace std { + template <> + struct modulus<double> { + double operator()(const double &lhs, const double &rhs) const { + return std::fmod(lhs, rhs); + } + }; +} // namespace std