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 %zu", 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 size_t size = strlen(spec); 386 size_t offset = 0; 387 388 if (sscanf(spec, "%02x %02x ", &native, &dummy) != 2) { 389 return false; 390 } 391 392 offset += 6; // skip native and preferred-display-mode-supported 393 CHECK_LE(offset + 58, size); 394 while (offset < size) { 395 parseH264Codec(spec + offset); 396 offset += 60; // skip H.264-codec + ", " 397 } 398 399 mNativeIndex = native >> 3; 400 mNativeType = (ResolutionType)(native & 7); 401 402 bool success; 403 if (mNativeType >= kNumResolutionTypes) { 404 success = false; 405 } else { 406 success = GetConfiguration( 407 mNativeType, mNativeIndex, NULL, NULL, NULL, NULL); 408 } 409 410 if (!success) { 411 ALOGW("sink advertised an illegal native resolution, fortunately " 412 "this value is ignored for the time being..."); 413 } 414 415 return true; 416 } 417 418 AString VideoFormats::getFormatSpec(bool forM4Message) const { 419 CHECK_EQ(kNumResolutionTypes, 3); 420 421 // wfd_video_formats: 422 // 1 byte "native" 423 // 1 byte "preferred-display-mode-supported" 0 or 1 424 // one or more avc codec structures 425 // 1 byte profile 426 // 1 byte level 427 // 4 byte CEA mask 428 // 4 byte VESA mask 429 // 4 byte HH mask 430 // 1 byte latency 431 // 2 byte min-slice-slice 432 // 2 byte slice-enc-params 433 // 1 byte framerate-control-support 434 // max-hres (none or 2 byte) 435 // max-vres (none or 2 byte) 436 437 return AStringPrintf( 438 "%02x 00 %02x %02x %08x %08x %08x 00 0000 0000 00 none none", 439 forM4Message ? 0x00 : ((mNativeIndex << 3) | mNativeType), 440 mConfigs[mNativeType][mNativeIndex].profile, 441 mConfigs[mNativeType][mNativeIndex].level, 442 mResolutionEnabled[0], 443 mResolutionEnabled[1], 444 mResolutionEnabled[2]); 445 } 446 447 // static 448 bool VideoFormats::PickBestFormat( 449 const VideoFormats &sinkSupported, 450 const VideoFormats &sourceSupported, 451 ResolutionType *chosenType, 452 size_t *chosenIndex, 453 ProfileType *chosenProfile, 454 LevelType *chosenLevel) { 455 #if 0 456 // Support for the native format is a great idea, the spec includes 457 // these features, but nobody supports it and the tests don't validate it. 458 459 ResolutionType nativeType; 460 size_t nativeIndex; 461 sinkSupported.getNativeResolution(&nativeType, &nativeIndex); 462 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 463 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 464 ALOGI("Choosing sink's native resolution"); 465 *chosenType = nativeType; 466 *chosenIndex = nativeIndex; 467 return true; 468 } 469 } else { 470 ALOGW("Sink advertised native resolution that it doesn't " 471 "actually support... ignoring"); 472 } 473 474 sourceSupported.getNativeResolution(&nativeType, &nativeIndex); 475 if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) { 476 if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) { 477 ALOGI("Choosing source's native resolution"); 478 *chosenType = nativeType; 479 *chosenIndex = nativeIndex; 480 return true; 481 } 482 } else { 483 ALOGW("Source advertised native resolution that it doesn't " 484 "actually support... ignoring"); 485 } 486 #endif 487 488 bool first = true; 489 uint32_t bestScore = 0; 490 size_t bestType = 0; 491 size_t bestIndex = 0; 492 for (size_t i = 0; i < kNumResolutionTypes; ++i) { 493 for (size_t j = 0; j < 32; ++j) { 494 size_t width, height, framesPerSecond; 495 bool interlaced; 496 if (!GetConfiguration( 497 (ResolutionType)i, 498 j, 499 &width, &height, &framesPerSecond, &interlaced)) { 500 break; 501 } 502 503 if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j) 504 || !sourceSupported.isResolutionEnabled( 505 (ResolutionType)i, j)) { 506 continue; 507 } 508 509 ALOGV("type %zu, index %zu, %zu x %zu %c%zu supported", 510 i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond); 511 512 uint32_t score = width * height * framesPerSecond; 513 if (!interlaced) { 514 score *= 2; 515 } 516 517 if (first || score > bestScore) { 518 bestScore = score; 519 bestType = i; 520 bestIndex = j; 521 522 first = false; 523 } 524 } 525 } 526 527 if (first) { 528 return false; 529 } 530 531 *chosenType = (ResolutionType)bestType; 532 *chosenIndex = bestIndex; 533 534 // Pick the best profile/level supported by both sink and source. 535 ProfileType srcProfile, sinkProfile; 536 LevelType srcLevel, sinkLevel; 537 sourceSupported.getProfileLevel( 538 (ResolutionType)bestType, bestIndex, 539 &srcProfile, &srcLevel); 540 sinkSupported.getProfileLevel( 541 (ResolutionType)bestType, bestIndex, 542 &sinkProfile, &sinkLevel); 543 *chosenProfile = srcProfile < sinkProfile ? srcProfile : sinkProfile; 544 *chosenLevel = srcLevel < sinkLevel ? srcLevel : sinkLevel; 545 546 return true; 547 } 548 549 } // namespace android 550 551