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