xref: /aosp_15_r20/frameworks/av/media/libmedia/include/media/CodecCapabilitiesUtils.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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_