Motown: Rename Ratio and LinearFunction classes
The new Ratio and LinearFunction classes are intended to help dealing
with timeline transformations. The names suggest that they implement the
mathematical concepts in a general way - this is not the case.
Furthermore, the generic names of their methods force a developer to
map between concepts, diluting the helpfulness of these helper classes.
This CL is strictly a rename...no functional changes were made. The
name mapping is:
from: to:
Ratio TimelineRate
numerator subject_delta
denominator reference_delta
LinearFunction TimelineFunction
domain_basis reference_time
range_basis subject_time
slope rate
domain_delta reference_delta
range_delta subject_delta
R=kulakowski@chromium.org
Review URL: https://codereview.chromium.org/1952673003 .
diff --git a/mojo/dart/packages/mojo_services/BUILD.gn b/mojo/dart/packages/mojo_services/BUILD.gn
index 140f817..2915f70 100644
--- a/mojo/dart/packages/mojo_services/BUILD.gn
+++ b/mojo/dart/packages/mojo_services/BUILD.gn
@@ -78,6 +78,7 @@
"lib/mojo/tcp_server_socket.mojom.dart",
"lib/mojo/terminal/terminal_client.mojom.dart",
"lib/mojo/terminal/terminal.mojom.dart",
+ "lib/mojo/timelines.mojom.dart",
"lib/mojo/udp_socket.mojom.dart",
"lib/mojo/ui/input_connection.mojom.dart",
"lib/mojo/ui/input_dispatcher.mojom.dart",
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/timelines.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/timelines.mojom.dart
new file mode 100644
index 0000000..1c97d38
--- /dev/null
+++ b/mojo/dart/packages/mojo_services/lib/mojo/timelines.mojom.dart
@@ -0,0 +1,564 @@
+// Copyright 2014 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.
+
+library timelines_mojom;
+import 'dart:async';
+import 'package:mojo/bindings.dart' as bindings;
+import 'package:mojo/core.dart' as core;
+import 'package:mojo/mojo/bindings/types/service_describer.mojom.dart' as service_describer;
+
+
+
+class TimelineTransform extends bindings.Struct {
+ static const List<bindings.StructDataHeader> kVersions = const [
+ const bindings.StructDataHeader(32, 0)
+ ];
+ int referenceTime = 0;
+ int subjectTime = 0;
+ int referenceDelta = 1;
+ int subjectDelta = 0;
+
+ TimelineTransform() : super(kVersions.last.size);
+
+ static TimelineTransform deserialize(bindings.Message message) {
+ var decoder = new bindings.Decoder(message);
+ var result = decode(decoder);
+ if (decoder.excessHandles != null) {
+ decoder.excessHandles.forEach((h) => h.close());
+ }
+ return result;
+ }
+
+ static TimelineTransform decode(bindings.Decoder decoder0) {
+ if (decoder0 == null) {
+ return null;
+ }
+ TimelineTransform result = new TimelineTransform();
+
+ var mainDataHeader = decoder0.decodeStructDataHeader();
+ if (mainDataHeader.version <= kVersions.last.version) {
+ // Scan in reverse order to optimize for more recent versions.
+ for (int i = kVersions.length - 1; i >= 0; --i) {
+ if (mainDataHeader.version >= kVersions[i].version) {
+ if (mainDataHeader.size == kVersions[i].size) {
+ // Found a match.
+ break;
+ }
+ throw new bindings.MojoCodecError(
+ 'Header size doesn\'t correspond to known version size.');
+ }
+ }
+ } else if (mainDataHeader.size < kVersions.last.size) {
+ throw new bindings.MojoCodecError(
+ 'Message newer than the last known version cannot be shorter than '
+ 'required by the last known version.');
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.referenceTime = decoder0.decodeInt64(8);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.subjectTime = decoder0.decodeInt64(16);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.referenceDelta = decoder0.decodeUint32(24);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.subjectDelta = decoder0.decodeUint32(28);
+ }
+ return result;
+ }
+
+ void encode(bindings.Encoder encoder) {
+ var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+ try {
+ encoder0.encodeInt64(referenceTime, 8);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "referenceTime of struct TimelineTransform: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeInt64(subjectTime, 16);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "subjectTime of struct TimelineTransform: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeUint32(referenceDelta, 24);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "referenceDelta of struct TimelineTransform: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeUint32(subjectDelta, 28);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "subjectDelta of struct TimelineTransform: $e";
+ rethrow;
+ }
+ }
+
+ String toString() {
+ return "TimelineTransform("
+ "referenceTime: $referenceTime" ", "
+ "subjectTime: $subjectTime" ", "
+ "referenceDelta: $referenceDelta" ", "
+ "subjectDelta: $subjectDelta" ")";
+ }
+
+ Map toJson() {
+ Map map = new Map();
+ map["referenceTime"] = referenceTime;
+ map["subjectTime"] = subjectTime;
+ map["referenceDelta"] = referenceDelta;
+ map["subjectDelta"] = subjectDelta;
+ return map;
+ }
+}
+
+
+class _TimelineConsumerSetTimelineTransformParams extends bindings.Struct {
+ static const List<bindings.StructDataHeader> kVersions = const [
+ const bindings.StructDataHeader(40, 0)
+ ];
+ int subjectTime = 0;
+ int referenceDelta = 0;
+ int subjectDelta = 0;
+ int effectiveReferenceTime = 0;
+ int effectiveSubjectTime = 0;
+
+ _TimelineConsumerSetTimelineTransformParams() : super(kVersions.last.size);
+
+ static _TimelineConsumerSetTimelineTransformParams deserialize(bindings.Message message) {
+ var decoder = new bindings.Decoder(message);
+ var result = decode(decoder);
+ if (decoder.excessHandles != null) {
+ decoder.excessHandles.forEach((h) => h.close());
+ }
+ return result;
+ }
+
+ static _TimelineConsumerSetTimelineTransformParams decode(bindings.Decoder decoder0) {
+ if (decoder0 == null) {
+ return null;
+ }
+ _TimelineConsumerSetTimelineTransformParams result = new _TimelineConsumerSetTimelineTransformParams();
+
+ var mainDataHeader = decoder0.decodeStructDataHeader();
+ if (mainDataHeader.version <= kVersions.last.version) {
+ // Scan in reverse order to optimize for more recent versions.
+ for (int i = kVersions.length - 1; i >= 0; --i) {
+ if (mainDataHeader.version >= kVersions[i].version) {
+ if (mainDataHeader.size == kVersions[i].size) {
+ // Found a match.
+ break;
+ }
+ throw new bindings.MojoCodecError(
+ 'Header size doesn\'t correspond to known version size.');
+ }
+ }
+ } else if (mainDataHeader.size < kVersions.last.size) {
+ throw new bindings.MojoCodecError(
+ 'Message newer than the last known version cannot be shorter than '
+ 'required by the last known version.');
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.subjectTime = decoder0.decodeInt64(8);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.referenceDelta = decoder0.decodeUint32(16);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.subjectDelta = decoder0.decodeUint32(20);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.effectiveReferenceTime = decoder0.decodeInt64(24);
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.effectiveSubjectTime = decoder0.decodeInt64(32);
+ }
+ return result;
+ }
+
+ void encode(bindings.Encoder encoder) {
+ var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+ try {
+ encoder0.encodeInt64(subjectTime, 8);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "subjectTime of struct _TimelineConsumerSetTimelineTransformParams: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeUint32(referenceDelta, 16);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "referenceDelta of struct _TimelineConsumerSetTimelineTransformParams: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeUint32(subjectDelta, 20);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "subjectDelta of struct _TimelineConsumerSetTimelineTransformParams: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeInt64(effectiveReferenceTime, 24);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "effectiveReferenceTime of struct _TimelineConsumerSetTimelineTransformParams: $e";
+ rethrow;
+ }
+ try {
+ encoder0.encodeInt64(effectiveSubjectTime, 32);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "effectiveSubjectTime of struct _TimelineConsumerSetTimelineTransformParams: $e";
+ rethrow;
+ }
+ }
+
+ String toString() {
+ return "_TimelineConsumerSetTimelineTransformParams("
+ "subjectTime: $subjectTime" ", "
+ "referenceDelta: $referenceDelta" ", "
+ "subjectDelta: $subjectDelta" ", "
+ "effectiveReferenceTime: $effectiveReferenceTime" ", "
+ "effectiveSubjectTime: $effectiveSubjectTime" ")";
+ }
+
+ Map toJson() {
+ Map map = new Map();
+ map["subjectTime"] = subjectTime;
+ map["referenceDelta"] = referenceDelta;
+ map["subjectDelta"] = subjectDelta;
+ map["effectiveReferenceTime"] = effectiveReferenceTime;
+ map["effectiveSubjectTime"] = effectiveSubjectTime;
+ return map;
+ }
+}
+
+
+class TimelineConsumerSetTimelineTransformResponseParams extends bindings.Struct {
+ static const List<bindings.StructDataHeader> kVersions = const [
+ const bindings.StructDataHeader(16, 0)
+ ];
+ bool completed = false;
+
+ TimelineConsumerSetTimelineTransformResponseParams() : super(kVersions.last.size);
+
+ static TimelineConsumerSetTimelineTransformResponseParams deserialize(bindings.Message message) {
+ var decoder = new bindings.Decoder(message);
+ var result = decode(decoder);
+ if (decoder.excessHandles != null) {
+ decoder.excessHandles.forEach((h) => h.close());
+ }
+ return result;
+ }
+
+ static TimelineConsumerSetTimelineTransformResponseParams decode(bindings.Decoder decoder0) {
+ if (decoder0 == null) {
+ return null;
+ }
+ TimelineConsumerSetTimelineTransformResponseParams result = new TimelineConsumerSetTimelineTransformResponseParams();
+
+ var mainDataHeader = decoder0.decodeStructDataHeader();
+ if (mainDataHeader.version <= kVersions.last.version) {
+ // Scan in reverse order to optimize for more recent versions.
+ for (int i = kVersions.length - 1; i >= 0; --i) {
+ if (mainDataHeader.version >= kVersions[i].version) {
+ if (mainDataHeader.size == kVersions[i].size) {
+ // Found a match.
+ break;
+ }
+ throw new bindings.MojoCodecError(
+ 'Header size doesn\'t correspond to known version size.');
+ }
+ }
+ } else if (mainDataHeader.size < kVersions.last.size) {
+ throw new bindings.MojoCodecError(
+ 'Message newer than the last known version cannot be shorter than '
+ 'required by the last known version.');
+ }
+ if (mainDataHeader.version >= 0) {
+
+ result.completed = decoder0.decodeBool(8, 0);
+ }
+ return result;
+ }
+
+ void encode(bindings.Encoder encoder) {
+ var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+ try {
+ encoder0.encodeBool(completed, 8, 0);
+ } on bindings.MojoCodecError catch(e) {
+ e.message = "Error encountered while encoding field "
+ "completed of struct TimelineConsumerSetTimelineTransformResponseParams: $e";
+ rethrow;
+ }
+ }
+
+ String toString() {
+ return "TimelineConsumerSetTimelineTransformResponseParams("
+ "completed: $completed" ")";
+ }
+
+ Map toJson() {
+ Map map = new Map();
+ map["completed"] = completed;
+ return map;
+ }
+}
+
+const int _timelineConsumerMethodSetTimelineTransformName = 0;
+
+class _TimelineConsumerServiceDescription implements service_describer.ServiceDescription {
+ dynamic getTopLevelInterface([Function responseFactory]) =>
+ responseFactory(null);
+
+ dynamic getTypeDefinition(String typeKey, [Function responseFactory]) =>
+ responseFactory(null);
+
+ dynamic getAllTypeDefinitions([Function responseFactory]) =>
+ responseFactory(null);
+}
+
+abstract class TimelineConsumer {
+ static const String serviceName = null;
+ dynamic setTimelineTransform(int subjectTime,int referenceDelta,int subjectDelta,int effectiveReferenceTime,int effectiveSubjectTime,[Function responseFactory = null]);
+ static const int kUnspecifiedTime = 9223372036854775807;
+}
+
+
+class _TimelineConsumerProxyImpl extends bindings.Proxy {
+ _TimelineConsumerProxyImpl.fromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+ _TimelineConsumerProxyImpl.fromHandle(core.MojoHandle handle) :
+ super.fromHandle(handle);
+
+ _TimelineConsumerProxyImpl.unbound() : super.unbound();
+
+ static _TimelineConsumerProxyImpl newFromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint) {
+ assert(endpoint.setDescription("For _TimelineConsumerProxyImpl"));
+ return new _TimelineConsumerProxyImpl.fromEndpoint(endpoint);
+ }
+
+ service_describer.ServiceDescription get serviceDescription =>
+ new _TimelineConsumerServiceDescription();
+
+ void handleResponse(bindings.ServiceMessage message) {
+ switch (message.header.type) {
+ case _timelineConsumerMethodSetTimelineTransformName:
+ var r = TimelineConsumerSetTimelineTransformResponseParams.deserialize(
+ message.payload);
+ if (!message.header.hasRequestId) {
+ proxyError("Expected a message with a valid request Id.");
+ return;
+ }
+ Completer c = completerMap[message.header.requestId];
+ if (c == null) {
+ proxyError(
+ "Message had unknown request Id: ${message.header.requestId}");
+ return;
+ }
+ completerMap.remove(message.header.requestId);
+ if (c.isCompleted) {
+ proxyError("Response completer already completed");
+ return;
+ }
+ c.complete(r);
+ break;
+ default:
+ proxyError("Unexpected message type: ${message.header.type}");
+ close(immediate: true);
+ break;
+ }
+ }
+
+ String toString() {
+ var superString = super.toString();
+ return "_TimelineConsumerProxyImpl($superString)";
+ }
+}
+
+
+class _TimelineConsumerProxyCalls implements TimelineConsumer {
+ _TimelineConsumerProxyImpl _proxyImpl;
+
+ _TimelineConsumerProxyCalls(this._proxyImpl);
+ dynamic setTimelineTransform(int subjectTime,int referenceDelta,int subjectDelta,int effectiveReferenceTime,int effectiveSubjectTime,[Function responseFactory = null]) {
+ var params = new _TimelineConsumerSetTimelineTransformParams();
+ params.subjectTime = subjectTime;
+ params.referenceDelta = referenceDelta;
+ params.subjectDelta = subjectDelta;
+ params.effectiveReferenceTime = effectiveReferenceTime;
+ params.effectiveSubjectTime = effectiveSubjectTime;
+ return _proxyImpl.sendMessageWithRequestId(
+ params,
+ _timelineConsumerMethodSetTimelineTransformName,
+ -1,
+ bindings.MessageHeader.kMessageExpectsResponse);
+ }
+}
+
+
+class TimelineConsumerProxy implements bindings.ProxyBase {
+ final bindings.Proxy impl;
+ TimelineConsumer ptr;
+
+ TimelineConsumerProxy(_TimelineConsumerProxyImpl proxyImpl) :
+ impl = proxyImpl,
+ ptr = new _TimelineConsumerProxyCalls(proxyImpl);
+
+ TimelineConsumerProxy.fromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint) :
+ impl = new _TimelineConsumerProxyImpl.fromEndpoint(endpoint) {
+ ptr = new _TimelineConsumerProxyCalls(impl);
+ }
+
+ TimelineConsumerProxy.fromHandle(core.MojoHandle handle) :
+ impl = new _TimelineConsumerProxyImpl.fromHandle(handle) {
+ ptr = new _TimelineConsumerProxyCalls(impl);
+ }
+
+ TimelineConsumerProxy.unbound() :
+ impl = new _TimelineConsumerProxyImpl.unbound() {
+ ptr = new _TimelineConsumerProxyCalls(impl);
+ }
+
+ factory TimelineConsumerProxy.connectToService(
+ bindings.ServiceConnector s, String url, [String serviceName]) {
+ TimelineConsumerProxy p = new TimelineConsumerProxy.unbound();
+ s.connectToService(url, p, serviceName);
+ return p;
+ }
+
+ static TimelineConsumerProxy newFromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint) {
+ assert(endpoint.setDescription("For TimelineConsumerProxy"));
+ return new TimelineConsumerProxy.fromEndpoint(endpoint);
+ }
+
+ String get serviceName => TimelineConsumer.serviceName;
+
+ Future close({bool immediate: false}) => impl.close(immediate: immediate);
+
+ Future responseOrError(Future f) => impl.responseOrError(f);
+
+ Future get errorFuture => impl.errorFuture;
+
+ int get version => impl.version;
+
+ Future<int> queryVersion() => impl.queryVersion();
+
+ void requireVersion(int requiredVersion) {
+ impl.requireVersion(requiredVersion);
+ }
+
+ String toString() {
+ return "TimelineConsumerProxy($impl)";
+ }
+}
+
+
+class TimelineConsumerStub extends bindings.Stub {
+ TimelineConsumer _impl = null;
+
+ TimelineConsumerStub.fromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint, [this._impl])
+ : super.fromEndpoint(endpoint);
+
+ TimelineConsumerStub.fromHandle(core.MojoHandle handle, [this._impl])
+ : super.fromHandle(handle);
+
+ TimelineConsumerStub.unbound() : super.unbound();
+
+ static TimelineConsumerStub newFromEndpoint(
+ core.MojoMessagePipeEndpoint endpoint) {
+ assert(endpoint.setDescription("For TimelineConsumerStub"));
+ return new TimelineConsumerStub.fromEndpoint(endpoint);
+ }
+
+
+ TimelineConsumerSetTimelineTransformResponseParams _timelineConsumerSetTimelineTransformResponseParamsFactory(bool completed) {
+ var result = new TimelineConsumerSetTimelineTransformResponseParams();
+ result.completed = completed;
+ return result;
+ }
+
+ dynamic handleMessage(bindings.ServiceMessage message) {
+ if (bindings.ControlMessageHandler.isControlMessage(message)) {
+ return bindings.ControlMessageHandler.handleMessage(this,
+ 0,
+ message);
+ }
+ assert(_impl != null);
+ switch (message.header.type) {
+ case _timelineConsumerMethodSetTimelineTransformName:
+ var params = _TimelineConsumerSetTimelineTransformParams.deserialize(
+ message.payload);
+ var response = _impl.setTimelineTransform(params.subjectTime,params.referenceDelta,params.subjectDelta,params.effectiveReferenceTime,params.effectiveSubjectTime,_timelineConsumerSetTimelineTransformResponseParamsFactory);
+ if (response is Future) {
+ return response.then((response) {
+ if (response != null) {
+ return buildResponseWithId(
+ response,
+ _timelineConsumerMethodSetTimelineTransformName,
+ message.header.requestId,
+ bindings.MessageHeader.kMessageIsResponse);
+ }
+ });
+ } else if (response != null) {
+ return buildResponseWithId(
+ response,
+ _timelineConsumerMethodSetTimelineTransformName,
+ message.header.requestId,
+ bindings.MessageHeader.kMessageIsResponse);
+ }
+ break;
+ default:
+ throw new bindings.MojoCodecError("Unexpected message name");
+ break;
+ }
+ return null;
+ }
+
+ TimelineConsumer get impl => _impl;
+ set impl(TimelineConsumer d) {
+ assert(_impl == null);
+ _impl = d;
+ }
+
+ String toString() {
+ var superString = super.toString();
+ return "TimelineConsumerStub($superString)";
+ }
+
+ int get version => 0;
+
+ static service_describer.ServiceDescription _cachedServiceDescription;
+ static service_describer.ServiceDescription get serviceDescription {
+ if (_cachedServiceDescription == null) {
+ _cachedServiceDescription = new _TimelineConsumerServiceDescription();
+ }
+ return _cachedServiceDescription;
+ }
+}
+
+
+
diff --git a/mojo/services/media/common/cpp/BUILD.gn b/mojo/services/media/common/cpp/BUILD.gn
index e46af00..c2f6b70 100644
--- a/mojo/services/media/common/cpp/BUILD.gn
+++ b/mojo/services/media/common/cpp/BUILD.gn
@@ -12,17 +12,17 @@
"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",
+ "timeline_function.cc",
+ "timeline_function.h",
+ "timeline_rate.cc",
+ "timeline_rate.h",
]
if (is_posix) {
diff --git a/mojo/services/media/common/cpp/linear_function.cc b/mojo/services/media/common/cpp/linear_function.cc
deleted file mode 100644
index ec662e7..0000000
--- a/mojo/services/media/common/cpp/linear_function.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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
deleted file mode 100644
index be66bb3..0000000
--- a/mojo/services/media/common/cpp/linear_function.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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
deleted file mode 100644
index 56a3f51..0000000
--- a/mojo/services/media/common/cpp/ratio.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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
deleted file mode 100644
index 0755c6e..0000000
--- a/mojo/services/media/common/cpp/ratio.h
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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/mojo/services/media/common/cpp/timeline_function.cc b/mojo/services/media/common/cpp/timeline_function.cc
new file mode 100644
index 0000000..350fde6
--- /dev/null
+++ b/mojo/services/media/common/cpp/timeline_function.cc
@@ -0,0 +1,32 @@
+// 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/timeline_function.h"
+
+namespace mojo {
+namespace media {
+
+// static
+int64_t TimelineFunction::Apply(
+ int64_t reference_time,
+ int64_t subject_time,
+ const TimelineRate& rate, // subject_delta / reference_delta
+ int64_t reference_input) {
+ return rate.Scale(reference_input - reference_time) + subject_time;
+}
+
+// static
+TimelineFunction TimelineFunction::Compose(const TimelineFunction& bc,
+ const TimelineFunction& ab,
+ bool exact) {
+ return TimelineFunction(ab.reference_time(), bc.Apply(ab.subject_time()),
+ TimelineRate::Product(ab.rate(), bc.rate(), exact));
+}
+
+} // namespace media
+} // namespace mojo
diff --git a/mojo/services/media/common/cpp/timeline_function.h b/mojo/services/media/common/cpp/timeline_function.h
new file mode 100644
index 0000000..67ac80a
--- /dev/null
+++ b/mojo/services/media/common/cpp/timeline_function.h
@@ -0,0 +1,133 @@
+// 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_TIMELINE_FUNCTION_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_TIMELINE_FUNCTION_H_
+
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/services/media/common/cpp/timeline_rate.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 that
+// translates reference timeline values into subject timeline values (the
+// 'subject' being the timeline that's represented by the function). The
+// representation is in point-slope form. The point is represented as two
+// int64_t time values (reference_time, subject_time), and the slope (rate) is
+// represented as a TimelineRate, the ratio of two uint32_t values
+// (subject_delta / reference_delta).
+class TimelineFunction {
+ public:
+ // Applies a timeline function.
+ static int64_t Apply(
+ int64_t reference_time,
+ int64_t subject_time,
+ const TimelineRate& rate, // subject_delta / reference_delta
+ int64_t reference_input);
+
+ // Applies the inverse of a timeline function.
+ static int64_t ApplyInverse(
+ int64_t reference_time,
+ int64_t subject_time,
+ const TimelineRate& rate, // subject_delta / reference_delta
+ int64_t subject_input) {
+ MOJO_DCHECK(rate.reference_delta() != 0u);
+ return Apply(subject_time, reference_time, rate.Inverse(), subject_input);
+ }
+
+ // Composes two timeline functions B->C and A->B producing A->C. If exact is
+ // true, DCHECKs on loss of precision.
+ static TimelineFunction Compose(const TimelineFunction& bc,
+ const TimelineFunction& ab,
+ bool exact = true);
+
+ TimelineFunction() : reference_time_(0), subject_time_(0) {}
+
+ TimelineFunction(int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta)
+ : reference_time_(reference_time),
+ subject_time_(subject_time),
+ rate_(subject_delta, reference_delta) {}
+
+ TimelineFunction(int64_t reference_time,
+ int64_t subject_time,
+ const TimelineRate& rate) // subject_delta / reference_delta
+ : reference_time_(reference_time),
+ subject_time_(subject_time),
+ rate_(rate) {}
+
+ explicit TimelineFunction(
+ const TimelineRate& rate) // subject_delta / reference_delta
+ : reference_time_(0),
+ subject_time_(0),
+ rate_(rate) {}
+
+ // Applies the function. Returns TimelineRate::kOverflow on overflow.
+ int64_t Apply(int64_t reference_input) const {
+ return Apply(reference_time_, subject_time_, rate_, reference_input);
+ }
+
+ // Applies the inverse of the function. Returns TimelineRate::kOverflow on
+ // overflow.
+ int64_t ApplyInverse(int64_t subject_input) const {
+ MOJO_DCHECK(rate_.reference_delta() != 0u);
+ return ApplyInverse(reference_time_, subject_time_, rate_, subject_input);
+ }
+
+ // Applies the function. Returns TimelineRate::kOverflow on overflow.
+ int64_t operator()(int64_t reference_input) const {
+ return Apply(reference_input);
+ }
+
+ // Returns a timeline function that is the inverse if this timeline function.
+ TimelineFunction Inverse() const {
+ MOJO_DCHECK(rate_.reference_delta() != 0u);
+ return TimelineFunction(subject_time_, reference_time_, rate_.Inverse());
+ }
+
+ int64_t reference_time() const { return reference_time_; }
+
+ int64_t subject_time() const { return subject_time_; }
+
+ const TimelineRate& rate() const { return rate_; }
+
+ uint32_t reference_delta() const { return rate_.reference_delta(); }
+
+ uint32_t subject_delta() const { return rate_.subject_delta(); }
+
+ private:
+ int64_t reference_time_;
+ int64_t subject_time_;
+ TimelineRate rate_; // subject_delta / reference_delta
+};
+
+// Tests two timeline functions for equality. Equality requires equal basis
+// values.
+inline bool operator==(const TimelineFunction& a, const TimelineFunction& b) {
+ return a.reference_time() == b.reference_time() &&
+ a.subject_time() == b.subject_time() && a.rate() == b.rate();
+}
+
+// Tests two timeline functions for inequality. Equality requires equal basis
+// values.
+inline bool operator!=(const TimelineFunction& a, const TimelineFunction& b) {
+ return !(a == b);
+}
+
+// Composes two timeline functions B->C and A->B producing A->C. DCHECKs on
+// loss of precision.
+inline TimelineFunction operator*(const TimelineFunction& bc,
+ const TimelineFunction& ab) {
+ return TimelineFunction::Compose(bc, ab);
+}
+
+} // namespace media
+} // namespace mojo
+
+#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_TIMELINE_FUNCTION_H_
diff --git a/mojo/services/media/common/cpp/timeline_rate.cc b/mojo/services/media/common/cpp/timeline_rate.cc
new file mode 100644
index 0000000..a450e10
--- /dev/null
+++ b/mojo/services/media/common/cpp/timeline_rate.cc
@@ -0,0 +1,233 @@
+// 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/timeline_rate.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 ratio 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 subject_delta,
+ uint32_t reference_delta,
+ bool round_up,
+ bool* overflow) {
+ MOJO_DCHECK(reference_delta != 0u);
+ MOJO_DCHECK(overflow != nullptr);
+
+ constexpr uint64_t kLow32Bits = 0xffffffffu;
+ constexpr uint64_t kHigh32Bits = kLow32Bits << 32u;
+
+ // high and low are the product of the subject_delta and the high and low
+ // halves
+ // (respectively) of value.
+ uint64_t high = subject_delta * (value >> 32u);
+ uint64_t low = subject_delta * (value & kLow32Bits);
+ // Ignoring overflow and remainder, the result we want is:
+ // ((high << 32) + low) / reference_delta.
+
+ // 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) / reference_delta.
+
+ // When we divide high by reference_delta, there'll be a remainder. Make
+ // that the high end of low, which is currently all zeroes.
+ low |= (high % reference_delta) << 32u;
+
+ // Determine if we need to round up when we're done:
+ round_up = round_up && (low % reference_delta) != 0;
+
+ // Do the division.
+ high /= reference_delta;
+ low /= reference_delta;
+
+ // 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 TimelineRate::Reduce(uint32_t* subject_delta, uint32_t* reference_delta) {
+ ReduceRatio(subject_delta, reference_delta);
+}
+
+// static
+void TimelineRate::Product(uint32_t a_subject_delta,
+ uint32_t a_reference_delta,
+ uint32_t b_subject_delta,
+ uint32_t b_reference_delta,
+ uint32_t* product_subject_delta,
+ uint32_t* product_reference_delta,
+ bool exact) {
+ MOJO_DCHECK(a_reference_delta != 0);
+ MOJO_DCHECK(b_reference_delta != 0);
+ MOJO_DCHECK(product_subject_delta != nullptr);
+ MOJO_DCHECK(product_reference_delta != nullptr);
+
+ uint64_t subject_delta =
+ static_cast<uint64_t>(a_subject_delta) * b_subject_delta;
+ uint64_t reference_delta =
+ static_cast<uint64_t>(a_reference_delta) * b_reference_delta;
+
+ ReduceRatio(&subject_delta, &reference_delta);
+
+ if (subject_delta > std::numeric_limits<uint32_t>::max() ||
+ reference_delta > std::numeric_limits<uint32_t>::max()) {
+ MOJO_DCHECK(!exact);
+
+ do {
+ subject_delta >>= 1;
+ reference_delta >>= 1;
+ } while (subject_delta > std::numeric_limits<uint32_t>::max() ||
+ reference_delta > std::numeric_limits<uint32_t>::max());
+
+ if (reference_delta == 0) {
+ // Product is larger than we can represent. Return the largest value we
+ // can represent.
+ *product_subject_delta = std::numeric_limits<uint32_t>::max();
+ *product_reference_delta = 1;
+ return;
+ }
+ }
+
+ *product_subject_delta = static_cast<uint32_t>(subject_delta);
+ *product_reference_delta = static_cast<uint32_t>(reference_delta);
+}
+
+// static
+int64_t TimelineRate::Scale(int64_t value,
+ uint32_t subject_delta,
+ uint32_t reference_delta) {
+ static constexpr uint64_t abs_of_min_int64 =
+ static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
+
+ MOJO_DCHECK(reference_delta != 0u);
+
+ bool overflow;
+
+ uint64_t abs_result;
+
+ if (value >= 0) {
+ abs_result = ScaleUInt64(static_cast<uint64_t>(value), subject_delta,
+ reference_delta, false, &overflow);
+ } else if (value == std::numeric_limits<int64_t>::min()) {
+ abs_result = ScaleUInt64(abs_of_min_int64, subject_delta, reference_delta,
+ true, &overflow);
+ } else {
+ abs_result = ScaleUInt64(static_cast<uint64_t>(-value), subject_delta,
+ reference_delta, true, &overflow);
+ }
+
+ if (overflow) {
+ return TimelineRate::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 TimelineRate::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/timeline_rate.h b/mojo/services/media/common/cpp/timeline_rate.h
new file mode 100644
index 0000000..7aa0216
--- /dev/null
+++ b/mojo/services/media/common/cpp/timeline_rate.h
@@ -0,0 +1,128 @@
+// 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_TIMELINE_RATE_H_
+#define MOJO_SERVICES_MEDIA_COMMON_CPP_TIMELINE_RATE_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 the relative rate of a timeline as the ratio between two uint32_t
+// values subject_delta / reference_delta. "subject" refers to the timeline
+// whose rate is being represented, and "reference" refers to the timeline
+// relative to which the rate is expressed.
+class TimelineRate {
+ public:
+ // Used to indicate overflow of scaling operations.
+ static constexpr int64_t kOverflow = std::numeric_limits<int64_t>::max();
+
+ // Reduces the ratio of *subject_delta and *reference_delta.
+ static void Reduce(uint32_t* subject_delta, uint32_t* reference_delta);
+
+ // Produces the product of the rates. If exact is true, DCHECKs on loss of
+ // precision.
+ static void Product(uint32_t a_subject_delta,
+ uint32_t a_reference_delta,
+ uint32_t b_subject_delta,
+ uint32_t b_reference_delta,
+ uint32_t* product_subject_delta,
+ uint32_t* product_reference_delta,
+ bool exact = true);
+
+ // Produces the product of the rates and the int64_t as an int64_t. Returns
+ // kOverflow on overflow.
+ static int64_t Scale(int64_t value,
+ uint32_t subject_delta,
+ uint32_t reference_delta);
+
+ // Returns the product of the rates. If exact is true, DCHECKs on loss of
+ // precision.
+ static TimelineRate Product(const TimelineRate& a,
+ const TimelineRate& b,
+ bool exact = true) {
+ uint32_t result_subject_delta;
+ uint32_t result_reference_delta;
+ Product(a.subject_delta(), a.reference_delta(), b.subject_delta(),
+ b.reference_delta(), &result_subject_delta, &result_reference_delta,
+ exact);
+ return TimelineRate(result_subject_delta, result_reference_delta);
+ }
+
+ TimelineRate() : subject_delta_(0), reference_delta_(1) {}
+
+ explicit TimelineRate(uint32_t subject_delta)
+ : subject_delta_(subject_delta), reference_delta_(1) {}
+
+ TimelineRate(uint32_t subject_delta, uint32_t reference_delta)
+ : subject_delta_(subject_delta), reference_delta_(reference_delta) {
+ MOJO_DCHECK(reference_delta != 0);
+ Reduce(&subject_delta_, &reference_delta_);
+ }
+
+ // Returns the inverse of the rate. DCHECKs if the subject_delta of this
+ // rate is zero.
+ TimelineRate Inverse() const {
+ MOJO_DCHECK(subject_delta_ != 0);
+ return TimelineRate(reference_delta_, subject_delta_);
+ }
+
+ // Scales the value by this rate. Returns kOverflow on overflow.
+ int64_t Scale(int64_t value) const {
+ return Scale(value, subject_delta_, reference_delta_);
+ }
+
+ uint32_t subject_delta() const { return subject_delta_; }
+ uint32_t reference_delta() const { return reference_delta_; }
+
+ private:
+ uint32_t subject_delta_;
+ uint32_t reference_delta_;
+};
+
+// Tests two rates for equality.
+inline bool operator==(const TimelineRate& a, const TimelineRate& b) {
+ return a.subject_delta() == b.subject_delta() &&
+ a.reference_delta() == b.reference_delta();
+}
+
+// Tests two rates for inequality.
+inline bool operator!=(const TimelineRate& a, const TimelineRate& b) {
+ return !(a == b);
+}
+
+// Returns the product of the two rates. DCHECKs on loss of precision.
+inline TimelineRate operator*(const TimelineRate& a, const TimelineRate& b) {
+ return TimelineRate::Product(a, b);
+}
+
+// Returns the product of the rate and the int64_t. Returns kOverflow on
+// overflow.
+inline int64_t operator*(const TimelineRate& a, int64_t b) {
+ return a.Scale(b);
+}
+
+// Returns the product of the rate and the int64_t. Returns kOverflow on
+// overflow.
+inline int64_t operator*(int64_t a, const TimelineRate& b) {
+ return b.Scale(a);
+}
+
+// Returns the the int64_t divided by the rate. Returns kOverflow on
+// overflow.
+inline int64_t operator/(int64_t a, const TimelineRate& b) {
+ return b.Inverse().Scale(a);
+}
+
+} // namespace media
+} // namespace mojo
+
+#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_TIMELINE_RATE_H_
diff --git a/mojo/services/media/common/interfaces/timelines.mojom b/mojo/services/media/common/interfaces/timelines.mojom
new file mode 100644
index 0000000..f79697d
--- /dev/null
+++ b/mojo/services/media/common/interfaces/timelines.mojom
@@ -0,0 +1,57 @@
+// 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.
+
+[DartPackage="mojo_services"]
+module mojo;
+
+// TODO(dalesat): Move out of media to somewhere more generic.
+
+// Represents the relationship between and subject timeline and a reference
+// timeline.
+//
+// To translate a reference timeline value r to the subject timeline, apply
+// the following formula:
+//
+// (r - reference_time) * subject_delta / reference_delta + subject_time
+//
+// To translate a subject timeline value s to the reference timeline, apply
+// this formula provided subject_delta isn't zero:
+//
+// (s - subject_time) * reference_delta / subject_delta + reference_time
+//
+struct TimelineTransform {
+ // A value from the reference timeline that correlates to timeline_time.
+ int64 reference_time = 0;
+
+ // A value from the subject timeline that correlates to reference_time.
+ int64 subject_time = 0;
+
+ // The change in the reference timeline corresponding to timeline_delta.
+ // Cannnot be zero.
+ uint32 reference_delta = 1;
+
+ // The change in the subject timeline corresponding to reference_delta.
+ uint32 subject_delta = 0;
+};
+
+// A push-mode consumer of timeline updates.
+interface TimelineConsumer {
+ const int64 kUnspecifiedTime = 0x7fffffffffffffff;
+
+ // Sets the timeline transform at the indicated effective time. Exactly one
+ // of the effective_*_time values must be kUnspecifiedTime.
+ // effective_subject_time can only be specified if the current subject_delta
+ // isn’t zero. reference_delta may not be zero. subject_time may be
+ // kUnspecifiedTime to indicate that the new transform subject_time should
+ // be inferred from the effective time. The new transform reference_time is
+ // always inferred from the effective time. The callback is called at the
+ // effective time or when a pending operation is cancelled due to a
+ // subsequent call, in which case the 'completed' value is false.
+ SetTimelineTransform(
+ int64 subject_time,
+ uint32 reference_delta,
+ uint32 subject_delta,
+ int64 effective_reference_time,
+ int64 effective_subject_time) => (bool completed);
+};
diff --git a/services/media/common/BUILD.gn b/services/media/common/BUILD.gn
index dc8e8b6..bc1e1b2 100644
--- a/services/media/common/BUILD.gn
+++ b/services/media/common/BUILD.gn
@@ -26,9 +26,9 @@
testonly = true
sources = [
- "test/linear_function_test.cc",
- "test/ratio_test.cc",
"test/test_base.h",
+ "test/timeline_function_test.cc",
+ "test/timeline_rate_test.cc",
]
deps = [
diff --git a/services/media/common/test/linear_function_test.cc b/services/media/common/test/linear_function_test.cc
deleted file mode 100644
index b2ab53d..0000000
--- a/services/media/common/test/linear_function_test.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// 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
deleted file mode 100644
index 8a0ce3e..0000000
--- a/services/media/common/test/ratio_test.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// 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/timeline_function_test.cc b/services/media/common/test/timeline_function_test.cc
new file mode 100644
index 0000000..8d3adb0
--- /dev/null
+++ b/services/media/common/test/timeline_function_test.cc
@@ -0,0 +1,227 @@
+// 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/timeline_function.h"
+#include "services/media/common/test/test_base.h"
+
+namespace mojo {
+namespace media {
+namespace {
+
+class TimelineFunctionTest : public TestBase {
+ public:
+ // Verifies that a TimelineFunction instantiated in three different ways with
+ // the given arguments has the expected properties.
+ void VerifyBasics(int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta) {
+ TimelineFunction under_test_1(reference_time, subject_time, reference_delta,
+ subject_delta);
+ VerifyBasics(under_test_1, reference_time, subject_time, reference_delta,
+ subject_delta);
+
+ TimelineFunction under_test_2(reference_time, subject_time,
+ TimelineRate(subject_delta, reference_delta));
+ VerifyBasics(under_test_2, reference_time, subject_time, reference_delta,
+ subject_delta);
+
+ TimelineFunction under_test_3(TimelineRate(subject_delta, reference_delta));
+ VerifyBasics(under_test_3, 0, 0, reference_delta, subject_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 (reference_time == 0 && subject_time == 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 TimelineFunction instantiated with the given
+ // arguments has the expected properties.
+ void VerifyBasics(const TimelineFunction& under_test,
+ int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta) {
+ TimelineRate::Reduce(&subject_delta, &reference_delta);
+ EXPECT_EQ(reference_time, under_test.reference_time());
+ EXPECT_EQ(subject_time, under_test.subject_time());
+ EXPECT_EQ(reference_delta, under_test.reference_delta());
+ EXPECT_EQ(subject_delta, under_test.subject_delta());
+ EXPECT_EQ(reference_delta, under_test.rate().reference_delta());
+ EXPECT_EQ(subject_delta, under_test.rate().subject_delta());
+ }
+
+ // Verifies that the inverse of a TimelineFunction instantiated in three
+ // different ways with the given arguments has the expected properties.
+ void VerifyInverse(int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta) {
+ TimelineFunction under_test_1(reference_time, subject_time, reference_delta,
+ subject_delta);
+ VerifyBasics(under_test_1.Inverse(), subject_time, reference_time,
+ subject_delta, reference_delta);
+
+ TimelineFunction under_test_2(reference_time, subject_time,
+ TimelineRate(subject_delta, reference_delta));
+ VerifyBasics(under_test_2.Inverse(), subject_time, reference_time,
+ subject_delta, reference_delta);
+
+ TimelineFunction under_test_3(TimelineRate(subject_delta, reference_delta));
+ VerifyBasics(under_test_3.Inverse(), 0, 0, subject_delta, reference_delta);
+ }
+
+ // Verifies that TimelineFunction::Apply, in its various forms, works as
+ // expected for the given arguments.
+ void VerifyApply(int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta,
+ int64_t reference_input,
+ int64_t expected_result) {
+ // Verify the static method.
+ EXPECT_EQ(expected_result, TimelineFunction::Apply(
+ reference_time, subject_time,
+ TimelineRate(subject_delta, reference_delta),
+ reference_input));
+
+ // Verify the instance method.
+ TimelineFunction under_test(reference_time, subject_time, reference_delta,
+ subject_delta);
+ EXPECT_EQ(expected_result, under_test.Apply(reference_input));
+
+ // Verify the operator.
+ EXPECT_EQ(expected_result, under_test(reference_input));
+ }
+
+ // Verifies that TimelineFunction::ApplyInverse, in its various forms, works
+ // as
+ // expected for the given arguments.
+ void VerifyApplyInverse(int64_t reference_time,
+ int64_t subject_time,
+ uint32_t reference_delta,
+ uint32_t subject_delta,
+ int64_t subject_input,
+ int64_t expected_result) {
+ // Verify the static method.
+ EXPECT_EQ(expected_result,
+ TimelineFunction::ApplyInverse(
+ reference_time, subject_time,
+ TimelineRate(subject_delta, reference_delta), subject_input));
+
+ // Verify the instance method.
+ TimelineFunction under_test(reference_time, subject_time, reference_delta,
+ subject_delta);
+ EXPECT_EQ(expected_result, under_test.ApplyInverse(subject_input));
+ }
+
+ // Verifies that TimelineFunction::Compose works as expected with the given
+ // inputs.
+ void VerifyCompose(const TimelineFunction& a,
+ const TimelineFunction& b,
+ bool exact,
+ const TimelineFunction& expected_result) {
+ // Verify the static method.
+ EXPECT_EQ(expected_result, TimelineFunction::Compose(a, b, exact));
+ }
+};
+
+// Tests TimelineFunction basics for various instantiation arguments.
+TEST_F(TimelineFunctionTest, 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 TimelineFunction::Inverse.
+TEST_F(TimelineFunctionTest, 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 TimelineFunction::Apply in its variations.
+TEST_F(TimelineFunctionTest, 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 TimelineFunction::Apply in its variations.
+TEST_F(TimelineFunctionTest, 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 TimelineFunction::Compose.
+TEST_F(TimelineFunctionTest, Compose) {
+ VerifyCompose(TimelineFunction(0, 0, 1, 0), TimelineFunction(0, 0, 1, 0),
+ true, TimelineFunction(0, 0, 1, 0));
+ VerifyCompose(TimelineFunction(0, 0, 1, 1), TimelineFunction(0, 0, 1, 1),
+ true, TimelineFunction(0, 0, 1, 1));
+ VerifyCompose(TimelineFunction(1, 0, 1, 1), TimelineFunction(0, 0, 1, 1),
+ true, TimelineFunction(0, -1, 1, 1));
+ VerifyCompose(TimelineFunction(10, 10, 1, 1), TimelineFunction(0, 0, 1, 1),
+ true, TimelineFunction(0, 0, 1, 1));
+ VerifyCompose(TimelineFunction(0, 0, 1, 2), TimelineFunction(0, 0, 1, 2),
+ true, TimelineFunction(0, 0, 1, 4));
+ VerifyCompose(TimelineFunction(0, 0, 2, 1), TimelineFunction(0, 0, 2, 1),
+ true, TimelineFunction(0, 0, 4, 1));
+ VerifyCompose(TimelineFunction(0, 0, 2, 1), TimelineFunction(0, 0, 1, 2),
+ true, TimelineFunction(0, 0, 1, 1));
+}
+
+} // namespace
+} // namespace media
+} // namespace mojo
diff --git a/services/media/common/test/timeline_rate_test.cc b/services/media/common/test/timeline_rate_test.cc
new file mode 100644
index 0000000..d7080a0
--- /dev/null
+++ b/services/media/common/test/timeline_rate_test.cc
@@ -0,0 +1,186 @@
+// 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/timeline_rate.h"
+#include "services/media/common/test/test_base.h"
+
+namespace mojo {
+namespace media {
+namespace {
+
+class TimelineRateTest : 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 TimelineRate::Reduce and the constructor, ensuring that the ratio
+ // subject_delta * common_factor / reference_delta * common_factor is reduced
+ // to subject_delta / reference_delta. subject_delta and reference_delta need
+ // to be relatively prime for this to work.
+ void VerifyReduce(uint32_t subject_delta,
+ uint32_t reference_delta,
+ uint32_t common_factor) {
+ // Make sure subject_delta and reference_delta are relatively prime.
+ EXPECT_EQ(1u, gcd(subject_delta, reference_delta));
+
+ uint32_t test_subject_delta = subject_delta * common_factor;
+ uint32_t test_reference_delta = reference_delta * common_factor;
+
+ // Make sure the constructor reduces.
+ TimelineRate rate(test_subject_delta, test_reference_delta);
+ EXPECT_EQ(subject_delta, rate.subject_delta());
+ EXPECT_EQ(reference_delta, rate.reference_delta());
+
+ // Test the static method.
+ TimelineRate::Reduce(&test_subject_delta, &test_reference_delta);
+ EXPECT_EQ(subject_delta, test_subject_delta);
+ EXPECT_EQ(reference_delta, test_reference_delta);
+ }
+
+ // Verifies the TimelineRate::Scale methods by scaling value by subject_delta
+ // /
+ // reference_delta and verifying the result.
+ void VerifyScale(int64_t value,
+ uint32_t subject_delta,
+ uint32_t reference_delta,
+ int64_t result) {
+ // Test the instance method.
+ EXPECT_EQ(result,
+ TimelineRate(subject_delta, reference_delta).Scale(value));
+
+ // Test the static method.
+ EXPECT_EQ(result,
+ TimelineRate::Scale(value, subject_delta, reference_delta));
+
+ // Test the operators.
+ EXPECT_EQ(result, value * TimelineRate(subject_delta, reference_delta));
+ EXPECT_EQ(result, TimelineRate(subject_delta, reference_delta) * value);
+ if (subject_delta != 0) {
+ EXPECT_EQ(result, value / TimelineRate(reference_delta, subject_delta));
+ }
+ }
+
+ // Verifies the TimelineRate::Product methods by multiplying the given a and b
+ // rates and checking the result against the expected rate.
+ void VerifyProduct(uint32_t a_subject_delta,
+ uint32_t a_reference_delta,
+ uint32_t b_subject_delta,
+ uint32_t b_reference_delta,
+ uint32_t expected_subject_delta,
+ uint32_t expected_reference_delta,
+ bool exact) {
+ // Test the first static method.
+ uint32_t actual_subject_delta;
+ uint32_t actual_reference_delta;
+ TimelineRate::Product(a_subject_delta, a_reference_delta, b_subject_delta,
+ b_reference_delta, &actual_subject_delta,
+ &actual_reference_delta, exact);
+ EXPECT_EQ(expected_subject_delta, actual_subject_delta);
+ EXPECT_EQ(expected_reference_delta, actual_reference_delta);
+
+ // Test the second static method.
+ EXPECT_EQ(TimelineRate(expected_subject_delta, expected_reference_delta),
+ TimelineRate::Product(
+ TimelineRate(a_subject_delta, a_reference_delta),
+ TimelineRate(b_subject_delta, b_reference_delta), exact));
+
+ // Test the operator
+ if (exact) {
+ EXPECT_EQ(TimelineRate(expected_subject_delta, expected_reference_delta),
+ TimelineRate(a_subject_delta, a_reference_delta) *
+ TimelineRate(b_subject_delta, b_reference_delta));
+ }
+ }
+
+ // Verifies the TimelineRaten::Inverse method using the given rate.
+ void VerifyInverse(uint32_t subject_delta, uint32_t reference_delta) {
+ TimelineRate rate(subject_delta, reference_delta);
+ TimelineRate inverse(rate.Inverse());
+ EXPECT_EQ(rate.reference_delta(), inverse.subject_delta());
+ EXPECT_EQ(rate.subject_delta(), inverse.reference_delta());
+ }
+};
+
+// Tests TimelineRate::Reduce and that the TimelineRate constructor reduces.
+TEST_F(TimelineRateTest, 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 TimelineRate::Scale, static, instance and operator versions.
+TEST_F(TimelineRateTest, 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, TimelineRate::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, TimelineRate::kOverflow);
+}
+
+// Tests TimelineRate::Product, static and operator versions.
+TEST_F(TimelineRateTest, 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 TimelineRate::Inverse.
+TEST_F(TimelineRateTest, Inverse) {
+ VerifyInverse(1, 1);
+ VerifyInverse(2, 1);
+ VerifyInverse(1, 2);
+ VerifyInverse(1000000, 1234);
+ VerifyInverse(1234, 1000000);
+}
+
+} // namespace
+} // namespace media
+} // namespace mojo