1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef CODEC_CAPABILITIES__UTILS_H_
18
19 #define CODEC_CAPABILITIES__UTILS_H_
20
21 #include <algorithm>
22 #include <cerrno>
23 #include <cmath>
24 #include <cstdlib>
25 #include <numeric>
26 #include <optional>
27 #include <regex>
28 #include <string>
29 #include <vector>
30
31 #include <utils/Log.h>
32
33 #include <media/stagefright/foundation/AUtils.h>
34
35 namespace android {
36
37 struct ProfileLevel {
38 uint32_t mProfile;
39 uint32_t mLevel;
40 bool operator <(const ProfileLevel &o) const {
41 return mProfile < o.mProfile || (mProfile == o.mProfile && mLevel < o.mLevel);
42 }
43 };
44
45 struct Feature {
46 std::string mName;
47 int mValue;
48 bool mDefault;
49 bool mInternal;
FeatureFeature50 Feature(std::string name, int value, bool def, bool internal) {
51 mName = name;
52 mValue = value;
53 mDefault = def;
54 mInternal = internal;
55 }
FeatureFeature56 Feature(std::string name, int value, bool def) :
57 Feature(name, value, def, false /* internal */) {}
58 };
59
60 /**
61 * Immutable class for describing the range of two numeric values.
62 *
63 * To make it immutable, all data are private and all functions are const.
64 *
65 * From frameworks/base/core/java/android/util/Range.java
66 */
67 template<typename T>
68 struct Range {
RangeRange69 Range() : lower_(), upper_() {}
70
RangeRange71 Range(T l, T u) : lower_(l), upper_(u) {}
72
emptyRange73 constexpr bool empty() const { return lower_ > upper_; }
74
lowerRange75 T lower() const { return lower_; }
76
upperRange77 T upper() const { return upper_; }
78
79 // Check if a value is in the range.
containsRange80 bool contains(T value) const {
81 return lower_ <= value && upper_ >= value;
82 }
83
containsRange84 bool contains(Range<T> range) const {
85 return (range.lower_ >= lower_) && (range.upper_ <= upper_);
86 }
87
88 // Clamp a value in the range
clampRange89 T clamp(T value) const{
90 if (value < lower_) {
91 return lower_;
92 } else if (value > upper_) {
93 return upper_;
94 } else {
95 return value;
96 }
97 }
98
99 // Return the intersected range
intersectRange100 Range<T> intersect(Range<T> range) const {
101 if (lower_ >= range.lower() && range.upper() >= upper_) {
102 // range includes this
103 return *this;
104 } else if (range.lower() >= lower_ && range.upper() <= upper_) {
105 // this includes range
106 return range;
107 } else {
108 // if ranges are disjoint returns an empty Range(lower > upper)
109 Range<T> result = Range<T>(std::max(lower_, range.lower_),
110 std::min(upper_, range.upper_));
111 if (result.empty()) {
112 ALOGV("Failed to intersect 2 ranges as they are disjoint");
113 }
114 return result;
115 }
116 }
117
118 /**
119 * Returns the intersection of this range and the inclusive range
120 * specified by {@code [lower, upper]}.
121 * <p>
122 * See {@link #intersect(Range)} for more details.</p>
123 *
124 * @param lower a non-{@code null} {@code T} reference
125 * @param upper a non-{@code null} {@code T} reference
126 * @return the intersection of this range and the other range
127 */
intersectRange128 Range<T> intersect(T lower, T upper) {
129 Range<T> range = Range<T>(lower, upper);
130 return this->intersect(range);
131 }
132
133 /**
134 * Returns the smallest range that includes this range and
135 * another range.
136 *
137 * E.g. if a < b < c < d, the
138 * extension of [a, c] and [b, d] ranges is [a, d].
139 * As the endpoints are object references, there is no guarantee
140 * which specific endpoint reference is used from the input ranges:
141 *
142 * E.g. if a == a' < b < c, the
143 * extension of [a, b] and [a', c] ranges could be either
144 * [a, c] or ['a, c], where ['a, c] could be either the exact
145 * input range, or a newly created range with the same endpoints.
146 *
147 * @param range a non-null Range<T> reference
148 * @return the extension of this range and the other range.
149 */
extendRange150 Range<T> extend(Range<T> range) {
151 return Range<T>(std::min(lower_, range.lower_), std::max(upper_, range.upper_));
152 }
153
alignRange154 Range<T> align(T align) {
155 return this->intersect(
156 divUp(lower_, align) * align, (upper_ / align) * align);
157 }
158
factorRange159 Range<T> factor(T factor) {
160 if (factor == 1) {
161 return *this;
162 }
163 return Range(divUp(this->lower(), factor), this->upper() / factor);
164 }
165
166 // parse a string into a range
ParseRange167 static std::optional<Range<T>> Parse(const std::string &str) {
168 if (str.empty()) {
169 ALOGW("could not parse empty integer range");
170 return std::nullopt;
171 }
172 long long lower, upper;
173 std::regex regex("^([0-9]+)-([0-9]+)$");
174 std::smatch match;
175 errno = 0;
176 if (std::regex_match(str, match, regex)) {
177 lower = std::strtoll(match[1].str().c_str(), NULL, 10);
178 upper = std::strtoll(match[2].str().c_str(), NULL, 10);
179 } else {
180 char *end;
181 lower = upper = std::strtoll(str.c_str(), &end, 10);
182 if (*end != '\0') {
183 ALOGW("could not parse integer range: %s", str.c_str());
184 return std::nullopt;
185 }
186 }
187
188 if (errno == ERANGE || lower < std::numeric_limits<T>::min()
189 || std::numeric_limits<T>::max() < upper || upper < lower) {
190 ALOGW("could not parse integer range: %s", str.c_str());
191 return std::nullopt;
192 }
193
194 return std::make_optional<Range<T>>((T)lower, (T)upper);
195 }
196
RangeForRange197 static Range<T> RangeFor(double v) {
198 return Range((T)v, (T)ceil(v));
199 }
200
201 private:
202 T lower_;
203 T upper_;
204 };
205
206 static const Range<int32_t> POSITIVE_INT32 = Range<int32_t>(1, INT32_MAX);
207
208 // found stuff that is not supported by framework (=> this should not happen)
209 constexpr int ERROR_CAPABILITIES_UNRECOGNIZED = (1 << 0);
210 // found profile/level for which we don't have capability estimates
211 constexpr int ERROR_CAPABILITIES_UNSUPPORTED = (1 << 1);
212 // have not found any profile/level for which we don't have capability estimate
213 constexpr int ERROR_CAPABILITIES_NONE_SUPPORTED = (1 << 2);
214
215 /**
216 * Sorts distinct (non-intersecting) range array in ascending order.
217 * From frameworks/base/media/java/android/media/Utils.java
218 */
219 template<typename T>
sortDistinctRanges(std::vector<Range<T>> * ranges)220 void sortDistinctRanges(std::vector<Range<T>> *ranges) {
221 std::sort(ranges->begin(), ranges->end(),
222 [](Range<T> r1, Range<T> r2) {
223 if (r1.upper() < r2.lower()) {
224 return true;
225 } else if (r1.lower() > r2.upper()) {
226 return false;
227 } else {
228 ALOGE("sample rate ranges must be distinct.");
229 return false;
230 }
231 });
232 }
233
234 /**
235 * Returns the intersection of two sets of non-intersecting ranges
236 * From frameworks/base/media/java/android/media/Utils.java
237 * @param one a sorted set of non-intersecting ranges in ascending order
238 * @param another another sorted set of non-intersecting ranges in ascending order
239 * @return the intersection of the two sets, sorted in ascending order
240 */
241 template<typename T>
intersectSortedDistinctRanges(const std::vector<Range<T>> & one,const std::vector<Range<T>> & another)242 std::vector<Range<T>> intersectSortedDistinctRanges(
243 const std::vector<Range<T>> &one, const std::vector<Range<T>> &another) {
244 std::vector<Range<T>> result;
245 int ix = 0;
246 for (Range<T> range : another) {
247 while (ix < one.size() && one[ix].upper() < range.lower()) {
248 ++ix;
249 }
250 while (ix < one.size() && one[ix].upper() < range.upper()) {
251 result.push_back(range.intersect(one[ix]));
252 ++ix;
253 }
254 if (ix == one.size()) {
255 break;
256 }
257 if (one[ix].lower() <= range.upper()) {
258 result.push_back(range.intersect(one[ix]));
259 }
260 }
261 return result;
262 }
263
264 /**
265 * Immutable class for describing width and height dimensions in pixels.
266 */
267 struct VideoSize {
268 /**
269 * Create a new immutable VideoSize instance.
270 *
271 * @param width The width of the size, in pixels
272 * @param height The height of the size, in pixels
273 */
274 VideoSize(int32_t width, int32_t height);
275
276 // default constructor
277 VideoSize();
278
279 /**
280 * Get the width of the size (in pixels).
281 * @return width
282 */
283 int32_t getWidth() const;
284
285 /**
286 * Get the height of the size (in pixels).
287 * @return height
288 */
289 int32_t getHeight() const;
290
291 /**
292 * Check if this size is equal to another size.
293 *
294 * Two sizes are equal if and only if both their widths and heights are
295 * equal.
296 *
297 * A size object is never equal to any other type of object.
298 *
299 * @return true if the objects were equal, false otherwise
300 */
301 bool equals(VideoSize other) const;
302
303 bool empty() const;
304
305 std::string toString() const;
306
307 /**
308 * Parses the specified string as a size value.
309 *
310 * The ASCII characters {@code \}{@code u002a} ('*') and
311 * {@code \}{@code u0078} ('x') are recognized as separators between
312 * the width and height.
313 *
314 * For any {@code VideoSize s}: {@code VideoSize::ParseSize(s.toString()).equals(s)}.
315 * However, the method also handles sizes expressed in the
316 * following forms:
317 *
318 * "<i>width</i>{@code x}<i>height</i>" or
319 * "<i>width</i>{@code *}<i>height</i>" {@code => new VideoSize(width, height)},
320 * where <i>width</i> and <i>height</i> are string integers potentially
321 * containing a sign, such as "-10", "+7" or "5".
322 *
323 * <pre>{@code
324 * VideoSize::ParseSize("3*+6").equals(new VideoSize(3, 6)) == true
325 * VideoSize::ParseSize("-3x-6").equals(new VideoSize(-3, -6)) == true
326 * VideoSize::ParseSize("4 by 3") => throws NumberFormatException
327 * }</pre>
328 *
329 * @param string the string representation of a size value.
330 * @return the size value represented by {@code string}.
331 */
332 static std::optional<VideoSize> ParseSize(std::string str);
333
334 static std::optional<std::pair<VideoSize, VideoSize>> ParseSizeRange(const std::string str);
335
336 static Range<int32_t> GetAllowedDimensionRange();
337
338 private:
339 int32_t mWidth;
340 int32_t mHeight;
341 };
342
343 // This is used for the std::map<VideoSize> in VideoCapabilities
344 struct VideoSizeCompare {
operatorVideoSizeCompare345 bool operator() (const VideoSize& lhs, const VideoSize& rhs) const {
346 if (lhs.getWidth() == rhs.getWidth()) {
347 return lhs.getHeight() < rhs.getHeight();
348 } else {
349 return lhs.getWidth() < rhs.getWidth();
350 }
351 }
352 };
353
354 /**
355 * An immutable data type representation a rational number.
356 *
357 * Contains a pair of ints representing the numerator and denominator of a
358 * Rational number.
359 */
360 struct Rational {
361 /**
362 * <p>Create a {@code Rational} with a given numerator and denominator.</p>
363 *
364 * <p>The signs of the numerator and the denominator may be flipped such that the denominator
365 * is always positive. Both the numerator and denominator will be converted to their reduced
366 * forms (see {@link #equals} for more details).</p>
367 *
368 * <p>For example,
369 * <ul>
370 * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}.
371 * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1}
372 * <li>a rational of {@code 5/0} will be reduced to {@code 1/0}
373 * <li>a rational of {@code 0/5} will be reduced to {@code 0/1}
374 * </ul>
375 * </p>
376 *
377 * @param numerator the numerator of the rational
378 * @param denominator the denominator of the rational
379 *
380 * @see #equals
381 */
RationalRational382 Rational(int32_t numerator, int32_t denominator) {
383 if (denominator < 0) {
384 numerator = -numerator;
385 denominator = -denominator;
386 }
387
388 // Convert to reduced form
389 if (denominator == 0 && numerator > 0) {
390 mNumerator = 1; // +Inf
391 mDenominator = 0;
392 } else if (denominator == 0 && numerator < 0) {
393 mNumerator = -1; // -Inf
394 mDenominator = 0;
395 } else if (denominator == 0 && numerator == 0) {
396 mNumerator = 0; // NaN
397 mDenominator = 0;
398 } else if (numerator == 0) {
399 mNumerator = 0;
400 mDenominator = 1;
401 } else {
402 int gcd = std::gcd(numerator, denominator);
403
404 mNumerator = numerator / gcd;
405 mDenominator = denominator / gcd;
406 }
407 }
408
409 // default constructor;
RationalRational410 Rational() {
411 Rational(0, 0);
412 }
413
414 /**
415 * Gets the numerator of the rational.
416 *
417 * <p>The numerator will always return {@code 1} if this rational represents
418 * infinity (that is, the denominator is {@code 0}).</p>
419 */
getNumeratorRational420 int32_t getNumerator() const {
421 return mNumerator;
422 }
423
424 /**
425 * Gets the denominator of the rational
426 *
427 * <p>The denominator may return {@code 0}, in which case the rational may represent
428 * positive infinity (if the numerator was positive), negative infinity (if the numerator
429 * was negative), or {@code NaN} (if the numerator was {@code 0}).</p>
430 *
431 * <p>The denominator will always return {@code 1} if the numerator is {@code 0}.
432 */
getDenominatorRational433 int32_t getDenominator() const {
434 return mDenominator;
435 }
436
437 /**
438 * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value.
439 *
440 * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p>
441 *
442 * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value;
443 * {@code false} if this is a (potentially infinite) number value
444 */
isNaNRational445 bool isNaN() const {
446 return mDenominator == 0 && mNumerator == 0;
447 }
448
449 /**
450 * Indicates whether this rational represents an infinite value.
451 *
452 * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p>
453 *
454 * @return {@code true} if this rational is a (positive or negative) infinite value;
455 * {@code false} if this is a finite number value (or {@code NaN})
456 */
isInfiniteRational457 bool isInfinite() const {
458 return mNumerator != 0 && mDenominator == 0;
459 }
460
461 /**
462 * Indicates whether this rational represents a finite value.
463 *
464 * <p>A finite value occurs when the denominator is not {@code 0}; in other words
465 * the rational is neither infinity or {@code NaN}.</p>
466 *
467 * @return {@code true} if this rational is a (positive or negative) infinite value;
468 * {@code false} if this is a finite number value (or {@code NaN})
469 */
isFiniteRational470 bool isFinite() const {
471 return mDenominator != 0;
472 }
473
474 /**
475 * Indicates whether this rational represents a zero value.
476 *
477 * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p>
478 *
479 * @return {@code true} if this rational is finite zero value;
480 * {@code false} otherwise
481 */
isZeroRational482 bool isZero() const {
483 return isFinite() && mNumerator == 0;
484 }
485
486 /**
487 * Return a string representation of this rational, e.g. {@code "1/2"}.
488 *
489 * <p>The following rules of conversion apply:
490 * <ul>
491 * <li>{@code NaN} values will return {@code "NaN"}
492 * <li>Positive infinity values will return {@code "Infinity"}
493 * <li>Negative infinity values will return {@code "-Infinity"}
494 * <li>All other values will return {@code "numerator/denominator"} where {@code numerator}
495 * and {@code denominator} are substituted with the appropriate numerator and denominator
496 * values.
497 * </ul></p>
498 */
toStringRational499 std::string toString() const {
500 if (isNaN()) {
501 return "NaN";
502 } else if (isPosInf()) {
503 return "Infinity";
504 } else if (isNegInf()) {
505 return "-Infinity";
506 } else {
507 return std::to_string(mNumerator) + "/" + std::to_string(mDenominator);
508 }
509 }
510
511 /**
512 * Returns the value of the specified number as a {@code double}.
513 *
514 * <p>The {@code double} is calculated by converting both the numerator and denominator
515 * to a {@code double}; then returning the result of dividing the numerator by the
516 * denominator.</p>
517 *
518 * @return the divided value of the numerator and denominator as a {@code double}.
519 */
asDoubleRational520 double asDouble() const {
521 double num = mNumerator;
522 double den = mDenominator;
523
524 return num / den;
525 }
526
527 /**
528 * Returns the value of the specified number as a {@code float}.
529 *
530 * <p>The {@code float} is calculated by converting both the numerator and denominator
531 * to a {@code float}; then returning the result of dividing the numerator by the
532 * denominator.</p>
533 *
534 * @return the divided value of the numerator and denominator as a {@code float}.
535 */
asfloatRational536 float asfloat() const {
537 float num = mNumerator;
538 float den = mDenominator;
539
540 return num / den;
541 }
542
543 /**
544 * Returns the value of the specified number as a {@code int}.
545 *
546 * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value
547 * by dividing the numerator by the denominator; conversion for non-finite values happens
548 * identically to casting a floating point value to an {@code int}, in particular:
549 *
550 * @return the divided value of the numerator and denominator as a {@code int}.
551 */
asInt32Rational552 int32_t asInt32() const {
553 // Mimic float to int conversion rules from JLS 5.1.3
554
555 if (isPosInf()) {
556 return INT32_MAX;
557 } else if (isNegInf()) {
558 return INT32_MIN;
559 } else if (isNaN()) {
560 return 0;
561 } else { // finite
562 return mNumerator / mDenominator;
563 }
564 }
565
566 /**
567 * Returns the value of the specified number as a {@code long}.
568 *
569 * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value
570 * by dividing the numerator by the denominator; conversion for non-finite values happens
571 * identically to casting a floating point value to a {@code long}, in particular:
572 *
573 * @return the divided value of the numerator and denominator as a {@code long}.
574 */
asInt64Rational575 int64_t asInt64() const {
576 // Mimic float to long conversion rules from JLS 5.1.3
577
578 if (isPosInf()) {
579 return INT64_MAX;
580 } else if (isNegInf()) {
581 return INT64_MIN;
582 } else if (isNaN()) {
583 return 0;
584 } else { // finite
585 return mNumerator / mDenominator;
586 }
587 }
588
589 /**
590 * Returns the value of the specified number as a {@code short}.
591 *
592 * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value
593 * identically to {@link #intValue}; the {@code int} result is then truncated to a
594 * {@code short} before returning the value.</p>
595 *
596 * @return the divided value of the numerator and denominator as a {@code short}.
597 */
asInt16Rational598 int16_t asInt16() const {
599 return (int16_t) asInt32();
600 }
601
602 /**
603 * Compare this rational to the specified rational to determine their natural order.
604 *
605 * Nan is considered to be equal to itself and greater than all other
606 * Rational values. Otherwise, if the objects are not equal, then
607 * the following rules apply:
608 *
609 * Positive infinity is greater than any other finite number (or negative infinity)
610 * Negative infinity is less than any other finite number (or positive infinity)
611 * The finite number represented by this rational is checked numerically
612 * against the other finite number by converting both rationals to a common denominator multiple
613 * and comparing their numerators.
614 *
615 * @param another the rational to be compared
616 *
617 * @return a negative integer, zero, or a positive integer as this object is less than,
618 * equal to, or greater than the specified rational.
619 */
620 // bool operator> (const Rational& another) {
compareToRational621 int compareTo(Rational another) const {
622 if (equals(another)) {
623 return 0;
624 } else if (isNaN()) { // NaN is greater than the other non-NaN value
625 return 1;
626 } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value
627 return -1;
628 } else if (isPosInf() || another.isNegInf()) {
629 return 1; // positive infinity is greater than any non-NaN/non-posInf value
630 } else if (isNegInf() || another.isPosInf()) {
631 return -1; // negative infinity is less than any non-NaN/non-negInf value
632 }
633
634 // else both this and another are finite numbers
635
636 // make the denominators the same, then compare numerators. int64_t to avoid overflow
637 int64_t thisNumerator = ((int64_t)mNumerator) * another.mDenominator;
638 int64_t otherNumerator = ((int64_t)another.mNumerator) * mDenominator;
639
640 // avoid underflow from subtraction by doing comparisons
641 if (thisNumerator < otherNumerator) {
642 return -1;
643 } else if (thisNumerator > otherNumerator) {
644 return 1;
645 } else {
646 // This should be covered by #equals, but have this code path just in case
647 return 0;
648 }
649 }
650
651 bool operator > (const Rational& another) const {
652 return compareTo(another) > 0;
653 }
654
655 bool operator >= (const Rational& another) const {
656 return compareTo(another) >= 0;
657 }
658
659 bool operator < (const Rational& another) const {
660 return compareTo(another) < 0;
661 }
662
663 bool operator <= (const Rational& another) const {
664 return compareTo(another) <= 0;
665 }
666
667 bool operator == (const Rational& another) const {
668 return equals(another);
669 }
670
671 static std::optional<Range<Rational>> ParseRange(const std::string str);
672
673 static Range<Rational> ScaleRange(Range<Rational> range, int32_t num, int32_t den);
674
675 private:
676 int32_t mNumerator;
677 int32_t mDenominator;
678
isPosInfRational679 bool isPosInf() const {
680 return mDenominator == 0 && mNumerator > 0;
681 }
682
isNegInfRational683 bool isNegInf() const {
684 return mDenominator == 0 && mNumerator < 0;
685 }
686
equalsRational687 bool equals(Rational other) const {
688 return (mNumerator == other.mNumerator && mDenominator == other.mDenominator);
689 }
690
691 Rational scale(int32_t num, int32_t den);
692
693 /**
694 * Parses the specified string as a rational value.
695 * The ASCII characters {@code \}{@code u003a} (':') and
696 * {@code \}{@code u002f} ('/') are recognized as separators between
697 * the numerator and denominator.
698 *
699 * For any {@code Rational r}: {@code Rational::parseRational(r.toString()).equals(r)}.
700 * However, the method also handles rational numbers expressed in the
701 * following forms:
702 *
703 * "<i>num</i>{@code /}<i>den</i>" or
704 * "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);},
705 * where <i>num</i> and <i>den</i> are string integers potentially
706 * containing a sign, such as "-10", "+7" or "5".
707 *
708 * Rational::Parse("3:+6").equals(new Rational(1, 2)) == true
709 * Rational::Parse("-3/-6").equals(new Rational(1, 2)) == true
710 * Rational::Parse("4.56") => return std::nullopt
711 *
712 * @param str the string representation of a rational value.
713 * @return the rational value wrapped by std::optional represented by str.
714 */
715 static std::optional<Rational> Parse(std::string str);
716 };
717
718 static const Rational NaN = Rational(0, 0);
719 static const Rational POSITIVE_INFINITY = Rational(1, 0);
720 static const Rational NEGATIVE_INFINITY = Rational(-1, 0);
721 static const Rational ZERO = Rational(0, 1);
722
723 } // namespace android
724
725 #endif // CODEC_CAPABILITIES__UTILS_H_