VideoFormats.cpp revision aef5c98cd3f67e0209e1fa28489078e9f40d6f46
1/* 2 * Copyright 2013, 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 "VideoFormats" 19#include <utils/Log.h> 20 21#include "VideoFormats.h" 22 23#include <media/stagefright/foundation/ADebug.h> 24 25namespace android { 26 27VideoFormats::config_t VideoFormats::mConfigs[][32] = { 28 { 29 // CEA Resolutions 30 { 640, 480, 60, false, 0, 0}, 31 { 720, 480, 60, false, 0, 0}, 32 { 720, 480, 60, true, 0, 0}, 33 { 720, 576, 50, false, 0, 0}, 34 { 720, 576, 50, true, 0, 0}, 35 { 1280, 720, 30, false, 0, 0}, 36 { 1280, 720, 60, false, 0, 0}, 37 { 1920, 1080, 30, false, 0, 0}, 38 { 1920, 1080, 60, false, 0, 0}, 39 { 1920, 1080, 60, true, 0, 0}, 40 { 1280, 720, 25, false, 0, 0}, 41 { 1280, 720, 50, false, 0, 0}, 42 { 1920, 1080, 25, false, 0, 0}, 43 { 1920, 1080, 50, false, 0, 0}, 44 { 1920, 1080, 50, true, 0, 0}, 45 { 1280, 720, 24, false, 0, 0}, 46 { 1920, 1080, 24, false, 0, 0}, 47 { 0, 0, 0, false, 0, 0}, 48 { 0, 0, 0, false, 0, 0}, 49 { 0, 0, 0, false, 0, 0}, 50 { 0, 0, 0, false, 0, 0}, 51 { 0, 0, 0, false, 0, 0}, 52 { 0, 0, 0, false, 0, 0}, 53 { 0, 0, 0, false, 0, 0}, 54 { 0, 0, 0, false, 0, 0}, 55 { 0, 0, 0, false, 0, 0}, 56 { 0, 0, 0, false, 0, 0}, 57 { 0, 0, 0, false, 0, 0}, 58 { 0, 0, 0, false, 0, 0}, 59 { 0, 0, 0, false, 0, 0}, 60 { 0, 0, 0, false, 0, 0}, 61 { 0, 0, 0, false, 0, 0}, 62 }, 63 { 64 // VESA Resolutions 65 { 800, 600, 30, false, 0, 0}, 66 { 800, 600, 60, false, 0, 0}, 67 { 1024, 768, 30, false, 0, 0}, 68 { 1024, 768, 60, false, 0, 0}, 69 { 1152, 864, 30, false, 0, 0}, 70 { 1152, 864, 60, false, 0, 0}, 71 { 1280, 768, 30, false, 0, 0}, 72 { 1280, 768, 60, false, 0, 0}, 73 { 1280, 800, 30, false, 0, 0}, 74 { 1280, 800, 60, false, 0, 0}, 75 { 1360, 768, 30, false, 0, 0}, 76 { 1360, 768, 60, false, 0, 0}, 77 { 1366, 768, 30, false, 0, 0}, 78 { 1366, 768, 60, false, 0, 0}, 79 { 1280, 1024, 30, false, 0, 0}, 80 { 1280, 1024, 60, false, 0, 0}, 81 { 1400, 1050, 30, false, 0, 0}, 82 { 1400, 1050, 60, false, 0, 0}, 83 { 1440, 900, 30, false, 0, 0}, 84 { 1440, 900, 60, false, 0, 0}, 85 { 1600, 900, 30, false, 0, 0}, 86 { 1600, 900, 60, false, 0, 0}, 87 { 1600, 1200, 30, false, 0, 0}, 88 { 1600, 1200, 60, false, 0, 0}, 89 { 1680, 1024, 30, false, 0, 0}, 90 { 1680, 1024, 60, false, 0, 0}, 91 { 1680, 1050, 30, false, 0, 0}, 92 { 1680, 1050, 60, false, 0, 0}, 93 { 1920, 1200, 30, false, 0, 0}, 94 { 1920, 1200, 60, false, 0, 0}, 95 { 0, 0, 0, false, 0, 0}, 96 { 0, 0, 0, false, 0, 0}, 97 }, 98 { 99 // HH Resolutions 100 { 800, 480, 30, false, 0, 0}, 101 { 800, 480, 60, false, 0, 0}, 102 { 854, 480, 30, false, 0, 0}, 103 { 854, 480, 60, false, 0, 0}, 104 { 864, 480, 30, false, 0, 0}, 105 { 864, 480, 60, false, 0, 0}, 106 { 640, 360, 30, false, 0, 0}, 107 { 640, 360, 60, false, 0, 0}, 108 { 960, 540, 30, false, 0, 0}, 109 { 960, 540, 60, false, 0, 0}, 110 { 848, 480, 30, false, 0, 0}, 111 { 848, 480, 60, false, 0, 0}, 112 { 0, 0, 0, false, 0, 0}, 113 { 0, 0, 0, false, 0, 0}, 114 { 0, 0, 0, false, 0, 0}, 115 { 0, 0, 0, false, 0, 0}, 116 { 0, 0, 0, false, 0, 0}, 117 { 0, 0, 0, false, 0, 0}, 118 { 0, 0, 0, false, 0, 0}, 119 { 0, 0, 0, false, 0, 0}, 120 { 0, 0, 0, false, 0, 0}, 121 { 0, 0, 0, false, 0, 0}, 122 { 0, 0, 0, false, 0, 0}, 123 { 0, 0, 0, false, 0, 0}, 124 { 0, 0, 0, false, 0, 0}, 125 { 0, 0, 0, false, 0, 0}, 126 { 0, 0, 0, false, 0, 0}, 127 { 0, 0, 0, false, 0, 0}, 128 { 0, 0, 0, false, 0, 0}, 129 { 0, 0, 0, false, 0, 0}, 130 { 0, 0, 0, false, 0, 0}, 131 { 0, 0, 0, false, 0, 0}, 132 } 133}; 134 135VideoFormats::VideoFormats() { 136 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 137 mResolutionEnabled[i] = 0; 138 } 139 140 setNativeResolution(RESOLUTION_CEA, 0); // default to 640x480 p60 141} 142 143void VideoFormats::setNativeResolution(ResolutionType type, size_t index) { 144 CHECK_LT(type, kNumResolutionTypes); 145 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 146 147 mNativeType = type; 148 mNativeIndex = index; 149 150 setResolutionEnabled(type, index); 151} 152 153void VideoFormats::getNativeResolution( 154 ResolutionType *type, size_t *index) const { 155 *type = mNativeType; 156 *index = mNativeIndex; 157} 158 159void VideoFormats::disableAll() { 160 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 161 mResolutionEnabled[i] = 0; 162 for (size_t j = 0; j < 32; j++) { 163 mConfigs[i][j].profile = mConfigs[i][j].level = 0; 164 } 165 } 166} 167 168void VideoFormats::enableAll() { 169 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 170 mResolutionEnabled[i] = 0xffffffff; 171 for (size_t j = 0; j < 32; j++) { 172 mConfigs[i][j].profile = (1ul << PROFILE_CBP); 173 mConfigs[i][j].level = (1ul << LEVEL_31); 174 } 175 } 176} 177 178void VideoFormats::setResolutionEnabled( 179 ResolutionType type, size_t index, bool enabled) { 180 CHECK_LT(type, kNumResolutionTypes); 181 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 182 183 if (enabled) { 184 mResolutionEnabled[type] |= (1ul << index); 185 } else { 186 mResolutionEnabled[type] &= ~(1ul << index); 187 } 188} 189 190bool VideoFormats::isResolutionEnabled( 191 ResolutionType type, size_t index) const { 192 CHECK_LT(type, kNumResolutionTypes); 193 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 194 195 return mResolutionEnabled[type] & (1ul << index); 196} 197 198// static 199bool VideoFormats::GetConfiguration( 200 ResolutionType type, 201 size_t index, 202 size_t *width, size_t *height, size_t *framesPerSecond, 203 bool *interlaced) { 204 CHECK_LT(type, kNumResolutionTypes); 205 206 if (index >= 32) { 207 return false; 208 } 209 210 const config_t *config = &mConfigs[type][index]; 211 212 if (config->width == 0) { 213 return false; 214 } 215 216 if (width) { 217 *width = config->width; 218 } 219 220 if (height) { 221 *height = config->height; 222 } 223 224 if (framesPerSecond) { 225 *framesPerSecond = config->framesPerSecond; 226 } 227 228 if (interlaced) { 229 *interlaced = config->interlaced; 230 } 231 232 return true; 233} 234 235bool VideoFormats::parseH264Codec(const char *spec) { 236 unsigned profile, level, res[3]; 237 238 if (sscanf( 239 spec, 240 "%02x %02x %08X %08X %08X", 241 &profile, 242 &level, 243 &res[0], 244 &res[1], 245 &res[2]) != 5) { 246 return false; 247 } 248 249 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 250 for (size_t j = 0; j < 32; ++j) { 251 if (res[i] & (1ul << j)){ 252 mResolutionEnabled[i] |= (1ul << j); 253 if (profile > mConfigs[i][j].profile) { 254 mConfigs[i][j].profile = profile; 255 if (level > mConfigs[i][j].level) 256 mConfigs[i][j].level = level; 257 } 258 } 259 } 260 } 261 262 return true; 263} 264 265bool VideoFormats::parseFormatSpec(const char *spec) { 266 CHECK_EQ(kNumResolutionTypes, 3); 267 268 unsigned native, dummy; 269 unsigned res[3]; 270 size_t size = strlen(spec); 271 size_t offset = 0; 272 273 if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) { 274 return false; 275 } 276 277 offset += 6; // skip native and preferred-display-mode-supported 278 CHECK_LE(offset + 58, size); 279 while (offset < size) { 280 parseH264Codec(spec + offset); 281 offset += 60; // skip H.264-codec + ", " 282 } 283 284 mNativeIndex = native >> 3; 285 mNativeType = (ResolutionType)(native & 7); 286 287 bool success; 288 if (mNativeType >= kNumResolutionTypes) { 289 success = false; 290 } else { 291 success = GetConfiguration( 292 mNativeType, mNativeIndex, NULL, NULL, NULL, NULL); 293 } 294 295 if (!success) { 296 ALOGW("sink advertised an illegal native resolution, fortunately " 297 "this value is ignored for the time being..."); 298 } 299 300 return true; 301} 302 303AString VideoFormats::getFormatSpec(bool forM4Message) const { 304 CHECK_EQ(kNumResolutionTypes, 3); 305 306 // wfd_video_formats: 307 // 1 byte "native" 308 // 1 byte "preferred-display-mode-supported" 0 or 1 309 // one or more avc codec structures 310 // 1 byte profile 311 // 1 byte level 312 // 4 byte CEA mask 313 // 4 byte VESA mask 314 // 4 byte HH mask 315 // 1 byte latency 316 // 2 byte min-slice-slice 317 // 2 byte slice-enc-params 318 // 1 byte framerate-control-support 319 // max-hres (none or 2 byte) 320 // max-vres (none or 2 byte) 321 322 return StringPrintf( 323 "%02x 00 02 02 %08x %08x %08x 00 0000 0000 00 none none", 324 forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType), 325 mResolutionEnabled[0], 326 mResolutionEnabled[1], 327 mResolutionEnabled[2]); 328} 329 330// static 331bool VideoFormats::PickBestFormat( 332 const VideoFormats &sinkSupported, 333 const VideoFormats &sourceSupported, 334 ResolutionType *chosenType, 335 size_t *chosenIndex) { 336#if 0 337 // Support for the native format is a great idea, the spec includes 338 // these features, but nobody supports it and the tests don't validate it. 339 340 ResolutionType nativeType; 341 size_t nativeIndex; 342 sinkSupported.getNativeResolution(&nativeType, &nativeIndex); 343 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 344 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 345 ALOGI("Choosing sink's native resolution"); 346 *chosenType = nativeType; 347 *chosenIndex = nativeIndex; 348 return true; 349 } 350 } else { 351 ALOGW("Sink advertised native resolution that it doesn't " 352 "actually support... ignoring"); 353 } 354 355 sourceSupported.getNativeResolution(&nativeType, &nativeIndex); 356 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 357 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 358 ALOGI("Choosing source's native resolution"); 359 *chosenType = nativeType; 360 *chosenIndex = nativeIndex; 361 return true; 362 } 363 } else { 364 ALOGW("Source advertised native resolution that it doesn't " 365 "actually support... ignoring"); 366 } 367#endif 368 369 bool first = true; 370 uint32_t bestScore = 0; 371 size_t bestType = 0; 372 size_t bestIndex = 0; 373 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 374 for (size_t j = 0; j < 32; ++j) { 375 size_t width, height, framesPerSecond; 376 bool interlaced; 377 if (!GetConfiguration( 378 (ResolutionType)i, 379 j, 380 &width, &height, &framesPerSecond, &interlaced)) { 381 break; 382 } 383 384 if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j) 385 || !sourceSupported.isResolutionEnabled( 386 (ResolutionType)i, j)) { 387 continue; 388 } 389 390 ALOGV("type %u, index %u, %u x %u %c%u supported", 391 i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond); 392 393 uint32_t score = width * height * framesPerSecond; 394 if (!interlaced) { 395 score *= 2; 396 } 397 398 if (first || score > bestScore) { 399 bestScore = score; 400 bestType = i; 401 bestIndex = j; 402 403 first = false; 404 } 405 } 406 } 407 408 if (first) { 409 return false; 410 } 411 412 *chosenType = (ResolutionType)bestType; 413 *chosenIndex = bestIndex; 414 415 return true; 416} 417 418} // namespace android 419 420