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 ALOGE("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 *
128 * @throws NullPointerException if {@code lower} or {@code upper} was {@code null}
129 * @throws IllegalArgumentException if the ranges are disjoint.
130 */
intersectRange131 Range<T> intersect(T lower, T upper) {
132 return Range(std::max(lower_, lower), std::min(upper_, upper));
133 }
134
135 /**
136 * Returns the smallest range that includes this range and
137 * another range.
138 *
139 * E.g. if a < b < c < d, the
140 * extension of [a, c] and [b, d] ranges is [a, d].
141 * As the endpoints are object references, there is no guarantee
142 * which specific endpoint reference is used from the input ranges:
143 *
144 * E.g. if a == a' < b < c, the
145 * extension of [a, b] and [a', c] ranges could be either
146 * [a, c] or ['a, c], where ['a, c] could be either the exact
147 * input range, or a newly created range with the same endpoints.
148 *
149 * @param range a non-null Range<T> reference
150 * @return the extension of this range and the other range.
151 */
extendRange152 Range<T> extend(Range<T> range) {
153 return Range<T>(std::min(lower_, range.lower_), std::max(upper_, range.upper_));
154 }
155
alignRange156 Range<T> align(T align) {
157 return this->intersect(
158 divUp(lower_, align) * align, (upper_ / align) * align);
159 }
160
factorRange161 Range<T> factor(T factor) {
162 if (factor == 1) {
163 return *this;
164 }
165 return Range(divUp(this->lower(), factor), this->upper() / factor);
166 }
167
168 // parse a string into a range
ParseRange169 static std::optional<Range<T>> Parse(const std::string &str) {
170 if (str.empty()) {
171 ALOGW("could not parse empty integer range");
172 return std::nullopt;
173 }
174 long long lower, upper;
175 std::regex regex("^([0-9]+)-([0-9]+)$");
176 std::smatch match;
177 errno = 0;
178 if (std::regex_match(str, match, regex)) {
179 lower = std::strtoll(match[1].str().c_str(), NULL, 10);
180 upper = std::strtoll(match[2].str().c_str(), NULL, 10);
181 } else {
182 char *end;
183 lower = upper = std::strtoll(str.c_str(), &end, 10);
184 if (*end != '\0') {
185 ALOGW("could not parse integer range: %s", str.c_str());
186 return std::nullopt;
187 }
188 }
189
190 if (errno == ERANGE || lower < std::numeric_limits<T>::min()
191 || std::numeric_limits<T>::max() < upper || upper < lower) {
192 ALOGW("could not parse integer range: %s", str.c_str());
193 return std::nullopt;
194 }
195
196 return std::make_optional<Range<T>>((T)lower, (T)upper);
197 }
198
RangeForRange199 static Range<T> RangeFor(double v) {
200 return Range((T)v, (T)ceil(v));
201 }
202
203 private:
204 T lower_;
205 T upper_;
206 };
207
208 static const Range<int32_t> POSITIVE_INT32 = Range<int32_t>(1, INT32_MAX);
209
210 // found stuff that is not supported by framework (=> this should not happen)
211 constexpr int ERROR_CAPABILITIES_UNRECOGNIZED = (1 << 0);
212 // found profile/level for which we don't have capability estimates
213 constexpr int ERROR_CAPABILITIES_UNSUPPORTED = (1 << 1);
214 // have not found any profile/level for which we don't have capability estimate
215 constexpr int ERROR_CAPABILITIES_NONE_SUPPORTED = (1 << 2);
216
217 /**
218 * Sorts distinct (non-intersecting) range array in ascending order.
219 * From frameworks/base/media/java/android/media/Utils.java
220 */
221 template<typename T>
sortDistinctRanges(std::vector<Range<T>> * ranges)222 void sortDistinctRanges(std::vector<Range<T>> *ranges) {
223 std::sort(ranges->begin(), ranges->end(),
224 [](Range<T> r1, Range<T> r2) {
225 if (r1.upper() < r2.lower()) {
226 return true;
227 } else if (r1.lower() > r2.upper()) {
228 return false;
229 } else {
230 ALOGE("sample rate ranges must be distinct.");
231 return false;
232 }
233 });
234 }
235
236 /**
237 * Returns the intersection of two sets of non-intersecting ranges
238 * From frameworks/base/media/java/android/media/Utils.java
239 * @param one a sorted set of non-intersecting ranges in ascending order
240 * @param another another sorted set of non-intersecting ranges in ascending order
241 * @return the intersection of the two sets, sorted in ascending order
242 */
243 template<typename T>
intersectSortedDistinctRanges(const std::vector<Range<T>> & one,const std::vector<Range<T>> & another)244 std::vector<Range<T>> intersectSortedDistinctRanges(
245 const std::vector<Range<T>> &one, const std::vector<Range<T>> &another) {
246 std::vector<Range<T>> result;
247 int ix = 0;
248 for (Range<T> range : another) {
249 while (ix < one.size() && one[ix].upper() < range.lower()) {
250 ++ix;
251 }
252 while (ix < one.size() && one[ix].upper() < range.upper()) {
253 result.push_back(range.intersect(one[ix]));
254 ++ix;
255 }
256 if (ix == one.size()) {
257 break;
258 }
259 if (one[ix].lower() <= range.upper()) {
260 result.push_back(range.intersect(one[ix]));
261 }
262 }
263 return result;
264 }
265
266 /**
267 * Immutable class for describing width and height dimensions in pixels.
268 */
269 struct VideoSize {
270 /**
271 * Create a new immutable VideoSize instance.
272 *
273 * @param width The width of the size, in pixels
274 * @param height The height of the size, in pixels
275 */
276 VideoSize(int32_t width, int32_t height);
277
278 // default constructor
279 VideoSize();
280
281 /**
282 * Get the width of the size (in pixels).
283 * @return width
284 */
285 int32_t getWidth() const;
286
287 /**
288 * Get the height of the size (in pixels).
289 * @return height
290 */
291 int32_t getHeight() const;
292
293 /**
294 * Check if this size is equal to another size.
295 *
296 * Two sizes are equal if and only if both their widths and heights are
297 * equal.
298 *
299 * A size object is never equal to any other type of object.
300 *
301 * @return true if the objects were equal, false otherwise
302 */
303 bool equals(VideoSize other) const;
304
305 bool empty() const;
306
307 std::string toString() const;
308
309 /**
310 * Parses the specified string as a size value.
311 *
312 * The ASCII characters {@code \}{@code u002a} ('*') and
313 * {@code \}{@code u0078} ('x') are recognized as separators between
314 * the width and height.
315 *
316 * For any {@code VideoSize s}: {@code VideoSize::ParseSize(s.toString()).equals(s)}.
317 * However, the method also handles sizes expressed in the
318 * following forms:
319 *
320 * "<i>width</i>{@code x}<i>height</i>" or
321 * "<i>width</i>{@code *}<i>height</i>" {@code => new VideoSize(width, height)},
322 * where <i>width</i> and <i>height</i> are string integers potentially
323 * containing a sign, such as "-10", "+7" or "5".
324 *
325 * <pre>{@code
326 * VideoSize::ParseSize("3*+6").equals(new VideoSize(3, 6)) == true
327 * VideoSize::ParseSize("-3x-6").equals(new VideoSize(-3, -6)) == true
328 * VideoSize::ParseSize("4 by 3") => throws NumberFormatException
329 * }</pre>
330 *
331 * @param string the string representation of a size value.
332 * @return the size value represented by {@code string}.
333 */
334 static std::optional<VideoSize> ParseSize(std::string str);
335
336 static std::optional<std::pair<VideoSize, VideoSize>> ParseSizeRange(const std::string str);
337
338 static Range<int32_t> GetAllowedDimensionRange();
339
340 private:
341 int32_t mWidth;
342 int32_t mHeight;
343 };
344
345 // This is used for the std::map<VideoSize> in VideoCapabilities
346 struct VideoSizeCompare {
operatorVideoSizeCompare347 bool operator() (const VideoSize& lhs, const VideoSize& rhs) const {
348 if (lhs.getWidth() == rhs.getWidth()) {
349 return lhs.getHeight() < rhs.getHeight();
350 } else {
351 return lhs.getWidth() < rhs.getWidth();
352 }
353 }
354 };
355
356 /**
357 * An immutable data type representation a rational number.
358 *
359 * Contains a pair of ints representing the numerator and denominator of a
360 * Rational number.
361 */
362 struct Rational {
363 /**
364 * <p>Create a {@code Rational} with a given numerator and denominator.</p>
365 *
366 * <p>The signs of the numerator and the denominator may be flipped such that the denominator
367 * is always positive. Both the numerator and denominator will be converted to their reduced
368 * forms (see {@link #equals} for more details).</p>
369 *
370 * <p>For example,
371 * <ul>
372 * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}.
373 * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1}
374 * <li>a rational of {@code 5/0} will be reduced to {@code 1/0}
375 * <li>a rational of {@code 0/5} will be reduced to {@code 0/1}
376 * </ul>
377 * </p>
378 *
379 * @param numerator the numerator of the rational
380 * @param denominator the denominator of the rational
381 *
382 * @see #equals
383 */
RationalRational384 Rational(int32_t numerator, int32_t denominator) {
385 if (denominator < 0) {
386 numerator = -numerator;
387 denominator = -denominator;
388 }
389
390 // Convert to reduced form
391 if (denominator == 0 && numerator > 0) {
392 mNumerator = 1; // +Inf
393 mDenominator = 0;
394 } else if (denominator == 0 && numerator < 0) {
395 mNumerator = -1; // -Inf
396 mDenominator = 0;
397 } else if (denominator == 0 && numerator == 0) {
398 mNumerator = 0; // NaN
399 mDenominator = 0;
400 } else if (numerator == 0) {
401 mNumerator = 0;
402 mDenominator = 1;
403 } else {
404 int gcd = std::gcd(numerator, denominator);
405
406 mNumerator = numerator / gcd;
407 mDenominator = denominator / gcd;
408 }
409 }
410
411 // default constructor;
RationalRational412 Rational() {
413 Rational(0, 0);
414 }
415
416 /**
417 * Gets the numerator of the rational.
418 *
419 * <p>The numerator will always return {@code 1} if this rational represents
420 * infinity (that is, the denominator is {@code 0}).</p>
421 */
getNumeratorRational422 int32_t getNumerator() const {
423 return mNumerator;
424 }
425
426 /**
427 * Gets the denominator of the rational
428 *
429 * <p>The denominator may return {@code 0}, in which case the rational may represent
430 * positive infinity (if the numerator was positive), negative infinity (if the numerator
431 * was negative), or {@code NaN} (if the numerator was {@code 0}).</p>
432 *
433 * <p>The denominator will always return {@code 1} if the numerator is {@code 0}.
434 */
getDenominatorRational435 int32_t getDenominator() const {
436 return mDenominator;
437 }
438
439 /**
440 * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value.
441 *
442 * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p>
443 *
444 * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value;
445 * {@code false} if this is a (potentially infinite) number value
446 */
isNaNRational447 bool isNaN() const {
448 return mDenominator == 0 && mNumerator == 0;
449 }
450
451 /**
452 * Indicates whether this rational represents an infinite value.
453 *
454 * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p>
455 *
456 * @return {@code true} if this rational is a (positive or negative) infinite value;
457 * {@code false} if this is a finite number value (or {@code NaN})
458 */
isInfiniteRational459 bool isInfinite() const {
460 return mNumerator != 0 && mDenominator == 0;
461 }
462
463 /**
464 * Indicates whether this rational represents a finite value.
465 *
466 * <p>A finite value occurs when the denominator is not {@code 0}; in other words
467 * the rational is neither infinity or {@code NaN}.</p>
468 *
469 * @return {@code true} if this rational is a (positive or negative) infinite value;
470 * {@code false} if this is a finite number value (or {@code NaN})
471 */
isFiniteRational472 bool isFinite() const {
473 return mDenominator != 0;
474 }
475
476 /**
477 * Indicates whether this rational represents a zero value.
478 *
479 * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p>
480 *
481 * @return {@code true} if this rational is finite zero value;
482 * {@code false} otherwise
483 */
isZeroRational484 bool isZero() const {
485 return isFinite() && mNumerator == 0;
486 }
487
488 /**
489 * Return a string representation of this rational, e.g. {@code "1/2"}.
490 *
491 * <p>The following rules of conversion apply:
492 * <ul>
493 * <li>{@code NaN} values will return {@code "NaN"}
494 * <li>Positive infinity values will return {@code "Infinity"}
495 * <li>Negative infinity values will return {@code "-Infinity"}
496 * <li>All other values will return {@code "numerator/denominator"} where {@code numerator}
497 * and {@code denominator} are substituted with the appropriate numerator and denominator
498 * values.
499 * </ul></p>
500 */
toStringRational501 std::string toString() const {
502 if (isNaN()) {
503 return "NaN";
504 } else if (isPosInf()) {
505 return "Infinity";
506 } else if (isNegInf()) {
507 return "-Infinity";
508 } else {
509 return std::to_string(mNumerator) + "/" + std::to_string(mDenominator);
510 }
511 }
512
513 /**
514 * Returns the value of the specified number as a {@code double}.
515 *
516 * <p>The {@code double} is calculated by converting both the numerator and denominator
517 * to a {@code double}; then returning the result of dividing the numerator by the
518 * denominator.</p>
519 *
520 * @return the divided value of the numerator and denominator as a {@code double}.
521 */
asDoubleRational522 double asDouble() const {
523 double num = mNumerator;
524 double den = mDenominator;
525
526 return num / den;
527 }
528
529 /**
530 * Returns the value of the specified number as a {@code float}.
531 *
532 * <p>The {@code float} is calculated by converting both the numerator and denominator
533 * to a {@code float}; then returning the result of dividing the numerator by the
534 * denominator.</p>
535 *
536 * @return the divided value of the numerator and denominator as a {@code float}.
537 */
asfloatRational538 float asfloat() const {
539 float num = mNumerator;
540 float den = mDenominator;
541
542 return num / den;
543 }
544
545 /**
546 * Returns the value of the specified number as a {@code int}.
547 *
548 * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value
549 * by dividing the numerator by the denominator; conversion for non-finite values happens
550 * identically to casting a floating point value to an {@code int}, in particular:
551 *
552 * @return the divided value of the numerator and denominator as a {@code int}.
553 */
asInt32Rational554 int32_t asInt32() const {
555 // Mimic float to int conversion rules from JLS 5.1.3
556
557 if (isPosInf()) {
558 return INT32_MAX;
559 } else if (isNegInf()) {
560 return INT32_MIN;
561 } else if (isNaN()) {
562 return 0;
563 } else { // finite
564 return mNumerator / mDenominator;
565 }
566 }
567
568 /**
569 * Returns the value of the specified number as a {@code long}.
570 *
571 * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value
572 * by dividing the numerator by the denominator; conversion for non-finite values happens
573 * identically to casting a floating point value to a {@code long}, in particular:
574 *
575 * @return the divided value of the numerator and denominator as a {@code long}.
576 */
asInt64Rational577 int64_t asInt64() const {
578 // Mimic float to long conversion rules from JLS 5.1.3
579
580 if (isPosInf()) {
581 return INT64_MAX;
582 } else if (isNegInf()) {
583 return INT64_MIN;
584 } else if (isNaN()) {
585 return 0;
586 } else { // finite
587 return mNumerator / mDenominator;
588 }
589 }
590
591 /**
592 * Returns the value of the specified number as a {@code short}.
593 *
594 * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value
595 * identically to {@link #intValue}; the {@code int} result is then truncated to a
596 * {@code short} before returning the value.</p>
597 *
598 * @return the divided value of the numerator and denominator as a {@code short}.
599 */
asInt16Rational600 int16_t asInt16() const {
601 return (int16_t) asInt32();
602 }
603
604 /**
605 * Compare this rational to the specified rational to determine their natural order.
606 *
607 * Nan is considered to be equal to itself and greater than all other
608 * Rational values. Otherwise, if the objects are not equal, then
609 * the following rules apply:
610 *
611 * Positive infinity is greater than any other finite number (or negative infinity)
612 * Negative infinity is less than any other finite number (or positive infinity)
613 * The finite number represented by this rational is checked numerically
614 * against the other finite number by converting both rationals to a common denominator multiple
615 * and comparing their numerators.
616 *
617 * @param another the rational to be compared
618 *
619 * @return a negative integer, zero, or a positive integer as this object is less than,
620 * equal to, or greater than the specified rational.
621 */
622 // bool operator> (const Rational& another) {
compareToRational623 int compareTo(Rational another) const {
624 if (equals(another)) {
625 return 0;
626 } else if (isNaN()) { // NaN is greater than the other non-NaN value
627 return 1;
628 } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value
629 return -1;
630 } else if (isPosInf() || another.isNegInf()) {
631 return 1; // positive infinity is greater than any non-NaN/non-posInf value
632 } else if (isNegInf() || another.isPosInf()) {
633 return -1; // negative infinity is less than any non-NaN/non-negInf value
634 }
635
636 // else both this and another are finite numbers
637
638 // make the denominators the same, then compare numerators. int64_t to avoid overflow
639 int64_t thisNumerator = ((int64_t)mNumerator) * another.mDenominator;
640 int64_t otherNumerator = ((int64_t)another.mNumerator) * mDenominator;
641
642 // avoid underflow from subtraction by doing comparisons
643 if (thisNumerator < otherNumerator) {
644 return -1;
645 } else if (thisNumerator > otherNumerator) {
646 return 1;
647 } else {
648 // This should be covered by #equals, but have this code path just in case
649 return 0;
650 }
651 }
652
653 bool operator > (const Rational& another) const {
654 return compareTo(another) > 0;
655 }
656
657 bool operator >= (const Rational& another) const {
658 return compareTo(another) >= 0;
659 }
660
661 bool operator < (const Rational& another) const {
662 return compareTo(another) < 0;
663 }
664
665 bool operator <= (const Rational& another) const {
666 return compareTo(another) <= 0;
667 }
668
669 bool operator == (const Rational& another) const {
670 return equals(another);
671 }
672
673 static std::optional<Range<Rational>> ParseRange(const std::string str);
674
675 static Range<Rational> ScaleRange(Range<Rational> range, int32_t num, int32_t den);
676
677 private:
678 int32_t mNumerator;
679 int32_t mDenominator;
680
isPosInfRational681 bool isPosInf() const {
682 return mDenominator == 0 && mNumerator > 0;
683 }
684
isNegInfRational685 bool isNegInf() const {
686 return mDenominator == 0 && mNumerator < 0;
687 }
688
equalsRational689 bool equals(Rational other) const {
690 return (mNumerator == other.mNumerator && mDenominator == other.mDenominator);
691 }
692
693 Rational scale(int32_t num, int32_t den);
694
695 /**
696 * Parses the specified string as a rational value.
697 * The ASCII characters {@code \}{@code u003a} (':') and
698 * {@code \}{@code u002f} ('/') are recognized as separators between
699 * the numerator and denominator.
700 *
701 * For any {@code Rational r}: {@code Rational::parseRational(r.toString()).equals(r)}.
702 * However, the method also handles rational numbers expressed in the
703 * following forms:
704 *
705 * "<i>num</i>{@code /}<i>den</i>" or
706 * "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);},
707 * where <i>num</i> and <i>den</i> are string integers potentially
708 * containing a sign, such as "-10", "+7" or "5".
709 *
710 * Rational::Parse("3:+6").equals(new Rational(1, 2)) == true
711 * Rational::Parse("-3/-6").equals(new Rational(1, 2)) == true
712 * Rational::Parse("4.56") => return std::nullopt
713 *
714 * @param str the string representation of a rational value.
715 * @return the rational value wrapped by std::optional represented by str.
716 */
717 static std::optional<Rational> Parse(std::string str);
718 };
719
720 static const Rational NaN = Rational(0, 0);
721 static const Rational POSITIVE_INFINITY = Rational(1, 0);
722 static const Rational NEGATIVE_INFINITY = Rational(-1, 0);
723 static const Rational ZERO = Rational(0, 1);
724
725 } // namespace android
726
727 #endif // CODEC_CAPABILITIES__UTILS_H_