Motown: Add new Ratio and LinearFunction classes to media/common/cpp.
Ratio and LinearFunction duplicate LinearTransform::Ratio and
LinearTransform with some improvements in terminology and notational
convenience. Unit tests are included. These classes have been added to
mojo/services/media/common/cpp so that clients can use them. The new
timing code will use these classes.

R=kulakowski@chromium.org

Review URL: https://codereview.chromium.org/1950603002 .
diff --git a/mojo/services/media/common/cpp/BUILD.gn b/mojo/services/media/common/cpp/BUILD.gn
index 627a726..e46af00 100644
--- a/mojo/services/media/common/cpp/BUILD.gn
+++ b/mojo/services/media/common/cpp/BUILD.gn
@@ -12,11 +12,15 @@
     "circular_buffer_media_pipe_adapter.h",
     "fifo_allocator.cc",
     "fifo_allocator.h",
+    "linear_function.cc",
+    "linear_function.h",
     "linear_transform.cc",
     "linear_transform.h",
     "local_time.h",
     "mapped_shared_buffer.cc",
     "mapped_shared_buffer.h",
+    "ratio.cc",
+    "ratio.h",
     "shared_media_buffer_allocator.cc",
     "shared_media_buffer_allocator.h",
   ]
@@ -36,3 +40,5 @@
     "$mojo_sdk_root/mojo/services/media/common/interfaces",
   ]
 }
