tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

h265_profile_tier_level.cc (11740B)


      1 /*
      2 *  Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "api/video_codecs/h265_profile_tier_level.h"
     12 
     13 #include <optional>
     14 #include <string>
     15 
     16 #include "api/rtp_parameters.h"
     17 #include "api/video/resolution.h"
     18 #include "rtc_base/string_to_number.h"
     19 
     20 namespace webrtc {
     21 
     22 namespace {
     23 
     24 const char kH265FmtpProfile[] = "profile-id";
     25 const char kH265FmtpTier[] = "tier-flag";
     26 const char kH265FmtpLevel[] = "level-id";
     27 
     28 // Used to align frame width and height for luma picture size calculation.
     29 // Use the maximum value allowed by spec to get upper bound of luma picture
     30 // size for given resolution.
     31 constexpr int kMinCbSizeYMax = 64;
     32 
     33 struct LevelConstraint {
     34  const int max_luma_picture_size;
     35  const double max_luma_sample_rate;
     36  const int max_pic_width_or_height_in_pixels;
     37  const H265Level level;
     38 };
     39 
     40 // This is from ITU-T H.265 (09/2023) Table A.8, A.9 & A.11 – Level limits.
     41 // The max_pic_width_or_height_in_luma_samples is pre-calculated following
     42 // ITU-T H.265 section A.4.1, that is, find the largest integer value that
     43 // is multiple of minimal MinCbSizeY(8 according to equation 7-10 and 7-12), is
     44 // less than sqrt(max_luma_picture_size * 8). For example, at level 1,
     45 // max_luma_picture_size is 36864, so pic_width_in_luma_samples <= sqrt(36864 *
     46 // 8) = 543.06. The largest integer that is multiple of 8 and less than 543.06
     47 // is 536.
     48 constexpr LevelConstraint kLevelConstraints[] = {
     49    {.max_luma_picture_size = 36864,
     50     .max_luma_sample_rate = 552960,
     51     .max_pic_width_or_height_in_pixels = 536,
     52     .level = H265Level::kLevel1},
     53    {.max_luma_picture_size = 122880,
     54     .max_luma_sample_rate = 3686400,
     55     .max_pic_width_or_height_in_pixels = 984,
     56     .level = H265Level::kLevel2},
     57    {.max_luma_picture_size = 245760,
     58     .max_luma_sample_rate = 7372800,
     59     .max_pic_width_or_height_in_pixels = 1400,
     60     .level = H265Level::kLevel2_1},
     61    {.max_luma_picture_size = 552960,
     62     .max_luma_sample_rate = 16588800,
     63     .max_pic_width_or_height_in_pixels = 2096,
     64     .level = H265Level::kLevel3},
     65    {.max_luma_picture_size = 983040,
     66     .max_luma_sample_rate = 33177600,
     67     .max_pic_width_or_height_in_pixels = 2800,
     68     .level = H265Level::kLevel3_1},
     69    {.max_luma_picture_size = 2228224,
     70     .max_luma_sample_rate = 66846720,
     71     .max_pic_width_or_height_in_pixels = 4216,
     72     .level = H265Level::kLevel4},
     73    {.max_luma_picture_size = 2228224,
     74     .max_luma_sample_rate = 133693400,
     75     .max_pic_width_or_height_in_pixels = 4216,
     76     .level = H265Level::kLevel4_1},
     77    {.max_luma_picture_size = 8912896,
     78     .max_luma_sample_rate = 267386880,
     79     .max_pic_width_or_height_in_pixels = 8440,
     80     .level = H265Level::kLevel5},
     81    {.max_luma_picture_size = 8912896,
     82     .max_luma_sample_rate = 534773760,
     83     .max_pic_width_or_height_in_pixels = 8440,
     84     .level = H265Level::kLevel5_1},
     85    {.max_luma_picture_size = 8912896,
     86     .max_luma_sample_rate = 1069547520,
     87     .max_pic_width_or_height_in_pixels = 8440,
     88     .level = H265Level::kLevel5_2},
     89    {.max_luma_picture_size = 35651584,
     90     .max_luma_sample_rate = 1069547520,
     91     .max_pic_width_or_height_in_pixels = 16888,
     92     .level = H265Level::kLevel6},
     93    {.max_luma_picture_size = 35651584,
     94     .max_luma_sample_rate = 2139095040,
     95     .max_pic_width_or_height_in_pixels = 16888,
     96     .level = H265Level::kLevel6_1},
     97    {.max_luma_picture_size = 35651584,
     98     .max_luma_sample_rate = 4278190080,
     99     .max_pic_width_or_height_in_pixels = 16888,
    100     .level = H265Level::kLevel6_2},
    101 };
    102 
    103 }  // anonymous namespace
    104 
    105 // Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.3.
    106 std::optional<H265Profile> StringToH265Profile(const std::string& profile) {
    107  std::optional<int> i = StringToNumber<int>(profile);
    108  if (!i.has_value()) {
    109    return std::nullopt;
    110  }
    111 
    112  switch (i.value()) {
    113    case 1:
    114      return H265Profile::kProfileMain;
    115    case 2:
    116      return H265Profile::kProfileMain10;
    117    case 3:
    118      return H265Profile::kProfileMainStill;
    119    case 4:
    120      return H265Profile::kProfileRangeExtensions;
    121    case 5:
    122      return H265Profile::kProfileHighThroughput;
    123    case 6:
    124      return H265Profile::kProfileMultiviewMain;
    125    case 7:
    126      return H265Profile::kProfileScalableMain;
    127    case 8:
    128      return H265Profile::kProfile3dMain;
    129    case 9:
    130      return H265Profile::kProfileScreenContentCoding;
    131    case 10:
    132      return H265Profile::kProfileScalableRangeExtensions;
    133    case 11:
    134      return H265Profile::kProfileHighThroughputScreenContentCoding;
    135    default:
    136      return std::nullopt;
    137  }
    138 }
    139 
    140 // Annex A of https://www.itu.int/rec/T-REC-H.265 (08/21), section A.4,
    141 // tiers and levels.
    142 std::optional<H265Tier> StringToH265Tier(const std::string& tier) {
    143  std::optional<int> i = StringToNumber<int>(tier);
    144  if (!i.has_value()) {
    145    return std::nullopt;
    146  }
    147 
    148  switch (i.value()) {
    149    case 0:
    150      return H265Tier::kTier0;
    151    case 1:
    152      return H265Tier::kTier1;
    153    default:
    154      return std::nullopt;
    155  }
    156 }
    157 
    158 std::optional<H265Level> StringToH265Level(const std::string& level) {
    159  const std::optional<int> i = StringToNumber<int>(level);
    160  if (!i.has_value())
    161    return std::nullopt;
    162 
    163  switch (i.value()) {
    164    case 30:
    165      return H265Level::kLevel1;
    166    case 60:
    167      return H265Level::kLevel2;
    168    case 63:
    169      return H265Level::kLevel2_1;
    170    case 90:
    171      return H265Level::kLevel3;
    172    case 93:
    173      return H265Level::kLevel3_1;
    174    case 120:
    175      return H265Level::kLevel4;
    176    case 123:
    177      return H265Level::kLevel4_1;
    178    case 150:
    179      return H265Level::kLevel5;
    180    case 153:
    181      return H265Level::kLevel5_1;
    182    case 156:
    183      return H265Level::kLevel5_2;
    184    case 180:
    185      return H265Level::kLevel6;
    186    case 183:
    187      return H265Level::kLevel6_1;
    188    case 186:
    189      return H265Level::kLevel6_2;
    190    default:
    191      return std::nullopt;
    192  }
    193 }
    194 
    195 std::string H265ProfileToString(H265Profile profile) {
    196  switch (profile) {
    197    case H265Profile::kProfileMain:
    198      return "1";
    199    case H265Profile::kProfileMain10:
    200      return "2";
    201    case H265Profile::kProfileMainStill:
    202      return "3";
    203    case H265Profile::kProfileRangeExtensions:
    204      return "4";
    205    case H265Profile::kProfileHighThroughput:
    206      return "5";
    207    case H265Profile::kProfileMultiviewMain:
    208      return "6";
    209    case H265Profile::kProfileScalableMain:
    210      return "7";
    211    case H265Profile::kProfile3dMain:
    212      return "8";
    213    case H265Profile::kProfileScreenContentCoding:
    214      return "9";
    215    case H265Profile::kProfileScalableRangeExtensions:
    216      return "10";
    217    case H265Profile::kProfileHighThroughputScreenContentCoding:
    218      return "11";
    219  }
    220 }
    221 
    222 std::string H265TierToString(H265Tier tier) {
    223  switch (tier) {
    224    case H265Tier::kTier0:
    225      return "0";
    226    case H265Tier::kTier1:
    227      return "1";
    228  }
    229 }
    230 
    231 std::string H265LevelToString(H265Level level) {
    232  switch (level) {
    233    case H265Level::kLevel1:
    234      return "30";
    235    case H265Level::kLevel2:
    236      return "60";
    237    case H265Level::kLevel2_1:
    238      return "63";
    239    case H265Level::kLevel3:
    240      return "90";
    241    case H265Level::kLevel3_1:
    242      return "93";
    243    case H265Level::kLevel4:
    244      return "120";
    245    case H265Level::kLevel4_1:
    246      return "123";
    247    case H265Level::kLevel5:
    248      return "150";
    249    case H265Level::kLevel5_1:
    250      return "153";
    251    case H265Level::kLevel5_2:
    252      return "156";
    253    case H265Level::kLevel6:
    254      return "180";
    255    case H265Level::kLevel6_1:
    256      return "183";
    257    case H265Level::kLevel6_2:
    258      return "186";
    259  }
    260 }
    261 
    262 std::optional<H265ProfileTierLevel> ParseSdpForH265ProfileTierLevel(
    263    const CodecParameterMap& params) {
    264  static const H265ProfileTierLevel kDefaultProfileTierLevel(
    265      H265Profile::kProfileMain, H265Tier::kTier0, H265Level::kLevel3_1);
    266  bool profile_tier_level_specified = false;
    267 
    268  std::optional<H265Profile> profile;
    269  const auto profile_it = params.find(kH265FmtpProfile);
    270  if (profile_it != params.end()) {
    271    profile_tier_level_specified = true;
    272    const std::string& profile_str = profile_it->second;
    273    profile = StringToH265Profile(profile_str);
    274    if (!profile) {
    275      return std::nullopt;
    276    }
    277  } else {
    278    profile = H265Profile::kProfileMain;
    279  }
    280  std::optional<H265Tier> tier;
    281  const auto tier_it = params.find(kH265FmtpTier);
    282  if (tier_it != params.end()) {
    283    profile_tier_level_specified = true;
    284    const std::string& tier_str = tier_it->second;
    285    tier = StringToH265Tier(tier_str);
    286    if (!tier) {
    287      return std::nullopt;
    288    }
    289  } else {
    290    tier = H265Tier::kTier0;
    291  }
    292  std::optional<H265Level> level;
    293  const auto level_it = params.find(kH265FmtpLevel);
    294  if (level_it != params.end()) {
    295    profile_tier_level_specified = true;
    296    const std::string& level_str = level_it->second;
    297    level = StringToH265Level(level_str);
    298    if (!level) {
    299      return std::nullopt;
    300    }
    301  } else {
    302    level = H265Level::kLevel3_1;
    303  }
    304 
    305  // Spec Table A.9, level 1 to level 3.1 does not allow high tiers.
    306  if (level <= H265Level::kLevel3_1 && tier == H265Tier::kTier1) {
    307    return std::nullopt;
    308  }
    309 
    310  return !profile_tier_level_specified
    311             ? kDefaultProfileTierLevel
    312             : H265ProfileTierLevel(profile.value(), tier.value(),
    313                                    level.value());
    314 }
    315 
    316 bool H265IsSameProfileTierLevel(const CodecParameterMap& params1,
    317                                const CodecParameterMap& params2) {
    318  const std::optional<H265ProfileTierLevel> ptl1 =
    319      ParseSdpForH265ProfileTierLevel(params1);
    320  const std::optional<H265ProfileTierLevel> ptl2 =
    321      ParseSdpForH265ProfileTierLevel(params2);
    322  return ptl1 && ptl2 && ptl1->profile == ptl2->profile &&
    323         ptl1->tier == ptl2->tier && ptl1->level == ptl2->level;
    324 }
    325 
    326 bool H265IsSameProfile(const CodecParameterMap& params1,
    327                       const CodecParameterMap& params2) {
    328  const std::optional<H265ProfileTierLevel> ptl1 =
    329      ParseSdpForH265ProfileTierLevel(params1);
    330  const std::optional<H265ProfileTierLevel> ptl2 =
    331      ParseSdpForH265ProfileTierLevel(params2);
    332  return ptl1 && ptl2 && ptl1->profile == ptl2->profile;
    333 }
    334 
    335 bool H265IsSameTier(const CodecParameterMap& params1,
    336                    const CodecParameterMap& params2) {
    337  const std::optional<H265ProfileTierLevel> ptl1 =
    338      ParseSdpForH265ProfileTierLevel(params1);
    339  const std::optional<H265ProfileTierLevel> ptl2 =
    340      ParseSdpForH265ProfileTierLevel(params2);
    341  return ptl1 && ptl2 && ptl1->tier == ptl2->tier;
    342 }
    343 
    344 std::optional<H265Level> GetSupportedH265Level(const Resolution& resolution,
    345                                               float max_fps) {
    346  int aligned_width =
    347      (resolution.width + kMinCbSizeYMax - 1) & ~(kMinCbSizeYMax - 1);
    348  int aligned_height =
    349      (resolution.height + kMinCbSizeYMax - 1) & ~(kMinCbSizeYMax - 1);
    350 
    351  for (int i = std::ssize(kLevelConstraints) - 1; i >= 0; --i) {
    352    const LevelConstraint& level_constraint = kLevelConstraints[i];
    353    if (level_constraint.max_luma_picture_size <=
    354            aligned_width * aligned_height &&
    355        level_constraint.max_luma_sample_rate <=
    356            aligned_width * aligned_height * max_fps &&
    357        level_constraint.max_pic_width_or_height_in_pixels >= aligned_width &&
    358        level_constraint.max_pic_width_or_height_in_pixels >= aligned_height) {
    359      return level_constraint.level;
    360    }
    361  }
    362  return std::nullopt;
    363 }
    364 
    365 }  // namespace webrtc