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 25 namespace android { 26 27 // static 28 const VideoFormats::config_t VideoFormats::mResolutionTable[][32] = { 29 { 30 // CEA Resolutions 31 { 640, 480, 60, false, 0, 0}, 32 { 720, 480, 60, false, 0, 0}, 33 { 720, 480, 60, true, 0, 0}, 34 { 720, 576, 50, false, 0, 0}, 35 { 720, 576, 50, true, 0, 0}, 36 { 1280, 720, 30, false, 0, 0}, 37 { 1280, 720, 60, false, 0, 0}, 38 { 1920, 1080, 30, false, 0, 0}, 39 { 1920, 1080, 60, false, 0, 0}, 40 { 1920, 1080, 60, true, 0, 0}, 41 { 1280, 720, 25, false, 0, 0}, 42 { 1280, 720, 50, false, 0, 0}, 43 { 1920, 1080, 25, false, 0, 0}, 44 { 1920, 1080, 50, false, 0, 0}, 45 { 1920, 1080, 50, true, 0, 0}, 46 { 1280, 720, 24, false, 0, 0}, 47 { 1920, 1080, 24, 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 { 0, 0, 0, false, 0, 0}, 63 }, 64 { 65 // VESA Resolutions 66 { 800, 600, 30, false, 0, 0}, 67 { 800, 600, 60, false, 0, 0}, 68 { 1024, 768, 30, false, 0, 0}, 69 { 1024, 768, 60, false, 0, 0}, 70 { 1152, 864, 30, false, 0, 0}, 71 { 1152, 864, 60, false, 0, 0}, 72 { 1280, 768, 30, false, 0, 0}, 73 { 1280, 768, 60, false, 0, 0}, 74 { 1280, 800, 30, false, 0, 0}, 75 { 1280, 800, 60, false, 0, 0}, 76 { 1360, 768, 30, false, 0, 0}, 77 { 1360, 768, 60, false, 0, 0}, 78 { 1366, 768, 30, false, 0, 0}, 79 { 1366, 768, 60, false, 0, 0}, 80 { 1280, 1024, 30, false, 0, 0}, 81 { 1280, 1024, 60, false, 0, 0}, 82 { 1400, 1050, 30, false, 0, 0}, 83 { 1400, 1050, 60, false, 0, 0}, 84 { 1440, 900, 30, false, 0, 0}, 85 { 1440, 900, 60, false, 0, 0}, 86 { 1600, 900, 30, false, 0, 0}, 87 { 1600, 900, 60, false, 0, 0}, 88 { 1600, 1200, 30, false, 0, 0}, 89 { 1600, 1200, 60, false, 0, 0}, 90 { 1680, 1024, 30, false, 0, 0}, 91 { 1680, 1024, 60, false, 0, 0}, 92 { 1680, 1050, 30, false, 0, 0}, 93 { 1680, 1050, 60, false, 0, 0}, 94 { 1920, 1200, 30, false, 0, 0}, 95 { 1920, 1200, 60, false, 0, 0}, 96 { 0, 0, 0, false, 0, 0}, 97 { 0, 0, 0, false, 0, 0}, 98 }, 99 { 100 // HH Resolutions 101 { 800, 480, 30, false, 0, 0}, 102 { 800, 480, 60, false, 0, 0}, 103 { 854, 480, 30, false, 0, 0}, 104 { 854, 480, 60, false, 0, 0}, 105 { 864, 480, 30, false, 0, 0}, 106 { 864, 480, 60, false, 0, 0}, 107 { 640, 360, 30, false, 0, 0}, 108 { 640, 360, 60, false, 0, 0}, 109 { 960, 540, 30, false, 0, 0}, 110 { 960, 540, 60, false, 0, 0}, 111 { 848, 480, 30, false, 0, 0}, 112 { 848, 480, 60, 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 { 0, 0, 0, false, 0, 0}, 133 } 134 }; 135 136 VideoFormats::VideoFormats() { 137 memcpy(mConfigs, mResolutionTable, sizeof(mConfigs)); 138 139 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 140 mResolutionEnabled[i] = 0; 141 } 142 143 setNativeResolution(RESOLUTION_CEA, 0); // default to 640x480 p60 144 } 145 146 void VideoFormats::setNativeResolution(ResolutionType type, size_t index) { 147 CHECK_LT(type, kNumResolutionTypes); 148 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 149 150 mNativeType = type; 151 mNativeIndex = index; 152 153 setResolutionEnabled(type, index); 154 } 155 156 void VideoFormats::getNativeResolution( 157 ResolutionType *type, size_t *index) const { 158 *type = mNativeType; 159 *index = mNativeIndex; 160 } 161 162 void VideoFormats::disableAll() { 163 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 164 mResolutionEnabled[i] = 0; 165 for (size_t j = 0; j < 32; j++) { 166 mConfigs[i][j].profile = mConfigs[i][j].level = 0; 167 } 168 } 169 } 170 171 void VideoFormats::enableAll() { 172 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 173 mResolutionEnabled[i] = 0xffffffff; 174 for (size_t j = 0; j < 32; j++) { 175 mConfigs[i][j].profile = (1ul << PROFILE_CBP); 176 mConfigs[i][j].level = (1ul << LEVEL_31); 177 } 178 } 179 } 180 181 void VideoFormats::enableResolutionUpto( 182 ResolutionType type, size_t index, 183 ProfileType profile, LevelType level) { 184 size_t width, height, fps, score; 185 bool interlaced; 186 if (!GetConfiguration(type, index, &width, &height, 187 &fps, &interlaced)) { 188 ALOGE("Maximum resolution not found!"); 189 return; 190 } 191 score = width * height * fps * (!interlaced + 1); 192 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 193 for (size_t j = 0; j < 32; j++) { 194 if (GetConfiguration((ResolutionType)i, j, 195 &width, &height, &fps, &interlaced) 196 && score >= width * height * fps * (!interlaced + 1)) { 197 setResolutionEnabled((ResolutionType)i, j); 198 setProfileLevel((ResolutionType)i, j, profile, level); 199 } 200 } 201 } 202 } 203 204 void VideoFormats::setResolutionEnabled( 205 ResolutionType type, size_t index, bool enabled) { 206 CHECK_LT(type, kNumResolutionTypes); 207 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 208 209 if (enabled) { 210 mResolutionEnabled[type] |= (1ul << index); 211 mConfigs[type][index].profile = (1ul << PROFILE_CBP); 212 mConfigs[type][index].level = (1ul << LEVEL_31); 213 } else { 214 mResolutionEnabled[type] &= ~(1ul << index); 215 mConfigs[type][index].profile = 0; 216 mConfigs[type][index].level = 0; 217 } 218 } 219 220 void VideoFormats::setProfileLevel( 221 ResolutionType type, size_t index, 222 ProfileType profile, LevelType level) { 223 CHECK_LT(type, kNumResolutionTypes); 224 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 225 226 mConfigs[type][index].profile = (1ul << profile); 227 mConfigs[type][index].level = (1ul << level); 228 } 229 230 void VideoFormats::getProfileLevel( 231 ResolutionType type, size_t index, 232 ProfileType *profile, LevelType *level) const{ 233 CHECK_LT(type, kNumResolutionTypes); 234 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 235 236 int i, bestProfile = -1, bestLevel = -1; 237 238 for (i = 0; i < kNumProfileTypes; ++i) { 239 if (mConfigs[type][index].profile & (1ul << i)) { 240 bestProfile = i; 241 } 242 } 243 244 for (i = 0; i < kNumLevelTypes; ++i) { 245 if (mConfigs[type][index].level & (1ul << i)) { 246 bestLevel = i; 247 } 248 } 249 250 if (bestProfile == -1 || bestLevel == -1) { 251 ALOGE("Profile or level not set for resolution type %d, index %d", 252 type, index); 253 bestProfile = PROFILE_CBP; 254 bestLevel = LEVEL_31; 255 } 256 257 *profile = (ProfileType) bestProfile; 258 *level = (LevelType) bestLevel; 259 } 260 261 bool VideoFormats::isResolutionEnabled( 262 ResolutionType type, size_t index) const { 263 CHECK_LT(type, kNumResolutionTypes); 264 CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL)); 265 266 return mResolutionEnabled[type] & (1ul << index); 267 } 268 269 // static 270 bool VideoFormats::GetConfiguration( 271 ResolutionType type, 272 size_t index, 273 size_t *width, size_t *height, size_t *framesPerSecond, 274 bool *interlaced) { 275 CHECK_LT(type, kNumResolutionTypes); 276 277 if (index >= 32) { 278 return false; 279 } 280 281 const config_t *config = &mResolutionTable[type][index]; 282 283 if (config->width == 0) { 284 return false; 285 } 286 287 if (width) { 288 *width = config->width; 289 } 290 291 if (height) { 292 *height = config->height; 293 } 294 295 if (framesPerSecond) { 296 *framesPerSecond = config->framesPerSecond; 297 } 298 299 if (interlaced) { 300 *interlaced = config->interlaced; 301 } 302 303 return true; 304 } 305 306 bool VideoFormats::parseH264Codec(const char *spec) { 307 unsigned profile, level, res[3]; 308 309 if (sscanf( 310 spec, 311 "%02x %02x %08X %08X %08X", 312 &profile, 313 &level, 314 &res[0], 315 &res[1], 316 &res[2]) != 5) { 317 return false; 318 } 319 320 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 321 for (size_t j = 0; j < 32; ++j) { 322 if (res[i] & (1ul << j)){ 323 mResolutionEnabled[i] |= (1ul << j); 324 if (profile > mConfigs[i][j].profile) { 325 // prefer higher profile (even if level is lower) 326 mConfigs[i][j].profile = profile; 327 mConfigs[i][j].level = level; 328 } else if (profile == mConfigs[i][j].profile && 329 level > mConfigs[i][j].level) { 330 mConfigs[i][j].level = level; 331 } 332 } 333 } 334 } 335 336 return true; 337 } 338 339 // static 340 bool VideoFormats::GetProfileLevel( 341 ProfileType profile, LevelType level, unsigned *profileIdc, 342 unsigned *levelIdc, unsigned *constraintSet) { 343 CHECK_LT(profile, kNumProfileTypes); 344 CHECK_LT(level, kNumLevelTypes); 345 346 static const unsigned kProfileIDC[kNumProfileTypes] = { 347 66, // PROFILE_CBP 348 100, // PROFILE_CHP 349 }; 350 351 static const unsigned kLevelIDC[kNumLevelTypes] = { 352 31, // LEVEL_31 353 32, // LEVEL_32 354 40, // LEVEL_40 355 41, // LEVEL_41 356 42, // LEVEL_42 357 }; 358 359 static const unsigned kConstraintSet[kNumProfileTypes] = { 360 0xc0, // PROFILE_CBP 361 0x0c, // PROFILE_CHP 362 }; 363 364 if (profileIdc) { 365 *profileIdc = kProfileIDC[profile]; 366 } 367 368 if (levelIdc) { 369 *levelIdc = kLevelIDC[level]; 370 } 371 372 if (constraintSet) { 373 *constraintSet = kConstraintSet[profile]; 374 } 375 376 return true; 377 } 378 379 bool VideoFormats::parseFormatSpec(const char *spec) { 380 CHECK_EQ(kNumResolutionTypes, 3); 381 382 disableAll(); 383 384 unsigned native, dummy; 385 unsigned res[3]; 386 size_t size = strlen(spec); 387 size_t offset = 0; 388 389 if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) { 390 return false; 391 } 392 393 offset += 6; // skip native and preferred-display-mode-supported 394 CHECK_LE(offset + 58, size); 395 while (offset < size) { 396 parseH264Codec(spec + offset); 397 offset += 60; // skip H.264-codec + ", " 398 } 399 400 mNativeIndex = native >> 3; 401 mNativeType = (ResolutionType)(native & 7); 402 403 bool success; 404 if (mNativeType >= kNumResolutionTypes) { 405 success = false; 406 } else { 407 success = GetConfiguration( 408 mNativeType, mNativeIndex, NULL, NULL, NULL, NULL); 409 } 410 411 if (!success) { 412 ALOGW("sink advertised an illegal native resolution, fortunately " 413 "this value is ignored for the time being..."); 414 } 415 416 return true; 417 } 418 419 AString VideoFormats::getFormatSpec(bool forM4Message) const { 420 CHECK_EQ(kNumResolutionTypes, 3); 421 422 // wfd_video_formats: 423 // 1 byte "native" 424 // 1 byte "preferred-display-mode-supported" 0 or 1 425 // one or more avc codec structures 426 // 1 byte profile 427 // 1 byte level 428 // 4 byte CEA mask 429 // 4 byte VESA mask 430 // 4 byte HH mask 431 // 1 byte latency 432 // 2 byte min-slice-slice 433 // 2 byte slice-enc-params 434 // 1 byte framerate-control-support 435 // max-hres (none or 2 byte) 436 // max-vres (none or 2 byte) 437 438 return StringPrintf( 439 "%02x 00 %02x %02x %08x %08x %08x 00 0000 0000 00 none none", 440 forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType), 441 mConfigs[mNativeType][mNativeIndex].profile, 442 mConfigs[mNativeType][mNativeIndex].level, 443 mResolutionEnabled[0], 444 mResolutionEnabled[1], 445 mResolutionEnabled[2]); 446 } 447 448 // static 449 bool VideoFormats::PickBestFormat( 450 const VideoFormats &sinkSupported, 451 const VideoFormats &sourceSupported, 452 ResolutionType *chosenType, 453 size_t *chosenIndex, 454 ProfileType *chosenProfile, 455 LevelType *chosenLevel) { 456 #if 0 457 // Support for the native format is a great idea, the spec includes 458 // these features, but nobody supports it and the tests don't validate it. 459 460 ResolutionType nativeType; 461 size_t nativeIndex; 462 sinkSupported.getNativeResolution(&nativeType, &nativeIndex); 463 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 464 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 465 ALOGI("Choosing sink's native resolution"); 466 *chosenType = nativeType; 467 *chosenIndex = nativeIndex; 468 return true; 469 } 470 } else { 471 ALOGW("Sink advertised native resolution that it doesn't " 472 "actually support... ignoring"); 473 } 474 475 sourceSupported.getNativeResolution(&nativeType, &nativeIndex); 476 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 477 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 478 ALOGI("Choosing source's native resolution"); 479 *chosenType = nativeType; 480 *chosenIndex = nativeIndex; 481 return true; 482 } 483 } else { 484 ALOGW("Source advertised native resolution that it doesn't " 485 "actually support... ignoring"); 486 } 487 #endif 488 489 bool first = true; 490 uint32_t bestScore = 0; 491 size_t bestType = 0; 492 size_t bestIndex = 0; 493 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 494 for (size_t j = 0; j < 32; ++j) { 495 size_t width, height, framesPerSecond; 496 bool interlaced; 497 if (!GetConfiguration( 498 (ResolutionType)i, 499 j, 500 &width, &height, &framesPerSecond, &interlaced)) { 501 break; 502 } 503 504 if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j) 505 || !sourceSupported.isResolutionEnabled( 506 (ResolutionType)i, j)) { 507 continue; 508 } 509 510 ALOGV("type %u, index %u, %u x %u %c%u supported", 511 i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond); 512 513 uint32_t score = width * height * framesPerSecond; 514 if (!interlaced) { 515 score *= 2; 516 } 517 518 if (first || score > bestScore) { 519 bestScore = score; 520 bestType = i; 521 bestIndex = j; 522 523 first = false; 524 } 525 } 526 } 527 528 if (first) { 529 return false; 530 } 531 532 *chosenType = (ResolutionType)bestType; 533 *chosenIndex = bestIndex; 534 535 // Pick the best profile/level supported by both sink and source. 536 ProfileType srcProfile, sinkProfile; 537 LevelType srcLevel, sinkLevel; 538 sourceSupported.getProfileLevel( 539 (ResolutionType)bestType, bestIndex, 540 &srcProfile, &srcLevel); 541 sinkSupported.getProfileLevel( 542 (ResolutionType)bestType, bestIndex, 543 &sinkProfile, &sinkLevel); 544 *chosenProfile = srcProfile < sinkProfile ? srcProfile : sinkProfile; 545 *chosenLevel = srcLevel < sinkLevel ? srcLevel : sinkLevel; 546 547 return true; 548 } 549 550 } // namespace android 551 552