+# Look for unit tests in services/media/common/test
+# TODO(dalesat): Move unit tests here using different test infrastructure.
diff --git a/mojo/services/media/common/cpp/linear_function.cc b/mojo/services/media/common/cpp/linear_function.cc
new file mode 100644
index 0000000..ec662e7
--- /dev/null
+++ b/mojo/services/media/common/cpp/linear_function.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <utility>
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/linear_function.h"
+
+namespace mojo {
+namespace media {
+
+// static
+int64_t LinearFunction::Apply(int64_t domain_basis,
+                              int64_t range_basis,
+                              const Ratio& slope,  // range_delta / domain_delta
+                              int64_t domain_input) {
+  return slope.Scale(domain_input - domain_basis) + range_basis;
+}
+
+// static
+LinearFunction LinearFunction::Compose(const LinearFunction& bc,
+                                       const LinearFunction& ab,
+                                       bool exact) {
+  return LinearFunction(ab.domain_basis(), bc.Apply(ab.range_basis()),
+                        Ratio::Product(ab.slope(), bc.slope(), exact));
+}
+
+}  // namespace media
+}  // namespace mojo
diff --git a/mojo/services/media/common/cpp/linear_function.h b/mojo/services/media/common/cpp/linear_function.h
new file mode 100644
index 0000000..be66bb3
--- /dev/null
+++ b/mojo/services/media/common/cpp/linear_function.h
@@ -0,0 +1,123 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_LINEAR_FUNCTION_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_LINEAR_FUNCTION_H_
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/ratio.h"
+
+namespace mojo {
+namespace media {
+
+// TODO(dalesat): Consider always allowing inexact results.
+
+// A linear function from int64_t to int64_t with non-negative slope. The
+// representation is in point-slope form. The point is represented as two
+// int64_t values (domain_basis, range_basis), and the slope is represented as
+// the ratio of two uint32_t values (range_delta / domain_delta). 'Domain'
+// refers to the input space, and 'range' refers to the output space.
+struct LinearFunction {
+  // Applies a linear function.
+  static int64_t Apply(int64_t domain_basis,
+                       int64_t range_basis,
+                       const Ratio& slope,  // range_delta / domain_delta
+                       int64_t domain_input);
+
+  // Applies the inverse of a linear function.
+  static int64_t ApplyInverse(int64_t domain_basis,
+                              int64_t range_basis,
+                              const Ratio& slope,  // range_delta / domain_delta
+                              int64_t range_input) {
+    MOJO_DCHECK(slope.denominator() != 0u);
+    return Apply(range_basis, domain_basis, slope.Inverse(), range_input);
+  }
+
+  // Composes two linear functions B->C and A->B producing A->C. If exact is
+  // true, DCHECKs on loss of precision.
+  static LinearFunction Compose(const LinearFunction& bc,
+                                const LinearFunction& ab,
+                                bool exact = true);
+
+  LinearFunction() : domain_basis_(0), range_basis_(0) {}
+
+  LinearFunction(int64_t domain_basis,
+                 int64_t range_basis,
+                 uint32_t domain_delta,
+                 uint32_t range_delta)
+      : domain_basis_(domain_basis),
+        range_basis_(range_basis),
+        slope_(range_delta, domain_delta) {}
+
+  LinearFunction(int64_t domain_basis,
+                 int64_t range_basis,
+                 const Ratio& slope)  // range_delta / domain_delta
+      : domain_basis_(domain_basis),
+        range_basis_(range_basis),
+        slope_(slope) {}
+
+  explicit LinearFunction(const Ratio& slope)  // range_delta / domain_delta
+      : domain_basis_(0),
+        range_basis_(0),
+        slope_(slope) {}
+
+  // Applies the function. Returns Ratio::kOverflow on overflow.
+  int64_t Apply(int64_t domain_input) const {
+    return Apply(domain_basis_, range_basis_, slope_, domain_input);
+  }
+
+  // Applies the inverse of the function. Returns Ratio::kOverflow on overflow.
+  int64_t ApplyInverse(int64_t range_input) const {
+    MOJO_DCHECK(slope_.denominator() != 0u);
+    return ApplyInverse(domain_basis_, range_basis_, slope_, range_input);
+  }
+
+  // Applies the function.  Returns Ratio::kOverflow on overflow.
+  int64_t operator()(int64_t domain_input) const { return Apply(domain_input); }
+
+  // Returns a linear function that is the inverse if this linear function.
+  LinearFunction Inverse() const {
+    MOJO_DCHECK(slope_.denominator() != 0u);
+    return LinearFunction(range_basis_, domain_basis_, slope_.Inverse());
+  }
+
+  int64_t domain_basis() const { return domain_basis_; }
+
+  int64_t range_basis() const { return range_basis_; }
+
+  const Ratio& slope() const { return slope_; }
+
+  uint32_t domain_delta() const { return slope_.denominator(); }
+
+  uint32_t range_delta() const { return slope_.numerator(); }
+
+  int64_t domain_basis_;
+  int64_t range_basis_;
+  Ratio slope_;  // range_delta / domain_delta
+};
+
+// Tests two linear functions for equality. Equality requires equal basis
+// values.
+inline bool operator==(const LinearFunction& a, const LinearFunction& b) {
+  return a.domain_basis() == b.domain_basis() &&
+         a.range_basis() == b.range_basis() && a.slope() == b.slope();
+}
+
+// Tests two linear functions for inequality. Equality requires equal basis
+// values.
+inline bool operator!=(const LinearFunction& a, const LinearFunction& b) {
+  return !(a == b);
+}
+
+// Composes two linear functions B->C and A->B producing A->C. DCHECKs on
+// loss of precision.
+inline LinearFunction operator*(const LinearFunction& bc,
+                                const LinearFunction& ab) {
+  return LinearFunction::Compose(bc, ab);
+}
+
+}  // namespace media
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_MEDIA_COMMON_CPP_LINEAR_FUNCTION_H_
diff --git a/mojo/services/media/common/cpp/ratio.cc b/mojo/services/media/common/cpp/ratio.cc
new file mode 100644
index 0000000..56a3f51
--- /dev/null
+++ b/mojo/services/media/common/cpp/ratio.cc
@@ -0,0 +1,228 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <utility>
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/ratio.h"
+
+namespace mojo {
+namespace media {
+
+namespace {
+
+// Calculates the greatest common denominator (factor) of two values.
+template <typename T>
+T BinaryGcd(T a, T b) {
+  if (a == 0) {
+    return b;
+  }
+
+  if (b == 0) {
+    return a;
+  }
+
+  // Remove and count the common factors of 2.
+  uint8_t twos;
+  for (twos = 0; ((a | b) & 1) == 0; ++twos) {
+    a >>= 1;
+    b >>= 1;
+  }
+
+  // Get rid of the non-common factors of 2 in a. a is non-zero, so this
+  // terminates.
+  while ((a & 1) == 0) {
+    a >>= 1;
+  }
+
+  do {
+    // Get rid of the non-common factors of 2 in b. b is non-zero, so this
+    // terminates.
+    while ((b & 1) == 0) {
+      b >>= 1;
+    }
+
+    // Apply the Euclid subtraction method.
+    if (a > b) {
+      std::swap(a, b);
+    }
+
+    b = b - a;
+  } while (b != 0);
+
+  // Multiply in the common factors of two.
+  return a << twos;
+}
+
+// Reduces the ration of *numerator and *denominator.
+template <typename T>
+void ReduceRatio(T* numerator, T* denominator) {
+  MOJO_DCHECK(numerator != nullptr);
+  MOJO_DCHECK(denominator != nullptr);
+  MOJO_DCHECK(*denominator != 0);
+
+  T gcd = BinaryGcd(*numerator, *denominator);
+
+  if (gcd == 0) {
+    *denominator = 1;
+    return;
+  }
+
+  if (gcd == 1) {
+    return;
+  }
+
+  *numerator = *numerator / gcd;
+  *denominator = *denominator / gcd;
+}
+
+template void ReduceRatio<uint64_t>(uint64_t* numerator, uint64_t* denominator);
+template void ReduceRatio<uint32_t>(uint32_t* numerator, uint32_t* denominator);
+
+// Scales a uint64_t value by the ratio of two uint32_t values. If round_up is
+// true, the result is rounded up rather than down. overflow is set to indicate
+// overflow.
+uint64_t ScaleUInt64(uint64_t value,
+                     uint32_t numerator,
+                     uint32_t denominator,
+                     bool round_up,
+                     bool* overflow) {
+  MOJO_DCHECK(denominator != 0u);
+  MOJO_DCHECK(overflow != nullptr);
+
+  constexpr uint64_t kLow32Bits = 0xffffffffu;
+  constexpr uint64_t kHigh32Bits = kLow32Bits << 32u;
+
+  // high and low are the product of the numerator and the high and low halves
+  // (respectively) of value.
+  uint64_t high = numerator * (value >> 32u);
+  uint64_t low = numerator * (value & kLow32Bits);
+  // Ignoring overflow and remainder, the result we want is:
+  // ((high << 32) + low) / denominator.
+
+  // Move the high end of low into the low end of high.
+  high += low >> 32u;
+  low = low & kLow32Bits;
+  // Ignoring overflow and remainder, the result we want is still:
+  // ((high << 32) + low) / denominator.
+
+  // When we divide high by denominator, there'll be a remainder. Make
+  // that the high end of low, which is currently all zeroes.
+  low |= (high % denominator) << 32u;
+
+  // Determine if we need to round up when we're done:
+  round_up = round_up && (low % denominator) != 0;
+
+  // Do the division.
+  high /= denominator;
+  low /= denominator;
+
+  // If high's top 32 bits aren't all zero, we have overflow.
+  if (high & kHigh32Bits) {
+    *overflow = true;
+    return 0;
+  }
+
+  uint64_t result = (high << 32u) | low;
+  if (round_up) {
+    if (result == std::numeric_limits<int64_t>::max()) {
+      *overflow = true;
+      return 0;
+    }
+    ++result;
+  }
+
+  *overflow = false;
+  return result;
+}
+
+}  // namespace
+
+// static
+void Ratio::Reduce(uint32_t* numerator, uint32_t* denominator) {
+  ReduceRatio(numerator, denominator);
+}
+
+// static
+void Ratio::Product(uint32_t a_numerator,
+                    uint32_t a_denominator,
+                    uint32_t b_numerator,
+                    uint32_t b_denominator,
+                    uint32_t* product_numerator,
+                    uint32_t* product_denominator,
+                    bool exact) {
+  MOJO_DCHECK(a_denominator != 0);
+  MOJO_DCHECK(b_denominator != 0);
+  MOJO_DCHECK(product_numerator != nullptr);
+  MOJO_DCHECK(product_denominator != nullptr);
+
+  uint64_t numerator = static_cast<uint64_t>(a_numerator) * b_numerator;
+  uint64_t denominator = static_cast<uint64_t>(a_denominator) * b_denominator;
+
+  ReduceRatio(&numerator, &denominator);
+
+  if (numerator > std::numeric_limits<uint32_t>::max() ||
+      denominator > std::numeric_limits<uint32_t>::max()) {
+    MOJO_DCHECK(!exact);
+
+    do {
+      numerator >>= 1;
+      denominator >>= 1;
+    } while (numerator > std::numeric_limits<uint32_t>::max() ||
+             denominator > std::numeric_limits<uint32_t>::max());
+
+    if (denominator == 0) {
+      // Product is larger than we can represent. Return the largest value we
+      // can represent.
+      *product_numerator = std::numeric_limits<uint32_t>::max();
+      *product_denominator = 1;
+      return;
+    }
+  }
+
+  *product_numerator = static_cast<uint32_t>(numerator);
+  *product_denominator = static_cast<uint32_t>(denominator);
+}
+
+// static
+int64_t Ratio::Scale(int64_t value, uint32_t numerator, uint32_t denominator) {
+  static constexpr uint64_t abs_of_min_int64 =
+      static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
+
+  MOJO_DCHECK(denominator != 0u);
+
+  bool overflow;
+
+  uint64_t abs_result;
+
+  if (value >= 0) {
+    abs_result = ScaleUInt64(static_cast<uint64_t>(value), numerator,
+                             denominator, false, &overflow);
+  } else if (value == std::numeric_limits<int64_t>::min()) {
+    abs_result = ScaleUInt64(abs_of_min_int64, numerator, denominator,
+                             true, &overflow);
+  } else {
+    abs_result = ScaleUInt64(static_cast<uint64_t>(-value), numerator,
+                             denominator, true, &overflow);
+  }
+
+  if (overflow) {
+    return Ratio::kOverflow;
+  }
+
+  // Make sure we won't overflow when we cast to int64_t.
+  if (abs_result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+    if (value < 0 && abs_result == abs_of_min_int64) {
+      return std::numeric_limits<int64_t>::min();
+    }
+    return Ratio::kOverflow;
+  }
+
+  return value >= 0 ? static_cast<int64_t>(abs_result)
+                    : -static_cast<int64_t>(abs_result);
+}
+
+}  // namespace media
+}  // namespace mojo
diff --git a/mojo/services/media/common/cpp/ratio.h b/mojo/services/media/common/cpp/ratio.h
new file mode 100644
index 0000000..0755c6e
--- /dev/null
+++ b/mojo/services/media/common/cpp/ratio.h
@@ -0,0 +1,118 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_RATIO_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_RATIO_H_
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "mojo/public/cpp/environment/logging.h"
+
+namespace mojo {
+namespace media {
+
+// TODO(dalesat): Consider always allowing inexact results.
+
+// Expresses a non-negative rational number as the ratio between two uint32_t
+// values.
+struct Ratio {
+  // Used to indicate overflow of scaling operations.
+  static constexpr int64_t kOverflow = std::numeric_limits<int64_t>::max();
+
+  // Reduces the ratio of *numerator and *denominator.
+  static void Reduce(uint32_t* numerator, uint32_t* denominator);
+
+  // Produces the product of the ratios. If exact is true, DCHECKs on loss of
+  // precision.
+  static void Product(uint32_t a_numerator,
+                      uint32_t a_denominator,
+                      uint32_t b_numerator,
+                      uint32_t b_denominator,
+                      uint32_t* product_numerator,
+                      uint32_t* product_denominator,
+                      bool exact = true);
+
+  // Produces the product of the ratios and the int64_t as an int64_t. Returns
+  // kOverflow on overflow.
+  static int64_t Scale(int64_t value, uint32_t numerator, uint32_t denominator);
+
+  // Returns the product of the ratios. If exact is true, DCHECKs on loss of
+  // precision.
+  static Ratio Product(const Ratio& a, const Ratio& b, bool exact = true) {
+    uint32_t result_numerator;
+    uint32_t result_denominator;
+    Product(a.numerator(), a.denominator(), b.numerator(), b.denominator(),
+            &result_numerator, &result_denominator, exact);
+    return Ratio(result_numerator, result_denominator);
+  }
+
+  Ratio() : numerator_(0), denominator_(1) {}
+
+  explicit Ratio(uint32_t numerator) : numerator_(numerator), denominator_(1) {}
+
+  Ratio(uint32_t numerator, uint32_t denominator)
+      : numerator_(numerator), denominator_(denominator) {
+    MOJO_DCHECK(denominator != 0);
+    Reduce(&numerator_, &denominator_);
+  }
+
+  // Returns the inverse of the ratio. DCHECKs if the numerator of this ratio
+  // is zero.
+  Ratio Inverse() const {
+    MOJO_DCHECK(numerator_ != 0);
+    return Ratio(denominator_, numerator_);
+  }
+
+  // Scales the value by this ratio. Returns kOverflow on overflow.
+  int64_t Scale(int64_t value) const {
+    return Scale(value, numerator_, denominator_);
+  }
+
+  uint32_t numerator() const { return numerator_; }
+  uint32_t denominator() const { return denominator_; }
+
+ private:
+  uint32_t numerator_;
+  uint32_t denominator_;
+};
+
+// Tests two ratios for equality.
+inline bool operator==(const Ratio& a, const Ratio& b) {
+  return a.numerator() == b.numerator() && a.denominator() == b.denominator();
+}
+
+// Tests two ratios for inequality.
+inline bool operator!=(const Ratio& a, const Ratio& b) {
+  return !(a == b);
+}
+
+// Returns the product of the two ratios. DCHECKs on loss of precision.
+inline Ratio operator*(const Ratio& a, const Ratio& b) {
+  return Ratio::Product(a, b);
+}
+
+// Returns the product of the ratio and the int64_t. Returns kOverflow on
+// overflow.
+inline int64_t operator*(const Ratio& a, int64_t b) {
+  return a.Scale(b);
+}
+
+// Returns the product of the ratio and the int64_t. Returns kOverflow on
+// overflow.
+inline int64_t operator*(int64_t a, const Ratio& b) {
+  return b.Scale(a);
+}
+
+// Returns the the int64_t divided by the ratio. Returns kOverflow on
+// overflow.
+inline int64_t operator/(int64_t a, const Ratio& b) {
+  return b.Inverse().Scale(a);
+}
+
+}  // namespace media
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_MEDIA_COMMON_CPP_LINEAR_TRANSFORM_H_
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 8254c5e..6d4e00b 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -82,6 +82,7 @@
     "//services/clipboard:apptests",
     "//services/gfx/compositor:apptests",
     "//services/http_server:apptests",
+    "//services/media/common:apptests",
     "//services/native_support:apptests",
     "//services/prediction:apptests",
   ]
diff --git a/services/media/common/BUILD.gn b/services/media/common/BUILD.gn
index fb22148..dc8e8b6 100644
--- a/services/media/common/BUILD.gn
+++ b/services/media/common/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/module_args/mojo.gni")
+import("//mojo/public/mojo_application.gni")
 import("$mojo_sdk_root/mojo/public/mojo_sdk.gni")
 
 source_set("common") {
@@ -18,3 +19,22 @@
     "//mojo/services/media/common/interfaces",
   ]
 }
