1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright 2024, The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "VideoCapabilities"
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <android-base/strings.h>
21*ec779b8eSAndroid Build Coastguard Worker
22*ec779b8eSAndroid Build Coastguard Worker #include <media/CodecCapabilities.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <media/VideoCapabilities.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ADebug.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaCodecConstants.h>
26*ec779b8eSAndroid Build Coastguard Worker
27*ec779b8eSAndroid Build Coastguard Worker #include <utils/Errors.h>
28*ec779b8eSAndroid Build Coastguard Worker
29*ec779b8eSAndroid Build Coastguard Worker namespace android {
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker static const Range<int64_t> POSITIVE_INT64 = Range((int64_t)1, INT64_MAX);
32*ec779b8eSAndroid Build Coastguard Worker static const Range<int32_t> BITRATE_RANGE = Range<int32_t>(0, 500000000);
33*ec779b8eSAndroid Build Coastguard Worker static const Range<int32_t> FRAME_RATE_RANGE = Range<int32_t>(0, 960);
34*ec779b8eSAndroid Build Coastguard Worker static const Range<Rational> POSITIVE_RATIONALS =
35*ec779b8eSAndroid Build Coastguard Worker Range<Rational>(Rational((int32_t)1, INT32_MAX), Rational(INT32_MAX, (int32_t)1));
36*ec779b8eSAndroid Build Coastguard Worker
getBitrateRange() const37*ec779b8eSAndroid Build Coastguard Worker const Range<int32_t>& VideoCapabilities::getBitrateRange() const {
38*ec779b8eSAndroid Build Coastguard Worker return mBitrateRange;
39*ec779b8eSAndroid Build Coastguard Worker }
40*ec779b8eSAndroid Build Coastguard Worker
getSupportedWidths() const41*ec779b8eSAndroid Build Coastguard Worker const Range<int32_t>& VideoCapabilities::getSupportedWidths() const {
42*ec779b8eSAndroid Build Coastguard Worker return mWidthRange;
43*ec779b8eSAndroid Build Coastguard Worker }
44*ec779b8eSAndroid Build Coastguard Worker
getSupportedHeights() const45*ec779b8eSAndroid Build Coastguard Worker const Range<int32_t>& VideoCapabilities::getSupportedHeights() const {
46*ec779b8eSAndroid Build Coastguard Worker return mHeightRange;
47*ec779b8eSAndroid Build Coastguard Worker }
48*ec779b8eSAndroid Build Coastguard Worker
getWidthAlignment() const49*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::getWidthAlignment() const {
50*ec779b8eSAndroid Build Coastguard Worker return mWidthAlignment;
51*ec779b8eSAndroid Build Coastguard Worker }
52*ec779b8eSAndroid Build Coastguard Worker
getHeightAlignment() const53*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::getHeightAlignment() const {
54*ec779b8eSAndroid Build Coastguard Worker return mHeightAlignment;
55*ec779b8eSAndroid Build Coastguard Worker }
56*ec779b8eSAndroid Build Coastguard Worker
getSmallerDimensionUpperLimit() const57*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::getSmallerDimensionUpperLimit() const {
58*ec779b8eSAndroid Build Coastguard Worker return mSmallerDimensionUpperLimit;
59*ec779b8eSAndroid Build Coastguard Worker }
60*ec779b8eSAndroid Build Coastguard Worker
getSupportedFrameRates() const61*ec779b8eSAndroid Build Coastguard Worker const Range<int32_t>& VideoCapabilities::getSupportedFrameRates() const {
62*ec779b8eSAndroid Build Coastguard Worker return mFrameRateRange;
63*ec779b8eSAndroid Build Coastguard Worker }
64*ec779b8eSAndroid Build Coastguard Worker
getSupportedWidthsFor(int32_t height) const65*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int32_t>> VideoCapabilities::getSupportedWidthsFor(int32_t height) const {
66*ec779b8eSAndroid Build Coastguard Worker Range<int32_t> range = mWidthRange;
67*ec779b8eSAndroid Build Coastguard Worker if (!mHeightRange.contains(height)
68*ec779b8eSAndroid Build Coastguard Worker || (height % mHeightAlignment) != 0) {
69*ec779b8eSAndroid Build Coastguard Worker ALOGE("unsupported height");
70*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
71*ec779b8eSAndroid Build Coastguard Worker }
72*ec779b8eSAndroid Build Coastguard Worker const int32_t heightInBlocks = divUp(height, mBlockHeight);
73*ec779b8eSAndroid Build Coastguard Worker
74*ec779b8eSAndroid Build Coastguard Worker // constrain by block count and by block aspect ratio
75*ec779b8eSAndroid Build Coastguard Worker const int32_t minWidthInBlocks = std::max(
76*ec779b8eSAndroid Build Coastguard Worker divUp(mBlockCountRange.lower(), heightInBlocks),
77*ec779b8eSAndroid Build Coastguard Worker (int32_t)std::ceil(mBlockAspectRatioRange.lower().asDouble()
78*ec779b8eSAndroid Build Coastguard Worker * heightInBlocks));
79*ec779b8eSAndroid Build Coastguard Worker const int32_t maxWidthInBlocks = std::min(
80*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.upper() / heightInBlocks,
81*ec779b8eSAndroid Build Coastguard Worker (int32_t)(mBlockAspectRatioRange.upper().asDouble()
82*ec779b8eSAndroid Build Coastguard Worker * heightInBlocks));
83*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(
84*ec779b8eSAndroid Build Coastguard Worker (minWidthInBlocks - 1) * mBlockWidth + mWidthAlignment,
85*ec779b8eSAndroid Build Coastguard Worker maxWidthInBlocks * mBlockWidth);
86*ec779b8eSAndroid Build Coastguard Worker
87*ec779b8eSAndroid Build Coastguard Worker // constrain by smaller dimension limit
88*ec779b8eSAndroid Build Coastguard Worker if (height > mSmallerDimensionUpperLimit) {
89*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(1, mSmallerDimensionUpperLimit);
90*ec779b8eSAndroid Build Coastguard Worker }
91*ec779b8eSAndroid Build Coastguard Worker
92*ec779b8eSAndroid Build Coastguard Worker // constrain by aspect ratio
93*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(
94*ec779b8eSAndroid Build Coastguard Worker (int32_t)std::ceil(mAspectRatioRange.lower().asDouble()
95*ec779b8eSAndroid Build Coastguard Worker * height),
96*ec779b8eSAndroid Build Coastguard Worker (int32_t)(mAspectRatioRange.upper().asDouble() * height));
97*ec779b8eSAndroid Build Coastguard Worker return range;
98*ec779b8eSAndroid Build Coastguard Worker }
99*ec779b8eSAndroid Build Coastguard Worker
getSupportedHeightsFor(int32_t width) const100*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int32_t>> VideoCapabilities::getSupportedHeightsFor(int32_t width) const {
101*ec779b8eSAndroid Build Coastguard Worker Range<int32_t> range = mHeightRange;
102*ec779b8eSAndroid Build Coastguard Worker if (!mWidthRange.contains(width)
103*ec779b8eSAndroid Build Coastguard Worker || (width % mWidthAlignment) != 0) {
104*ec779b8eSAndroid Build Coastguard Worker ALOGE("unsupported width");
105*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
106*ec779b8eSAndroid Build Coastguard Worker }
107*ec779b8eSAndroid Build Coastguard Worker const int32_t widthInBlocks = divUp(width, mBlockWidth);
108*ec779b8eSAndroid Build Coastguard Worker
109*ec779b8eSAndroid Build Coastguard Worker // constrain by block count and by block aspect ratio
110*ec779b8eSAndroid Build Coastguard Worker const int32_t minHeightInBlocks = std::max(
111*ec779b8eSAndroid Build Coastguard Worker divUp(mBlockCountRange.lower(), widthInBlocks),
112*ec779b8eSAndroid Build Coastguard Worker (int32_t)std::ceil(widthInBlocks /
113*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange.upper().asDouble()));
114*ec779b8eSAndroid Build Coastguard Worker const int32_t maxHeightInBlocks = std::min(
115*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.upper() / widthInBlocks,
116*ec779b8eSAndroid Build Coastguard Worker (int32_t)(widthInBlocks /
117*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange.lower().asDouble()));
118*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(
119*ec779b8eSAndroid Build Coastguard Worker (minHeightInBlocks - 1) * mBlockHeight + mHeightAlignment,
120*ec779b8eSAndroid Build Coastguard Worker maxHeightInBlocks * mBlockHeight);
121*ec779b8eSAndroid Build Coastguard Worker
122*ec779b8eSAndroid Build Coastguard Worker // constrain by smaller dimension limit
123*ec779b8eSAndroid Build Coastguard Worker if (width > mSmallerDimensionUpperLimit) {
124*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(1, mSmallerDimensionUpperLimit);
125*ec779b8eSAndroid Build Coastguard Worker }
126*ec779b8eSAndroid Build Coastguard Worker
127*ec779b8eSAndroid Build Coastguard Worker // constrain by aspect ratio
128*ec779b8eSAndroid Build Coastguard Worker range = range.intersect(
129*ec779b8eSAndroid Build Coastguard Worker (int32_t)std::ceil(width /
130*ec779b8eSAndroid Build Coastguard Worker mAspectRatioRange.upper().asDouble()),
131*ec779b8eSAndroid Build Coastguard Worker (int32_t)(width / mAspectRatioRange.lower().asDouble()));
132*ec779b8eSAndroid Build Coastguard Worker return range;
133*ec779b8eSAndroid Build Coastguard Worker }
134*ec779b8eSAndroid Build Coastguard Worker
getSupportedFrameRatesFor(int32_t width,int32_t height) const135*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<double>> VideoCapabilities::getSupportedFrameRatesFor(
136*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height) const {
137*ec779b8eSAndroid Build Coastguard Worker if (!supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
138*ec779b8eSAndroid Build Coastguard Worker std::nullopt /* rate */)) {
139*ec779b8eSAndroid Build Coastguard Worker ALOGE("Unsupported size. width: %d, height: %d", width, height);
140*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
141*ec779b8eSAndroid Build Coastguard Worker }
142*ec779b8eSAndroid Build Coastguard Worker
143*ec779b8eSAndroid Build Coastguard Worker const int32_t blockCount =
144*ec779b8eSAndroid Build Coastguard Worker divUp(width, mBlockWidth) * divUp(height, mBlockHeight);
145*ec779b8eSAndroid Build Coastguard Worker
146*ec779b8eSAndroid Build Coastguard Worker return std::make_optional(Range(
147*ec779b8eSAndroid Build Coastguard Worker std::max(mBlocksPerSecondRange.lower() / (double) blockCount,
148*ec779b8eSAndroid Build Coastguard Worker (double) mFrameRateRange.lower()),
149*ec779b8eSAndroid Build Coastguard Worker std::min(mBlocksPerSecondRange.upper() / (double) blockCount,
150*ec779b8eSAndroid Build Coastguard Worker (double) mFrameRateRange.upper())));
151*ec779b8eSAndroid Build Coastguard Worker }
152*ec779b8eSAndroid Build Coastguard Worker
getBlockCount(int32_t width,int32_t height) const153*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::getBlockCount(int32_t width, int32_t height) const {
154*ec779b8eSAndroid Build Coastguard Worker return divUp(width, mBlockWidth) * divUp(height, mBlockHeight);
155*ec779b8eSAndroid Build Coastguard Worker }
156*ec779b8eSAndroid Build Coastguard Worker
findClosestSize(int32_t width,int32_t height) const157*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> VideoCapabilities::findClosestSize(
158*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height) const {
159*ec779b8eSAndroid Build Coastguard Worker int32_t targetBlockCount = getBlockCount(width, height);
160*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> closestSize;
161*ec779b8eSAndroid Build Coastguard Worker int32_t minDiff = INT32_MAX;
162*ec779b8eSAndroid Build Coastguard Worker for (const auto &[size, range] : mMeasuredFrameRates) {
163*ec779b8eSAndroid Build Coastguard Worker int32_t diff = std::abs(targetBlockCount -
164*ec779b8eSAndroid Build Coastguard Worker getBlockCount(size.getWidth(), size.getHeight()));
165*ec779b8eSAndroid Build Coastguard Worker if (diff < minDiff) {
166*ec779b8eSAndroid Build Coastguard Worker minDiff = diff;
167*ec779b8eSAndroid Build Coastguard Worker closestSize = size;
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker }
170*ec779b8eSAndroid Build Coastguard Worker return closestSize;
171*ec779b8eSAndroid Build Coastguard Worker }
172*ec779b8eSAndroid Build Coastguard Worker
estimateFrameRatesFor(int32_t width,int32_t height) const173*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<double>> VideoCapabilities::estimateFrameRatesFor(
174*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height) const {
175*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> size = findClosestSize(width, height);
176*ec779b8eSAndroid Build Coastguard Worker if (!size) {
177*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
178*ec779b8eSAndroid Build Coastguard Worker }
179*ec779b8eSAndroid Build Coastguard Worker auto rangeItr = mMeasuredFrameRates.find(size.value());
180*ec779b8eSAndroid Build Coastguard Worker if (rangeItr == mMeasuredFrameRates.end()) {
181*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
182*ec779b8eSAndroid Build Coastguard Worker }
183*ec779b8eSAndroid Build Coastguard Worker Range<int64_t> range = rangeItr->second;
184*ec779b8eSAndroid Build Coastguard Worker double ratio = getBlockCount(size.value().getWidth(), size.value().getHeight())
185*ec779b8eSAndroid Build Coastguard Worker / (double)std::max(getBlockCount(width, height), 1);
186*ec779b8eSAndroid Build Coastguard Worker return std::make_optional(Range(range.lower() * ratio, range.upper() * ratio));
187*ec779b8eSAndroid Build Coastguard Worker }
188*ec779b8eSAndroid Build Coastguard Worker
getAchievableFrameRatesFor(int32_t width,int32_t height) const189*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<double>> VideoCapabilities::getAchievableFrameRatesFor(
190*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height) const {
191*ec779b8eSAndroid Build Coastguard Worker if (!supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
192*ec779b8eSAndroid Build Coastguard Worker std::nullopt /* rate */)) {
193*ec779b8eSAndroid Build Coastguard Worker ALOGE("Unsupported size. width: %d, height: %d", width, height);
194*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
195*ec779b8eSAndroid Build Coastguard Worker }
196*ec779b8eSAndroid Build Coastguard Worker
197*ec779b8eSAndroid Build Coastguard Worker if (mMeasuredFrameRates.empty()) {
198*ec779b8eSAndroid Build Coastguard Worker ALOGW("Codec did not publish any measurement data.");
199*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
200*ec779b8eSAndroid Build Coastguard Worker }
201*ec779b8eSAndroid Build Coastguard Worker
202*ec779b8eSAndroid Build Coastguard Worker return estimateFrameRatesFor(width, height);
203*ec779b8eSAndroid Build Coastguard Worker }
204*ec779b8eSAndroid Build Coastguard Worker
205*ec779b8eSAndroid Build Coastguard Worker // VideoCapabilities::PerformancePoint
206*ec779b8eSAndroid Build Coastguard Worker
getMaxMacroBlocks() const207*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::getMaxMacroBlocks() const {
208*ec779b8eSAndroid Build Coastguard Worker return saturateInt64ToInt32(mWidth * (int64_t)mHeight);
209*ec779b8eSAndroid Build Coastguard Worker }
210*ec779b8eSAndroid Build Coastguard Worker
getWidth() const211*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::getWidth() const {
212*ec779b8eSAndroid Build Coastguard Worker return mWidth;
213*ec779b8eSAndroid Build Coastguard Worker }
214*ec779b8eSAndroid Build Coastguard Worker
getHeight() const215*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::getHeight() const {
216*ec779b8eSAndroid Build Coastguard Worker return mHeight;
217*ec779b8eSAndroid Build Coastguard Worker }
218*ec779b8eSAndroid Build Coastguard Worker
getMaxFrameRate() const219*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::getMaxFrameRate() const {
220*ec779b8eSAndroid Build Coastguard Worker return mMaxFrameRate;
221*ec779b8eSAndroid Build Coastguard Worker }
222*ec779b8eSAndroid Build Coastguard Worker
getMaxMacroBlockRate() const223*ec779b8eSAndroid Build Coastguard Worker int64_t VideoCapabilities::PerformancePoint::getMaxMacroBlockRate() const {
224*ec779b8eSAndroid Build Coastguard Worker return mMaxMacroBlockRate;
225*ec779b8eSAndroid Build Coastguard Worker }
226*ec779b8eSAndroid Build Coastguard Worker
getBlockSize() const227*ec779b8eSAndroid Build Coastguard Worker VideoSize VideoCapabilities::PerformancePoint::getBlockSize() const {
228*ec779b8eSAndroid Build Coastguard Worker return mBlockSize;
229*ec779b8eSAndroid Build Coastguard Worker }
230*ec779b8eSAndroid Build Coastguard Worker
toString() const231*ec779b8eSAndroid Build Coastguard Worker std::string VideoCapabilities::PerformancePoint::toString() const {
232*ec779b8eSAndroid Build Coastguard Worker int64_t blockWidth = 16 * (int64_t)mBlockSize.getWidth();
233*ec779b8eSAndroid Build Coastguard Worker int64_t blockHeight = 16 * (int64_t)mBlockSize.getHeight();
234*ec779b8eSAndroid Build Coastguard Worker int32_t origRate = (int32_t)divUp(mMaxMacroBlockRate, (int64_t)getMaxMacroBlocks());
235*ec779b8eSAndroid Build Coastguard Worker std::string info = std::to_string(mWidth * (int64_t)16) + "x"
236*ec779b8eSAndroid Build Coastguard Worker + std::to_string(mHeight * (int64_t)16) + "@" + std::to_string(origRate);
237*ec779b8eSAndroid Build Coastguard Worker if (origRate < mMaxFrameRate) {
238*ec779b8eSAndroid Build Coastguard Worker info += ", max " + std::to_string(mMaxFrameRate) + "fps";
239*ec779b8eSAndroid Build Coastguard Worker }
240*ec779b8eSAndroid Build Coastguard Worker if (blockWidth > 16 || blockHeight > 16) {
241*ec779b8eSAndroid Build Coastguard Worker info += ", " + std::to_string(blockWidth) + "x"
242*ec779b8eSAndroid Build Coastguard Worker + std::to_string(blockHeight) + " blocks";
243*ec779b8eSAndroid Build Coastguard Worker }
244*ec779b8eSAndroid Build Coastguard Worker return "PerformancePoint(" + info + ")";
245*ec779b8eSAndroid Build Coastguard Worker }
246*ec779b8eSAndroid Build Coastguard Worker
init(int32_t width,int32_t height,int32_t frameRate,int32_t maxFrameRate,VideoSize blockSize)247*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::PerformancePoint::init(int32_t width, int32_t height,
248*ec779b8eSAndroid Build Coastguard Worker int32_t frameRate, int32_t maxFrameRate, VideoSize blockSize) {
249*ec779b8eSAndroid Build Coastguard Worker mBlockSize = VideoSize(divUp(blockSize.getWidth(), (int32_t)16),
250*ec779b8eSAndroid Build Coastguard Worker divUp(blockSize.getHeight(), (int32_t)16));
251*ec779b8eSAndroid Build Coastguard Worker // Use IsPowerOfTwoStrict as we do not want width and height to be 0;
252*ec779b8eSAndroid Build Coastguard Worker if (!IsPowerOfTwoStrict(blockSize.getWidth()) || !IsPowerOfTwoStrict(blockSize.getHeight())) {
253*ec779b8eSAndroid Build Coastguard Worker ALOGE("The width and height of a PerformancePoint must be the power of two and not zero."
254*ec779b8eSAndroid Build Coastguard Worker " width: %d, height: %d", blockSize.getWidth(), blockSize.getHeight());
255*ec779b8eSAndroid Build Coastguard Worker }
256*ec779b8eSAndroid Build Coastguard Worker
257*ec779b8eSAndroid Build Coastguard Worker // these are guaranteed not to overflow as we decimate by 16
258*ec779b8eSAndroid Build Coastguard Worker mWidth = (int32_t)(divUp(std::max(width, 1),
259*ec779b8eSAndroid Build Coastguard Worker std::max(blockSize.getWidth(), 16))
260*ec779b8eSAndroid Build Coastguard Worker * mBlockSize.getWidth());
261*ec779b8eSAndroid Build Coastguard Worker mHeight = (int32_t)(divUp(std::max(height, 1),
262*ec779b8eSAndroid Build Coastguard Worker std::max(blockSize.getHeight(), 16))
263*ec779b8eSAndroid Build Coastguard Worker * mBlockSize.getHeight());
264*ec779b8eSAndroid Build Coastguard Worker mMaxFrameRate = std::max(std::max(frameRate, maxFrameRate), 1);
265*ec779b8eSAndroid Build Coastguard Worker mMaxMacroBlockRate = std::max(frameRate, 1) * (int64_t)getMaxMacroBlocks();
266*ec779b8eSAndroid Build Coastguard Worker }
267*ec779b8eSAndroid Build Coastguard Worker
PerformancePoint(int32_t width,int32_t height,int32_t frameRate,int32_t maxFrameRate,VideoSize blockSize)268*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::PerformancePoint::PerformancePoint(int32_t width, int32_t height,
269*ec779b8eSAndroid Build Coastguard Worker int32_t frameRate, int32_t maxFrameRate, VideoSize blockSize) {
270*ec779b8eSAndroid Build Coastguard Worker init(width, height, frameRate, maxFrameRate, blockSize);
271*ec779b8eSAndroid Build Coastguard Worker }
272*ec779b8eSAndroid Build Coastguard Worker
PerformancePoint(VideoSize blockSize,int32_t width,int32_t height,int32_t maxFrameRate,int64_t maxMacroBlockRate)273*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::PerformancePoint::PerformancePoint(VideoSize blockSize, int32_t width,
274*ec779b8eSAndroid Build Coastguard Worker int32_t height, int32_t maxFrameRate, int64_t maxMacroBlockRate) :
275*ec779b8eSAndroid Build Coastguard Worker mBlockSize(blockSize), mWidth(width), mHeight(height), mMaxFrameRate(maxFrameRate),
276*ec779b8eSAndroid Build Coastguard Worker mMaxMacroBlockRate(maxMacroBlockRate) {}
277*ec779b8eSAndroid Build Coastguard Worker
PerformancePoint(const PerformancePoint & pp,VideoSize newBlockSize)278*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::PerformancePoint::PerformancePoint(
279*ec779b8eSAndroid Build Coastguard Worker const PerformancePoint &pp, VideoSize newBlockSize) {
280*ec779b8eSAndroid Build Coastguard Worker init(16 * pp.mWidth, 16 * pp.mHeight,
281*ec779b8eSAndroid Build Coastguard Worker // guaranteed not to overflow as these were multiplied at construction
282*ec779b8eSAndroid Build Coastguard Worker (int32_t)divUp(pp.mMaxMacroBlockRate, (int64_t)pp.getMaxMacroBlocks()),
283*ec779b8eSAndroid Build Coastguard Worker pp.mMaxFrameRate,
284*ec779b8eSAndroid Build Coastguard Worker VideoSize(std::max(newBlockSize.getWidth(), 16 * pp.mBlockSize.getWidth()),
285*ec779b8eSAndroid Build Coastguard Worker std::max(newBlockSize.getHeight(), 16 * pp.mBlockSize.getHeight())));
286*ec779b8eSAndroid Build Coastguard Worker }
287*ec779b8eSAndroid Build Coastguard Worker
PerformancePoint(int32_t width,int32_t height,int32_t frameRate)288*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::PerformancePoint::PerformancePoint(
289*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height, int32_t frameRate) {
290*ec779b8eSAndroid Build Coastguard Worker init(width, height, frameRate, frameRate /* maxFrameRate */, VideoSize(16, 16));
291*ec779b8eSAndroid Build Coastguard Worker }
292*ec779b8eSAndroid Build Coastguard Worker
saturateInt64ToInt32(int64_t value) const293*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::saturateInt64ToInt32(int64_t value) const {
294*ec779b8eSAndroid Build Coastguard Worker if (value < INT32_MIN) {
295*ec779b8eSAndroid Build Coastguard Worker return INT32_MIN;
296*ec779b8eSAndroid Build Coastguard Worker } else if (value > INT32_MAX) {
297*ec779b8eSAndroid Build Coastguard Worker return INT32_MAX;
298*ec779b8eSAndroid Build Coastguard Worker } else {
299*ec779b8eSAndroid Build Coastguard Worker return (int32_t)value;
300*ec779b8eSAndroid Build Coastguard Worker }
301*ec779b8eSAndroid Build Coastguard Worker }
302*ec779b8eSAndroid Build Coastguard Worker
303*ec779b8eSAndroid Build Coastguard Worker /* This method may overflow */
align(int32_t value,int32_t alignment) const304*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::PerformancePoint::align(
305*ec779b8eSAndroid Build Coastguard Worker int32_t value, int32_t alignment) const {
306*ec779b8eSAndroid Build Coastguard Worker return divUp(value, alignment) * alignment;
307*ec779b8eSAndroid Build Coastguard Worker }
308*ec779b8eSAndroid Build Coastguard Worker
covers(const sp<AMessage> & format) const309*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::PerformancePoint::covers(
310*ec779b8eSAndroid Build Coastguard Worker const sp<AMessage> &format) const {
311*ec779b8eSAndroid Build Coastguard Worker int32_t width, height;
312*ec779b8eSAndroid Build Coastguard Worker format->findInt32(KEY_WIDTH, &width);
313*ec779b8eSAndroid Build Coastguard Worker format->findInt32(KEY_HEIGHT, &height);
314*ec779b8eSAndroid Build Coastguard Worker double frameRate;
315*ec779b8eSAndroid Build Coastguard Worker format->findDouble(KEY_FRAME_RATE, &frameRate);
316*ec779b8eSAndroid Build Coastguard Worker PerformancePoint other = PerformancePoint(
317*ec779b8eSAndroid Build Coastguard Worker width, height,
318*ec779b8eSAndroid Build Coastguard Worker // safely convert ceil(double) to int through float cast and std::round
319*ec779b8eSAndroid Build Coastguard Worker std::round((float)(std::ceil(frameRate)))
320*ec779b8eSAndroid Build Coastguard Worker );
321*ec779b8eSAndroid Build Coastguard Worker return covers(other);
322*ec779b8eSAndroid Build Coastguard Worker }
323*ec779b8eSAndroid Build Coastguard Worker
covers(const PerformancePoint & other) const324*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::PerformancePoint::covers(
325*ec779b8eSAndroid Build Coastguard Worker const PerformancePoint &other) const {
326*ec779b8eSAndroid Build Coastguard Worker // convert performance points to common block size
327*ec779b8eSAndroid Build Coastguard Worker VideoSize commonSize = getCommonBlockSize(other);
328*ec779b8eSAndroid Build Coastguard Worker PerformancePoint aligned = PerformancePoint(*this, commonSize);
329*ec779b8eSAndroid Build Coastguard Worker PerformancePoint otherAligned = PerformancePoint(other, commonSize);
330*ec779b8eSAndroid Build Coastguard Worker
331*ec779b8eSAndroid Build Coastguard Worker return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
332*ec779b8eSAndroid Build Coastguard Worker && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
333*ec779b8eSAndroid Build Coastguard Worker && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
334*ec779b8eSAndroid Build Coastguard Worker }
335*ec779b8eSAndroid Build Coastguard Worker
getCommonBlockSize(const PerformancePoint & other) const336*ec779b8eSAndroid Build Coastguard Worker VideoSize VideoCapabilities::PerformancePoint::getCommonBlockSize(
337*ec779b8eSAndroid Build Coastguard Worker const PerformancePoint &other) const {
338*ec779b8eSAndroid Build Coastguard Worker return VideoSize(
339*ec779b8eSAndroid Build Coastguard Worker 16 * std::max(mBlockSize.getWidth(), other.mBlockSize.getWidth()),
340*ec779b8eSAndroid Build Coastguard Worker 16 * std::max(mBlockSize.getHeight(), other.mBlockSize.getHeight()));
341*ec779b8eSAndroid Build Coastguard Worker }
342*ec779b8eSAndroid Build Coastguard Worker
equals(const PerformancePoint & other) const343*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::PerformancePoint::equals(
344*ec779b8eSAndroid Build Coastguard Worker const PerformancePoint &other) const {
345*ec779b8eSAndroid Build Coastguard Worker // convert performance points to common block size
346*ec779b8eSAndroid Build Coastguard Worker VideoSize commonSize = getCommonBlockSize(other);
347*ec779b8eSAndroid Build Coastguard Worker PerformancePoint aligned = PerformancePoint(*this, commonSize);
348*ec779b8eSAndroid Build Coastguard Worker PerformancePoint otherAligned = PerformancePoint(other, commonSize);
349*ec779b8eSAndroid Build Coastguard Worker
350*ec779b8eSAndroid Build Coastguard Worker return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
351*ec779b8eSAndroid Build Coastguard Worker && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
352*ec779b8eSAndroid Build Coastguard Worker && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
353*ec779b8eSAndroid Build Coastguard Worker }
354*ec779b8eSAndroid Build Coastguard Worker
355*ec779b8eSAndroid Build Coastguard Worker // VideoCapabilities
356*ec779b8eSAndroid Build Coastguard Worker
357*ec779b8eSAndroid Build Coastguard Worker const std::vector<VideoCapabilities::PerformancePoint>&
getSupportedPerformancePoints() const358*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::getSupportedPerformancePoints() const {
359*ec779b8eSAndroid Build Coastguard Worker return mPerformancePoints;
360*ec779b8eSAndroid Build Coastguard Worker }
361*ec779b8eSAndroid Build Coastguard Worker
areSizeAndRateSupported(int32_t width,int32_t height,double frameRate) const362*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::areSizeAndRateSupported(
363*ec779b8eSAndroid Build Coastguard Worker int32_t width, int32_t height, double frameRate) const {
364*ec779b8eSAndroid Build Coastguard Worker return supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
365*ec779b8eSAndroid Build Coastguard Worker std::make_optional<double>(frameRate));
366*ec779b8eSAndroid Build Coastguard Worker }
367*ec779b8eSAndroid Build Coastguard Worker
isSizeSupported(int32_t width,int32_t height) const368*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::isSizeSupported(int32_t width, int32_t height) const {
369*ec779b8eSAndroid Build Coastguard Worker return supports(std::make_optional<int32_t>(width), std::make_optional<int32_t>(height),
370*ec779b8eSAndroid Build Coastguard Worker std::nullopt /* rate */);
371*ec779b8eSAndroid Build Coastguard Worker }
372*ec779b8eSAndroid Build Coastguard Worker
supports(std::optional<int32_t> width,std::optional<int32_t> height,std::optional<double> rate) const373*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::supports(std::optional<int32_t> width, std::optional<int32_t> height,
374*ec779b8eSAndroid Build Coastguard Worker std::optional<double> rate) const {
375*ec779b8eSAndroid Build Coastguard Worker bool ok = true;
376*ec779b8eSAndroid Build Coastguard Worker
377*ec779b8eSAndroid Build Coastguard Worker if (width) {
378*ec779b8eSAndroid Build Coastguard Worker ok &= mWidthRange.contains(width.value())
379*ec779b8eSAndroid Build Coastguard Worker && (width.value() % mWidthAlignment == 0);
380*ec779b8eSAndroid Build Coastguard Worker }
381*ec779b8eSAndroid Build Coastguard Worker if (height) {
382*ec779b8eSAndroid Build Coastguard Worker ok &= mHeightRange.contains(height.value())
383*ec779b8eSAndroid Build Coastguard Worker && (height.value() % mHeightAlignment == 0);
384*ec779b8eSAndroid Build Coastguard Worker }
385*ec779b8eSAndroid Build Coastguard Worker if (rate) {
386*ec779b8eSAndroid Build Coastguard Worker ok &= mFrameRateRange.contains(Range<int32_t>::RangeFor(rate.value()));
387*ec779b8eSAndroid Build Coastguard Worker }
388*ec779b8eSAndroid Build Coastguard Worker if (height && width) {
389*ec779b8eSAndroid Build Coastguard Worker ok &= std::min(height.value(), width.value()) <= mSmallerDimensionUpperLimit;
390*ec779b8eSAndroid Build Coastguard Worker
391*ec779b8eSAndroid Build Coastguard Worker const int32_t widthInBlocks = divUp(width.value(), mBlockWidth);
392*ec779b8eSAndroid Build Coastguard Worker const int32_t heightInBlocks = divUp(height.value(), mBlockHeight);
393*ec779b8eSAndroid Build Coastguard Worker const int32_t blockCount = widthInBlocks * heightInBlocks;
394*ec779b8eSAndroid Build Coastguard Worker ok &= mBlockCountRange.contains(blockCount)
395*ec779b8eSAndroid Build Coastguard Worker && mBlockAspectRatioRange.contains(
396*ec779b8eSAndroid Build Coastguard Worker Rational(widthInBlocks, heightInBlocks))
397*ec779b8eSAndroid Build Coastguard Worker && mAspectRatioRange.contains(Rational(width.value(), height.value()));
398*ec779b8eSAndroid Build Coastguard Worker if (rate) {
399*ec779b8eSAndroid Build Coastguard Worker double blocksPerSec = blockCount * rate.value();
400*ec779b8eSAndroid Build Coastguard Worker ok &= mBlocksPerSecondRange.contains(
401*ec779b8eSAndroid Build Coastguard Worker Range<int64_t>::RangeFor(blocksPerSec));
402*ec779b8eSAndroid Build Coastguard Worker }
403*ec779b8eSAndroid Build Coastguard Worker }
404*ec779b8eSAndroid Build Coastguard Worker return ok;
405*ec779b8eSAndroid Build Coastguard Worker }
406*ec779b8eSAndroid Build Coastguard Worker
supportsFormat(const sp<AMessage> & format) const407*ec779b8eSAndroid Build Coastguard Worker bool VideoCapabilities::supportsFormat(const sp<AMessage> &format) const {
408*ec779b8eSAndroid Build Coastguard Worker int32_t widthVal, heightVal;
409*ec779b8eSAndroid Build Coastguard Worker std::optional<int32_t> width = format->findInt32(KEY_WIDTH, &widthVal)
410*ec779b8eSAndroid Build Coastguard Worker ? std::make_optional<int32_t>(widthVal) : std::nullopt;
411*ec779b8eSAndroid Build Coastguard Worker std::optional<int32_t> height = format->findInt32(KEY_HEIGHT, &heightVal)
412*ec779b8eSAndroid Build Coastguard Worker ? std::make_optional<int32_t>(heightVal) : std::nullopt;
413*ec779b8eSAndroid Build Coastguard Worker double rateVal;
414*ec779b8eSAndroid Build Coastguard Worker std::optional<double> rate = format->findDouble(KEY_FRAME_RATE, &rateVal)
415*ec779b8eSAndroid Build Coastguard Worker ? std::make_optional<double>(rateVal) : std::nullopt;
416*ec779b8eSAndroid Build Coastguard Worker
417*ec779b8eSAndroid Build Coastguard Worker if (!supports(width, height, rate)) {
418*ec779b8eSAndroid Build Coastguard Worker return false;
419*ec779b8eSAndroid Build Coastguard Worker }
420*ec779b8eSAndroid Build Coastguard Worker
421*ec779b8eSAndroid Build Coastguard Worker if (!CodecCapabilities::SupportsBitrate(mBitrateRange, format)) {
422*ec779b8eSAndroid Build Coastguard Worker return false;
423*ec779b8eSAndroid Build Coastguard Worker }
424*ec779b8eSAndroid Build Coastguard Worker
425*ec779b8eSAndroid Build Coastguard Worker // we ignore color-format for now as it is not reliably reported by codec
426*ec779b8eSAndroid Build Coastguard Worker return true;
427*ec779b8eSAndroid Build Coastguard Worker }
428*ec779b8eSAndroid Build Coastguard Worker
429*ec779b8eSAndroid Build Coastguard Worker // static
Create(std::string mediaType,std::vector<ProfileLevel> profLevs,const sp<AMessage> & format)430*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<VideoCapabilities> VideoCapabilities::Create(std::string mediaType,
431*ec779b8eSAndroid Build Coastguard Worker std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
432*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<VideoCapabilities> caps(new VideoCapabilities());
433*ec779b8eSAndroid Build Coastguard Worker caps->init(mediaType, profLevs, format);
434*ec779b8eSAndroid Build Coastguard Worker return caps;
435*ec779b8eSAndroid Build Coastguard Worker }
436*ec779b8eSAndroid Build Coastguard Worker
init(std::string mediaType,std::vector<ProfileLevel> profLevs,const sp<AMessage> & format)437*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
438*ec779b8eSAndroid Build Coastguard Worker const sp<AMessage> &format) {
439*ec779b8eSAndroid Build Coastguard Worker mMediaType = mediaType;
440*ec779b8eSAndroid Build Coastguard Worker mProfileLevels = profLevs;
441*ec779b8eSAndroid Build Coastguard Worker mError = 0;
442*ec779b8eSAndroid Build Coastguard Worker
443*ec779b8eSAndroid Build Coastguard Worker initWithPlatformLimits();
444*ec779b8eSAndroid Build Coastguard Worker applyLevelLimits();
445*ec779b8eSAndroid Build Coastguard Worker parseFromInfo(format);
446*ec779b8eSAndroid Build Coastguard Worker updateLimits();
447*ec779b8eSAndroid Build Coastguard Worker }
448*ec779b8eSAndroid Build Coastguard Worker
getBlockSize() const449*ec779b8eSAndroid Build Coastguard Worker VideoSize VideoCapabilities::getBlockSize() const {
450*ec779b8eSAndroid Build Coastguard Worker return VideoSize(mBlockWidth, mBlockHeight);
451*ec779b8eSAndroid Build Coastguard Worker }
452*ec779b8eSAndroid Build Coastguard Worker
getBlockCountRange() const453*ec779b8eSAndroid Build Coastguard Worker const Range<int32_t>& VideoCapabilities::getBlockCountRange() const {
454*ec779b8eSAndroid Build Coastguard Worker return mBlockCountRange;
455*ec779b8eSAndroid Build Coastguard Worker }
456*ec779b8eSAndroid Build Coastguard Worker
getBlocksPerSecondRange() const457*ec779b8eSAndroid Build Coastguard Worker const Range<int64_t>& VideoCapabilities::getBlocksPerSecondRange() const {
458*ec779b8eSAndroid Build Coastguard Worker return mBlocksPerSecondRange;
459*ec779b8eSAndroid Build Coastguard Worker }
460*ec779b8eSAndroid Build Coastguard Worker
getAspectRatioRange(bool blocks) const461*ec779b8eSAndroid Build Coastguard Worker Range<Rational> VideoCapabilities::getAspectRatioRange(bool blocks) const {
462*ec779b8eSAndroid Build Coastguard Worker return blocks ? mBlockAspectRatioRange : mAspectRatioRange;
463*ec779b8eSAndroid Build Coastguard Worker }
464*ec779b8eSAndroid Build Coastguard Worker
initWithPlatformLimits()465*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::initWithPlatformLimits() {
466*ec779b8eSAndroid Build Coastguard Worker mBitrateRange = BITRATE_RANGE;
467*ec779b8eSAndroid Build Coastguard Worker
468*ec779b8eSAndroid Build Coastguard Worker mWidthRange = VideoSize::GetAllowedDimensionRange();
469*ec779b8eSAndroid Build Coastguard Worker mHeightRange = VideoSize::GetAllowedDimensionRange();
470*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = FRAME_RATE_RANGE;
471*ec779b8eSAndroid Build Coastguard Worker
472*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange = VideoSize::GetAllowedDimensionRange();
473*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange = VideoSize::GetAllowedDimensionRange();
474*ec779b8eSAndroid Build Coastguard Worker
475*ec779b8eSAndroid Build Coastguard Worker // full positive ranges are supported as these get calculated
476*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = POSITIVE_INT32;
477*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = POSITIVE_INT64;
478*ec779b8eSAndroid Build Coastguard Worker
479*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = POSITIVE_RATIONALS;
480*ec779b8eSAndroid Build Coastguard Worker mAspectRatioRange = POSITIVE_RATIONALS;
481*ec779b8eSAndroid Build Coastguard Worker
482*ec779b8eSAndroid Build Coastguard Worker // YUV 4:2:0 requires 2:2 alignment
483*ec779b8eSAndroid Build Coastguard Worker mWidthAlignment = 2;
484*ec779b8eSAndroid Build Coastguard Worker mHeightAlignment = 2;
485*ec779b8eSAndroid Build Coastguard Worker mBlockWidth = 2;
486*ec779b8eSAndroid Build Coastguard Worker mBlockHeight = 2;
487*ec779b8eSAndroid Build Coastguard Worker mSmallerDimensionUpperLimit = VideoSize::GetAllowedDimensionRange().upper();
488*ec779b8eSAndroid Build Coastguard Worker }
489*ec779b8eSAndroid Build Coastguard Worker
490*ec779b8eSAndroid Build Coastguard Worker std::vector<VideoCapabilities::PerformancePoint>
getPerformancePoints(const sp<AMessage> & format) const491*ec779b8eSAndroid Build Coastguard Worker VideoCapabilities::getPerformancePoints(
492*ec779b8eSAndroid Build Coastguard Worker const sp<AMessage> &format) const {
493*ec779b8eSAndroid Build Coastguard Worker std::vector<PerformancePoint> ret;
494*ec779b8eSAndroid Build Coastguard Worker AMessage::Type type;
495*ec779b8eSAndroid Build Coastguard Worker for (int i = 0; i < format->countEntries(); i++) {
496*ec779b8eSAndroid Build Coastguard Worker const char *name = format->getEntryNameAt(i, &type);
497*ec779b8eSAndroid Build Coastguard Worker AString rangeStr;
498*ec779b8eSAndroid Build Coastguard Worker if (!format->findString(name, &rangeStr)) {
499*ec779b8eSAndroid Build Coastguard Worker continue;
500*ec779b8eSAndroid Build Coastguard Worker }
501*ec779b8eSAndroid Build Coastguard Worker
502*ec779b8eSAndroid Build Coastguard Worker const std::string key = std::string(name);
503*ec779b8eSAndroid Build Coastguard Worker // looking for: performance-point-WIDTHxHEIGHT-range
504*ec779b8eSAndroid Build Coastguard Worker
505*ec779b8eSAndroid Build Coastguard Worker // check none performance point
506*ec779b8eSAndroid Build Coastguard Worker if (key == "performance-point-none" && ret.size() == 0) {
507*ec779b8eSAndroid Build Coastguard Worker // This means that component knowingly did not publish performance points.
508*ec779b8eSAndroid Build Coastguard Worker // This is different from when the component forgot to publish performance
509*ec779b8eSAndroid Build Coastguard Worker // points.
510*ec779b8eSAndroid Build Coastguard Worker return ret;
511*ec779b8eSAndroid Build Coastguard Worker }
512*ec779b8eSAndroid Build Coastguard Worker
513*ec779b8eSAndroid Build Coastguard Worker // parse size from key
514*ec779b8eSAndroid Build Coastguard Worker std::regex sizeRegex("performance-point-(.+)-range");
515*ec779b8eSAndroid Build Coastguard Worker std::smatch sizeMatch;
516*ec779b8eSAndroid Build Coastguard Worker if (!std::regex_match(key, sizeMatch, sizeRegex)) {
517*ec779b8eSAndroid Build Coastguard Worker continue;
518*ec779b8eSAndroid Build Coastguard Worker }
519*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> size = VideoSize::ParseSize(sizeMatch[1].str());
520*ec779b8eSAndroid Build Coastguard Worker if (!size || size.value().getWidth() * size.value().getHeight() <= 0) {
521*ec779b8eSAndroid Build Coastguard Worker continue;
522*ec779b8eSAndroid Build Coastguard Worker }
523*ec779b8eSAndroid Build Coastguard Worker
524*ec779b8eSAndroid Build Coastguard Worker // parse range from value
525*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int64_t>> range = Range<int64_t>::Parse(std::string(rangeStr.c_str()));
526*ec779b8eSAndroid Build Coastguard Worker if (!range || range.value().lower() < 0 || range.value().upper() < 0) {
527*ec779b8eSAndroid Build Coastguard Worker continue;
528*ec779b8eSAndroid Build Coastguard Worker }
529*ec779b8eSAndroid Build Coastguard Worker
530*ec779b8eSAndroid Build Coastguard Worker PerformancePoint given = PerformancePoint(
531*ec779b8eSAndroid Build Coastguard Worker size.value().getWidth(), size.value().getHeight(), (int32_t)range.value().lower(),
532*ec779b8eSAndroid Build Coastguard Worker (int32_t)range.value().upper(), VideoSize(mBlockWidth, mBlockHeight));
533*ec779b8eSAndroid Build Coastguard Worker PerformancePoint rotated = PerformancePoint(
534*ec779b8eSAndroid Build Coastguard Worker size.value().getHeight(), size.value().getWidth(), (int32_t)range.value().lower(),
535*ec779b8eSAndroid Build Coastguard Worker (int32_t)range.value().upper(), VideoSize(mBlockWidth, mBlockHeight));
536*ec779b8eSAndroid Build Coastguard Worker ret.push_back(given);
537*ec779b8eSAndroid Build Coastguard Worker if (!given.covers(rotated)) {
538*ec779b8eSAndroid Build Coastguard Worker ret.push_back(rotated);
539*ec779b8eSAndroid Build Coastguard Worker }
540*ec779b8eSAndroid Build Coastguard Worker }
541*ec779b8eSAndroid Build Coastguard Worker
542*ec779b8eSAndroid Build Coastguard Worker // check if the component specified no performance point indication
543*ec779b8eSAndroid Build Coastguard Worker if (ret.size() == 0) {
544*ec779b8eSAndroid Build Coastguard Worker return ret;
545*ec779b8eSAndroid Build Coastguard Worker }
546*ec779b8eSAndroid Build Coastguard Worker
547*ec779b8eSAndroid Build Coastguard Worker // sort reversed by area first, then by frame rate
548*ec779b8eSAndroid Build Coastguard Worker std::sort(ret.begin(), ret.end(), [](const PerformancePoint &a, const PerformancePoint &b) {
549*ec779b8eSAndroid Build Coastguard Worker return -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
550*ec779b8eSAndroid Build Coastguard Worker (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
551*ec779b8eSAndroid Build Coastguard Worker (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
552*ec779b8eSAndroid Build Coastguard Worker (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
553*ec779b8eSAndroid Build Coastguard Worker (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
554*ec779b8eSAndroid Build Coastguard Worker (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0);
555*ec779b8eSAndroid Build Coastguard Worker });
556*ec779b8eSAndroid Build Coastguard Worker
557*ec779b8eSAndroid Build Coastguard Worker return ret;
558*ec779b8eSAndroid Build Coastguard Worker }
559*ec779b8eSAndroid Build Coastguard Worker
560*ec779b8eSAndroid Build Coastguard Worker std::map<VideoSize, Range<int64_t>, VideoSizeCompare> VideoCapabilities
getMeasuredFrameRates(const sp<AMessage> & format) const561*ec779b8eSAndroid Build Coastguard Worker ::getMeasuredFrameRates(const sp<AMessage> &format) const {
562*ec779b8eSAndroid Build Coastguard Worker std::map<VideoSize, Range<int64_t>, VideoSizeCompare> ret;
563*ec779b8eSAndroid Build Coastguard Worker AMessage::Type type;
564*ec779b8eSAndroid Build Coastguard Worker for (int i = 0; i < format->countEntries(); i++) {
565*ec779b8eSAndroid Build Coastguard Worker const char *name = format->getEntryNameAt(i, &type);
566*ec779b8eSAndroid Build Coastguard Worker AString rangeStr;
567*ec779b8eSAndroid Build Coastguard Worker if (!format->findString(name, &rangeStr)) {
568*ec779b8eSAndroid Build Coastguard Worker continue;
569*ec779b8eSAndroid Build Coastguard Worker }
570*ec779b8eSAndroid Build Coastguard Worker
571*ec779b8eSAndroid Build Coastguard Worker const std::string key = std::string(name);
572*ec779b8eSAndroid Build Coastguard Worker // looking for: measured-frame-rate-WIDTHxHEIGHT-range
573*ec779b8eSAndroid Build Coastguard Worker
574*ec779b8eSAndroid Build Coastguard Worker std::regex sizeRegex("measured-frame-rate-(.+)-range");
575*ec779b8eSAndroid Build Coastguard Worker std::smatch sizeMatch;
576*ec779b8eSAndroid Build Coastguard Worker if (!std::regex_match(key, sizeMatch, sizeRegex)) {
577*ec779b8eSAndroid Build Coastguard Worker continue;
578*ec779b8eSAndroid Build Coastguard Worker }
579*ec779b8eSAndroid Build Coastguard Worker
580*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> size = VideoSize::ParseSize(sizeMatch[1].str());
581*ec779b8eSAndroid Build Coastguard Worker if (!size || size.value().getWidth() * size.value().getHeight() <= 0) {
582*ec779b8eSAndroid Build Coastguard Worker continue;
583*ec779b8eSAndroid Build Coastguard Worker }
584*ec779b8eSAndroid Build Coastguard Worker
585*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int64_t>> range = Range<int64_t>::Parse(std::string(rangeStr.c_str()));
586*ec779b8eSAndroid Build Coastguard Worker if (!range || range.value().lower() < 0 || range.value().upper() < 0) {
587*ec779b8eSAndroid Build Coastguard Worker continue;
588*ec779b8eSAndroid Build Coastguard Worker }
589*ec779b8eSAndroid Build Coastguard Worker
590*ec779b8eSAndroid Build Coastguard Worker ret.emplace(size.value(), range.value());
591*ec779b8eSAndroid Build Coastguard Worker }
592*ec779b8eSAndroid Build Coastguard Worker return ret;
593*ec779b8eSAndroid Build Coastguard Worker }
594*ec779b8eSAndroid Build Coastguard Worker
595*ec779b8eSAndroid Build Coastguard Worker // static
596*ec779b8eSAndroid Build Coastguard Worker std::optional<std::pair<Range<int32_t>, Range<int32_t>>> VideoCapabilities
ParseWidthHeightRanges(const std::string & str)597*ec779b8eSAndroid Build Coastguard Worker ::ParseWidthHeightRanges(const std::string &str) {
598*ec779b8eSAndroid Build Coastguard Worker std::optional<std::pair<VideoSize, VideoSize>> range = VideoSize::ParseSizeRange(str);
599*ec779b8eSAndroid Build Coastguard Worker if (!range) {
600*ec779b8eSAndroid Build Coastguard Worker ALOGW("could not parse size range: %s", str.c_str());
601*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
602*ec779b8eSAndroid Build Coastguard Worker }
603*ec779b8eSAndroid Build Coastguard Worker
604*ec779b8eSAndroid Build Coastguard Worker return std::make_optional(std::pair(
605*ec779b8eSAndroid Build Coastguard Worker Range(range.value().first.getWidth(), range.value().second.getWidth()),
606*ec779b8eSAndroid Build Coastguard Worker Range(range.value().first.getHeight(), range.value().second.getHeight())));
607*ec779b8eSAndroid Build Coastguard Worker }
608*ec779b8eSAndroid Build Coastguard Worker
609*ec779b8eSAndroid Build Coastguard Worker // static
EquivalentVP9Level(const sp<AMessage> & format)610*ec779b8eSAndroid Build Coastguard Worker int32_t VideoCapabilities::EquivalentVP9Level(const sp<AMessage> &format) {
611*ec779b8eSAndroid Build Coastguard Worker int32_t blockSizeWidth = 8;
612*ec779b8eSAndroid Build Coastguard Worker int32_t blockSizeHeight = 8;
613*ec779b8eSAndroid Build Coastguard Worker // VideoSize *blockSizePtr = &VideoSize(8, 8);
614*ec779b8eSAndroid Build Coastguard Worker AString blockSizeStr;
615*ec779b8eSAndroid Build Coastguard Worker if (format->findString("block-size", &blockSizeStr)) {
616*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> parsedBlockSize
617*ec779b8eSAndroid Build Coastguard Worker = VideoSize::ParseSize(std::string(blockSizeStr.c_str()));
618*ec779b8eSAndroid Build Coastguard Worker if (parsedBlockSize) {
619*ec779b8eSAndroid Build Coastguard Worker // blockSize = parsedBlockSize.value();
620*ec779b8eSAndroid Build Coastguard Worker blockSizeWidth = parsedBlockSize.value().getWidth();
621*ec779b8eSAndroid Build Coastguard Worker blockSizeHeight = parsedBlockSize.value().getHeight();
622*ec779b8eSAndroid Build Coastguard Worker }
623*ec779b8eSAndroid Build Coastguard Worker }
624*ec779b8eSAndroid Build Coastguard Worker int32_t BS = blockSizeWidth * blockSizeHeight;
625*ec779b8eSAndroid Build Coastguard Worker
626*ec779b8eSAndroid Build Coastguard Worker int32_t FS = 0;
627*ec779b8eSAndroid Build Coastguard Worker AString blockCountRangeStr;
628*ec779b8eSAndroid Build Coastguard Worker if (format->findString("block-count-range", &blockCountRangeStr)) {
629*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int>> counts = Range<int32_t>::Parse(
630*ec779b8eSAndroid Build Coastguard Worker std::string(blockCountRangeStr.c_str()));
631*ec779b8eSAndroid Build Coastguard Worker if (counts) {
632*ec779b8eSAndroid Build Coastguard Worker FS = BS * counts.value().upper();
633*ec779b8eSAndroid Build Coastguard Worker }
634*ec779b8eSAndroid Build Coastguard Worker }
635*ec779b8eSAndroid Build Coastguard Worker
636*ec779b8eSAndroid Build Coastguard Worker int64_t SR = 0;
637*ec779b8eSAndroid Build Coastguard Worker AString blockRatesStr;
638*ec779b8eSAndroid Build Coastguard Worker if (format->findString("blocks-per-second-range", &blockRatesStr)) {
639*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int64_t>> blockRates
640*ec779b8eSAndroid Build Coastguard Worker = Range<int64_t>::Parse(std::string(blockRatesStr.c_str()));
641*ec779b8eSAndroid Build Coastguard Worker if (blockRates) {
642*ec779b8eSAndroid Build Coastguard Worker // ToDo: Catch the potential overflow issue.
643*ec779b8eSAndroid Build Coastguard Worker SR = BS * blockRates.value().upper();
644*ec779b8eSAndroid Build Coastguard Worker }
645*ec779b8eSAndroid Build Coastguard Worker }
646*ec779b8eSAndroid Build Coastguard Worker
647*ec779b8eSAndroid Build Coastguard Worker int32_t D = 0;
648*ec779b8eSAndroid Build Coastguard Worker AString dimensionRangesStr;
649*ec779b8eSAndroid Build Coastguard Worker if (format->findString("size-range", &dimensionRangesStr)) {
650*ec779b8eSAndroid Build Coastguard Worker std::optional<std::pair<Range<int>, Range<int>>> dimensionRanges =
651*ec779b8eSAndroid Build Coastguard Worker ParseWidthHeightRanges(std::string(dimensionRangesStr.c_str()));
652*ec779b8eSAndroid Build Coastguard Worker if (dimensionRanges) {
653*ec779b8eSAndroid Build Coastguard Worker D = std::max(dimensionRanges.value().first.upper(),
654*ec779b8eSAndroid Build Coastguard Worker dimensionRanges.value().second.upper());
655*ec779b8eSAndroid Build Coastguard Worker }
656*ec779b8eSAndroid Build Coastguard Worker }
657*ec779b8eSAndroid Build Coastguard Worker
658*ec779b8eSAndroid Build Coastguard Worker int32_t BR = 0;
659*ec779b8eSAndroid Build Coastguard Worker AString bitrateRangeStr;
660*ec779b8eSAndroid Build Coastguard Worker if (format->findString("bitrate-range", &bitrateRangeStr)) {
661*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int>> bitRates = Range<int32_t>::Parse(
662*ec779b8eSAndroid Build Coastguard Worker std::string(bitrateRangeStr.c_str()));
663*ec779b8eSAndroid Build Coastguard Worker if (bitRates) {
664*ec779b8eSAndroid Build Coastguard Worker BR = divUp(bitRates.value().upper(), 1000);
665*ec779b8eSAndroid Build Coastguard Worker }
666*ec779b8eSAndroid Build Coastguard Worker }
667*ec779b8eSAndroid Build Coastguard Worker
668*ec779b8eSAndroid Build Coastguard Worker if (SR <= 829440 && FS <= 36864 && BR <= 200 && D <= 512)
669*ec779b8eSAndroid Build Coastguard Worker return VP9Level1;
670*ec779b8eSAndroid Build Coastguard Worker if (SR <= 2764800 && FS <= 73728 && BR <= 800 && D <= 768)
671*ec779b8eSAndroid Build Coastguard Worker return VP9Level11;
672*ec779b8eSAndroid Build Coastguard Worker if (SR <= 4608000 && FS <= 122880 && BR <= 1800 && D <= 960)
673*ec779b8eSAndroid Build Coastguard Worker return VP9Level2;
674*ec779b8eSAndroid Build Coastguard Worker if (SR <= 9216000 && FS <= 245760 && BR <= 3600 && D <= 1344)
675*ec779b8eSAndroid Build Coastguard Worker return VP9Level21;
676*ec779b8eSAndroid Build Coastguard Worker if (SR <= 20736000 && FS <= 552960 && BR <= 7200 && D <= 2048)
677*ec779b8eSAndroid Build Coastguard Worker return VP9Level3;
678*ec779b8eSAndroid Build Coastguard Worker if (SR <= 36864000 && FS <= 983040 && BR <= 12000 && D <= 2752)
679*ec779b8eSAndroid Build Coastguard Worker return VP9Level31;
680*ec779b8eSAndroid Build Coastguard Worker if (SR <= 83558400 && FS <= 2228224 && BR <= 18000 && D <= 4160)
681*ec779b8eSAndroid Build Coastguard Worker return VP9Level4;
682*ec779b8eSAndroid Build Coastguard Worker if (SR <= 160432128 && FS <= 2228224 && BR <= 30000 && D <= 4160)
683*ec779b8eSAndroid Build Coastguard Worker return VP9Level41;
684*ec779b8eSAndroid Build Coastguard Worker if (SR <= 311951360 && FS <= 8912896 && BR <= 60000 && D <= 8384)
685*ec779b8eSAndroid Build Coastguard Worker return VP9Level5;
686*ec779b8eSAndroid Build Coastguard Worker if (SR <= 588251136 && FS <= 8912896 && BR <= 120000 && D <= 8384)
687*ec779b8eSAndroid Build Coastguard Worker return VP9Level51;
688*ec779b8eSAndroid Build Coastguard Worker if (SR <= 1176502272 && FS <= 8912896 && BR <= 180000 && D <= 8384)
689*ec779b8eSAndroid Build Coastguard Worker return VP9Level52;
690*ec779b8eSAndroid Build Coastguard Worker if (SR <= 1176502272 && FS <= 35651584 && BR <= 180000 && D <= 16832)
691*ec779b8eSAndroid Build Coastguard Worker return VP9Level6;
692*ec779b8eSAndroid Build Coastguard Worker if (SR <= 2353004544L && FS <= 35651584 && BR <= 240000 && D <= 16832)
693*ec779b8eSAndroid Build Coastguard Worker return VP9Level61;
694*ec779b8eSAndroid Build Coastguard Worker if (SR <= 4706009088L && FS <= 35651584 && BR <= 480000 && D <= 16832)
695*ec779b8eSAndroid Build Coastguard Worker return VP9Level62;
696*ec779b8eSAndroid Build Coastguard Worker // returning largest level
697*ec779b8eSAndroid Build Coastguard Worker return VP9Level62;
698*ec779b8eSAndroid Build Coastguard Worker }
699*ec779b8eSAndroid Build Coastguard Worker
parseFromInfo(const sp<AMessage> & format)700*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::parseFromInfo(const sp<AMessage> &format) {
701*ec779b8eSAndroid Build Coastguard Worker VideoSize blockSize = VideoSize(mBlockWidth, mBlockHeight);
702*ec779b8eSAndroid Build Coastguard Worker VideoSize alignment = VideoSize(mWidthAlignment, mHeightAlignment);
703*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int32_t>> counts, widths, heights;
704*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int32_t>> frameRates, bitRates;
705*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int64_t>> blockRates;
706*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<Rational>> ratios, blockRatios;
707*ec779b8eSAndroid Build Coastguard Worker
708*ec779b8eSAndroid Build Coastguard Worker AString blockSizeStr;
709*ec779b8eSAndroid Build Coastguard Worker if (format->findString("block-size", &blockSizeStr)) {
710*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> parsedBlockSize
711*ec779b8eSAndroid Build Coastguard Worker = VideoSize::ParseSize(std::string(blockSizeStr.c_str()));
712*ec779b8eSAndroid Build Coastguard Worker blockSize = parsedBlockSize.value_or(blockSize);
713*ec779b8eSAndroid Build Coastguard Worker }
714*ec779b8eSAndroid Build Coastguard Worker AString alignmentStr;
715*ec779b8eSAndroid Build Coastguard Worker if (format->findString("alignment", &alignmentStr)) {
716*ec779b8eSAndroid Build Coastguard Worker std::optional<VideoSize> parsedAlignment
717*ec779b8eSAndroid Build Coastguard Worker = VideoSize::ParseSize(std::string(alignmentStr.c_str()));
718*ec779b8eSAndroid Build Coastguard Worker alignment = parsedAlignment.value_or(alignment);
719*ec779b8eSAndroid Build Coastguard Worker }
720*ec779b8eSAndroid Build Coastguard Worker AString blockCountRangeStr;
721*ec779b8eSAndroid Build Coastguard Worker if (format->findString("block-count-range", &blockCountRangeStr)) {
722*ec779b8eSAndroid Build Coastguard Worker std::optional<Range<int>> parsedBlockCountRange =
723*ec779b8eSAndroid Build Coastguard Worker Range<int32_t>::Parse(std::string(blockCountRangeStr.c_str()));
724*ec779b8eSAndroid Build Coastguard Worker if (parsedBlockCountRange) {
725*ec779b8eSAndroid Build Coastguard Worker counts = parsedBlockCountRange.value();
726*ec779b8eSAndroid Build Coastguard Worker }
727*ec779b8eSAndroid Build Coastguard Worker }
728*ec779b8eSAndroid Build Coastguard Worker AString blockRatesStr;
729*ec779b8eSAndroid Build Coastguard Worker if (format->findString("blocks-per-second-range", &blockRatesStr)) {
730*ec779b8eSAndroid Build Coastguard Worker blockRates = Range<int64_t>::Parse(std::string(blockRatesStr.c_str()));
731*ec779b8eSAndroid Build Coastguard Worker }
732*ec779b8eSAndroid Build Coastguard Worker mMeasuredFrameRates = getMeasuredFrameRates(format);
733*ec779b8eSAndroid Build Coastguard Worker mPerformancePoints = getPerformancePoints(format);
734*ec779b8eSAndroid Build Coastguard Worker AString sizeRangesStr;
735*ec779b8eSAndroid Build Coastguard Worker if (format->findString("size-range", &sizeRangesStr)) {
736*ec779b8eSAndroid Build Coastguard Worker std::optional<std::pair<Range<int>, Range<int>>> sizeRanges =
737*ec779b8eSAndroid Build Coastguard Worker ParseWidthHeightRanges(std::string(sizeRangesStr.c_str()));
738*ec779b8eSAndroid Build Coastguard Worker if (sizeRanges) {
739*ec779b8eSAndroid Build Coastguard Worker widths = sizeRanges.value().first;
740*ec779b8eSAndroid Build Coastguard Worker heights = sizeRanges.value().second;
741*ec779b8eSAndroid Build Coastguard Worker }
742*ec779b8eSAndroid Build Coastguard Worker }
743*ec779b8eSAndroid Build Coastguard Worker // for now this just means using the smaller max size as 2nd
744*ec779b8eSAndroid Build Coastguard Worker // upper limit.
745*ec779b8eSAndroid Build Coastguard Worker // for now we are keeping the profile specific "width/height
746*ec779b8eSAndroid Build Coastguard Worker // in macroblocks" limits.
747*ec779b8eSAndroid Build Coastguard Worker if (format->contains("feature-can-swap-width-height")) {
748*ec779b8eSAndroid Build Coastguard Worker if (widths && heights) {
749*ec779b8eSAndroid Build Coastguard Worker mSmallerDimensionUpperLimit =
750*ec779b8eSAndroid Build Coastguard Worker std::min(widths.value().upper(), heights.value().upper());
751*ec779b8eSAndroid Build Coastguard Worker widths = heights = widths.value().extend(heights.value());
752*ec779b8eSAndroid Build Coastguard Worker } else {
753*ec779b8eSAndroid Build Coastguard Worker ALOGW("feature can-swap-width-height is best used with size-range");
754*ec779b8eSAndroid Build Coastguard Worker mSmallerDimensionUpperLimit =
755*ec779b8eSAndroid Build Coastguard Worker std::min(mWidthRange.upper(), mHeightRange.upper());
756*ec779b8eSAndroid Build Coastguard Worker mWidthRange = mHeightRange = mWidthRange.extend(mHeightRange);
757*ec779b8eSAndroid Build Coastguard Worker }
758*ec779b8eSAndroid Build Coastguard Worker }
759*ec779b8eSAndroid Build Coastguard Worker
760*ec779b8eSAndroid Build Coastguard Worker AString ratioStr;
761*ec779b8eSAndroid Build Coastguard Worker if (format->findString("block-aspect-ratio-range", &ratioStr)) {
762*ec779b8eSAndroid Build Coastguard Worker ratios = Rational::ParseRange(std::string(ratioStr.c_str()));
763*ec779b8eSAndroid Build Coastguard Worker }
764*ec779b8eSAndroid Build Coastguard Worker AString blockRatiosStr;
765*ec779b8eSAndroid Build Coastguard Worker if (format->findString("pixel-aspect-ratio-range", &blockRatiosStr)) {
766*ec779b8eSAndroid Build Coastguard Worker blockRatios = Rational::ParseRange(std::string(blockRatiosStr.c_str()));
767*ec779b8eSAndroid Build Coastguard Worker }
768*ec779b8eSAndroid Build Coastguard Worker AString frameRatesStr;
769*ec779b8eSAndroid Build Coastguard Worker if (format->findString("frame-rate-range", &frameRatesStr)) {
770*ec779b8eSAndroid Build Coastguard Worker frameRates = Range<int32_t>::Parse(std::string(frameRatesStr.c_str()));
771*ec779b8eSAndroid Build Coastguard Worker if (frameRates) {
772*ec779b8eSAndroid Build Coastguard Worker frameRates = frameRates.value().intersect(FRAME_RATE_RANGE);
773*ec779b8eSAndroid Build Coastguard Worker if (frameRates.value().empty()) {
774*ec779b8eSAndroid Build Coastguard Worker ALOGW("frame rate range is out of limits");
775*ec779b8eSAndroid Build Coastguard Worker frameRates = std::nullopt;
776*ec779b8eSAndroid Build Coastguard Worker }
777*ec779b8eSAndroid Build Coastguard Worker }
778*ec779b8eSAndroid Build Coastguard Worker }
779*ec779b8eSAndroid Build Coastguard Worker AString bitRatesStr;
780*ec779b8eSAndroid Build Coastguard Worker if (format->findString("bitrate-range", &bitRatesStr)) {
781*ec779b8eSAndroid Build Coastguard Worker bitRates = Range<int32_t>::Parse(std::string(bitRatesStr.c_str()));
782*ec779b8eSAndroid Build Coastguard Worker if (bitRates) {
783*ec779b8eSAndroid Build Coastguard Worker bitRates = bitRates.value().intersect(BITRATE_RANGE);
784*ec779b8eSAndroid Build Coastguard Worker if (bitRates.value().empty()) {
785*ec779b8eSAndroid Build Coastguard Worker ALOGW("bitrate range is out of limits");
786*ec779b8eSAndroid Build Coastguard Worker bitRates = std::nullopt;
787*ec779b8eSAndroid Build Coastguard Worker }
788*ec779b8eSAndroid Build Coastguard Worker }
789*ec779b8eSAndroid Build Coastguard Worker }
790*ec779b8eSAndroid Build Coastguard Worker
791*ec779b8eSAndroid Build Coastguard Worker if (!IsPowerOfTwo(blockSize.getWidth()) || !IsPowerOfTwo(blockSize.getHeight())
792*ec779b8eSAndroid Build Coastguard Worker || !IsPowerOfTwo(alignment.getWidth()) || !IsPowerOfTwo(alignment.getHeight())) {
793*ec779b8eSAndroid Build Coastguard Worker ALOGE("The widths and heights of blockSizes and alignments must be the power of two."
794*ec779b8eSAndroid Build Coastguard Worker " blockSize width: %d; blockSize height: %d;"
795*ec779b8eSAndroid Build Coastguard Worker " alignment width: %d; alignment height: %d.",
796*ec779b8eSAndroid Build Coastguard Worker blockSize.getWidth(), blockSize.getHeight(),
797*ec779b8eSAndroid Build Coastguard Worker alignment.getWidth(), alignment.getHeight());
798*ec779b8eSAndroid Build Coastguard Worker mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
799*ec779b8eSAndroid Build Coastguard Worker return;
800*ec779b8eSAndroid Build Coastguard Worker }
801*ec779b8eSAndroid Build Coastguard Worker
802*ec779b8eSAndroid Build Coastguard Worker // update block-size and alignment
803*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
804*ec779b8eSAndroid Build Coastguard Worker INT32_MAX, INT32_MAX, INT32_MAX, INT64_MAX,
805*ec779b8eSAndroid Build Coastguard Worker blockSize.getWidth(), blockSize.getHeight(),
806*ec779b8eSAndroid Build Coastguard Worker alignment.getWidth(), alignment.getHeight());
807*ec779b8eSAndroid Build Coastguard Worker
808*ec779b8eSAndroid Build Coastguard Worker if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0 || mAllowMbOverride) {
809*ec779b8eSAndroid Build Coastguard Worker // codec supports profiles that we don't know.
810*ec779b8eSAndroid Build Coastguard Worker // Use supplied values clipped to platform limits
811*ec779b8eSAndroid Build Coastguard Worker if (widths) {
812*ec779b8eSAndroid Build Coastguard Worker mWidthRange = VideoSize::GetAllowedDimensionRange().intersect(widths.value());
813*ec779b8eSAndroid Build Coastguard Worker }
814*ec779b8eSAndroid Build Coastguard Worker if (heights) {
815*ec779b8eSAndroid Build Coastguard Worker mHeightRange = VideoSize::GetAllowedDimensionRange().intersect(heights.value());
816*ec779b8eSAndroid Build Coastguard Worker }
817*ec779b8eSAndroid Build Coastguard Worker if (counts) {
818*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = POSITIVE_INT32.intersect(
819*ec779b8eSAndroid Build Coastguard Worker counts.value().factor(mBlockWidth * mBlockHeight
820*ec779b8eSAndroid Build Coastguard Worker / blockSize.getWidth() / blockSize.getHeight()));
821*ec779b8eSAndroid Build Coastguard Worker }
822*ec779b8eSAndroid Build Coastguard Worker if (blockRates) {
823*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = POSITIVE_INT64.intersect(
824*ec779b8eSAndroid Build Coastguard Worker blockRates.value().factor(mBlockWidth * mBlockHeight
825*ec779b8eSAndroid Build Coastguard Worker / blockSize.getWidth() / blockSize.getHeight()));
826*ec779b8eSAndroid Build Coastguard Worker }
827*ec779b8eSAndroid Build Coastguard Worker if (blockRatios) {
828*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect(
829*ec779b8eSAndroid Build Coastguard Worker Rational::ScaleRange(blockRatios.value(),
830*ec779b8eSAndroid Build Coastguard Worker mBlockHeight / blockSize.getHeight(),
831*ec779b8eSAndroid Build Coastguard Worker mBlockWidth / blockSize.getWidth()));
832*ec779b8eSAndroid Build Coastguard Worker }
833*ec779b8eSAndroid Build Coastguard Worker if (ratios) {
834*ec779b8eSAndroid Build Coastguard Worker mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios.value());
835*ec779b8eSAndroid Build Coastguard Worker }
836*ec779b8eSAndroid Build Coastguard Worker if (frameRates) {
837*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates.value());
838*ec779b8eSAndroid Build Coastguard Worker }
839*ec779b8eSAndroid Build Coastguard Worker if (bitRates) {
840*ec779b8eSAndroid Build Coastguard Worker // only allow bitrate override if unsupported profiles were encountered
841*ec779b8eSAndroid Build Coastguard Worker if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) {
842*ec779b8eSAndroid Build Coastguard Worker mBitrateRange = BITRATE_RANGE.intersect(bitRates.value());
843*ec779b8eSAndroid Build Coastguard Worker } else {
844*ec779b8eSAndroid Build Coastguard Worker mBitrateRange = mBitrateRange.intersect(bitRates.value());
845*ec779b8eSAndroid Build Coastguard Worker }
846*ec779b8eSAndroid Build Coastguard Worker }
847*ec779b8eSAndroid Build Coastguard Worker } else {
848*ec779b8eSAndroid Build Coastguard Worker // no unsupported profile/levels, so restrict values to known limits
849*ec779b8eSAndroid Build Coastguard Worker if (widths) {
850*ec779b8eSAndroid Build Coastguard Worker mWidthRange = mWidthRange.intersect(widths.value());
851*ec779b8eSAndroid Build Coastguard Worker }
852*ec779b8eSAndroid Build Coastguard Worker if (heights) {
853*ec779b8eSAndroid Build Coastguard Worker mHeightRange = mHeightRange.intersect(heights.value());
854*ec779b8eSAndroid Build Coastguard Worker }
855*ec779b8eSAndroid Build Coastguard Worker if (counts) {
856*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = mBlockCountRange.intersect(
857*ec779b8eSAndroid Build Coastguard Worker counts.value().factor(mBlockWidth * mBlockHeight
858*ec779b8eSAndroid Build Coastguard Worker / blockSize.getWidth() / blockSize.getHeight()));
859*ec779b8eSAndroid Build Coastguard Worker }
860*ec779b8eSAndroid Build Coastguard Worker if (blockRates) {
861*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
862*ec779b8eSAndroid Build Coastguard Worker blockRates.value().factor(mBlockWidth * mBlockHeight
863*ec779b8eSAndroid Build Coastguard Worker / blockSize.getWidth() / blockSize.getHeight()));
864*ec779b8eSAndroid Build Coastguard Worker }
865*ec779b8eSAndroid Build Coastguard Worker if (blockRatios) {
866*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
867*ec779b8eSAndroid Build Coastguard Worker Rational::ScaleRange(blockRatios.value(),
868*ec779b8eSAndroid Build Coastguard Worker mBlockHeight / blockSize.getHeight(),
869*ec779b8eSAndroid Build Coastguard Worker mBlockWidth / blockSize.getWidth()));
870*ec779b8eSAndroid Build Coastguard Worker }
871*ec779b8eSAndroid Build Coastguard Worker if (ratios) {
872*ec779b8eSAndroid Build Coastguard Worker mAspectRatioRange = mAspectRatioRange.intersect(ratios.value());
873*ec779b8eSAndroid Build Coastguard Worker }
874*ec779b8eSAndroid Build Coastguard Worker if (frameRates) {
875*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = mFrameRateRange.intersect(frameRates.value());
876*ec779b8eSAndroid Build Coastguard Worker }
877*ec779b8eSAndroid Build Coastguard Worker if (bitRates) {
878*ec779b8eSAndroid Build Coastguard Worker mBitrateRange = mBitrateRange.intersect(bitRates.value());
879*ec779b8eSAndroid Build Coastguard Worker }
880*ec779b8eSAndroid Build Coastguard Worker }
881*ec779b8eSAndroid Build Coastguard Worker updateLimits();
882*ec779b8eSAndroid Build Coastguard Worker }
883*ec779b8eSAndroid Build Coastguard Worker
applyBlockLimits(int32_t blockWidth,int32_t blockHeight,Range<int32_t> counts,Range<int64_t> rates,Range<Rational> ratios)884*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::applyBlockLimits(
885*ec779b8eSAndroid Build Coastguard Worker int32_t blockWidth, int32_t blockHeight,
886*ec779b8eSAndroid Build Coastguard Worker Range<int32_t> counts, Range<int64_t> rates, Range<Rational> ratios) {
887*ec779b8eSAndroid Build Coastguard Worker
888*ec779b8eSAndroid Build Coastguard Worker if (!IsPowerOfTwo(blockWidth) || !IsPowerOfTwo(blockHeight)) {
889*ec779b8eSAndroid Build Coastguard Worker ALOGE("blockWidth and blockHeight must be the power of two."
890*ec779b8eSAndroid Build Coastguard Worker " blockWidth: %d; blockHeight: %d", blockWidth, blockHeight);
891*ec779b8eSAndroid Build Coastguard Worker mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
892*ec779b8eSAndroid Build Coastguard Worker return;
893*ec779b8eSAndroid Build Coastguard Worker }
894*ec779b8eSAndroid Build Coastguard Worker
895*ec779b8eSAndroid Build Coastguard Worker const int32_t newBlockWidth = std::max(blockWidth, mBlockWidth);
896*ec779b8eSAndroid Build Coastguard Worker const int32_t newBlockHeight = std::max(blockHeight, mBlockHeight);
897*ec779b8eSAndroid Build Coastguard Worker
898*ec779b8eSAndroid Build Coastguard Worker // factor will always be a power-of-2
899*ec779b8eSAndroid Build Coastguard Worker int32_t factor =
900*ec779b8eSAndroid Build Coastguard Worker newBlockWidth * newBlockHeight / mBlockWidth / mBlockHeight;
901*ec779b8eSAndroid Build Coastguard Worker if (factor != 1) {
902*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = mBlockCountRange.factor(factor);
903*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = mBlocksPerSecondRange.factor(factor);
904*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = Rational::ScaleRange(
905*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange,
906*ec779b8eSAndroid Build Coastguard Worker newBlockHeight / mBlockHeight,
907*ec779b8eSAndroid Build Coastguard Worker newBlockWidth / mBlockWidth);
908*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange = mHorizontalBlockRange.factor(newBlockWidth / mBlockWidth);
909*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange = mVerticalBlockRange.factor(newBlockHeight / mBlockHeight);
910*ec779b8eSAndroid Build Coastguard Worker }
911*ec779b8eSAndroid Build Coastguard Worker factor = newBlockWidth * newBlockHeight / blockWidth / blockHeight;
912*ec779b8eSAndroid Build Coastguard Worker if (factor != 1) {
913*ec779b8eSAndroid Build Coastguard Worker counts = counts.factor(factor);
914*ec779b8eSAndroid Build Coastguard Worker rates = rates.factor((int64_t)factor);
915*ec779b8eSAndroid Build Coastguard Worker ratios = Rational::ScaleRange(
916*ec779b8eSAndroid Build Coastguard Worker ratios, newBlockHeight / blockHeight,
917*ec779b8eSAndroid Build Coastguard Worker newBlockWidth / blockWidth);
918*ec779b8eSAndroid Build Coastguard Worker }
919*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = mBlockCountRange.intersect(counts);
920*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(rates);
921*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(ratios);
922*ec779b8eSAndroid Build Coastguard Worker mBlockWidth = newBlockWidth;
923*ec779b8eSAndroid Build Coastguard Worker mBlockHeight = newBlockHeight;
924*ec779b8eSAndroid Build Coastguard Worker }
925*ec779b8eSAndroid Build Coastguard Worker
applyAlignment(int32_t widthAlignment,int32_t heightAlignment)926*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::applyAlignment(
927*ec779b8eSAndroid Build Coastguard Worker int32_t widthAlignment, int32_t heightAlignment) {
928*ec779b8eSAndroid Build Coastguard Worker if (!IsPowerOfTwo(widthAlignment) || !IsPowerOfTwo(heightAlignment)) {
929*ec779b8eSAndroid Build Coastguard Worker ALOGE("width and height alignments must be the power of two."
930*ec779b8eSAndroid Build Coastguard Worker " widthAlignment: %d; heightAlignment: %d", widthAlignment, heightAlignment);
931*ec779b8eSAndroid Build Coastguard Worker mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
932*ec779b8eSAndroid Build Coastguard Worker return;
933*ec779b8eSAndroid Build Coastguard Worker }
934*ec779b8eSAndroid Build Coastguard Worker
935*ec779b8eSAndroid Build Coastguard Worker if (widthAlignment > mBlockWidth || heightAlignment > mBlockHeight) {
936*ec779b8eSAndroid Build Coastguard Worker // maintain assumption that 0 < alignment <= block-size
937*ec779b8eSAndroid Build Coastguard Worker applyBlockLimits(
938*ec779b8eSAndroid Build Coastguard Worker std::max(widthAlignment, mBlockWidth),
939*ec779b8eSAndroid Build Coastguard Worker std::max(heightAlignment, mBlockHeight),
940*ec779b8eSAndroid Build Coastguard Worker POSITIVE_INT32, POSITIVE_INT64, POSITIVE_RATIONALS);
941*ec779b8eSAndroid Build Coastguard Worker }
942*ec779b8eSAndroid Build Coastguard Worker
943*ec779b8eSAndroid Build Coastguard Worker mWidthAlignment = std::max(widthAlignment, mWidthAlignment);
944*ec779b8eSAndroid Build Coastguard Worker mHeightAlignment = std::max(heightAlignment, mHeightAlignment);
945*ec779b8eSAndroid Build Coastguard Worker
946*ec779b8eSAndroid Build Coastguard Worker mWidthRange = mWidthRange.align(mWidthAlignment);
947*ec779b8eSAndroid Build Coastguard Worker mHeightRange = mHeightRange.align(mHeightAlignment);
948*ec779b8eSAndroid Build Coastguard Worker }
949*ec779b8eSAndroid Build Coastguard Worker
updateLimits()950*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::updateLimits() {
951*ec779b8eSAndroid Build Coastguard Worker // pixels -> blocks <- counts
952*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange = mHorizontalBlockRange.intersect(
953*ec779b8eSAndroid Build Coastguard Worker mWidthRange.factor(mBlockWidth));
954*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange = mHorizontalBlockRange.intersect(
955*ec779b8eSAndroid Build Coastguard Worker Range( mBlockCountRange.lower() / mVerticalBlockRange.upper(),
956*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.upper() / mVerticalBlockRange.lower()));
957*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange = mVerticalBlockRange.intersect(
958*ec779b8eSAndroid Build Coastguard Worker mHeightRange.factor(mBlockHeight));
959*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange = mVerticalBlockRange.intersect(
960*ec779b8eSAndroid Build Coastguard Worker Range( mBlockCountRange.lower() / mHorizontalBlockRange.upper(),
961*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.upper() / mHorizontalBlockRange.lower()));
962*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange = mBlockCountRange.intersect(
963*ec779b8eSAndroid Build Coastguard Worker Range( mHorizontalBlockRange.lower()
964*ec779b8eSAndroid Build Coastguard Worker * mVerticalBlockRange.lower(),
965*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange.upper()
966*ec779b8eSAndroid Build Coastguard Worker * mVerticalBlockRange.upper()));
967*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange = mBlockAspectRatioRange.intersect(
968*ec779b8eSAndroid Build Coastguard Worker Rational(mHorizontalBlockRange.lower(), mVerticalBlockRange.upper()),
969*ec779b8eSAndroid Build Coastguard Worker Rational(mHorizontalBlockRange.upper(), mVerticalBlockRange.lower()));
970*ec779b8eSAndroid Build Coastguard Worker
971*ec779b8eSAndroid Build Coastguard Worker // blocks -> pixels
972*ec779b8eSAndroid Build Coastguard Worker mWidthRange = mWidthRange.intersect(
973*ec779b8eSAndroid Build Coastguard Worker (mHorizontalBlockRange.lower() - 1) * mBlockWidth + mWidthAlignment,
974*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange.upper() * mBlockWidth);
975*ec779b8eSAndroid Build Coastguard Worker mHeightRange = mHeightRange.intersect(
976*ec779b8eSAndroid Build Coastguard Worker (mVerticalBlockRange.lower() - 1) * mBlockHeight + mHeightAlignment,
977*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange.upper() * mBlockHeight);
978*ec779b8eSAndroid Build Coastguard Worker mAspectRatioRange = mAspectRatioRange.intersect(
979*ec779b8eSAndroid Build Coastguard Worker Rational(mWidthRange.lower(), mHeightRange.upper()),
980*ec779b8eSAndroid Build Coastguard Worker Rational(mWidthRange.upper(), mHeightRange.lower()));
981*ec779b8eSAndroid Build Coastguard Worker
982*ec779b8eSAndroid Build Coastguard Worker mSmallerDimensionUpperLimit = std::min(
983*ec779b8eSAndroid Build Coastguard Worker mSmallerDimensionUpperLimit,
984*ec779b8eSAndroid Build Coastguard Worker std::min(mWidthRange.upper(), mHeightRange.upper()));
985*ec779b8eSAndroid Build Coastguard Worker
986*ec779b8eSAndroid Build Coastguard Worker // blocks -> rate
987*ec779b8eSAndroid Build Coastguard Worker mBlocksPerSecondRange = mBlocksPerSecondRange.intersect(
988*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.lower() * (int64_t)mFrameRateRange.lower(),
989*ec779b8eSAndroid Build Coastguard Worker mBlockCountRange.upper() * (int64_t)mFrameRateRange.upper());
990*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = mFrameRateRange.intersect(
991*ec779b8eSAndroid Build Coastguard Worker (int32_t)(mBlocksPerSecondRange.lower()
992*ec779b8eSAndroid Build Coastguard Worker / mBlockCountRange.upper()),
993*ec779b8eSAndroid Build Coastguard Worker (int32_t)(mBlocksPerSecondRange.upper()
994*ec779b8eSAndroid Build Coastguard Worker / (double)mBlockCountRange.lower()));
995*ec779b8eSAndroid Build Coastguard Worker }
996*ec779b8eSAndroid Build Coastguard Worker
applyMacroBlockLimits(int32_t maxHorizontalBlocks,int32_t maxVerticalBlocks,int32_t maxBlocks,int64_t maxBlocksPerSecond,int32_t blockWidth,int32_t blockHeight,int32_t widthAlignment,int32_t heightAlignment)997*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::applyMacroBlockLimits(
998*ec779b8eSAndroid Build Coastguard Worker int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
999*ec779b8eSAndroid Build Coastguard Worker int32_t maxBlocks, int64_t maxBlocksPerSecond,
1000*ec779b8eSAndroid Build Coastguard Worker int32_t blockWidth, int32_t blockHeight,
1001*ec779b8eSAndroid Build Coastguard Worker int32_t widthAlignment, int32_t heightAlignment) {
1002*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1003*ec779b8eSAndroid Build Coastguard Worker 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */,
1004*ec779b8eSAndroid Build Coastguard Worker maxHorizontalBlocks, maxVerticalBlocks,
1005*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1006*ec779b8eSAndroid Build Coastguard Worker blockWidth, blockHeight, widthAlignment, heightAlignment);
1007*ec779b8eSAndroid Build Coastguard Worker }
1008*ec779b8eSAndroid Build Coastguard Worker
applyMacroBlockLimits(int32_t minHorizontalBlocks,int32_t minVerticalBlocks,int32_t maxHorizontalBlocks,int32_t maxVerticalBlocks,int32_t maxBlocks,int64_t maxBlocksPerSecond,int32_t blockWidth,int32_t blockHeight,int32_t widthAlignment,int32_t heightAlignment)1009*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::applyMacroBlockLimits(
1010*ec779b8eSAndroid Build Coastguard Worker int32_t minHorizontalBlocks, int32_t minVerticalBlocks,
1011*ec779b8eSAndroid Build Coastguard Worker int32_t maxHorizontalBlocks, int32_t maxVerticalBlocks,
1012*ec779b8eSAndroid Build Coastguard Worker int32_t maxBlocks, int64_t maxBlocksPerSecond,
1013*ec779b8eSAndroid Build Coastguard Worker int32_t blockWidth, int32_t blockHeight,
1014*ec779b8eSAndroid Build Coastguard Worker int32_t widthAlignment, int32_t heightAlignment) {
1015*ec779b8eSAndroid Build Coastguard Worker applyAlignment(widthAlignment, heightAlignment);
1016*ec779b8eSAndroid Build Coastguard Worker applyBlockLimits(
1017*ec779b8eSAndroid Build Coastguard Worker blockWidth, blockHeight, Range((int32_t)1, maxBlocks),
1018*ec779b8eSAndroid Build Coastguard Worker Range((int64_t)1, maxBlocksPerSecond),
1019*ec779b8eSAndroid Build Coastguard Worker Range(Rational(1, maxVerticalBlocks), Rational(maxHorizontalBlocks, 1)));
1020*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange =
1021*ec779b8eSAndroid Build Coastguard Worker mHorizontalBlockRange.intersect(
1022*ec779b8eSAndroid Build Coastguard Worker divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)),
1023*ec779b8eSAndroid Build Coastguard Worker maxHorizontalBlocks / (mBlockWidth / blockWidth));
1024*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange =
1025*ec779b8eSAndroid Build Coastguard Worker mVerticalBlockRange.intersect(
1026*ec779b8eSAndroid Build Coastguard Worker divUp(minVerticalBlocks, (mBlockHeight / blockHeight)),
1027*ec779b8eSAndroid Build Coastguard Worker maxVerticalBlocks / (mBlockHeight / blockHeight));
1028*ec779b8eSAndroid Build Coastguard Worker }
1029*ec779b8eSAndroid Build Coastguard Worker
applyLevelLimits()1030*ec779b8eSAndroid Build Coastguard Worker void VideoCapabilities::applyLevelLimits() {
1031*ec779b8eSAndroid Build Coastguard Worker int64_t maxBlocksPerSecond = 0;
1032*ec779b8eSAndroid Build Coastguard Worker int32_t maxBlocks = 0;
1033*ec779b8eSAndroid Build Coastguard Worker int32_t maxBps = 0;
1034*ec779b8eSAndroid Build Coastguard Worker int32_t maxDPBBlocks = 0;
1035*ec779b8eSAndroid Build Coastguard Worker
1036*ec779b8eSAndroid Build Coastguard Worker int errors = ERROR_CAPABILITIES_NONE_SUPPORTED;
1037*ec779b8eSAndroid Build Coastguard Worker const char *mediaType = mMediaType.c_str();
1038*ec779b8eSAndroid Build Coastguard Worker if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_AVC)) {
1039*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 99;
1040*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 1485;
1041*ec779b8eSAndroid Build Coastguard Worker maxBps = 64000;
1042*ec779b8eSAndroid Build Coastguard Worker maxDPBBlocks = 396;
1043*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1044*ec779b8eSAndroid Build Coastguard Worker int32_t MBPS = 0, FS = 0, BR = 0, DPB = 0;
1045*ec779b8eSAndroid Build Coastguard Worker bool supported = true;
1046*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1047*ec779b8eSAndroid Build Coastguard Worker case AVCLevel1:
1048*ec779b8eSAndroid Build Coastguard Worker MBPS = 1485; FS = 99; BR = 64; DPB = 396; break;
1049*ec779b8eSAndroid Build Coastguard Worker case AVCLevel1b:
1050*ec779b8eSAndroid Build Coastguard Worker MBPS = 1485; FS = 99; BR = 128; DPB = 396; break;
1051*ec779b8eSAndroid Build Coastguard Worker case AVCLevel11:
1052*ec779b8eSAndroid Build Coastguard Worker MBPS = 3000; FS = 396; BR = 192; DPB = 900; break;
1053*ec779b8eSAndroid Build Coastguard Worker case AVCLevel12:
1054*ec779b8eSAndroid Build Coastguard Worker MBPS = 6000; FS = 396; BR = 384; DPB = 2376; break;
1055*ec779b8eSAndroid Build Coastguard Worker case AVCLevel13:
1056*ec779b8eSAndroid Build Coastguard Worker MBPS = 11880; FS = 396; BR = 768; DPB = 2376; break;
1057*ec779b8eSAndroid Build Coastguard Worker case AVCLevel2:
1058*ec779b8eSAndroid Build Coastguard Worker MBPS = 11880; FS = 396; BR = 2000; DPB = 2376; break;
1059*ec779b8eSAndroid Build Coastguard Worker case AVCLevel21:
1060*ec779b8eSAndroid Build Coastguard Worker MBPS = 19800; FS = 792; BR = 4000; DPB = 4752; break;
1061*ec779b8eSAndroid Build Coastguard Worker case AVCLevel22:
1062*ec779b8eSAndroid Build Coastguard Worker MBPS = 20250; FS = 1620; BR = 4000; DPB = 8100; break;
1063*ec779b8eSAndroid Build Coastguard Worker case AVCLevel3:
1064*ec779b8eSAndroid Build Coastguard Worker MBPS = 40500; FS = 1620; BR = 10000; DPB = 8100; break;
1065*ec779b8eSAndroid Build Coastguard Worker case AVCLevel31:
1066*ec779b8eSAndroid Build Coastguard Worker MBPS = 108000; FS = 3600; BR = 14000; DPB = 18000; break;
1067*ec779b8eSAndroid Build Coastguard Worker case AVCLevel32:
1068*ec779b8eSAndroid Build Coastguard Worker MBPS = 216000; FS = 5120; BR = 20000; DPB = 20480; break;
1069*ec779b8eSAndroid Build Coastguard Worker case AVCLevel4:
1070*ec779b8eSAndroid Build Coastguard Worker MBPS = 245760; FS = 8192; BR = 20000; DPB = 32768; break;
1071*ec779b8eSAndroid Build Coastguard Worker case AVCLevel41:
1072*ec779b8eSAndroid Build Coastguard Worker MBPS = 245760; FS = 8192; BR = 50000; DPB = 32768; break;
1073*ec779b8eSAndroid Build Coastguard Worker case AVCLevel42:
1074*ec779b8eSAndroid Build Coastguard Worker MBPS = 522240; FS = 8704; BR = 50000; DPB = 34816; break;
1075*ec779b8eSAndroid Build Coastguard Worker case AVCLevel5:
1076*ec779b8eSAndroid Build Coastguard Worker MBPS = 589824; FS = 22080; BR = 135000; DPB = 110400; break;
1077*ec779b8eSAndroid Build Coastguard Worker case AVCLevel51:
1078*ec779b8eSAndroid Build Coastguard Worker MBPS = 983040; FS = 36864; BR = 240000; DPB = 184320; break;
1079*ec779b8eSAndroid Build Coastguard Worker case AVCLevel52:
1080*ec779b8eSAndroid Build Coastguard Worker MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
1081*ec779b8eSAndroid Build Coastguard Worker case AVCLevel6:
1082*ec779b8eSAndroid Build Coastguard Worker MBPS = 4177920; FS = 139264; BR = 240000; DPB = 696320; break;
1083*ec779b8eSAndroid Build Coastguard Worker case AVCLevel61:
1084*ec779b8eSAndroid Build Coastguard Worker MBPS = 8355840; FS = 139264; BR = 480000; DPB = 696320; break;
1085*ec779b8eSAndroid Build Coastguard Worker case AVCLevel62:
1086*ec779b8eSAndroid Build Coastguard Worker MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break;
1087*ec779b8eSAndroid Build Coastguard Worker default:
1088*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
1089*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1090*ec779b8eSAndroid Build Coastguard Worker }
1091*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1092*ec779b8eSAndroid Build Coastguard Worker case AVCProfileConstrainedHigh:
1093*ec779b8eSAndroid Build Coastguard Worker case AVCProfileHigh:
1094*ec779b8eSAndroid Build Coastguard Worker BR *= 1250; break;
1095*ec779b8eSAndroid Build Coastguard Worker case AVCProfileHigh10:
1096*ec779b8eSAndroid Build Coastguard Worker BR *= 3000; break;
1097*ec779b8eSAndroid Build Coastguard Worker case AVCProfileExtended:
1098*ec779b8eSAndroid Build Coastguard Worker case AVCProfileHigh422:
1099*ec779b8eSAndroid Build Coastguard Worker case AVCProfileHigh444:
1100*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
1101*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1102*ec779b8eSAndroid Build Coastguard Worker supported = false;
1103*ec779b8eSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
1104*ec779b8eSAndroid Build Coastguard Worker // fall through - treat as base profile
1105*ec779b8eSAndroid Build Coastguard Worker case AVCProfileConstrainedBaseline:
1106*ec779b8eSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
1107*ec779b8eSAndroid Build Coastguard Worker case AVCProfileBaseline:
1108*ec779b8eSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
1109*ec779b8eSAndroid Build Coastguard Worker case AVCProfileMain:
1110*ec779b8eSAndroid Build Coastguard Worker BR *= 1000; break;
1111*ec779b8eSAndroid Build Coastguard Worker default:
1112*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1113*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1114*ec779b8eSAndroid Build Coastguard Worker BR *= 1000;
1115*ec779b8eSAndroid Build Coastguard Worker }
1116*ec779b8eSAndroid Build Coastguard Worker if (supported) {
1117*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1118*ec779b8eSAndroid Build Coastguard Worker }
1119*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
1120*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1121*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR, maxBps);
1122*ec779b8eSAndroid Build Coastguard Worker maxDPBBlocks = std::max(maxDPBBlocks, DPB);
1123*ec779b8eSAndroid Build Coastguard Worker }
1124*ec779b8eSAndroid Build Coastguard Worker
1125*ec779b8eSAndroid Build Coastguard Worker int32_t maxLengthInBlocks = (int32_t)(std::sqrt(8 * maxBlocks));
1126*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1127*ec779b8eSAndroid Build Coastguard Worker maxLengthInBlocks, maxLengthInBlocks,
1128*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1129*ec779b8eSAndroid Build Coastguard Worker 16 /* blockWidth */, 16 /* blockHeight */,
1130*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1131*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG2)) {
1132*ec779b8eSAndroid Build Coastguard Worker int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
1133*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 99;
1134*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 1485;
1135*ec779b8eSAndroid Build Coastguard Worker maxBps = 64000;
1136*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1137*ec779b8eSAndroid Build Coastguard Worker int32_t MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
1138*ec779b8eSAndroid Build Coastguard Worker bool supported = true;
1139*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1140*ec779b8eSAndroid Build Coastguard Worker case MPEG2ProfileSimple:
1141*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1142*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelML:
1143*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break;
1144*ec779b8eSAndroid Build Coastguard Worker default:
1145*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile/level %d/%d for %s",
1146*ec779b8eSAndroid Build Coastguard Worker profileLevel.mProfile, profileLevel.mLevel, mediaType);
1147*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1148*ec779b8eSAndroid Build Coastguard Worker }
1149*ec779b8eSAndroid Build Coastguard Worker break;
1150*ec779b8eSAndroid Build Coastguard Worker case MPEG2ProfileMain:
1151*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1152*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelLL:
1153*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break;
1154*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelML:
1155*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break;
1156*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelH14:
1157*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break;
1158*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelHL:
1159*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 120; H = 68; MBPS = 244800; FS = 8160; BR = 80000; break;
1160*ec779b8eSAndroid Build Coastguard Worker case MPEG2LevelHP:
1161*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 120; H = 68; MBPS = 489600; FS = 8160; BR = 80000; break;
1162*ec779b8eSAndroid Build Coastguard Worker default:
1163*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile/level %d / %d for %s",
1164*ec779b8eSAndroid Build Coastguard Worker profileLevel.mProfile, profileLevel.mLevel, mediaType);
1165*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1166*ec779b8eSAndroid Build Coastguard Worker }
1167*ec779b8eSAndroid Build Coastguard Worker break;
1168*ec779b8eSAndroid Build Coastguard Worker case MPEG2Profile422:
1169*ec779b8eSAndroid Build Coastguard Worker case MPEG2ProfileSNR:
1170*ec779b8eSAndroid Build Coastguard Worker case MPEG2ProfileSpatial:
1171*ec779b8eSAndroid Build Coastguard Worker case MPEG2ProfileHigh:
1172*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
1173*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNSUPPORTED;
1174*ec779b8eSAndroid Build Coastguard Worker supported = false;
1175*ec779b8eSAndroid Build Coastguard Worker break;
1176*ec779b8eSAndroid Build Coastguard Worker default:
1177*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1178*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1179*ec779b8eSAndroid Build Coastguard Worker }
1180*ec779b8eSAndroid Build Coastguard Worker if (supported) {
1181*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1182*ec779b8eSAndroid Build Coastguard Worker }
1183*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
1184*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1185*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR * 1000, maxBps);
1186*ec779b8eSAndroid Build Coastguard Worker maxWidth = std::max(W, maxWidth);
1187*ec779b8eSAndroid Build Coastguard Worker maxHeight = std::max(H, maxHeight);
1188*ec779b8eSAndroid Build Coastguard Worker maxRate = std::max(FR, maxRate);
1189*ec779b8eSAndroid Build Coastguard Worker }
1190*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(maxWidth, maxHeight,
1191*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1192*ec779b8eSAndroid Build Coastguard Worker 16 /* blockWidth */, 16 /* blockHeight */,
1193*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1194*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
1195*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) {
1196*ec779b8eSAndroid Build Coastguard Worker int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
1197*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 99;
1198*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 1485;
1199*ec779b8eSAndroid Build Coastguard Worker maxBps = 64000;
1200*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1201*ec779b8eSAndroid Build Coastguard Worker int32_t MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0;
1202*ec779b8eSAndroid Build Coastguard Worker bool strict = false; // true: W, H and FR are individual max limits
1203*ec779b8eSAndroid Build Coastguard Worker bool supported = true;
1204*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1205*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileSimple:
1206*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1207*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level0:
1208*ec779b8eSAndroid Build Coastguard Worker strict = true;
1209*ec779b8eSAndroid Build Coastguard Worker FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break;
1210*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level1:
1211*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break;
1212*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level0b:
1213*ec779b8eSAndroid Build Coastguard Worker strict = true;
1214*ec779b8eSAndroid Build Coastguard Worker FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break;
1215*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level2:
1216*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break;
1217*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level3:
1218*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
1219*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level4a:
1220*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
1221*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level5:
1222*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
1223*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level6:
1224*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
1225*ec779b8eSAndroid Build Coastguard Worker default:
1226*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile/level %d/%d for %s",
1227*ec779b8eSAndroid Build Coastguard Worker profileLevel.mProfile, profileLevel.mLevel, mediaType);
1228*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1229*ec779b8eSAndroid Build Coastguard Worker }
1230*ec779b8eSAndroid Build Coastguard Worker break;
1231*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileAdvancedSimple:
1232*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1233*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level0:
1234*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level1:
1235*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 11; H = 9; MBPS = 2970; FS = 99; BR = 128; break;
1236*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level2:
1237*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 384; break;
1238*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level3:
1239*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 768; break;
1240*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level3b:
1241*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 1500; break;
1242*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level4:
1243*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 44; H = 36; MBPS = 23760; FS = 792; BR = 3000; break;
1244*ec779b8eSAndroid Build Coastguard Worker case MPEG4Level5:
1245*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
1246*ec779b8eSAndroid Build Coastguard Worker default:
1247*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile/level %d/%d for %s",
1248*ec779b8eSAndroid Build Coastguard Worker profileLevel.mProfile, profileLevel.mLevel, mediaType);
1249*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1250*ec779b8eSAndroid Build Coastguard Worker }
1251*ec779b8eSAndroid Build Coastguard Worker break;
1252*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileMain: // 2-4
1253*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileNbit: // 2
1254*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileAdvancedRealTime: // 1-4
1255*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileCoreScalable: // 1-3
1256*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileAdvancedCoding: // 1-4
1257*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileCore: // 1-2
1258*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileAdvancedCore: // 1-4
1259*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileSimpleScalable: // 0-2
1260*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileHybrid: // 1-2
1261*ec779b8eSAndroid Build Coastguard Worker
1262*ec779b8eSAndroid Build Coastguard Worker // Studio profiles are not supported by our codecs.
1263*ec779b8eSAndroid Build Coastguard Worker
1264*ec779b8eSAndroid Build Coastguard Worker // Only profiles that can decode simple object types are considered.
1265*ec779b8eSAndroid Build Coastguard Worker // The following profiles are not able to.
1266*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileBasicAnimated: // 1-2
1267*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileScalableTexture: // 1
1268*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileSimpleFace: // 1-2
1269*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileAdvancedScalable: // 1-3
1270*ec779b8eSAndroid Build Coastguard Worker case MPEG4ProfileSimpleFBA: // 1-2
1271*ec779b8eSAndroid Build Coastguard Worker ALOGV("Unsupported profile %d for %s", profileLevel.mProfile, mediaType);
1272*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNSUPPORTED;
1273*ec779b8eSAndroid Build Coastguard Worker supported = false;
1274*ec779b8eSAndroid Build Coastguard Worker break;
1275*ec779b8eSAndroid Build Coastguard Worker default:
1276*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1277*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1278*ec779b8eSAndroid Build Coastguard Worker }
1279*ec779b8eSAndroid Build Coastguard Worker if (supported) {
1280*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1281*ec779b8eSAndroid Build Coastguard Worker }
1282*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
1283*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1284*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR * 1000, maxBps);
1285*ec779b8eSAndroid Build Coastguard Worker if (strict) {
1286*ec779b8eSAndroid Build Coastguard Worker maxWidth = std::max(W, maxWidth);
1287*ec779b8eSAndroid Build Coastguard Worker maxHeight = std::max(H, maxHeight);
1288*ec779b8eSAndroid Build Coastguard Worker maxRate = std::max(FR, maxRate);
1289*ec779b8eSAndroid Build Coastguard Worker } else {
1290*ec779b8eSAndroid Build Coastguard Worker // assuming max 60 fps frame rate and 1:2 aspect ratio
1291*ec779b8eSAndroid Build Coastguard Worker int32_t maxDim = (int32_t)std::sqrt(2 * FS);
1292*ec779b8eSAndroid Build Coastguard Worker maxWidth = std::max(maxDim, maxWidth);
1293*ec779b8eSAndroid Build Coastguard Worker maxHeight = std::max(maxDim, maxHeight);
1294*ec779b8eSAndroid Build Coastguard Worker maxRate = std::max(std::max(FR, 60), maxRate);
1295*ec779b8eSAndroid Build Coastguard Worker }
1296*ec779b8eSAndroid Build Coastguard Worker }
1297*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(maxWidth, maxHeight,
1298*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1299*ec779b8eSAndroid Build Coastguard Worker 16 /* blockWidth */, 16 /* blockHeight */,
1300*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1301*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = mFrameRateRange.intersect(12, maxRate);
1302*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) {
1303*ec779b8eSAndroid Build Coastguard Worker int32_t maxWidth = 11, maxHeight = 9, maxRate = 15;
1304*ec779b8eSAndroid Build Coastguard Worker int32_t minWidth = maxWidth, minHeight = maxHeight;
1305*ec779b8eSAndroid Build Coastguard Worker int32_t minAlignment = 16;
1306*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 99;
1307*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 1485;
1308*ec779b8eSAndroid Build Coastguard Worker maxBps = 64000;
1309*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1310*ec779b8eSAndroid Build Coastguard Worker int32_t MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight;
1311*ec779b8eSAndroid Build Coastguard Worker bool strict = false; // true: support only sQCIF, QCIF (maybe CIF)
1312*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1313*ec779b8eSAndroid Build Coastguard Worker case H263Level10:
1314*ec779b8eSAndroid Build Coastguard Worker strict = true; // only supports sQCIF & QCIF
1315*ec779b8eSAndroid Build Coastguard Worker FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break;
1316*ec779b8eSAndroid Build Coastguard Worker case H263Level20:
1317*ec779b8eSAndroid Build Coastguard Worker strict = true; // only supports sQCIF, QCIF & CIF
1318*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break;
1319*ec779b8eSAndroid Build Coastguard Worker case H263Level30:
1320*ec779b8eSAndroid Build Coastguard Worker strict = true; // only supports sQCIF, QCIF & CIF
1321*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break;
1322*ec779b8eSAndroid Build Coastguard Worker case H263Level40:
1323*ec779b8eSAndroid Build Coastguard Worker strict = true; // only supports sQCIF, QCIF & CIF
1324*ec779b8eSAndroid Build Coastguard Worker FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break;
1325*ec779b8eSAndroid Build Coastguard Worker case H263Level45:
1326*ec779b8eSAndroid Build Coastguard Worker // only implies level 10 support
1327*ec779b8eSAndroid Build Coastguard Worker strict = profileLevel.mProfile == H263ProfileBaseline
1328*ec779b8eSAndroid Build Coastguard Worker || profileLevel.mProfile ==
1329*ec779b8eSAndroid Build Coastguard Worker H263ProfileBackwardCompatible;
1330*ec779b8eSAndroid Build Coastguard Worker if (!strict) {
1331*ec779b8eSAndroid Build Coastguard Worker minW = 1; minH = 1; minAlignment = 4;
1332*ec779b8eSAndroid Build Coastguard Worker }
1333*ec779b8eSAndroid Build Coastguard Worker FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break;
1334*ec779b8eSAndroid Build Coastguard Worker case H263Level50:
1335*ec779b8eSAndroid Build Coastguard Worker // only supports 50fps for H > 15
1336*ec779b8eSAndroid Build Coastguard Worker minW = 1; minH = 1; minAlignment = 4;
1337*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break;
1338*ec779b8eSAndroid Build Coastguard Worker case H263Level60:
1339*ec779b8eSAndroid Build Coastguard Worker // only supports 50fps for H > 15
1340*ec779b8eSAndroid Build Coastguard Worker minW = 1; minH = 1; minAlignment = 4;
1341*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break;
1342*ec779b8eSAndroid Build Coastguard Worker case H263Level70:
1343*ec779b8eSAndroid Build Coastguard Worker // only supports 50fps for H > 30
1344*ec779b8eSAndroid Build Coastguard Worker minW = 1; minH = 1; minAlignment = 4;
1345*ec779b8eSAndroid Build Coastguard Worker FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break;
1346*ec779b8eSAndroid Build Coastguard Worker default:
1347*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile/level %d/%d for %s",
1348*ec779b8eSAndroid Build Coastguard Worker profileLevel.mProfile, profileLevel.mLevel, mediaType);
1349*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1350*ec779b8eSAndroid Build Coastguard Worker }
1351*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1352*ec779b8eSAndroid Build Coastguard Worker case H263ProfileBackwardCompatible:
1353*ec779b8eSAndroid Build Coastguard Worker case H263ProfileBaseline:
1354*ec779b8eSAndroid Build Coastguard Worker case H263ProfileH320Coding:
1355*ec779b8eSAndroid Build Coastguard Worker case H263ProfileHighCompression:
1356*ec779b8eSAndroid Build Coastguard Worker case H263ProfileHighLatency:
1357*ec779b8eSAndroid Build Coastguard Worker case H263ProfileInterlace:
1358*ec779b8eSAndroid Build Coastguard Worker case H263ProfileInternet:
1359*ec779b8eSAndroid Build Coastguard Worker case H263ProfileISWV2:
1360*ec779b8eSAndroid Build Coastguard Worker case H263ProfileISWV3:
1361*ec779b8eSAndroid Build Coastguard Worker break;
1362*ec779b8eSAndroid Build Coastguard Worker default:
1363*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1364*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1365*ec779b8eSAndroid Build Coastguard Worker }
1366*ec779b8eSAndroid Build Coastguard Worker if (strict) {
1367*ec779b8eSAndroid Build Coastguard Worker // Strict levels define sub-QCIF min size and enumerated sizes. We cannot
1368*ec779b8eSAndroid Build Coastguard Worker // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities
1369*ec779b8eSAndroid Build Coastguard Worker // but we can express "only QCIF (& CIF)", so set minimume size at QCIF.
1370*ec779b8eSAndroid Build Coastguard Worker // minW = 8; minH = 6;
1371*ec779b8eSAndroid Build Coastguard Worker minW = 11; minH = 9;
1372*ec779b8eSAndroid Build Coastguard Worker } else {
1373*ec779b8eSAndroid Build Coastguard Worker // any support for non-strict levels (including unrecognized profiles or
1374*ec779b8eSAndroid Build Coastguard Worker // levels) allow custom frame size support beyond supported limits
1375*ec779b8eSAndroid Build Coastguard Worker // (other than bitrate)
1376*ec779b8eSAndroid Build Coastguard Worker mAllowMbOverride = true;
1377*ec779b8eSAndroid Build Coastguard Worker }
1378*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1379*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max((int64_t)MBPS, maxBlocksPerSecond);
1380*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(W * H, maxBlocks);
1381*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR * 64000, maxBps);
1382*ec779b8eSAndroid Build Coastguard Worker maxWidth = std::max(W, maxWidth);
1383*ec779b8eSAndroid Build Coastguard Worker maxHeight = std::max(H, maxHeight);
1384*ec779b8eSAndroid Build Coastguard Worker maxRate = std::max(FR, maxRate);
1385*ec779b8eSAndroid Build Coastguard Worker minWidth = std::min(minW, minWidth);
1386*ec779b8eSAndroid Build Coastguard Worker minHeight = std::min(minH, minHeight);
1387*ec779b8eSAndroid Build Coastguard Worker }
1388*ec779b8eSAndroid Build Coastguard Worker // unless we encountered custom frame size support, limit size to QCIF and CIF
1389*ec779b8eSAndroid Build Coastguard Worker // using aspect ratio.
1390*ec779b8eSAndroid Build Coastguard Worker if (!mAllowMbOverride) {
1391*ec779b8eSAndroid Build Coastguard Worker mBlockAspectRatioRange =
1392*ec779b8eSAndroid Build Coastguard Worker Range(Rational(11, 9), Rational(11, 9));
1393*ec779b8eSAndroid Build Coastguard Worker }
1394*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1395*ec779b8eSAndroid Build Coastguard Worker minWidth, minHeight,
1396*ec779b8eSAndroid Build Coastguard Worker maxWidth, maxHeight,
1397*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1398*ec779b8eSAndroid Build Coastguard Worker 16 /* blockWidth */, 16 /* blockHeight */,
1399*ec779b8eSAndroid Build Coastguard Worker minAlignment /* widthAlignment */, minAlignment /* heightAlignment */);
1400*ec779b8eSAndroid Build Coastguard Worker mFrameRateRange = Range(1, maxRate);
1401*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_VP8)) {
1402*ec779b8eSAndroid Build Coastguard Worker maxBlocks = INT_MAX;
1403*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = INT_MAX;
1404*ec779b8eSAndroid Build Coastguard Worker
1405*ec779b8eSAndroid Build Coastguard Worker // TODO: set to 100Mbps for now, need a number for VP8
1406*ec779b8eSAndroid Build Coastguard Worker maxBps = 100000000;
1407*ec779b8eSAndroid Build Coastguard Worker
1408*ec779b8eSAndroid Build Coastguard Worker // profile levels are not indicative for VPx, but verify
1409*ec779b8eSAndroid Build Coastguard Worker // them nonetheless
1410*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1411*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1412*ec779b8eSAndroid Build Coastguard Worker case VP8Level_Version0:
1413*ec779b8eSAndroid Build Coastguard Worker case VP8Level_Version1:
1414*ec779b8eSAndroid Build Coastguard Worker case VP8Level_Version2:
1415*ec779b8eSAndroid Build Coastguard Worker case VP8Level_Version3:
1416*ec779b8eSAndroid Build Coastguard Worker break;
1417*ec779b8eSAndroid Build Coastguard Worker default:
1418*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
1419*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1420*ec779b8eSAndroid Build Coastguard Worker }
1421*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1422*ec779b8eSAndroid Build Coastguard Worker case VP8ProfileMain:
1423*ec779b8eSAndroid Build Coastguard Worker break;
1424*ec779b8eSAndroid Build Coastguard Worker default:
1425*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1426*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1427*ec779b8eSAndroid Build Coastguard Worker }
1428*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1429*ec779b8eSAndroid Build Coastguard Worker }
1430*ec779b8eSAndroid Build Coastguard Worker
1431*ec779b8eSAndroid Build Coastguard Worker const int32_t blockSize = 16;
1432*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(SHRT_MAX, SHRT_MAX,
1433*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
1434*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1435*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_VP9)) {
1436*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 829440;
1437*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 36864;
1438*ec779b8eSAndroid Build Coastguard Worker maxBps = 200000;
1439*ec779b8eSAndroid Build Coastguard Worker int32_t maxDim = 512;
1440*ec779b8eSAndroid Build Coastguard Worker
1441*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1442*ec779b8eSAndroid Build Coastguard Worker int64_t SR = 0; // luma sample rate
1443*ec779b8eSAndroid Build Coastguard Worker int32_t FS = 0; // luma picture size
1444*ec779b8eSAndroid Build Coastguard Worker int32_t BR = 0; // bit rate kbps
1445*ec779b8eSAndroid Build Coastguard Worker int32_t D = 0; // luma dimension
1446*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1447*ec779b8eSAndroid Build Coastguard Worker case VP9Level1:
1448*ec779b8eSAndroid Build Coastguard Worker SR = 829440; FS = 36864; BR = 200; D = 512; break;
1449*ec779b8eSAndroid Build Coastguard Worker case VP9Level11:
1450*ec779b8eSAndroid Build Coastguard Worker SR = 2764800; FS = 73728; BR = 800; D = 768; break;
1451*ec779b8eSAndroid Build Coastguard Worker case VP9Level2:
1452*ec779b8eSAndroid Build Coastguard Worker SR = 4608000; FS = 122880; BR = 1800; D = 960; break;
1453*ec779b8eSAndroid Build Coastguard Worker case VP9Level21:
1454*ec779b8eSAndroid Build Coastguard Worker SR = 9216000; FS = 245760; BR = 3600; D = 1344; break;
1455*ec779b8eSAndroid Build Coastguard Worker case VP9Level3:
1456*ec779b8eSAndroid Build Coastguard Worker SR = 20736000; FS = 552960; BR = 7200; D = 2048; break;
1457*ec779b8eSAndroid Build Coastguard Worker case VP9Level31:
1458*ec779b8eSAndroid Build Coastguard Worker SR = 36864000; FS = 983040; BR = 12000; D = 2752; break;
1459*ec779b8eSAndroid Build Coastguard Worker case VP9Level4:
1460*ec779b8eSAndroid Build Coastguard Worker SR = 83558400; FS = 2228224; BR = 18000; D = 4160; break;
1461*ec779b8eSAndroid Build Coastguard Worker case VP9Level41:
1462*ec779b8eSAndroid Build Coastguard Worker SR = 160432128; FS = 2228224; BR = 30000; D = 4160; break;
1463*ec779b8eSAndroid Build Coastguard Worker case VP9Level5:
1464*ec779b8eSAndroid Build Coastguard Worker SR = 311951360; FS = 8912896; BR = 60000; D = 8384; break;
1465*ec779b8eSAndroid Build Coastguard Worker case VP9Level51:
1466*ec779b8eSAndroid Build Coastguard Worker SR = 588251136; FS = 8912896; BR = 120000; D = 8384; break;
1467*ec779b8eSAndroid Build Coastguard Worker case VP9Level52:
1468*ec779b8eSAndroid Build Coastguard Worker SR = 1176502272; FS = 8912896; BR = 180000; D = 8384; break;
1469*ec779b8eSAndroid Build Coastguard Worker case VP9Level6:
1470*ec779b8eSAndroid Build Coastguard Worker SR = 1176502272; FS = 35651584; BR = 180000; D = 16832; break;
1471*ec779b8eSAndroid Build Coastguard Worker case VP9Level61:
1472*ec779b8eSAndroid Build Coastguard Worker SR = 2353004544L; FS = 35651584; BR = 240000; D = 16832; break;
1473*ec779b8eSAndroid Build Coastguard Worker case VP9Level62:
1474*ec779b8eSAndroid Build Coastguard Worker SR = 4706009088L; FS = 35651584; BR = 480000; D = 16832; break;
1475*ec779b8eSAndroid Build Coastguard Worker default:
1476*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
1477*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1478*ec779b8eSAndroid Build Coastguard Worker }
1479*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1480*ec779b8eSAndroid Build Coastguard Worker case VP9Profile0:
1481*ec779b8eSAndroid Build Coastguard Worker case VP9Profile1:
1482*ec779b8eSAndroid Build Coastguard Worker case VP9Profile2:
1483*ec779b8eSAndroid Build Coastguard Worker case VP9Profile3:
1484*ec779b8eSAndroid Build Coastguard Worker case VP9Profile2HDR:
1485*ec779b8eSAndroid Build Coastguard Worker case VP9Profile3HDR:
1486*ec779b8eSAndroid Build Coastguard Worker case VP9Profile2HDR10Plus:
1487*ec779b8eSAndroid Build Coastguard Worker case VP9Profile3HDR10Plus:
1488*ec779b8eSAndroid Build Coastguard Worker break;
1489*ec779b8eSAndroid Build Coastguard Worker default:
1490*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1491*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1492*ec779b8eSAndroid Build Coastguard Worker }
1493*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1494*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max(SR, maxBlocksPerSecond);
1495*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1496*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR * 1000, maxBps);
1497*ec779b8eSAndroid Build Coastguard Worker maxDim = std::max(D, maxDim);
1498*ec779b8eSAndroid Build Coastguard Worker }
1499*ec779b8eSAndroid Build Coastguard Worker
1500*ec779b8eSAndroid Build Coastguard Worker const int32_t blockSize = 8;
1501*ec779b8eSAndroid Build Coastguard Worker int32_t maxLengthInBlocks = divUp(maxDim, blockSize);
1502*ec779b8eSAndroid Build Coastguard Worker maxBlocks = divUp(maxBlocks, blockSize * blockSize);
1503*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = divUp(maxBlocksPerSecond, blockSize * (int64_t)blockSize);
1504*ec779b8eSAndroid Build Coastguard Worker
1505*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1506*ec779b8eSAndroid Build Coastguard Worker maxLengthInBlocks, maxLengthInBlocks,
1507*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1508*ec779b8eSAndroid Build Coastguard Worker blockSize, blockSize,
1509*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1510*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) {
1511*ec779b8eSAndroid Build Coastguard Worker // CTBs are at least 8x8 so use 8x8 block size
1512*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks
1513*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = maxBlocks * 15;
1514*ec779b8eSAndroid Build Coastguard Worker maxBps = 128000;
1515*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1516*ec779b8eSAndroid Build Coastguard Worker double FR = 0;
1517*ec779b8eSAndroid Build Coastguard Worker int32_t FS = 0, BR = 0;
1518*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1519*ec779b8eSAndroid Build Coastguard Worker /* The HEVC spec talks only in a very convoluted manner about the
1520*ec779b8eSAndroid Build Coastguard Worker existence of levels 1-3.1 for High tier, which could also be
1521*ec779b8eSAndroid Build Coastguard Worker understood as 'decoders and encoders should treat these levels
1522*ec779b8eSAndroid Build Coastguard Worker as if they were Main tier', so we do that. */
1523*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel1:
1524*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel1:
1525*ec779b8eSAndroid Build Coastguard Worker FR = 15; FS = 36864; BR = 128; break;
1526*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel2:
1527*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel2:
1528*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 122880; BR = 1500; break;
1529*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel21:
1530*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel21:
1531*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 245760; BR = 3000; break;
1532*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel3:
1533*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel3:
1534*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 552960; BR = 6000; break;
1535*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel31:
1536*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel31:
1537*ec779b8eSAndroid Build Coastguard Worker FR = 33.75; FS = 983040; BR = 10000; break;
1538*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel4:
1539*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 2228224; BR = 12000; break;
1540*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel4:
1541*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 2228224; BR = 30000; break;
1542*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel41:
1543*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 2228224; BR = 20000; break;
1544*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel41:
1545*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 2228224; BR = 50000; break;
1546*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel5:
1547*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 8912896; BR = 25000; break;
1548*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel5:
1549*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 8912896; BR = 100000; break;
1550*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel51:
1551*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 8912896; BR = 40000; break;
1552*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel51:
1553*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 8912896; BR = 160000; break;
1554*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel52:
1555*ec779b8eSAndroid Build Coastguard Worker FR = 120; FS = 8912896; BR = 60000; break;
1556*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel52:
1557*ec779b8eSAndroid Build Coastguard Worker FR = 120; FS = 8912896; BR = 240000; break;
1558*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel6:
1559*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 35651584; BR = 60000; break;
1560*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel6:
1561*ec779b8eSAndroid Build Coastguard Worker FR = 30; FS = 35651584; BR = 240000; break;
1562*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel61:
1563*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 35651584; BR = 120000; break;
1564*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel61:
1565*ec779b8eSAndroid Build Coastguard Worker FR = 60; FS = 35651584; BR = 480000; break;
1566*ec779b8eSAndroid Build Coastguard Worker case HEVCMainTierLevel62:
1567*ec779b8eSAndroid Build Coastguard Worker FR = 120; FS = 35651584; BR = 240000; break;
1568*ec779b8eSAndroid Build Coastguard Worker case HEVCHighTierLevel62:
1569*ec779b8eSAndroid Build Coastguard Worker FR = 120; FS = 35651584; BR = 800000; break;
1570*ec779b8eSAndroid Build Coastguard Worker default:
1571*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
1572*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1573*ec779b8eSAndroid Build Coastguard Worker }
1574*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1575*ec779b8eSAndroid Build Coastguard Worker case HEVCProfileMain:
1576*ec779b8eSAndroid Build Coastguard Worker case HEVCProfileMain10:
1577*ec779b8eSAndroid Build Coastguard Worker case HEVCProfileMainStill:
1578*ec779b8eSAndroid Build Coastguard Worker case HEVCProfileMain10HDR10:
1579*ec779b8eSAndroid Build Coastguard Worker case HEVCProfileMain10HDR10Plus:
1580*ec779b8eSAndroid Build Coastguard Worker break;
1581*ec779b8eSAndroid Build Coastguard Worker default:
1582*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1583*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1584*ec779b8eSAndroid Build Coastguard Worker }
1585*ec779b8eSAndroid Build Coastguard Worker
1586*ec779b8eSAndroid Build Coastguard Worker /* DPB logic:
1587*ec779b8eSAndroid Build Coastguard Worker if (width * height <= FS / 4) DPB = 16;
1588*ec779b8eSAndroid Build Coastguard Worker else if (width * height <= FS / 2) DPB = 12;
1589*ec779b8eSAndroid Build Coastguard Worker else if (width * height <= FS * 0.75) DPB = 8;
1590*ec779b8eSAndroid Build Coastguard Worker else DPB = 6;
1591*ec779b8eSAndroid Build Coastguard Worker */
1592*ec779b8eSAndroid Build Coastguard Worker
1593*ec779b8eSAndroid Build Coastguard Worker FS >>= 6; // convert pixels to blocks
1594*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1595*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max((int64_t)(FR * FS), maxBlocksPerSecond);
1596*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1597*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(1000 * BR, maxBps);
1598*ec779b8eSAndroid Build Coastguard Worker }
1599*ec779b8eSAndroid Build Coastguard Worker
1600*ec779b8eSAndroid Build Coastguard Worker int32_t maxLengthInBlocks = (int32_t)(std::sqrt(8 * maxBlocks));
1601*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1602*ec779b8eSAndroid Build Coastguard Worker maxLengthInBlocks, maxLengthInBlocks,
1603*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1604*ec779b8eSAndroid Build Coastguard Worker 8 /* blockWidth */, 8 /* blockHeight */,
1605*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1606*ec779b8eSAndroid Build Coastguard Worker } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_AV1)) {
1607*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = 829440;
1608*ec779b8eSAndroid Build Coastguard Worker maxBlocks = 36864;
1609*ec779b8eSAndroid Build Coastguard Worker maxBps = 200000;
1610*ec779b8eSAndroid Build Coastguard Worker int32_t maxDim = 512;
1611*ec779b8eSAndroid Build Coastguard Worker
1612*ec779b8eSAndroid Build Coastguard Worker // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec,
1613*ec779b8eSAndroid Build Coastguard Worker // corresponding to the definitions in
1614*ec779b8eSAndroid Build Coastguard Worker // "AV1 Bitstream & Decoding Process Specification", Annex A
1615*ec779b8eSAndroid Build Coastguard Worker // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
1616*ec779b8eSAndroid Build Coastguard Worker for (ProfileLevel profileLevel: mProfileLevels) {
1617*ec779b8eSAndroid Build Coastguard Worker int64_t SR = 0; // luma sample rate
1618*ec779b8eSAndroid Build Coastguard Worker int32_t FS = 0; // luma picture size
1619*ec779b8eSAndroid Build Coastguard Worker int32_t BR = 0; // bit rate kbps
1620*ec779b8eSAndroid Build Coastguard Worker int32_t D = 0; // luma D
1621*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mLevel) {
1622*ec779b8eSAndroid Build Coastguard Worker case AV1Level2:
1623*ec779b8eSAndroid Build Coastguard Worker SR = 5529600; FS = 147456; BR = 1500; D = 2048; break;
1624*ec779b8eSAndroid Build Coastguard Worker case AV1Level21:
1625*ec779b8eSAndroid Build Coastguard Worker case AV1Level22:
1626*ec779b8eSAndroid Build Coastguard Worker case AV1Level23:
1627*ec779b8eSAndroid Build Coastguard Worker SR = 10454400; FS = 278784; BR = 3000; D = 2816; break;
1628*ec779b8eSAndroid Build Coastguard Worker
1629*ec779b8eSAndroid Build Coastguard Worker case AV1Level3:
1630*ec779b8eSAndroid Build Coastguard Worker SR = 24969600; FS = 665856; BR = 6000; D = 4352; break;
1631*ec779b8eSAndroid Build Coastguard Worker case AV1Level31:
1632*ec779b8eSAndroid Build Coastguard Worker case AV1Level32:
1633*ec779b8eSAndroid Build Coastguard Worker case AV1Level33:
1634*ec779b8eSAndroid Build Coastguard Worker SR = 39938400; FS = 1065024; BR = 10000; D = 5504; break;
1635*ec779b8eSAndroid Build Coastguard Worker
1636*ec779b8eSAndroid Build Coastguard Worker case AV1Level4:
1637*ec779b8eSAndroid Build Coastguard Worker SR = 77856768; FS = 2359296; BR = 12000; D = 6144; break;
1638*ec779b8eSAndroid Build Coastguard Worker case AV1Level41:
1639*ec779b8eSAndroid Build Coastguard Worker case AV1Level42:
1640*ec779b8eSAndroid Build Coastguard Worker case AV1Level43:
1641*ec779b8eSAndroid Build Coastguard Worker SR = 155713536; FS = 2359296; BR = 20000; D = 6144; break;
1642*ec779b8eSAndroid Build Coastguard Worker
1643*ec779b8eSAndroid Build Coastguard Worker case AV1Level5:
1644*ec779b8eSAndroid Build Coastguard Worker SR = 273715200; FS = 8912896; BR = 30000; D = 8192; break;
1645*ec779b8eSAndroid Build Coastguard Worker case AV1Level51:
1646*ec779b8eSAndroid Build Coastguard Worker SR = 547430400; FS = 8912896; BR = 40000; D = 8192; break;
1647*ec779b8eSAndroid Build Coastguard Worker case AV1Level52:
1648*ec779b8eSAndroid Build Coastguard Worker SR = 1094860800; FS = 8912896; BR = 60000; D = 8192; break;
1649*ec779b8eSAndroid Build Coastguard Worker case AV1Level53:
1650*ec779b8eSAndroid Build Coastguard Worker SR = 1176502272; FS = 8912896; BR = 60000; D = 8192; break;
1651*ec779b8eSAndroid Build Coastguard Worker
1652*ec779b8eSAndroid Build Coastguard Worker case AV1Level6:
1653*ec779b8eSAndroid Build Coastguard Worker SR = 1176502272; FS = 35651584; BR = 60000; D = 16384; break;
1654*ec779b8eSAndroid Build Coastguard Worker case AV1Level61:
1655*ec779b8eSAndroid Build Coastguard Worker SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break;
1656*ec779b8eSAndroid Build Coastguard Worker case AV1Level62:
1657*ec779b8eSAndroid Build Coastguard Worker SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break;
1658*ec779b8eSAndroid Build Coastguard Worker case AV1Level63:
1659*ec779b8eSAndroid Build Coastguard Worker SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break;
1660*ec779b8eSAndroid Build Coastguard Worker
1661*ec779b8eSAndroid Build Coastguard Worker default:
1662*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized level %d for %s", profileLevel.mLevel, mediaType);
1663*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1664*ec779b8eSAndroid Build Coastguard Worker }
1665*ec779b8eSAndroid Build Coastguard Worker switch (profileLevel.mProfile) {
1666*ec779b8eSAndroid Build Coastguard Worker case AV1ProfileMain8:
1667*ec779b8eSAndroid Build Coastguard Worker case AV1ProfileMain10:
1668*ec779b8eSAndroid Build Coastguard Worker case AV1ProfileMain10HDR10:
1669*ec779b8eSAndroid Build Coastguard Worker case AV1ProfileMain10HDR10Plus:
1670*ec779b8eSAndroid Build Coastguard Worker break;
1671*ec779b8eSAndroid Build Coastguard Worker default:
1672*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile, mediaType);
1673*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNRECOGNIZED;
1674*ec779b8eSAndroid Build Coastguard Worker }
1675*ec779b8eSAndroid Build Coastguard Worker errors &= ~ERROR_CAPABILITIES_NONE_SUPPORTED;
1676*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = std::max(SR, maxBlocksPerSecond);
1677*ec779b8eSAndroid Build Coastguard Worker maxBlocks = std::max(FS, maxBlocks);
1678*ec779b8eSAndroid Build Coastguard Worker maxBps = std::max(BR * 1000, maxBps);
1679*ec779b8eSAndroid Build Coastguard Worker maxDim = std::max(D, maxDim);
1680*ec779b8eSAndroid Build Coastguard Worker }
1681*ec779b8eSAndroid Build Coastguard Worker
1682*ec779b8eSAndroid Build Coastguard Worker const int32_t blockSize = 8;
1683*ec779b8eSAndroid Build Coastguard Worker int32_t maxLengthInBlocks = divUp(maxDim, blockSize);
1684*ec779b8eSAndroid Build Coastguard Worker maxBlocks = divUp(maxBlocks, blockSize * blockSize);
1685*ec779b8eSAndroid Build Coastguard Worker maxBlocksPerSecond = divUp(maxBlocksPerSecond, blockSize * (int64_t)blockSize);
1686*ec779b8eSAndroid Build Coastguard Worker applyMacroBlockLimits(
1687*ec779b8eSAndroid Build Coastguard Worker maxLengthInBlocks, maxLengthInBlocks,
1688*ec779b8eSAndroid Build Coastguard Worker maxBlocks, maxBlocksPerSecond,
1689*ec779b8eSAndroid Build Coastguard Worker blockSize, blockSize,
1690*ec779b8eSAndroid Build Coastguard Worker 1 /* widthAlignment */, 1 /* heightAlignment */);
1691*ec779b8eSAndroid Build Coastguard Worker } else {
1692*ec779b8eSAndroid Build Coastguard Worker ALOGW("Unsupported mime %s", mediaType);
1693*ec779b8eSAndroid Build Coastguard Worker // using minimal bitrate here. should be overridden by
1694*ec779b8eSAndroid Build Coastguard Worker // info from media_codecs.xml
1695*ec779b8eSAndroid Build Coastguard Worker maxBps = 64000;
1696*ec779b8eSAndroid Build Coastguard Worker errors |= ERROR_CAPABILITIES_UNSUPPORTED;
1697*ec779b8eSAndroid Build Coastguard Worker }
1698*ec779b8eSAndroid Build Coastguard Worker mBitrateRange = Range(1, maxBps);
1699*ec779b8eSAndroid Build Coastguard Worker mError |= errors;
1700*ec779b8eSAndroid Build Coastguard Worker }
1701*ec779b8eSAndroid Build Coastguard Worker
1702*ec779b8eSAndroid Build Coastguard Worker } // namespace android