Home | History | Annotate | Download | only in wifi-display
      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