tor-browser

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

sdp_video_format.cc (9441B)


      1 /*
      2 *  Copyright (c) 2018 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/sdp_video_format.h"
     12 
     13 #include <optional>
     14 #include <string>
     15 
     16 #include "absl/container/inlined_vector.h"
     17 #include "absl/strings/match.h"
     18 #include "api/array_view.h"
     19 #include "api/rtp_parameters.h"
     20 #include "api/video/video_codec_type.h"
     21 #include "api/video_codecs/av1_profile.h"
     22 #include "api/video_codecs/h264_profile_level_id.h"
     23 #include "api/video_codecs/scalability_mode.h"
     24 #ifdef RTC_ENABLE_H265
     25 #include "api/video_codecs/h265_profile_tier_level.h"
     26 #endif
     27 #include "api/video_codecs/video_codec.h"
     28 #include "api/video_codecs/vp9_profile.h"
     29 #include "media/base/media_constants.h"
     30 #include "rtc_base/checks.h"
     31 #include "rtc_base/logging.h"
     32 #include "rtc_base/strings/string_builder.h"
     33 
     34 namespace webrtc {
     35 
     36 namespace {
     37 
     38 // TODO(bugs.webrtc.org/15847): remove code duplication of IsSameCodecSpecific
     39 // in media/base/codec.cc
     40 std::string GetFmtpParameterOrDefault(const CodecParameterMap& params,
     41                                      const std::string& name,
     42                                      const std::string& default_value) {
     43  const auto it = params.find(name);
     44  if (it != params.end()) {
     45    return it->second;
     46  }
     47  return default_value;
     48 }
     49 
     50 std::string H264GetPacketizationModeOrDefault(const CodecParameterMap& params) {
     51  // If packetization-mode is not present, default to "0".
     52  // https://tools.ietf.org/html/rfc6184#section-6.2
     53  return GetFmtpParameterOrDefault(params, kH264FmtpPacketizationMode, "0");
     54 }
     55 
     56 bool H264IsSamePacketizationMode(const CodecParameterMap& left,
     57                                 const CodecParameterMap& right) {
     58  return H264GetPacketizationModeOrDefault(left) ==
     59         H264GetPacketizationModeOrDefault(right);
     60 }
     61 
     62 #ifdef RTC_ENABLE_H265
     63 std::string GetH265TxModeOrDefault(const CodecParameterMap& params) {
     64  // If TxMode is not present, a value of "SRST" must be inferred.
     65  // https://tools.ietf.org/html/rfc7798@section-7.1
     66  return GetFmtpParameterOrDefault(params, kH265FmtpTxMode, "SRST");
     67 }
     68 
     69 bool IsSameH265TxMode(const CodecParameterMap& left,
     70                      const CodecParameterMap& right) {
     71  return absl::EqualsIgnoreCase(GetH265TxModeOrDefault(left),
     72                                GetH265TxModeOrDefault(right));
     73 }
     74 #endif
     75 
     76 // Some (video) codecs are actually families of codecs and rely on parameters
     77 // to distinguish different incompatible family members.
     78 bool IsSameCodecSpecific(const std::string& name1,
     79                         const CodecParameterMap& params1,
     80                         const std::string& name2,
     81                         const CodecParameterMap& params2) {
     82  // The assumption when calling this function is that the two formats have the
     83  // same name.
     84  RTC_DCHECK(absl::EqualsIgnoreCase(name1, name2));
     85 
     86  VideoCodecType codec_type = PayloadStringToCodecType(name1);
     87  switch (codec_type) {
     88    case kVideoCodecH264:
     89      return H264IsSameProfile(params1, params2) &&
     90             H264IsSamePacketizationMode(params1, params2);
     91    case kVideoCodecVP9:
     92      return VP9IsSameProfile(params1, params2);
     93    case kVideoCodecAV1:
     94      // https://aomediacodec.github.io/av1-rtp-spec/#723-usage-with-the-sdp-offeranswer-model
     95      //   These media configuration parameters are asymmetrical and the
     96      //   answerer MAY declare its own media configuration
     97      // TODO(bugs.webrtc.org/396434695): for backward compability we currently
     98      // compare profile.
     99      return AV1IsSameProfile(params1, params2);
    100 #ifdef RTC_ENABLE_H265
    101    case kVideoCodecH265:
    102      return H265IsSameProfile(params1, params2) &&
    103             H265IsSameTier(params1, params2) &&
    104             IsSameH265TxMode(params1, params2);
    105 #endif
    106    default:
    107      return true;
    108  }
    109 }
    110 
    111 }  // namespace
    112 
    113 SdpVideoFormat::SdpVideoFormat(const std::string& name) : name(name) {}
    114 
    115 SdpVideoFormat::SdpVideoFormat(const std::string& name,
    116                               const CodecParameterMap& parameters)
    117    : name(name), parameters(parameters) {}
    118 
    119 SdpVideoFormat::SdpVideoFormat(
    120    const std::string& name,
    121    const CodecParameterMap& parameters,
    122    const absl::InlinedVector<ScalabilityMode, kScalabilityModeCount>&
    123        scalability_modes)
    124    : name(name),
    125      parameters(parameters),
    126      scalability_modes(scalability_modes) {}
    127 
    128 SdpVideoFormat::SdpVideoFormat(
    129    const SdpVideoFormat& format,
    130    const absl::InlinedVector<ScalabilityMode, kScalabilityModeCount>& modes)
    131    : SdpVideoFormat(format) {
    132  scalability_modes = modes;
    133 }
    134 
    135 SdpVideoFormat::SdpVideoFormat(const SdpVideoFormat&) = default;
    136 SdpVideoFormat::SdpVideoFormat(SdpVideoFormat&&) = default;
    137 SdpVideoFormat& SdpVideoFormat::operator=(const SdpVideoFormat&) = default;
    138 SdpVideoFormat& SdpVideoFormat::operator=(SdpVideoFormat&&) = default;
    139 
    140 SdpVideoFormat::~SdpVideoFormat() = default;
    141 
    142 std::string SdpVideoFormat::ToString() const {
    143  StringBuilder builder;
    144  builder << "Codec name: " << name << ", parameters: {";
    145  for (const auto& kv : parameters) {
    146    builder << " " << kv.first << "=" << kv.second;
    147  }
    148 
    149  builder << " }";
    150  if (!scalability_modes.empty()) {
    151    builder << ", scalability_modes: [";
    152    bool first = true;
    153    for (const auto scalability_mode : scalability_modes) {
    154      if (first) {
    155        first = false;
    156      } else {
    157        builder << ", ";
    158      }
    159      builder << ScalabilityModeToString(scalability_mode);
    160    }
    161    builder << "]";
    162  }
    163 
    164  return builder.Release();
    165 }
    166 
    167 bool SdpVideoFormat::IsSameCodec(const SdpVideoFormat& other) const {
    168  // Two codecs are considered the same if the name matches (case insensitive)
    169  // and certain codec-specific parameters match.
    170  return absl::EqualsIgnoreCase(name, other.name) &&
    171         IsSameCodecSpecific(name, parameters, other.name, other.parameters);
    172 }
    173 
    174 bool SdpVideoFormat::IsCodecInList(
    175    ArrayView<const SdpVideoFormat> formats) const {
    176  for (const auto& format : formats) {
    177    if (IsSameCodec(format)) {
    178      return true;
    179    }
    180  }
    181  return false;
    182 }
    183 
    184 bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b) {
    185  return a.name == b.name && a.parameters == b.parameters &&
    186         a.scalability_modes == b.scalability_modes;
    187 }
    188 
    189 const SdpVideoFormat SdpVideoFormat::VP8() {
    190  return SdpVideoFormat(kVp8CodecName, {});
    191 }
    192 
    193 const SdpVideoFormat SdpVideoFormat::H264() {
    194  // H264 will typically require more tweaking like setting
    195  // * packetization-mode (which defaults to 0 but 1 is more common)
    196  // * level-asymmetry-allowed (which defaults to 0 but 1 is more common)
    197  // * profile-level-id of which there are many.
    198  return SdpVideoFormat(kH264CodecName, {});
    199 }
    200 
    201 const SdpVideoFormat SdpVideoFormat::H265() {
    202  return SdpVideoFormat(kH265CodecName, {});
    203 }
    204 
    205 const SdpVideoFormat SdpVideoFormat::VP9Profile0() {
    206  return SdpVideoFormat(
    207      kVp9CodecName,
    208      {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile0)}});
    209 }
    210 
    211 const SdpVideoFormat SdpVideoFormat::VP9Profile1() {
    212  return SdpVideoFormat(
    213      kVp9CodecName,
    214      {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile1)}});
    215 }
    216 
    217 const SdpVideoFormat SdpVideoFormat::VP9Profile2() {
    218  return SdpVideoFormat(
    219      kVp9CodecName,
    220      {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile2)}});
    221 }
    222 
    223 const SdpVideoFormat SdpVideoFormat::VP9Profile3() {
    224  return SdpVideoFormat(
    225      kVp9CodecName,
    226      {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile3)}});
    227 }
    228 
    229 const SdpVideoFormat SdpVideoFormat::AV1Profile0() {
    230  // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
    231  return SdpVideoFormat(
    232      kAv1CodecName,
    233      {{kAv1FmtpProfile, AV1ProfileToString(AV1Profile::kProfile0).data()},
    234       {kAv1FmtpLevelIdx, "5"},
    235       {kAv1FmtpTier, "0"}});
    236 }
    237 
    238 const SdpVideoFormat SdpVideoFormat::AV1Profile1() {
    239  // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
    240  return SdpVideoFormat(
    241      kAv1CodecName,
    242      {{kAv1FmtpProfile, AV1ProfileToString(AV1Profile::kProfile1).data()},
    243       {kAv1FmtpLevelIdx, "5"},
    244       {kAv1FmtpTier, "0"}});
    245 }
    246 
    247 std::optional<SdpVideoFormat> FuzzyMatchSdpVideoFormat(
    248    ArrayView<const SdpVideoFormat> supported_formats,
    249    const SdpVideoFormat& format) {
    250  std::optional<SdpVideoFormat> res;
    251  int best_parameter_match = 0;
    252  for (const auto& supported_format : supported_formats) {
    253    if (absl::EqualsIgnoreCase(supported_format.name, format.name)) {
    254      int matching_parameters = 0;
    255      for (const auto& kv : supported_format.parameters) {
    256        auto it = format.parameters.find(kv.first);
    257        if (it != format.parameters.end() && it->second == kv.second) {
    258          matching_parameters += 1;
    259        }
    260      }
    261 
    262      if (!res || matching_parameters > best_parameter_match) {
    263        res = supported_format;
    264        best_parameter_match = matching_parameters;
    265      }
    266    }
    267  }
    268 
    269  if (!res) {
    270    RTC_LOG(LS_INFO) << "Failed to match SdpVideoFormat " << format.ToString();
    271  } else if (*res != format) {
    272    RTC_LOG(LS_INFO) << "Matched SdpVideoFormat " << format.ToString()
    273                     << " with " << res->ToString();
    274  }
    275 
    276  return res;
    277 }
    278 
    279 }  // namespace webrtc