blob: e6b3c463e479ebdef4da5d68b6c149babf991741 [file] [log] [blame]
Ray Essick1831f7b2021-03-15 16:10:51 -07001/*
2 * Copyright 2021, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CodecProperties"
19#include <utils/Log.h>
20
21#include <string>
Ray Essicka727ef92021-03-29 13:35:02 -070022#include <stdlib.h>
Ray Essick1831f7b2021-03-15 16:10:51 -070023
24#include <media/formatshaper/CodecProperties.h>
25
Ray Essick244aaa52021-04-05 14:47:02 -070026
27// we aren't going to mess with shaping points dimensions beyond this
28static const int32_t DIMENSION_LIMIT = 16384;
29
Ray Essick1831f7b2021-03-15 16:10:51 -070030namespace android {
31namespace mediaformatshaper {
32
33CodecProperties::CodecProperties(std::string name, std::string mediaType) {
Ray Essick970f1c82021-03-25 13:37:45 -070034 ALOGV("CodecProperties(%s, %s)", name.c_str(), mediaType.c_str());
Ray Essick1831f7b2021-03-15 16:10:51 -070035 mName = name;
36 mMediaType = mediaType;
37}
38
39std::string CodecProperties::getName(){
40 return mName;
41}
42
43std::string CodecProperties::getMediaType(){
44 return mMediaType;
45}
46
47int CodecProperties::supportedMinimumQuality() {
48 return mMinimumQuality;
49}
50void CodecProperties::setSupportedMinimumQuality(int vmaf) {
51 mMinimumQuality = vmaf;
52}
53
54int CodecProperties::targetQpMax() {
55 return mTargetQpMax;
56}
57void CodecProperties::setTargetQpMax(int qpMax) {
58 mTargetQpMax = qpMax;
59}
60
61// what API is this codec set up for (e.g. API of the associated partition)
62// vendor-side (OEM) codecs may be older, due to 'vendor freeze' and treble
63int CodecProperties::supportedApi() {
64 return mApi;
65}
66
Ray Essick970f1c82021-03-25 13:37:45 -070067void CodecProperties::setFeatureValue(std::string key, int32_t value) {
68 ALOGD("setFeatureValue(%s,%d)", key.c_str(), value);
69 mFeatures.insert({key, value});
70
Ray Essicka727ef92021-03-29 13:35:02 -070071 if (!strcmp(key.c_str(), "qp-bounds")) { // official key
Ray Essick970f1c82021-03-25 13:37:45 -070072 setSupportsQp(1);
Ray Essicka727ef92021-03-29 13:35:02 -070073 } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping
Ray Essick970f1c82021-03-25 13:37:45 -070074 setSupportsQp(1);
Ray Essicka727ef92021-03-29 13:35:02 -070075 } else if (!strcmp(key.c_str(), "vq-minimum-quality")) {
76 setSupportedMinimumQuality(1);
Ray Essick970f1c82021-03-25 13:37:45 -070077 }
78}
79
80bool CodecProperties::getFeatureValue(std::string key, int32_t *valuep) {
81 ALOGV("getFeatureValue(%s)", key.c_str());
82 if (valuep == nullptr) {
83 return false;
84 }
85 auto mapped = mFeatures.find(key);
86 if (mapped != mFeatures.end()) {
87 *valuep = mapped->second;
88 return true;
89 }
90 return false;
91}
92
Ray Essicka727ef92021-03-29 13:35:02 -070093// Tuning values (which differ from Features)
94// this is where we set up things like target bitrates and QP ranges
95// NB the tuning values arrive as a string, allowing us to convert it into an appropriate
96// format (int, float, ranges, other combinations)
97//
98void CodecProperties::setTuningValue(std::string key, std::string value) {
99 ALOGD("setTuningValue(%s,%s)", key.c_str(), value.c_str());
100 mTunings.insert({key, value});
101
102 bool legal = false;
103 // NB: old school strtol() because std::stoi() throws exceptions
104 if (!strcmp(key.c_str(), "vq-target-qpmax")) {
105 const char *p = value.c_str();
106 char *q;
107 int32_t iValue = strtol(p, &q, 0);
108 if (q != p) {
109 setTargetQpMax(iValue);
110 legal = true;
111 }
112 } else if (!strcmp(key.c_str(), "vq-target-bpp")) {
113 const char *p = value.c_str();
114 char *q;
115 double bpp = strtod(p, &q);
116 if (q != p) {
117 setBpp(bpp);
118 legal = true;
119 }
Ray Essick244aaa52021-04-05 14:47:02 -0700120 } else if (!strncmp(key.c_str(), "vq-target-bpp-", strlen("vq-target-bpp-"))) {
121 std::string resolution = key.substr(strlen("vq-target-bpp-"));
122 if (bppPoint(resolution, value)) {
123 legal = true;
124 }
Ray Essicka727ef92021-03-29 13:35:02 -0700125 } else if (!strcmp(key.c_str(), "vq-target-bppx100")) {
Ray Essick244aaa52021-04-05 14:47:02 -0700126 // legacy, prototyping
Ray Essicka727ef92021-03-29 13:35:02 -0700127 const char *p = value.c_str();
128 char *q;
129 int32_t iValue = strtol(p, &q, 0);
130 if (q != p) {
131 double bpp = iValue / 100.0;
132 setBpp(bpp);
133 legal = true;
134 }
135 } else {
136 legal = true;
137 }
138
139 if (!legal) {
140 ALOGW("setTuningValue() unable to apply tuning '%s' with value '%s'",
141 key.c_str(), value.c_str());
142 }
143 return;
144}
145
146bool CodecProperties::getTuningValue(std::string key, std::string &value) {
147 ALOGV("getTuningValue(%s)", key.c_str());
148 auto mapped = mFeatures.find(key);
149 if (mapped != mFeatures.end()) {
150 value = mapped->second;
151 return true;
152 }
153 return false;
154}
155
Ray Essick244aaa52021-04-05 14:47:02 -0700156bool CodecProperties::bppPoint(std::string resolution, std::string value) {
157
158 int32_t width = 0;
159 int32_t height = 0;
160 double bpp = -1;
161
162 // resolution is "WxH", "W*H" or a standard name like "720p"
163 if (resolution == "1080p") {
164 width = 1080; height = 1920;
165 } else if (resolution == "720p") {
166 width = 720; height = 1280;
167 } else if (resolution == "540p") {
168 width = 540; height = 960;
169 } else if (resolution == "480p") {
170 width = 480; height = 854;
171 } else {
172 size_t sep = resolution.find('x');
173 if (sep == std::string::npos) {
174 sep = resolution.find('*');
175 }
176 if (sep == std::string::npos) {
177 ALOGW("unable to parse resolution: '%s'", resolution.c_str());
178 return false;
179 }
180 std::string w = resolution.substr(0, sep);
181 std::string h = resolution.substr(sep+1);
182
183 char *q;
184 const char *p = w.c_str();
185 width = strtol(p, &q, 0);
186 if (q == p) {
187 width = -1;
188 }
189 p = h.c_str();
190 height = strtol(p, &q, 0);
191 if (q == p) {
192 height = -1;
193 }
194 if (width <= 0 || height <= 0 || width > DIMENSION_LIMIT || height > DIMENSION_LIMIT) {
195 ALOGW("unparseable: width, height '%s'", resolution.c_str());
196 return false;
197 }
198 }
199
200 const char *p = value.c_str();
201 char *q;
202 bpp = strtod(p, &q);
203 if (q == p) {
204 ALOGW("unparseable bpp '%s'", value.c_str());
205 return false;
206 }
207
208 struct bpp_point *point = (struct bpp_point*) malloc(sizeof(*point));
209 if (point == nullptr) {
210 ALOGW("unable to allocate memory for bpp point");
211 return false;
212 }
213
214 point->pixels = width * height;
215 point->width = width;
216 point->height = height;
217 point->bpp = bpp;
218
219 if (mBppPoints == nullptr) {
220 point->next = nullptr;
221 mBppPoints = point;
222 } else if (point->pixels < mBppPoints->pixels) {
223 // at the front
224 point->next = mBppPoints;
225 mBppPoints = point;
226 } else {
227 struct bpp_point *after = mBppPoints;
228 while (after->next) {
229 if (point->pixels > after->next->pixels) {
230 after = after->next;
231 continue;
232 }
233
234 // insert before after->next
235 point->next = after->next;
236 after->next = point;
237 break;
238 }
239 if (after->next == nullptr) {
240 // hasn't gone in yet
241 point->next = nullptr;
242 after->next = point;
243 }
244 }
245
246 return true;
247}
248
249double CodecProperties::getBpp(int32_t width, int32_t height) {
250 // look in the per-resolution list
251
252 int32_t pixels = width * height;
253
254 if (mBppPoints) {
255 struct bpp_point *point = mBppPoints;
256 while (point && point->pixels < pixels) {
257 point = point->next;
258 }
259 if (point) {
260 ALOGV("getBpp(w=%d,h=%d) returns %f from bpppoint w=%d h=%d",
261 width, height, point->bpp, point->width, point->height);
262 return point->bpp;
263 }
264 }
265
266 ALOGV("defaulting to %f bpp", mBpp);
267 return mBpp;
268}
Ray Essick970f1c82021-03-25 13:37:45 -0700269
Ray Essick1831f7b2021-03-15 16:10:51 -0700270std::string CodecProperties::getMapping(std::string key, std::string kind) {
271 ALOGV("getMapping(key %s, kind %s )", key.c_str(), kind.c_str());
272 //play with mMappings
273 auto mapped = mMappings.find(kind + "-" + key);
274 if (mapped != mMappings.end()) {
275 std::string result = mapped->second;
276 ALOGV("getMapping(%s, %s) -> %s", key.c_str(), kind.c_str(), result.c_str());
277 return result;
278 }
279 ALOGV("nope, return unchanged key");
280 return key;
281}
282
283
284// really a bit of debugging code here.
285void CodecProperties::showMappings() {
286 ALOGD("Mappings:");
287 int count = 0;
288 for (const auto& [key, value] : mMappings) {
289 count++;
290 ALOGD("'%s' -> '%s'", key.c_str(), value.c_str());
291 }
292 ALOGD("total %d mappings", count);
293}
294
295void CodecProperties::setMapping(std::string kind, std::string key, std::string value) {
296 ALOGV("setMapping(%s,%s,%s)", kind.c_str(), key.c_str(), value.c_str());
297 std::string metaKey = kind + "-" + key;
298 mMappings.insert({metaKey, value});
299}
300
301const char **CodecProperties::getMappings(std::string kind, bool reverse) {
302 ALOGV("getMappings(kind %s, reverse %d", kind.c_str(), reverse);
303 // how many do we need?
304 int count = mMappings.size();
305 if (count == 0) {
306 ALOGV("empty mappings");
307 return nullptr;
308 }
309 size_t size = sizeof(char *) * (2 * count + 2);
310 const char **result = (const char **)malloc(size);
311 if (result == nullptr) {
312 ALOGW("no memory to return mappings");
313 return nullptr;
314 }
315 memset(result, '\0', size);
316
317 const char **pp = result;
318 for (const auto& [key, value] : mMappings) {
319 // split out the kind/key
320 size_t pos = key.find('-');
321 if (pos == std::string::npos) {
322 ALOGD("ignoring malformed key: %s", key.c_str());
323 continue;
324 }
325 std::string actualKind = key.substr(0,pos);
326 if (kind.length() != 0 && kind != actualKind) {
327 ALOGD("kinds don't match: want '%s' got '%s'", kind.c_str(), actualKind.c_str());
328 continue;
329 }
330 if (reverse) {
331 // codec specific -> std aka 'unmapping'
332 pp[0] = strdup( value.c_str());
333 pp[1] = strdup( key.substr(pos+1).c_str());
334 } else {
335 // std -> codec specific
336 pp[0] = strdup( key.substr(pos+1).c_str());
337 pp[1] = strdup( value.c_str());
338 }
339 ALOGV(" %s -> %s", pp[0], pp[1]);
340 pp += 2;
341 }
342
343 pp[0] = nullptr;
344 pp[1] = nullptr;
345
346 return result;
347}
348
349
350} // namespace mediaformatshaper
351} // namespace android
352