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 VideoFormats::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 
    135 VideoFormats::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 
    143 void 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 
    153 void VideoFormats::getNativeResolution(
    154         ResolutionType *type, size_t *index) const {
    155     *type = mNativeType;
    156     *index = mNativeIndex;
    157 }
    158 
    159 void 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 
    168 void 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 
    178 void 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 
    190 bool 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
    199 bool 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 
    235 bool 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 
    265 bool 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 
    303 AString 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
    331 bool 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