Correct H.265 level-id in fmtp line for offer/answer.

On a sendrecv m-line, the offered level-id represents the maximum that
can be both sent and received; on a sendonly m-line, the offered
level-id represents the maximum that can be sent; on a recvonly m-line,
the offered level-id represents the maximum that can be received.
Also according to RFC 7798 section 5, the highest level indicated by the
answer is either equal to or lower than that in the offer

Bug: chromium:41480904
Change-Id: I1729c8edc3aed0c00c41cea96204abafc37c002b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/367322
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#43425}
This commit is contained in:
Qiu Jianlin 2024-11-18 21:35:59 +08:00 committed by WebRTC LUCI CQ
parent 5f163fcaa0
commit 2d47c9395b
5 changed files with 1111 additions and 0 deletions

View File

@ -414,4 +414,10 @@ Codec CreateVideoCodec(const webrtc::SdpVideoFormat& c) {
return Codec(c);
}
Codec CreateVideoCodec(int id, const webrtc::SdpVideoFormat& sdp) {
Codec c = CreateVideoCodec(sdp);
c.id = id;
return c;
}
} // namespace cricket

View File

@ -239,6 +239,7 @@ Codec CreateAudioRtxCodec(int rtx_payload_type, int associated_payload_type);
Codec CreateVideoCodec(const std::string& name);
Codec CreateVideoCodec(int id, const std::string& name);
Codec CreateVideoCodec(const webrtc::SdpVideoFormat& c);
Codec CreateVideoCodec(int id, const webrtc::SdpVideoFormat& c);
Codec CreateVideoRtxCodec(int rtx_payload_type, int associated_payload_type);
// Get the codec setting associated with `payload_type`. If there

View File

@ -372,6 +372,7 @@ rtc_source_set("media_session") {
"../api:rtp_parameters",
"../api:rtp_transceiver_direction",
"../api/crypto:options",
"../api/video_codecs:video_codecs_api",
"../call:payload_type",
"../media:codec",
"../media:media_constants",

View File

@ -54,6 +54,10 @@
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/unique_id_generator.h"
#ifdef RTC_ENABLE_H265
#include "api/video_codecs/h265_profile_tier_level.h"
#endif
namespace {
using rtc::UniqueRandomIdGenerator;
@ -1064,6 +1068,60 @@ const TransportDescription* GetTransportDescription(
return desc;
}
// For offer, negotiated codec must have the same level-id as that in
// |supported_codecs| with same profile.
void NegotiateVideoCodecLevelsForOffer(
const MediaDescriptionOptions& media_description_options,
const std::vector<Codec>& supported_codecs,
std::vector<Codec>& filtered_codecs) {
if (filtered_codecs.empty() || supported_codecs.empty()) {
return;
}
// TODO(http://crbugs.com/376306259): We should handle level-idx for AV1.
// Ideally this should be done for all codecs, but RFCs of other codecs
// do not clear define the expected behavior for the level in the offer.
#ifdef RTC_ENABLE_H265
if (media_description_options.type == MEDIA_TYPE_VIDEO) {
std::unordered_map<webrtc::H265Profile, webrtc::H265Level>
supported_h265_profiles;
// The assumption here is that H.265 codecs with the same profile and tier
// are already with highest level for that profile in both
// |supported_codecs| and |filtered_codecs|.
for (const Codec& supported_codec : supported_codecs) {
if (absl::EqualsIgnoreCase(supported_codec.name, kH265CodecName)) {
std::optional<webrtc::H265ProfileTierLevel> supported_ptl =
webrtc::ParseSdpForH265ProfileTierLevel(supported_codec.params);
if (supported_ptl.has_value()) {
supported_h265_profiles[supported_ptl->profile] =
supported_ptl->level;
}
}
}
if (supported_h265_profiles.empty()) {
return;
}
for (auto& filtered_codec : filtered_codecs) {
if (absl::EqualsIgnoreCase(filtered_codec.name, kH265CodecName)) {
std::optional<webrtc::H265ProfileTierLevel> filtered_ptl =
webrtc::ParseSdpForH265ProfileTierLevel(filtered_codec.params);
if (filtered_ptl.has_value()) {
auto it = supported_h265_profiles.find(filtered_ptl->profile);
if (it != supported_h265_profiles.end() &&
filtered_ptl->level != it->second) {
filtered_codec.params[kH265FmtpLevelId] =
webrtc::H265LevelToString(it->second);
}
}
}
}
}
#endif
}
webrtc::RTCErrorOr<Codecs> GetNegotiatedCodecsForOffer(
const MediaDescriptionOptions& media_description_options,
const MediaSessionOptions& session_options,
@ -1139,6 +1197,8 @@ webrtc::RTCErrorOr<Codecs> GetNegotiatedCodecsForOffer(
}
}
}
NegotiateVideoCodecLevelsForOffer(media_description_options, supported_codecs,
filtered_codecs);
return filtered_codecs;
}
@ -2365,6 +2425,9 @@ void MediaSessionDescriptionFactory::ComputeVideoCodecsIntersectionAndUnion() {
// order we'd like to follow. The reasoning is that encoding is usually more
// expensive than decoding, and prioritizing a codec in the send list probably
// means it's a codec we can handle efficiently.
// Also for the same profile of a codec, if there are different levels in the
// send and receive codecs, |video_sendrecv_codecs_| will contain the lower
// level of the two for that profile.
NegotiateCodecs(video_recv_codecs_, video_send_codecs_,
&video_sendrecv_codecs_, true);
}

File diff suppressed because it is too large Load Diff