Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  codec_comparators.cc

  Sprache: C
 

/*
 *  Copyright 2024 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "media/base/codec_comparators.h"

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>

#include "absl/algorithm/container.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "api/media_types.h"
#include "api/payload_type.h"
#include "api/rtp_parameters.h"
#include "api/video_codecs/av1_profile.h"
#include "api/video_codecs/h264_profile_level_id.h"
#ifdef RTC_ENABLE_H265
#include "api/video_codecs/h265_profile_tier_level.h"
#endif
#include "api/video_codecs/vp9_profile.h"
#include "media/base/codec.h"
#include "media/base/media_constants.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/string_encode.h"

namespace webrtc {

namespace {

// TODO(bugs.webrtc.org/15847): remove code duplication of IsSameCodecSpecific
// in api/video_codecs/sdp_video_format.cc
std::string GetFmtpParameterOrDefault(const CodecParameterMap& params,
                                      const std::string& name,
                                      const std::string& default_value) {
  const auto it = params.find(name);
  if (it != params.end()) {
    return it->second;
  }
  return default_value;
}

bool HasParameter(const CodecParameterMap& params, const std::string& name) {
  return params.find(name) != params.end();
}

std::string H264GetPacketizationModeOrDefault(const CodecParameterMap& params) {
  // If packetization-mode is not present, default to "0".
  // https://tools.ietf.org/html/rfc6184#section-6.2
  return GetFmtpParameterOrDefault(params, kH264FmtpPacketizationMode, "0");
}

std::string AV1GetTierOrDefault(const CodecParameterMap& params) {
  // If the parameter is not present, the tier MUST be inferred to be 0.
  // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
  return GetFmtpParameterOrDefault(params, kAv1FmtpTier, "0");
}

std::string AV1GetLevelIdxOrDefault(const CodecParameterMap& params) {
  // If the parameter is not present, it MUST be inferred to be 5 (level 3.1).
  // https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
  return GetFmtpParameterOrDefault(params, kAv1FmtpLevelIdx, "5");
}

#ifdef RTC_ENABLE_H265
std::string GetH265TxModeOrDefault(const CodecParameterMap& params) {
  // If TxMode is not present, a value of "SRST" must be inferred.
  // https://tools.ietf.org/html/rfc7798@section-7.1
  return GetFmtpParameterOrDefault(params, kH265FmtpTxMode, "SRST");
}

bool IsSameH265TxMode(const CodecParameterMap& left,
                      const CodecParameterMap& right) {
  return absl::EqualsIgnoreCase(GetH265TxModeOrDefault(left),
                                GetH265TxModeOrDefault(right));
}
#endif

// Some (video) codecs are actually families of codecs and rely on parameters
// to distinguish different incompatible family members.
bool IsSameCodecSpecific(const std::string& name1,
                         const CodecParameterMap& params1,
                         const std::string& name2,
                         const CodecParameterMap& params2) {
  // The names might not necessarily match, so check both.
  auto either_name_matches = [&](const std::string name) {
    return absl::EqualsIgnoreCase(name, name1) ||
           absl::EqualsIgnoreCase(name, name2);
  };
  if (either_name_matches(kH264CodecName))
    return H264IsSameProfile(params1, params2) &&
           IsSameH264PacketizationMode(params1, params2);
  if (either_name_matches(kVp9CodecName))
    return VP9IsSameProfile(params1, params2);
  // https://aomediacodec.github.io/av1-rtp-spec/#723-usage-with-the-sdp-offeranswer-model
  //   These media configuration parameters are asymmetrical and the answerer
  //   MAY declare its own media configuration
  // TODO(bugs.webrtc.org/396434695): for backward compability we currently
  // compare profile.
  if (either_name_matches(kAv1CodecName))
    return AV1IsSameProfile(params1, params2);
#ifdef RTC_ENABLE_H265
  if (either_name_matches(kH265CodecName)) {
    return H265IsSameProfile(params1, params2) &&
           H265IsSameTier(params1, params2) &&
           IsSameH265TxMode(params1, params2);
  }
#endif
  return true;
}

bool ReferencedCodecsMatch(const std::vector<Codec>& codecs1,
                           const PayloadType codec1_id,
                           const std::vector<Codec>& codecs2,
                           const PayloadType codec2_id) {
  const Codec* codec1 = FindCodecById(codecs1, codec1_id);
  const Codec* codec2 = FindCodecById(codecs2, codec2_id);
  return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
}

bool MatchesWithReferenceAttributesAndComparator(
    const Codec& codec_to_match,
    const Codec& potential_match,
    absl::AnyInvocable<bool(PayloadType, PayloadType)> reference_comparator) {
  if (!MatchesWithCodecRules(codec_to_match, potential_match)) {
    return false;
  }
  Codec::ResiliencyType resiliency_type = codec_to_match.GetResiliencyType();
  if (resiliency_type == Codec::ResiliencyType::kRtx) {
    int apt_value_1_int = 0;
    int apt_value_2_int = 0;
    if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
                                 &apt_value_1_int) ||
        !potential_match.GetParam(kCodecParamAssociatedPayloadType,
                                  &apt_value_2_int)) {
      RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
      return false;
    }
    PayloadType apt_value_1 =
        PayloadType(static_cast<uint8_t>(apt_value_1_int));
    PayloadType apt_value_2 =
        PayloadType(static_cast<uint8_t>(apt_value_2_int));
    if (reference_comparator(apt_value_1, apt_value_2)) {
      return true;
    }
    return false;
  }
  if (resiliency_type == Codec::ResiliencyType::kRed) {
    auto red_parameters_1 =
        codec_to_match.params.find(kCodecParamNotInNameValueFormat);
    auto red_parameters_2 =
        potential_match.params.find(kCodecParamNotInNameValueFormat);
    bool has_parameters_1 = red_parameters_1 != codec_to_match.params.end();
    bool has_parameters_2 = red_parameters_2 != potential_match.params.end();

    if (has_parameters_1 && has_parameters_2) {
      // Different levels of redundancy between offer and answer are OK
      // since RED is considered to be declarative.
      std::vector<absl::string_view> redundant_payloads_1 =
          split(red_parameters_1->second, '/');
      std::vector<absl::string_view> redundant_payloads_2 =
          split(red_parameters_2->second, '/');
      // note: split returns at least 1 string even on empty strings.
      size_t smallest_size =
          std::min(redundant_payloads_1.size(), redundant_payloads_2.size());
      // If the smaller list is equivalent to the longer list, we consider them
      // equivalent even if size differs.
      for (size_t i = 0; i < smallest_size; i++) {
        int red_value_1;
        int red_value_2;
        if (FromString(redundant_payloads_1[i], &red_value_1) &&
            FromString(redundant_payloads_2[i], &red_value_2)) {
          if (!reference_comparator(red_value_1, red_value_2)) {
            return false;
          }
        } else {
          // At least one parameter was not an integer.
          // This is a syntax error, but we allow it here if the whole parameter
          // equals the other parameter, in order to not generate more errors
          // by duplicating the bad parameter.
          return red_parameters_1->second == red_parameters_2->second;
        }
      }
      return true;
    }
    if (!has_parameters_1 && !has_parameters_2) {
      return true;
    }
    // Exactly one lacks parameters.
    // Allow match if it is an audio RED codec and at least one of the
    // codecs has an unassigned payload type or they have the same ID.
    if (codec_to_match.type == Codec::Type::kAudio &&
        codec_to_match.name == kRedCodecName &&
        (codec_to_match.id == PayloadType::NotSet() ||
         potential_match.id == PayloadType::NotSet() ||
         codec_to_match.id == potential_match.id)) {
      return true;
    }
    return false;
  }
  return true;  // Not a codec with a PT-valued reference.
}

CodecParameterMap InsertDefaultParams(const std::string& name,
                                      const CodecParameterMap& params) {
  CodecParameterMap updated_params = params;
  if (absl::EqualsIgnoreCase(name, kVp9CodecName)) {
    if (!HasParameter(params, kVP9FmtpProfileId)) {
      if (std::optional<VP9Profile> default_profile =
              ParseSdpForVP9Profile({})) {
        updated_params.insert(
            {kVP9FmtpProfileId, VP9ProfileToString(*default_profile)});
      }
    }
  }
  if (absl::EqualsIgnoreCase(name, kAv1CodecName)) {
    if (!HasParameter(params, kAv1FmtpProfile)) {
      if (std::optional<AV1Profile> default_profile =
              ParseSdpForAV1Profile({})) {
        updated_params.insert(
            {kAv1FmtpProfile, AV1ProfileToString(*default_profile).data()});
      }
    }
    if (!HasParameter(params, kAv1FmtpTier)) {
      updated_params.insert({kAv1FmtpTier, AV1GetTierOrDefault({})});
    }
    if (!HasParameter(params, kAv1FmtpLevelIdx)) {
      updated_params.insert({kAv1FmtpLevelIdx, AV1GetLevelIdxOrDefault({})});
    }
  }
  if (absl::EqualsIgnoreCase(name, kH264CodecName)) {
    if (!HasParameter(params, kH264FmtpPacketizationMode)) {
      updated_params.insert(
          {kH264FmtpPacketizationMode, H264GetPacketizationModeOrDefault({})});
    }
  }
#ifdef RTC_ENABLE_H265
  if (absl::EqualsIgnoreCase(name, kH265CodecName)) {
    if (std::optional<H265ProfileTierLevel> default_params =
            ParseSdpForH265ProfileTierLevel({})) {
      if (!HasParameter(params, kH265FmtpProfileId)) {
        updated_params.insert(
            {kH265FmtpProfileId, H265ProfileToString(default_params->profile)});
      }
      if (!HasParameter(params, kH265FmtpLevelId)) {
        updated_params.insert(
            {kH265FmtpLevelId, H265LevelToString(default_params->level)});
      }
      if (!HasParameter(params, kH265FmtpTierFlag)) {
        updated_params.insert(
            {kH265FmtpTierFlag, H265TierToString(default_params->tier)});
      }
    }
    if (!HasParameter(params, kH265FmtpTxMode)) {
      updated_params.insert({kH265FmtpTxMode, GetH265TxModeOrDefault({})});
    }
  }
#endif
  return updated_params;
}

}  // namespace

bool MatchesWithCodecRules(const Codec& left_codec, const Codec& right_codec) {
  // Match the codec id/name based on the typical static/dynamic name rules.
  // Matching is case-insensitive.

  // We support the ranges [96, 127] and more recently [35, 65].
  // https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1
  // Within those ranges we match by codec name, outside by codec id.
  // We also match by name if either ID is unassigned.
  // Since no codecs are assigned an id in the range [66, 95] by us, these will
  // never match.
  const int kLowerDynamicRangeMin = 35;
  const int kLowerDynamicRangeMax = 65;
  const int kUpperDynamicRangeMin = 96;
  const int kUpperDynamicRangeMax = 127;
  const bool is_id_in_dynamic_range =
      (left_codec.id >= kLowerDynamicRangeMin &&
       left_codec.id <= kLowerDynamicRangeMax) ||
      (left_codec.id >= kUpperDynamicRangeMin &&
       left_codec.id <= kUpperDynamicRangeMax);
  const bool is_codec_id_in_dynamic_range =
      (right_codec.id >= kLowerDynamicRangeMin &&
       right_codec.id <= kLowerDynamicRangeMax) ||
      (right_codec.id >= kUpperDynamicRangeMin &&
       right_codec.id <= kUpperDynamicRangeMax);

  if (left_codec.type != right_codec.type) {
    return false;
  }

  bool matches_id;
  if ((is_id_in_dynamic_range && is_codec_id_in_dynamic_range) ||
      left_codec.id == PayloadType::NotSet() ||
      right_codec.id == PayloadType::NotSet()) {
    matches_id = absl::EqualsIgnoreCase(left_codec.name, right_codec.name);
  } else {
    matches_id = (left_codec.id == right_codec.id);
  }

  auto matches_type_specific = [&]() {
    switch (left_codec.type) {
      case Codec::Type::kAudio:
        // If a nonzero bitrate is specified, it must match the
        // actual bitrate, unless the codec is VBR (0), where we just force the
        // supplied value. The number of channels must match exactly, with the
        // exception that channels=0 is treated synonymously as channels=1, per
        // RFC 4566 section 6: " [The channels] parameter is OPTIONAL and may be
        // omitted if the number of channels is one."
        // Preference is ignored.
        return ((left_codec.clockrate == right_codec.clockrate) &&
                (right_codec.bitrate == 0 || left_codec.bitrate <= 0 ||
                 left_codec.bitrate == right_codec.bitrate) &&
                ((right_codec.channels < 2 && left_codec.channels < 2) ||
                 left_codec.channels == right_codec.channels));

      case Codec::Type::kVideo:
        return IsSameCodecSpecific(left_codec.name, left_codec.params,
                                   right_codec.name, right_codec.params);
    }
  };

  return matches_id && matches_type_specific();
}

bool MatchesWithReferenceAttributes(const Codec& codec1, const Codec& codec2) {
  return MatchesWithReferenceAttributesAndComparator(
      codec1, codec2, [](PayloadType a, PayloadType b) { return a == b; });
}

// Finds a codec in `codecs2` that matches `codec_to_match`, which is
// a member of `codecs1`. If `codec_to_match` is an RED or RTX codec, both
// the codecs themselves and their associated codecs must match.
std::optional<Codec> FindMatchingCodec(const std::vector<Codec>& codecs1,
                                       const std::vector<Codec>& codecs2,
                                       const Codec& codec_to_match) {
  // `codec_to_match` should be a member of `codecs1`, in order to look up
  // RED/RTX codecs' associated codecs correctly. If not, that's a programming
  // error.
  RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const Codec& codec) {
    return &codec == &codec_to_match;
  }));
  for (const Codec& potential_match : codecs2) {
    if (MatchesWithReferenceAttributesAndComparator(
            codec_to_match, potential_match,
            [&codecs1, &codecs2](PayloadType a, PayloadType b) {
              return ReferencedCodecsMatch(codecs1, a, codecs2, b);
            })) {
      return potential_match;
    }
  }
  return std::nullopt;
}

bool IsSameRtpCodec(const Codec& codec, const RtpCodec& rtp_codec) {
  RtpCodecParameters rtp_codec2 = codec.ToCodecParameters();

  if (!absl::EqualsIgnoreCase(rtp_codec.name, rtp_codec2.name) ||
      rtp_codec.kind != rtp_codec2.kind ||
      rtp_codec.num_channels != rtp_codec2.num_channels ||
      rtp_codec.clock_rate != rtp_codec2.clock_rate) {
    return false;
  }

  // audio/RED should ignore the parameters which specify payload types so
  // can not be compared.
  if (rtp_codec.kind == MediaType::AUDIO &&
      absl::EqualsIgnoreCase(rtp_codec.name, kRedCodecName)) {
    return true;
  }

  return InsertDefaultParams(rtp_codec.name, rtp_codec.parameters) ==
         InsertDefaultParams(rtp_codec2.name, rtp_codec2.parameters);
}

bool IsSameRtpCodecIgnoringLevel(const Codec& codec,
                                 const RtpCodec& rtp_codec) {
  RtpCodecParameters rtp_codec2 = codec.ToCodecParameters();

  if (!absl::EqualsIgnoreCase(rtp_codec.name, rtp_codec2.name) ||
      rtp_codec.kind != rtp_codec2.kind ||
      rtp_codec.num_channels != rtp_codec2.num_channels ||
      rtp_codec.clock_rate != rtp_codec2.clock_rate) {
    return false;
  }

  CodecParameterMap params1 =
      InsertDefaultParams(rtp_codec.name, rtp_codec.parameters);
  CodecParameterMap params2 =
      InsertDefaultParams(rtp_codec2.name, rtp_codec2.parameters);

  // Some video codecs are compatible with others (e.g. same profile but
  // different level). This comparison looks at the relevant parameters,
  // ignoring ones that are either irrelevant or unrecognized.
  if (rtp_codec.kind == MediaType::VIDEO && rtp_codec.IsMediaCodec()) {
    return IsSameCodecSpecific(rtp_codec.name, params1, rtp_codec2.name,
                               params2);
  }
  // audio/RED should ignore the parameters which specify payload types so
  // can not be compared.
  if (rtp_codec.kind == MediaType::AUDIO &&
      absl::EqualsIgnoreCase(rtp_codec.name, kRedCodecName)) {
    return true;
  }

  return params1 == params2;
}

bool IsSameH264PacketizationMode(const CodecParameterMap& left,
                                 const CodecParameterMap& right) {
  return H264GetPacketizationModeOrDefault(left) ==
         H264GetPacketizationModeOrDefault(right);
}

}  // namespace webrtc

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-08-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=434850
#Domains=655579