xref: /aosp_15_r20/external/webrtc/api/video_codecs/sdp_video_format.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 "absl/strings/match.h"
14 #include "absl/types/optional.h"
15 #include "api/array_view.h"
16 #include "api/video_codecs/av1_profile.h"
17 #include "api/video_codecs/h264_profile_level_id.h"
18 #include "api/video_codecs/video_codec.h"
19 #include "api/video_codecs/vp9_profile.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/strings/string_builder.h"
23 
24 namespace webrtc {
25 
26 namespace {
27 
H264GetPacketizationModeOrDefault(const SdpVideoFormat::Parameters & params)28 std::string H264GetPacketizationModeOrDefault(
29     const SdpVideoFormat::Parameters& params) {
30   constexpr char kH264FmtpPacketizationMode[] = "packetization-mode";
31   const auto it = params.find(kH264FmtpPacketizationMode);
32   if (it != params.end()) {
33     return it->second;
34   }
35   // If packetization-mode is not present, default to "0".
36   // https://tools.ietf.org/html/rfc6184#section-6.2
37   return "0";
38 }
39 
H264IsSamePacketizationMode(const SdpVideoFormat::Parameters & left,const SdpVideoFormat::Parameters & right)40 bool H264IsSamePacketizationMode(const SdpVideoFormat::Parameters& left,
41                                  const SdpVideoFormat::Parameters& right) {
42   return H264GetPacketizationModeOrDefault(left) ==
43          H264GetPacketizationModeOrDefault(right);
44 }
45 
46 // Some (video) codecs are actually families of codecs and rely on parameters
47 // to distinguish different incompatible family members.
IsSameCodecSpecific(const SdpVideoFormat & format1,const SdpVideoFormat & format2)48 bool IsSameCodecSpecific(const SdpVideoFormat& format1,
49                          const SdpVideoFormat& format2) {
50   // The assumption when calling this function is that the two formats have the
51   // same name.
52   RTC_DCHECK(absl::EqualsIgnoreCase(format1.name, format2.name));
53 
54   VideoCodecType codec_type = PayloadStringToCodecType(format1.name);
55   switch (codec_type) {
56     case kVideoCodecH264:
57       return H264IsSameProfile(format1.parameters, format2.parameters) &&
58              H264IsSamePacketizationMode(format1.parameters,
59                                          format2.parameters);
60     case kVideoCodecVP9:
61       return VP9IsSameProfile(format1.parameters, format2.parameters);
62     case kVideoCodecAV1:
63       return AV1IsSameProfile(format1.parameters, format2.parameters);
64     default:
65       return true;
66   }
67 }
68 }  // namespace
69 
SdpVideoFormat(const std::string & name)70 SdpVideoFormat::SdpVideoFormat(const std::string& name) : name(name) {}
71 
SdpVideoFormat(const std::string & name,const Parameters & parameters)72 SdpVideoFormat::SdpVideoFormat(const std::string& name,
73                                const Parameters& parameters)
74     : name(name), parameters(parameters) {}
75 
SdpVideoFormat(const std::string & name,const Parameters & parameters,const absl::InlinedVector<ScalabilityMode,kScalabilityModeCount> & scalability_modes)76 SdpVideoFormat::SdpVideoFormat(
77     const std::string& name,
78     const Parameters& parameters,
79     const absl::InlinedVector<ScalabilityMode, kScalabilityModeCount>&
80         scalability_modes)
81     : name(name),
82       parameters(parameters),
83       scalability_modes(scalability_modes) {}
84 
85 SdpVideoFormat::SdpVideoFormat(const SdpVideoFormat&) = default;
86 SdpVideoFormat::SdpVideoFormat(SdpVideoFormat&&) = default;
87 SdpVideoFormat& SdpVideoFormat::operator=(const SdpVideoFormat&) = default;
88 SdpVideoFormat& SdpVideoFormat::operator=(SdpVideoFormat&&) = default;
89 
90 SdpVideoFormat::~SdpVideoFormat() = default;
91 
ToString() const92 std::string SdpVideoFormat::ToString() const {
93   rtc::StringBuilder builder;
94   builder << "Codec name: " << name << ", parameters: {";
95   for (const auto& kv : parameters) {
96     builder << " " << kv.first << "=" << kv.second;
97   }
98 
99   builder << " }";
100   if (!scalability_modes.empty()) {
101     builder << ", scalability_modes: [";
102     bool first = true;
103     for (const auto scalability_mode : scalability_modes) {
104       if (first) {
105         first = false;
106       } else {
107         builder << ", ";
108       }
109       builder << ScalabilityModeToString(scalability_mode);
110     }
111     builder << "]";
112   }
113 
114   return builder.str();
115 }
116 
IsSameCodec(const SdpVideoFormat & other) const117 bool SdpVideoFormat::IsSameCodec(const SdpVideoFormat& other) const {
118   // Two codecs are considered the same if the name matches (case insensitive)
119   // and certain codec-specific parameters match.
120   return absl::EqualsIgnoreCase(name, other.name) &&
121          IsSameCodecSpecific(*this, other);
122 }
123 
IsCodecInList(rtc::ArrayView<const webrtc::SdpVideoFormat> formats) const124 bool SdpVideoFormat::IsCodecInList(
125     rtc::ArrayView<const webrtc::SdpVideoFormat> formats) const {
126   for (const auto& format : formats) {
127     if (IsSameCodec(format)) {
128       return true;
129     }
130   }
131   return false;
132 }
133 
operator ==(const SdpVideoFormat & a,const SdpVideoFormat & b)134 bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b) {
135   return a.name == b.name && a.parameters == b.parameters &&
136          a.scalability_modes == b.scalability_modes;
137 }
138 
FuzzyMatchSdpVideoFormat(rtc::ArrayView<const SdpVideoFormat> supported_formats,const SdpVideoFormat & format)139 absl::optional<SdpVideoFormat> FuzzyMatchSdpVideoFormat(
140     rtc::ArrayView<const SdpVideoFormat> supported_formats,
141     const SdpVideoFormat& format) {
142   absl::optional<SdpVideoFormat> res;
143   int best_parameter_match = 0;
144   for (const auto& supported_format : supported_formats) {
145     if (absl::EqualsIgnoreCase(supported_format.name, format.name)) {
146       int matching_parameters = 0;
147       for (const auto& kv : supported_format.parameters) {
148         auto it = format.parameters.find(kv.first);
149         if (it != format.parameters.end() && it->second == kv.second) {
150           matching_parameters += 1;
151         }
152       }
153 
154       if (!res || matching_parameters > best_parameter_match) {
155         res = supported_format;
156         best_parameter_match = matching_parameters;
157       }
158     }
159   }
160 
161   if (!res) {
162     RTC_LOG(LS_INFO) << "Failed to match SdpVideoFormat " << format.ToString();
163   } else if (*res != format) {
164     RTC_LOG(LS_INFO) << "Matched SdpVideoFormat " << format.ToString()
165                      << " with " << res->ToString();
166   }
167 
168   return res;
169 }
170 
171 }  // namespace webrtc
172