tor-browser

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

codec.cc (13179B)


      1 /*
      2 *  Copyright (c) 2004 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 "media/base/codec.h"
     12 
     13 #include <algorithm>
     14 #include <cstddef>
     15 #include <iterator>
     16 #include <optional>
     17 #include <string>
     18 #include <vector>
     19 
     20 #include "absl/algorithm/container.h"
     21 #include "absl/strings/match.h"
     22 #include "absl/strings/str_cat.h"
     23 #include "api/audio_codecs/audio_format.h"
     24 #include "api/media_types.h"
     25 #include "api/rtp_parameters.h"
     26 #include "api/video_codecs/h264_profile_level_id.h"
     27 #include "api/video_codecs/sdp_video_format.h"
     28 #ifdef RTC_ENABLE_H265
     29 #include "api/video_codecs/h265_profile_tier_level.h"  // IWYU pragma: keep
     30 #endif
     31 #include "media/base/codec_comparators.h"
     32 #include "media/base/media_constants.h"
     33 #include "rtc_base/checks.h"
     34 #include "rtc_base/logging.h"
     35 #include "rtc_base/string_encode.h"
     36 #include "rtc_base/strings/string_builder.h"
     37 
     38 namespace webrtc {
     39 
     40 FeedbackParams::FeedbackParams() = default;
     41 FeedbackParams::~FeedbackParams() = default;
     42 
     43 bool FeedbackParam::operator==(const FeedbackParam& other) const {
     44  return absl::EqualsIgnoreCase(other.id(), id()) &&
     45         absl::EqualsIgnoreCase(other.param(), param());
     46 }
     47 
     48 bool FeedbackParams::operator==(const FeedbackParams& other) const {
     49  return params_ == other.params_;
     50 }
     51 
     52 bool FeedbackParams::Has(const FeedbackParam& param) const {
     53  return absl::c_linear_search(params_, param);
     54 }
     55 
     56 void FeedbackParams::Add(const FeedbackParam& param) {
     57  if (param.id().empty()) {
     58    return;
     59  }
     60  if (Has(param)) {
     61    // Param already in `this`.
     62    return;
     63  }
     64  params_.push_back(param);
     65  RTC_CHECK(!HasDuplicateEntries());
     66 }
     67 
     68 bool FeedbackParams::Remove(const FeedbackParam& param) {
     69  if (!Has(param)) {
     70    return false;
     71  }
     72  std::erase(params_, param);
     73  return true;
     74 }
     75 
     76 void FeedbackParams::Intersect(const FeedbackParams& from) {
     77  std::vector<FeedbackParam>::iterator iter_to = params_.begin();
     78  while (iter_to != params_.end()) {
     79    if (!from.Has(*iter_to)) {
     80      iter_to = params_.erase(iter_to);
     81    } else {
     82      ++iter_to;
     83    }
     84  }
     85 }
     86 
     87 bool FeedbackParams::HasDuplicateEntries() const {
     88  for (std::vector<FeedbackParam>::const_iterator iter = params_.begin();
     89       iter != params_.end(); ++iter) {
     90    for (std::vector<FeedbackParam>::const_iterator found = iter + 1;
     91         found != params_.end(); ++found) {
     92      if (*found == *iter) {
     93        return true;
     94      }
     95    }
     96  }
     97  return false;
     98 }
     99 
    100 Codec::Codec(Type type, int id, const std::string& name, int clockrate)
    101    : Codec(type, id, name, clockrate, 0) {}
    102 Codec::Codec(Type type,
    103             int id,
    104             const std::string& name,
    105             int clockrate,
    106             size_t channels)
    107    : type(type),
    108      id(id),
    109      name(name),
    110      clockrate(clockrate),
    111      bitrate(0),
    112      channels(channels) {
    113  RTC_DCHECK_GT(clockrate, 0);
    114 }
    115 
    116 Codec::Codec(Type type)
    117    : Codec(type,
    118            kIdNotSet,
    119            "",
    120            type == Type::kVideo ? kDefaultVideoClockRateHz
    121                                 : kDefaultAudioClockRateHz) {}
    122 
    123 Codec::Codec(const SdpAudioFormat& c)
    124    : Codec(Type::kAudio, kIdNotSet, c.name, c.clockrate_hz, c.num_channels) {
    125  params = c.parameters;
    126 }
    127 
    128 Codec::Codec(const SdpVideoFormat& c)
    129    : Codec(Type::kVideo, kIdNotSet, c.name, kVideoCodecClockrate) {
    130  params = c.parameters;
    131  scalability_modes = c.scalability_modes;
    132 }
    133 
    134 Codec::Codec(const Codec& c) = default;
    135 Codec::Codec(Codec&& c) = default;
    136 Codec::~Codec() = default;
    137 Codec& Codec::operator=(const Codec& c) = default;
    138 Codec& Codec::operator=(Codec&& c) = default;
    139 
    140 bool Codec::operator==(const Codec& c) const {
    141  return type == c.type && this->id == c.id &&  // id is reserved in objective-c
    142         name == c.name && clockrate == c.clockrate && params == c.params &&
    143         feedback_params == c.feedback_params &&
    144         (type == Type::kAudio
    145              ? (bitrate == c.bitrate && channels == c.channels)
    146              : (packetization == c.packetization));
    147 }
    148 
    149 bool Codec::Matches(const Codec& codec) const {
    150  return MatchesWithCodecRules(*this, codec);
    151 }
    152 
    153 bool Codec::MatchesRtpCodec(const RtpCodec& codec_capability) const {
    154  RtpCodecParameters codec_parameters = ToCodecParameters();
    155 
    156  return codec_parameters.name == codec_capability.name &&
    157         codec_parameters.kind == codec_capability.kind &&
    158         codec_parameters.num_channels == codec_capability.num_channels &&
    159         codec_parameters.clock_rate == codec_capability.clock_rate &&
    160         (codec_parameters.name == kRtxCodecName ||
    161          codec_parameters.parameters == codec_capability.parameters);
    162 }
    163 
    164 bool Codec::GetParam(const std::string& key, std::string* out) const {
    165  CodecParameterMap::const_iterator iter = params.find(key);
    166  if (iter == params.end())
    167    return false;
    168  *out = iter->second;
    169  return true;
    170 }
    171 
    172 bool Codec::GetParam(const std::string& key, int* out) const {
    173  CodecParameterMap::const_iterator iter = params.find(key);
    174  if (iter == params.end())
    175    return false;
    176  return FromString(iter->second, out);
    177 }
    178 
    179 void Codec::SetParam(const std::string& key, const std::string& value) {
    180  params[key] = value;
    181 }
    182 
    183 void Codec::SetParam(const std::string& key, int value) {
    184  params[key] = absl::StrCat(value);
    185 }
    186 
    187 bool Codec::RemoveParam(const std::string& key) {
    188  return params.erase(key) == 1;
    189 }
    190 
    191 void Codec::AddFeedbackParam(const FeedbackParam& param) {
    192  feedback_params.Add(param);
    193 }
    194 
    195 bool Codec::HasFeedbackParam(const FeedbackParam& param) const {
    196  return feedback_params.Has(param);
    197 }
    198 
    199 void Codec::IntersectFeedbackParams(const Codec& other) {
    200  feedback_params.Intersect(other.feedback_params);
    201 }
    202 
    203 webrtc::RtpCodecParameters Codec::ToCodecParameters() const {
    204  RtpCodecParameters codec_params;
    205  codec_params.payload_type = id;
    206  codec_params.name = name;
    207  codec_params.clock_rate = clockrate;
    208  codec_params.parameters.insert(params.begin(), params.end());
    209 
    210  switch (type) {
    211    case Type::kAudio: {
    212      codec_params.num_channels = static_cast<int>(channels);
    213      codec_params.kind = MediaType::AUDIO;
    214      break;
    215    }
    216    case Type::kVideo: {
    217      codec_params.kind = MediaType::VIDEO;
    218      break;
    219    }
    220  }
    221 
    222  return codec_params;
    223 }
    224 
    225 bool Codec::IsMediaCodec() const {
    226  return !IsResiliencyCodec() &&
    227         !absl::EqualsIgnoreCase(name, kComfortNoiseCodecName);
    228 }
    229 
    230 bool Codec::IsResiliencyCodec() const {
    231  return GetResiliencyType() != ResiliencyType::kNone;
    232 }
    233 
    234 Codec::ResiliencyType Codec::GetResiliencyType() const {
    235  if (absl::EqualsIgnoreCase(name, kRedCodecName)) {
    236    return ResiliencyType::kRed;
    237  }
    238  if (absl::EqualsIgnoreCase(name, kUlpfecCodecName)) {
    239    return ResiliencyType::kUlpfec;
    240  }
    241  if (absl::EqualsIgnoreCase(name, kFlexfecCodecName)) {
    242    return ResiliencyType::kFlexfec;
    243  }
    244  if (absl::EqualsIgnoreCase(name, kRtxCodecName)) {
    245    return ResiliencyType::kRtx;
    246  }
    247  return ResiliencyType::kNone;
    248 }
    249 
    250 bool Codec::ValidateCodecFormat() const {
    251  if (id < 0 || id > 127) {
    252    RTC_LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString();
    253    return false;
    254  }
    255  if (IsResiliencyCodec()) {
    256    return true;
    257  }
    258 
    259  int min_bitrate = -1;
    260  int max_bitrate = -1;
    261  if (GetParam(kCodecParamMinBitrate, &min_bitrate) &&
    262      GetParam(kCodecParamMaxBitrate, &max_bitrate)) {
    263    if (max_bitrate < min_bitrate) {
    264      RTC_LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString();
    265      return false;
    266    }
    267  }
    268  return true;
    269 }
    270 
    271 std::string Codec::ToString() const {
    272  char buf[256];
    273 
    274  SimpleStringBuilder sb(buf);
    275  switch (type) {
    276    case Type::kAudio: {
    277      sb << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":"
    278         << bitrate << ":" << channels << "]";
    279      break;
    280    }
    281    case Type::kVideo: {
    282      sb << "VideoCodec[" << id << ":" << name;
    283      if (packetization.has_value()) {
    284        sb << ":" << *packetization;
    285      }
    286      sb << "]";
    287      break;
    288    }
    289  }
    290  return sb.str();
    291 }
    292 
    293 Codec CreateAudioRtxCodec(int rtx_payload_type, int associated_payload_type) {
    294  Codec rtx_codec = CreateAudioCodec(rtx_payload_type, kRtxCodecName,
    295                                     kDefaultAudioClockRateHz, 1);
    296  rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type);
    297  return rtx_codec;
    298 }
    299 
    300 Codec CreateVideoRtxCodec(int rtx_payload_type, int associated_payload_type) {
    301  Codec rtx_codec = CreateVideoCodec(rtx_payload_type, kRtxCodecName);
    302  rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type);
    303  return rtx_codec;
    304 }
    305 
    306 const Codec* FindCodecById(const std::vector<Codec>& codecs, int payload_type) {
    307  for (const auto& codec : codecs) {
    308    if (codec.id == payload_type)
    309      return &codec;
    310  }
    311  return nullptr;
    312 }
    313 
    314 bool HasLntf(const Codec& codec) {
    315  return codec.HasFeedbackParam(
    316      FeedbackParam(kRtcpFbParamLntf, kParamValueEmpty));
    317 }
    318 
    319 bool HasNack(const Codec& codec) {
    320  return codec.HasFeedbackParam(
    321      FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
    322 }
    323 
    324 bool HasRemb(const Codec& codec) {
    325  return codec.HasFeedbackParam(
    326      FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
    327 }
    328 
    329 bool HasRrtr(const Codec& codec) {
    330  return codec.HasFeedbackParam(
    331      FeedbackParam(kRtcpFbParamRrtr, kParamValueEmpty));
    332 }
    333 
    334 const Codec* FindMatchingVideoCodec(const std::vector<Codec>& supported_codecs,
    335                                    const Codec& codec) {
    336  SdpVideoFormat sdp_video_format{codec.name, codec.params};
    337  for (const Codec& supported_codec : supported_codecs) {
    338    if (sdp_video_format.IsSameCodec(
    339            {supported_codec.name, supported_codec.params})) {
    340      return &supported_codec;
    341    }
    342  }
    343  return nullptr;
    344 }
    345 
    346 std::vector<const Codec*> FindAllMatchingCodecs(
    347    const std::vector<Codec>& supported_codecs,
    348    const Codec& codec) {
    349  std::vector<const Codec*> result;
    350  SdpVideoFormat sdp(codec.name, codec.params);
    351  for (const Codec& supported_codec : supported_codecs) {
    352    if (sdp.IsSameCodec({supported_codec.name, supported_codec.params})) {
    353      result.push_back(&supported_codec);
    354    }
    355  }
    356  return result;
    357 }
    358 
    359 // If a decoder supports any H264 profile, it is implicitly assumed to also
    360 // support constrained base line even though it's not explicitly listed.
    361 void AddH264ConstrainedBaselineProfileToSupportedFormats(
    362    std::vector<SdpVideoFormat>* supported_formats) {
    363  std::vector<SdpVideoFormat> cbr_supported_formats;
    364 
    365  // For any H264 supported profile, add the corresponding constrained baseline
    366  // profile.
    367  for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
    368       ++it) {
    369    if (it->name == kH264CodecName) {
    370      const std::optional<H264ProfileLevelId> profile_level_id =
    371          ParseSdpForH264ProfileLevelId(it->parameters);
    372      if (profile_level_id && profile_level_id->profile !=
    373                                  H264Profile::kProfileConstrainedBaseline) {
    374        SdpVideoFormat cbp_format = *it;
    375        H264ProfileLevelId cbp_profile = *profile_level_id;
    376        cbp_profile.profile = H264Profile::kProfileConstrainedBaseline;
    377        cbp_format.parameters[kH264FmtpProfileLevelId] =
    378            *H264ProfileLevelIdToString(cbp_profile);
    379        cbr_supported_formats.push_back(cbp_format);
    380      }
    381    }
    382  }
    383 
    384  size_t original_size = supported_formats->size();
    385  // ...if it's not already in the list.
    386  std::copy_if(cbr_supported_formats.begin(), cbr_supported_formats.end(),
    387               std::back_inserter(*supported_formats),
    388               [supported_formats](const SdpVideoFormat& format) {
    389                 return !format.IsCodecInList(*supported_formats);
    390               });
    391 
    392  if (supported_formats->size() > original_size) {
    393    RTC_LOG(LS_INFO) << "Explicitly added H264 constrained baseline to list "
    394                        "of supported formats.";
    395  }
    396 }
    397 
    398 Codec CreateAudioCodec(int id,
    399                       const std::string& name,
    400                       int clockrate,
    401                       size_t channels) {
    402  return Codec(Codec::Type::kAudio, id, name, clockrate, channels);
    403 }
    404 
    405 Codec CreateAudioCodec(const SdpAudioFormat& c) {
    406  return Codec(c);
    407 }
    408 
    409 Codec CreateVideoCodec(const std::string& name) {
    410  return CreateVideoCodec(Codec::kIdNotSet, name);
    411 }
    412 
    413 Codec CreateVideoCodec(int id, const std::string& name) {
    414  Codec c(Codec::Type::kVideo, id, name, kVideoCodecClockrate);
    415  if (absl::EqualsIgnoreCase(kH264CodecName, name)) {
    416    // This default is set for all H.264 codecs created because
    417    // that was the default before packetization mode support was added.
    418    // TODO(hta): Move this to the places that create VideoCodecs from
    419    // SDP or from knowledge of implementation capabilities.
    420    c.SetParam(kH264FmtpPacketizationMode, "1");
    421  }
    422  return c;
    423 }
    424 
    425 Codec CreateVideoCodec(const SdpVideoFormat& c) {
    426  return Codec(c);
    427 }
    428 
    429 Codec CreateVideoCodec(int id, const SdpVideoFormat& sdp) {
    430  Codec c = CreateVideoCodec(sdp);
    431  c.id = id;
    432  return c;
    433 }
    434 
    435 }  // namespace webrtc