blob: 053f9d0e49c2df057b8765d1940f371a79ef5a69 [file] [log] [blame]
philipel2cb73412016-03-22 10:03:43 +01001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_
12#define WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_
13
14#include <limits>
15#include <type_traits>
16
kwiberg84f6a3f2017-09-05 08:43:13 -070017#include "webrtc/api/optional.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020018#include "webrtc/rtc_base/mod_ops.h"
philipel7956c0f2017-07-26 07:48:15 -070019#include "webrtc/rtc_base/safe_compare.h"
philipel2cb73412016-03-22 10:03:43 +010020
21namespace webrtc {
22
23// Test if the sequence number |a| is ahead or at sequence number |b|.
24//
25// If |M| is an even number and the two sequence numbers are at max distance
26// from each other, then the sequence number with the highest value is
27// considered to be ahead.
28template <typename T, T M>
philipel7956c0f2017-07-26 07:48:15 -070029inline typename std::enable_if<(M > 0), bool>::type AheadOrAt(T a, T b) {
philipel2cb73412016-03-22 10:03:43 +010030 static_assert(std::is_unsigned<T>::value,
31 "Type must be an unsigned integer.");
32 const T maxDist = M / 2;
33 if (!(M & 1) && MinDiff<T, M>(a, b) == maxDist)
34 return b < a;
35 return ForwardDiff<T, M>(b, a) <= maxDist;
36}
37
philipel7956c0f2017-07-26 07:48:15 -070038template <typename T, T M>
39inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) {
philipel2cb73412016-03-22 10:03:43 +010040 static_assert(std::is_unsigned<T>::value,
41 "Type must be an unsigned integer.");
42 const T maxDist = std::numeric_limits<T>::max() / 2 + T(1);
43 if (a - b == maxDist)
44 return b < a;
45 return ForwardDiff(b, a) < maxDist;
46}
47
philipel7956c0f2017-07-26 07:48:15 -070048template <typename T>
49inline bool AheadOrAt(T a, T b) {
50 return AheadOrAt<T, 0>(a, b);
51}
52
philipel2cb73412016-03-22 10:03:43 +010053// Test if the sequence number |a| is ahead of sequence number |b|.
54//
55// If |M| is an even number and the two sequence numbers are at max distance
56// from each other, then the sequence number with the highest value is
57// considered to be ahead.
philipel7956c0f2017-07-26 07:48:15 -070058template <typename T, T M = 0>
philipel2cb73412016-03-22 10:03:43 +010059inline bool AheadOf(T a, T b) {
60 static_assert(std::is_unsigned<T>::value,
61 "Type must be an unsigned integer.");
62 return a != b && AheadOrAt<T, M>(a, b);
63}
64
philipel7956c0f2017-07-26 07:48:15 -070065// Comparator used to compare sequence numbers in a continuous fashion.
66//
67// WARNING! If used to sort sequence numbers of length M then the interval
68// covered by the sequence numbers may not be larger than floor(M/2).
69template <typename T, T M = 0>
70struct AscendingSeqNumComp {
philipel2cb73412016-03-22 10:03:43 +010071 bool operator()(T a, T b) const { return AheadOf<T, M>(a, b); }
72};
73
philipel2cb73412016-03-22 10:03:43 +010074// Comparator used to compare sequence numbers in a continuous fashion.
75//
76// WARNING! If used to sort sequence numbers of length M then the interval
77// covered by the sequence numbers may not be larger than floor(M/2).
78template <typename T, T M = 0>
philipel7956c0f2017-07-26 07:48:15 -070079struct DescendingSeqNumComp {
80 bool operator()(T a, T b) const { return AheadOf<T, M>(b, a); }
philipel2cb73412016-03-22 10:03:43 +010081};
82
philipel7956c0f2017-07-26 07:48:15 -070083// A sequencer number unwrapper where the start value of the unwrapped sequence
84// can be set. The unwrapped value is not allowed to wrap.
philipel2cb73412016-03-22 10:03:43 +010085template <typename T, T M = 0>
philipel7956c0f2017-07-26 07:48:15 -070086class SeqNumUnwrapper {
brucedawson452ea0d2017-08-09 10:00:11 -070087 // Use '<' instead of rtc::SafeLt to avoid crbug.com/753488
philipel7956c0f2017-07-26 07:48:15 -070088 static_assert(
89 std::is_unsigned<T>::value &&
brucedawson452ea0d2017-08-09 10:00:11 -070090 std::numeric_limits<T>::max() < std::numeric_limits<uint64_t>::max(),
philipel7956c0f2017-07-26 07:48:15 -070091 "Type unwrapped must be an unsigned integer smaller than uint64_t.");
92
93 public:
philipel3b3c9c42017-09-11 09:38:36 -070094 // We want a default value that is close to 2^62 for a two reasons. Firstly,
95 // we can unwrap wrapping numbers in either direction, and secondly, the
96 // unwrapped numbers can be stored in either int64_t or uint64_t. We also want
97 // the default value to be human readable, which makes a power of 10 suitable.
98 static constexpr uint64_t kDefaultStartValue = 1000000000000000000UL;
philipeld4fac692017-09-04 07:03:46 -070099
100 SeqNumUnwrapper() : last_unwrapped_(kDefaultStartValue) {}
philipel7956c0f2017-07-26 07:48:15 -0700101 explicit SeqNumUnwrapper(uint64_t start_at) : last_unwrapped_(start_at) {}
102
103 uint64_t Unwrap(T value) {
104 if (!last_value_)
105 last_value_.emplace(value);
106
107 uint64_t unwrapped = 0;
108 if (AheadOrAt<T, M>(value, *last_value_)) {
109 unwrapped = last_unwrapped_ + ForwardDiff<T, M>(*last_value_, value);
110 RTC_CHECK_GE(unwrapped, last_unwrapped_);
111 } else {
112 unwrapped = last_unwrapped_ - ReverseDiff<T, M>(*last_value_, value);
113 RTC_CHECK_LT(unwrapped, last_unwrapped_);
114 }
115
116 *last_value_ = value;
117 last_unwrapped_ = unwrapped;
118 return last_unwrapped_;
philipel2cb73412016-03-22 10:03:43 +0100119 }
philipel7956c0f2017-07-26 07:48:15 -0700120
121 private:
122 uint64_t last_unwrapped_;
123 rtc::Optional<T> last_value_;
philipel2cb73412016-03-22 10:03:43 +0100124};
125
126} // namespace webrtc
127
128#endif // WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_