+
+mojo_native_application("apptests") {
+  output_name = "media_common_apptests"
+
+  testonly = true
+
+  sources = [
+    "test/linear_function_test.cc",
+    "test/ratio_test.cc",
+    "test/test_base.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/application",
+    "//mojo/application:test_support",
+    "//mojo/services/media/common/cpp",
+  ]
+}
diff --git a/services/media/common/test/linear_function_test.cc b/services/media/common/test/linear_function_test.cc
new file mode 100644
index 0000000..b2ab53d
--- /dev/null
+++ b/services/media/common/test/linear_function_test.cc
@@ -0,0 +1,226 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/services/media/common/cpp/linear_function.h"
+#include "services/media/common/test/test_base.h"
+
+namespace mojo {
+namespace media {
+namespace {
+
+class LinearFunctionTest : public TestBase {
+ public:
+  // Verifies that a LinearFunction instantiated in three different ways with
+  // the given arguments has the expected properties.
+  void VerifyBasics(int64_t domain_basis,
+                    int64_t range_basis,
+                    uint32_t domain_delta,
+                    uint32_t range_delta) {
+    LinearFunction under_test_1(domain_basis, range_basis, domain_delta,
+                                range_delta);
+    VerifyBasics(under_test_1, domain_basis, range_basis, domain_delta,
+                 range_delta);
+
+    LinearFunction under_test_2(domain_basis, range_basis,
+                                Ratio(range_delta, domain_delta));
+    VerifyBasics(under_test_2, domain_basis, range_basis, domain_delta,
+                 range_delta);
+
+    LinearFunction under_test_3(Ratio(range_delta, domain_delta));
+    VerifyBasics(under_test_3, 0, 0, domain_delta, range_delta);
+
+    EXPECT_EQ(under_test_1, under_test_1);
+    EXPECT_EQ(under_test_1, under_test_2);
+    EXPECT_EQ(under_test_2, under_test_1);
+    EXPECT_EQ(under_test_2, under_test_2);
+
+    if (domain_basis == 0 && range_basis == 0) {
+      EXPECT_EQ(under_test_1, under_test_3);
+      EXPECT_EQ(under_test_2, under_test_3);
+      EXPECT_EQ(under_test_3, under_test_1);
+      EXPECT_EQ(under_test_3, under_test_2);
+    } else {
+      EXPECT_NE(under_test_1, under_test_3);
+      EXPECT_NE(under_test_2, under_test_3);
+      EXPECT_NE(under_test_3, under_test_1);
+      EXPECT_NE(under_test_3, under_test_2);
+    }
+  }
+
+  // Verifies that the given LinearFunction instantiated with the given
+  // arguments has the expected properties.
+  void VerifyBasics(const LinearFunction& under_test,
+                    int64_t domain_basis,
+                    int64_t range_basis,
+                    uint32_t domain_delta,
+                    uint32_t range_delta) {
+    Ratio::Reduce(&range_delta, &domain_delta);
+    EXPECT_EQ(domain_basis, under_test.domain_basis());
+    EXPECT_EQ(range_basis, under_test.range_basis());
+    EXPECT_EQ(domain_delta, under_test.domain_delta());
+    EXPECT_EQ(range_delta, under_test.range_delta());
+    EXPECT_EQ(domain_delta, under_test.slope().denominator());
+    EXPECT_EQ(range_delta, under_test.slope().numerator());
+  }
+
+  // Verifies that the inverse of a LinearFunction instantiated in three
+  // different ways with the given arguments has the expected properties.
+  void VerifyInverse(int64_t domain_basis,
+                     int64_t range_basis,
+                     uint32_t domain_delta,
+                     uint32_t range_delta) {
+    LinearFunction under_test_1(domain_basis, range_basis, domain_delta,
+                                range_delta);
+    VerifyBasics(under_test_1.Inverse(), range_basis, domain_basis, range_delta,
+                 domain_delta);
+
+    LinearFunction under_test_2(domain_basis, range_basis,
+                                Ratio(range_delta, domain_delta));
+    VerifyBasics(under_test_2.Inverse(), range_basis, domain_basis, range_delta,
+                 domain_delta);
+
+    LinearFunction under_test_3(Ratio(range_delta, domain_delta));
+    VerifyBasics(under_test_3.Inverse(), 0, 0, range_delta, domain_delta);
+  }
+
+  // Verifies that LinearFunction::Apply, in its various forms, works as
+  // expected for the given arguments.
+  void VerifyApply(int64_t domain_basis,
+                   int64_t range_basis,
+                   uint32_t domain_delta,
+                   uint32_t range_delta,
+                   int64_t domain_input,
+                   int64_t expected_result) {
+    // Verify the static method.
+    EXPECT_EQ(
+        expected_result,
+        LinearFunction::Apply(domain_basis, range_basis,
+                              Ratio(range_delta, domain_delta), domain_input));
+
+    // Verify the instance method.
+    LinearFunction under_test(domain_basis, range_basis, domain_delta,
+                              range_delta);
+    EXPECT_EQ(expected_result, under_test.Apply(domain_input));
+
+    // Verify the operator.
+    EXPECT_EQ(expected_result, under_test(domain_input));
+  }
+
+  // Verifies that LinearFunction::ApplyInverse, in its various forms, works as
+  // expected for the given arguments.
+  void VerifyApplyInverse(int64_t domain_basis,
+                          int64_t range_basis,
+                          uint32_t domain_delta,
+                          uint32_t range_delta,
+                          int64_t range_input,
+                          int64_t expected_result) {
+    // Verify the static method.
+    EXPECT_EQ(expected_result,
+              LinearFunction::ApplyInverse(domain_basis, range_basis,
+                                           Ratio(range_delta, domain_delta),
+                                           range_input));
+
+    // Verify the instance method.
+    LinearFunction under_test(domain_basis, range_basis, domain_delta,
+                              range_delta);
+    EXPECT_EQ(expected_result, under_test.ApplyInverse(range_input));
+  }
+
+  // Verifies that LinearFunction::Compose works as expected with the given
+  // inputs.
+  void VerifyCompose(const LinearFunction& a,
+                     const LinearFunction& b,
+                     bool exact,
+                     const LinearFunction& expected_result) {
+    // Verify the static method.
+    EXPECT_EQ(expected_result, LinearFunction::Compose(a, b, exact));
+  }
+};
+
+// Tests LinearFunction basics for various instantiation arguments.
+TEST_F(LinearFunctionTest, Basics) {
+  VerifyBasics(0, 0, 1, 0);
+  VerifyBasics(0, 0, 1, 1);
+  VerifyBasics(1, 1, 10, 10);
+  VerifyBasics(1234, 5678, 4321, 8765);
+  VerifyBasics(-1234, 5678, 4321, 8765);
+  VerifyBasics(-1234, -5678, 4321, 8765);
+  VerifyBasics(1234, -5678, 4321, 8765);
+}
+
+// Tests LinearFunction::Inverse.
+TEST_F(LinearFunctionTest, Inverse) {
+  VerifyInverse(0, 0, 1, 1);
+  VerifyInverse(1, 1, 10, 10);
+  VerifyInverse(1234, 5678, 4321, 8765);
+  VerifyInverse(-1234, 5678, 4321, 8765);
+  VerifyInverse(-1234, -5678, 4321, 8765);
+  VerifyInverse(1234, -5678, 4321, 8765);
+}
+
+// Tests LinearFunction::Apply in its variations.
+TEST_F(LinearFunctionTest, Apply) {
+  VerifyApply(0, 0, 1, 0, 0, 0);
+  VerifyApply(0, 0, 1, 0, 1000, 0);
+  VerifyApply(0, 1234, 1, 0, 0, 1234);
+  VerifyApply(0, 1234, 1, 0, 1000, 1234);
+  VerifyApply(0, 1234, 1, 0, -1000, 1234);
+  VerifyApply(0, -1234, 1, 0, 0, -1234);
+  VerifyApply(0, -1234, 1, 0, 1000, -1234);
+  VerifyApply(0, -1234, 1, 0, -1000, -1234);
+  VerifyApply(0, 0, 1, 1, 0, 0);
+  VerifyApply(0, 0, 1, 1, 1000, 1000);
+  VerifyApply(0, 1234, 1, 1, 0, 1234);
+  VerifyApply(0, 1234, 1, 1, 1000, 2234);
+  VerifyApply(0, 1234, 1, 1, -1000, 234);
+  VerifyApply(0, -1234, 1, 1, 0, -1234);
+  VerifyApply(0, -1234, 1, 1, 1000, -234);
+  VerifyApply(0, -1234, 1, 1, -1000, -2234);
+  VerifyApply(10, 0, 1, 0, 0, 0);
+  VerifyApply(10, 0, 1, 1, 0, -10);
+  VerifyApply(-10, 0, 1, 0, 0, 0);
+  VerifyApply(-10, 0, 1, 1, 0, 10);
+  VerifyApply(0, 1234, 2, 1, 0, 1234);
+  VerifyApply(0, 1234, 2, 1, 1234, 1234 + 1234 / 2);
+  VerifyApply(0, 1234, 1, 2, 1234, 1234 + 1234 * 2);
+}
+
+// Tests LinearFunction::Apply in its variations.
+TEST_F(LinearFunctionTest, ApplyInverse) {
+  VerifyApplyInverse(0, 0, 1, 1, 0, 0);
+  VerifyApplyInverse(0, 0, 1, 1, 1000, 1000);
+  VerifyApplyInverse(0, 1234, 1, 1, 1234, 0);
+  VerifyApplyInverse(0, 1234, 1, 1, 2234, 1000);
+  VerifyApplyInverse(0, 1234, 1, 1, 234, -1000);
+  VerifyApplyInverse(0, -1234, 1, 1, -1234, 0);
+  VerifyApplyInverse(0, -1234, 1, 1, -234, 1000);
+  VerifyApplyInverse(0, -1234, 1, 1, -2234, -1000);
+  VerifyApplyInverse(10, 0, 1, 1, -10, 0);
+  VerifyApplyInverse(-10, 0, 1, 1, 10, 0);
+  VerifyApplyInverse(0, 1234, 2, 1, 1234, 0);
+  VerifyApplyInverse(0, 1234, 2, 1, 1234 + 1234 / 2, 1234);
+  VerifyApplyInverse(0, 1234, 1, 2, 1234 + 1234 * 2, 1234);
+}
+
+// Tests LinearFunction::Compose.
+TEST_F(LinearFunctionTest, Compose) {
+  VerifyCompose(LinearFunction(0, 0, 1, 0), LinearFunction(0, 0, 1, 0), true,
+                LinearFunction(0, 0, 1, 0));
+  VerifyCompose(LinearFunction(0, 0, 1, 1), LinearFunction(0, 0, 1, 1), true,
+                LinearFunction(0, 0, 1, 1));
+  VerifyCompose(LinearFunction(1, 0, 1, 1), LinearFunction(0, 0, 1, 1), true,
+                LinearFunction(0, -1, 1, 1));
+  VerifyCompose(LinearFunction(10, 10, 1, 1), LinearFunction(0, 0, 1, 1), true,
+                LinearFunction(0, 0, 1, 1));
+  VerifyCompose(LinearFunction(0, 0, 1, 2), LinearFunction(0, 0, 1, 2), true,
+                LinearFunction(0, 0, 1, 4));
+  VerifyCompose(LinearFunction(0, 0, 2, 1), LinearFunction(0, 0, 2, 1), true,
+                LinearFunction(0, 0, 4, 1));
+  VerifyCompose(LinearFunction(0, 0, 2, 1), LinearFunction(0, 0, 1, 2), true,
+                LinearFunction(0, 0, 1, 1));
+}
+
+}  // namespace
+}  // namespace media
+}  // namespace mojo
diff --git a/services/media/common/test/ratio_test.cc b/services/media/common/test/ratio_test.cc
new file mode 100644
index 0000000..8a0ce3e
--- /dev/null
+++ b/services/media/common/test/ratio_test.cc
@@ -0,0 +1,181 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "mojo/services/media/common/cpp/ratio.h"
+#include "services/media/common/test/test_base.h"
+
+namespace mojo {
+namespace media {
+namespace {
+
+class RatioTest : public TestBase {
+  static uint32_t gcd(uint32_t a, uint32_t b) {
+    while (b != 0) {
+      uint32_t t = a;
+      a = b;
+      b = t % b;
+    }
+    return a;
+  }
+
+ public:
+  // Verifies Ratio::Reduce and the constructor, ensuring that the ratio
+  // numerator * common_factor / denominator * common_factor is reduced to
+  // numerator / denominator. numerator and denominator need to be relatively
+  // prime for this to work.
+  void VerifyReduce(uint32_t numerator,
+                    uint32_t denominator,
+                    uint32_t common_factor) {
+    // Make sure numerator and denominator are relatively prime.
+    EXPECT_EQ(1u, gcd(numerator, denominator));
+
+    uint32_t test_numerator = numerator * common_factor;
+    uint32_t test_denominator = denominator * common_factor;
+
+    // Make sure the constructor reduces.
+    Ratio ratio(test_numerator, test_denominator);
+    EXPECT_EQ(numerator, ratio.numerator());
+    EXPECT_EQ(denominator, ratio.denominator());
+
+    // Test the static method.
+    Ratio::Reduce(&test_numerator, &test_denominator);
+    EXPECT_EQ(numerator, test_numerator);
+    EXPECT_EQ(denominator, test_denominator);
+  }
+
+  // Verifies the Ratio::Scale methods by scaling value by numerator /
+  // denominator and verifying the result.
+  void VerifyScale(int64_t value,
+                   uint32_t numerator,
+                   uint32_t denominator,
+                   int64_t result) {
+    // Test the instance method.
+    EXPECT_EQ(result, Ratio(numerator, denominator).Scale(value));
+
+    // Test the static method.
+    EXPECT_EQ(result, Ratio::Scale(value, numerator, denominator));
+
+    // Test the operators.
+    EXPECT_EQ(result, value * Ratio(numerator, denominator));
+    EXPECT_EQ(result, Ratio(numerator, denominator) * value);
+    if (numerator != 0) {
+      EXPECT_EQ(result, value / Ratio(denominator, numerator));
+    }
+  }
+
+  // Verifies the Ratio::Product methods by multiplying the given a and b
+  // ratios and checking the result against the expected ratio.
+  void VerifyProduct(uint32_t a_numerator,
+                     uint32_t a_denominator,
+                     uint32_t b_numerator,
+                     uint32_t b_denominator,
+                     uint32_t expected_numerator,
+                     uint32_t expected_denominator,
+                     bool exact) {
+    // Test the first static method.
+    uint32_t actual_numerator;
+    uint32_t actual_denominator;
+    Ratio::Product(a_numerator, a_denominator, b_numerator, b_denominator,
+                   &actual_numerator, &actual_denominator, exact);
+    EXPECT_EQ(expected_numerator, actual_numerator);
+    EXPECT_EQ(expected_denominator, actual_denominator);
+
+    // Test the second static method.
+    EXPECT_EQ(Ratio(expected_numerator, expected_denominator),
+              Ratio::Product(Ratio(a_numerator, a_denominator),
+                             Ratio(b_numerator, b_denominator), exact));
+
+    // Test the operator
+    if (exact) {
+      EXPECT_EQ(Ratio(expected_numerator, expected_denominator),
+                Ratio(a_numerator, a_denominator) *
+                    Ratio(b_numerator, b_denominator));
+    }
+  }
+
+  // Verifies the Ration::Inverse method using the given ratio.
+  void VerifyInverse(uint32_t numerator, uint32_t denominator) {
+    Ratio ratio(numerator, denominator);
+    Ratio inverse(ratio.Inverse());
+    EXPECT_EQ(ratio.denominator(), inverse.numerator());
+    EXPECT_EQ(ratio.numerator(), inverse.denominator());
+  }
+};
+
+// Tests Ratio::Reduce and that the Ratio constructor reduces.
+TEST_F(RatioTest, Reduce) {
+  VerifyReduce(0, 1, 1);
+  VerifyReduce(1, 1, 1);
+  VerifyReduce(1234, 1, 1);
+  VerifyReduce(1, 1234, 14);
+  VerifyReduce(1, 1, 1234);
+  VerifyReduce(10, 1, 1234);
+  VerifyReduce(1, 10, 1234);
+  VerifyReduce(49, 81, 1);
+  VerifyReduce(49, 81, 10);
+  VerifyReduce(49, 81, 100);
+  VerifyReduce(1, 8, 65536);
+  VerifyReduce(8, 1, 65536);
+}
+
+// Tests Ratio::Scale, static, instance and operator versions.
+TEST_F(RatioTest, Scale) {
+  const int64_t int64_min = std::numeric_limits<int64_t>::min();
+  VerifyScale(0, 0, 1, 0);
+  VerifyScale(1, 0, 1, 0);
+  VerifyScale(0, 1, 1, 0);
+  VerifyScale(1, 1, 1, 1);
+  VerifyScale(1, 2, 1, 2);
+  VerifyScale(1, 1, 2, 0);
+  VerifyScale(-1, 1, 2, -1);
+  VerifyScale(1000, 1, 2, 500);
+  VerifyScale(1001, 1, 2, 500);
+  VerifyScale(-1000, 1, 2, -500);
+  VerifyScale(-1001, 1, 2, -501);
+  VerifyScale(1000, 2, 1, 2000);
+  VerifyScale(1001, 2, 1, 2002);
+  VerifyScale(-1000, 2, 1, -2000);
+  VerifyScale(-1001, 2, 1, -2002);
+  VerifyScale(1ll << 32, 1, 1, 1ll << 32);
+  VerifyScale(1ll << 32, 1, 2, 1ll << 31);
+  VerifyScale(1ll << 32, 2, 1, 1ll << 33);
+  VerifyScale(1234ll << 30, 1, 1, 1234ll << 30);
+  VerifyScale(1234ll << 30, 1, 2, 1234ll << 29);
+  VerifyScale(1234ll << 30, 2, 1, 1234ll << 31);
+  VerifyScale(1234ll << 30, 1 << 31, 1, Ratio::kOverflow);
+  VerifyScale(1234ll << 30, 1ll << 31, (1ll << 31) - 2,
+              (1234ll << 30) + 1234ll);
+  VerifyScale(int64_min, 1, 1, int64_min);
+  VerifyScale(int64_min, 1, 2, int64_min / 2);
+  VerifyScale(int64_min / 2, 2, 1, int64_min);
+  VerifyScale(int64_min, 1000001, 1000000, Ratio::kOverflow);
+}
+
+// Tests Ratio::Product, static and operator versions.
+TEST_F(RatioTest, Product) {
+  VerifyProduct(0, 1, 0, 1, 0, 1, true);
+  VerifyProduct(1, 1, 1, 1, 1, 1, true);
+  VerifyProduct(10, 1, 1, 10, 1, 1, true);
+  VerifyProduct(4321, 1234, 617, 4321, 1, 2, true);
+  VerifyProduct(1234, 4321, 4321, 617, 2, 1, true);
+  VerifyProduct(1ll << 31, (1ll << 31) - 1, (1ll << 31) - 1, 1ll << 31, 1, 1,
+                true);
+  VerifyProduct(1ll << 31, (1ll << 31) - 1, (1ll << 31) - 2, 1ll << 31,
+                0x7ffffffe, 0x7fffffff, false);
+}
+
+// Tests Ratio::Inverse.
+TEST_F(RatioTest, Inverse) {
+  VerifyInverse(1, 1);
+  VerifyInverse(2, 1);
+  VerifyInverse(1, 2);
+  VerifyInverse(1000000, 1234);
+  VerifyInverse(1234, 1000000);
+}
+
+}  // namespace
+}  // namespace media
+}  // namespace mojo
diff --git a/services/media/common/test/test_base.h b/services/media/common/test/test_base.h
new file mode 100644
index 0000000..42c61cc
--- /dev/null
+++ b/services/media/common/test/test_base.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_TEST_TEST_BASE_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_TEST_TEST_BASE_H_
+
+#include "mojo/public/cpp/application/application_test_base.h"
+
+namespace mojo {
+namespace media {
+namespace {
+
+class TestBase : public test::ApplicationTestBase {
+ public:
+  TestBase() {}
+  ~TestBase() override {}
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(TestBase);
+};
+
+}  // namespace
+}  // namespace media
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_MEDIA_COMMON_CPP_TEST_TEST_BASE_H_