sdp: backfill default codec parameters for AV1
as required by https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters Also unify usage of profile fmtp parameter. Most notably this causes SDP answers to include the default values. These default values correspond to libaom's default values for AV1E_SET_TARGET_SEQ_LEVEL_IDX, AV1E_SET_TIER_MASK as used in https://source.chromium.org/chromium/chromium/src/+/main:third_party/libaom/source/libaom/aom/aomcx.h and g_profile in aom_codec_enc_cfg https://source.chromium.org/chromium/chromium/src/+/main:third_party/libaom/source/libaom/aom/aom_encoder.h;l=415;drc=b58207f5aecc39db7d3da766e7d171e5d2c3598e Note: AV1 is inconsistently cased in variable/struct/method/class names. The canonical casing should probably be "Av1" since it is an acronym standing for "AOMedia Video 1". BUG=webrtc:15703 Change-Id: I11864b7666fea906cd1a0759c7ad45997beab90e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/331360 Reviewed-by: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Philipp Hancke <phancke@microsoft.com> Cr-Commit-Position: refs/heads/main@{#41654}
This commit is contained in:
parent
89cf26f1e0
commit
c1cc6a36b2
@ -85,6 +85,7 @@ rtc_library("video_codecs_api") {
|
||||
"..:scoped_refptr",
|
||||
"../../api:array_view",
|
||||
"../../api:rtp_parameters",
|
||||
"../../media:media_constants",
|
||||
"../../modules/video_coding:codec_globals_headers",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:logging",
|
||||
|
||||
@ -13,13 +13,11 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "media/base/media_constants.h"
|
||||
#include "rtc_base/string_to_number.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Parameter name in the format parameter map for AV1 video.
|
||||
const char kAV1FmtpProfile[] = "profile";
|
||||
|
||||
absl::string_view AV1ProfileToString(AV1Profile profile) {
|
||||
switch (profile) {
|
||||
case AV1Profile::kProfile0:
|
||||
@ -51,7 +49,7 @@ absl::optional<AV1Profile> StringToAV1Profile(absl::string_view str) {
|
||||
|
||||
absl::optional<AV1Profile> ParseSdpForAV1Profile(
|
||||
const CodecParameterMap& params) {
|
||||
const auto profile_it = params.find(kAV1FmtpProfile);
|
||||
const auto profile_it = params.find(cricket::kAv1FmtpProfile);
|
||||
if (profile_it == params.end())
|
||||
return AV1Profile::kProfile0;
|
||||
const std::string& profile_str = profile_it->second;
|
||||
|
||||
@ -20,9 +20,6 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Profile information for AV1 video.
|
||||
extern RTC_EXPORT const char kAV1FmtpProfile[];
|
||||
|
||||
// Profiles can be found at:
|
||||
// https://aomedia.org/av1/specification/annex-a/#profiles
|
||||
// The enum values match the number specified in the SDP.
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#endif
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
@ -29,8 +30,7 @@ namespace webrtc {
|
||||
namespace {
|
||||
|
||||
std::string H264GetPacketizationModeOrDefault(const CodecParameterMap& params) {
|
||||
constexpr char kH264FmtpPacketizationMode[] = "packetization-mode";
|
||||
const auto it = params.find(kH264FmtpPacketizationMode);
|
||||
const auto it = params.find(cricket::kH264FmtpPacketizationMode);
|
||||
if (it != params.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ struct Dav1dDecoderTemplateAdapter {
|
||||
static std::vector<SdpVideoFormat> SupportedFormats() {
|
||||
return {SdpVideoFormat("AV1"),
|
||||
SdpVideoFormat(
|
||||
"AV1", {{kAV1FmtpProfile,
|
||||
"AV1", {{"profile",
|
||||
AV1ProfileToString(AV1Profile::kProfile1).data()}})};
|
||||
}
|
||||
|
||||
|
||||
@ -228,11 +228,11 @@ TEST(CodecTest, TestAV1CodecMatches) {
|
||||
VideoCodec c_no_profile =
|
||||
cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
VideoCodec c_profile0 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
c_profile0.params[webrtc::kAV1FmtpProfile] = kProfile0;
|
||||
c_profile0.params[cricket::kAv1FmtpProfile] = kProfile0;
|
||||
VideoCodec c_profile1 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
c_profile1.params[webrtc::kAV1FmtpProfile] = kProfile1;
|
||||
c_profile1.params[cricket::kAv1FmtpProfile] = kProfile1;
|
||||
VideoCodec c_profile2 = cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
c_profile2.params[webrtc::kAV1FmtpProfile] = kProfile2;
|
||||
c_profile2.params[cricket::kAv1FmtpProfile] = kProfile2;
|
||||
|
||||
// An AV1 entry with no profile specified should be treated as profile-0.
|
||||
EXPECT_TRUE(c_profile0.Matches(c_no_profile));
|
||||
@ -248,7 +248,7 @@ TEST(CodecTest, TestAV1CodecMatches) {
|
||||
// Two AV1 entries with profile 0 specified are treated as duplicates.
|
||||
VideoCodec c_profile0_eq =
|
||||
cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
c_profile0_eq.params[webrtc::kAV1FmtpProfile] = kProfile0;
|
||||
c_profile0_eq.params[cricket::kAv1FmtpProfile] = kProfile0;
|
||||
EXPECT_TRUE(c_profile0.Matches(c_profile0_eq));
|
||||
}
|
||||
|
||||
@ -256,7 +256,7 @@ TEST(CodecTest, TestAV1CodecMatches) {
|
||||
// Two AV1 entries with profile 1 specified are treated as duplicates.
|
||||
VideoCodec c_profile1_eq =
|
||||
cricket::CreateVideoCodec(95, cricket::kAv1CodecName);
|
||||
c_profile1_eq.params[webrtc::kAV1FmtpProfile] = kProfile1;
|
||||
c_profile1_eq.params[cricket::kAv1FmtpProfile] = kProfile1;
|
||||
EXPECT_TRUE(c_profile1.Matches(c_profile1_eq));
|
||||
}
|
||||
|
||||
|
||||
@ -124,8 +124,14 @@ const char kH265FmtpProfileCompatibilityIndicator[] =
|
||||
const char kH265FmtpInteropConstraints[] = "interop-constraints";
|
||||
const char kH265FmtpTxMode[] = "tx-mode";
|
||||
|
||||
// draft-ietf-payload-vp9
|
||||
const char kVP9ProfileId[] = "profile-id";
|
||||
|
||||
// https://aomediacodec.github.io/av1-rtp-spec/
|
||||
const char kAv1FmtpProfile[] = "profile";
|
||||
const char kAv1FmtpLevelIdx[] = "level-idx";
|
||||
const char kAv1FmtpTier[] = "tier";
|
||||
|
||||
const int kDefaultVideoMaxFramerate = 60;
|
||||
// Max encode quantizer for VP8/9 and AV1 encoders assuming libvpx/libaom API
|
||||
// range [0, 63]
|
||||
|
||||
@ -147,8 +147,14 @@ RTC_EXPORT extern const char kH265FmtpProfileCompatibilityIndicator[];
|
||||
RTC_EXPORT extern const char kH265FmtpInteropConstraints[];
|
||||
RTC_EXPORT extern const char kH265FmtpTxMode[];
|
||||
|
||||
// draft-ietf-payload-vp9
|
||||
extern const char kVP9ProfileId[];
|
||||
|
||||
// https://aomediacodec.github.io/av1-rtp-spec/
|
||||
extern const char kAv1FmtpProfile[];
|
||||
extern const char kAv1FmtpLevelIdx[];
|
||||
extern const char kAv1FmtpTier[];
|
||||
|
||||
extern const int kDefaultVideoMaxFramerate;
|
||||
extern const int kDefaultVideoMaxQpVpx;
|
||||
extern const int kDefaultVideoMaxQpH26x;
|
||||
|
||||
@ -51,9 +51,10 @@ std::vector<SdpVideoFormat> InternalDecoderFactory::GetSupportedFormats()
|
||||
|
||||
if (kDav1dIsIncluded) {
|
||||
formats.push_back(SdpVideoFormat(cricket::kAv1CodecName));
|
||||
formats.push_back(SdpVideoFormat(
|
||||
cricket::kAv1CodecName,
|
||||
{{kAV1FmtpProfile, AV1ProfileToString(AV1Profile::kProfile1).data()}}));
|
||||
formats.push_back(
|
||||
SdpVideoFormat(cricket::kAv1CodecName,
|
||||
{{cricket::kAv1FmtpProfile,
|
||||
AV1ProfileToString(AV1Profile::kProfile1).data()}}));
|
||||
}
|
||||
|
||||
return formats;
|
||||
|
||||
@ -121,7 +121,7 @@ TEST(InternalDecoderFactoryTest, Av1Profile1_Dav1dDecoderTrialEnabled) {
|
||||
InternalDecoderFactory factory;
|
||||
std::unique_ptr<VideoDecoder> decoder = factory.CreateVideoDecoder(
|
||||
SdpVideoFormat(cricket::kAv1CodecName,
|
||||
{{kAV1FmtpProfile,
|
||||
{{cricket::kAv1FmtpProfile,
|
||||
AV1ProfileToString(AV1Profile::kProfile1).data()}}));
|
||||
EXPECT_EQ(static_cast<bool>(decoder), kDav1dIsIncluded);
|
||||
}
|
||||
|
||||
@ -2615,6 +2615,17 @@ static void BackfillCodecParameters(std::vector<cricket::Codec>& codecs) {
|
||||
if (!codec.GetParam(cricket::kH264FmtpPacketizationMode, &unused_value)) {
|
||||
codec.SetParam(cricket::kH264FmtpPacketizationMode, "0");
|
||||
}
|
||||
} else if (absl::EqualsIgnoreCase(cricket::kAv1CodecName, codec.name)) {
|
||||
// https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
|
||||
if (!codec.GetParam(cricket::kAv1FmtpProfile, &unused_value)) {
|
||||
codec.SetParam(cricket::kAv1FmtpProfile, "0");
|
||||
}
|
||||
if (!codec.GetParam(cricket::kAv1FmtpLevelIdx, &unused_value)) {
|
||||
codec.SetParam(cricket::kAv1FmtpLevelIdx, "5");
|
||||
}
|
||||
if (!codec.GetParam(cricket::kAv1FmtpTier, &unused_value)) {
|
||||
codec.SetParam(cricket::kAv1FmtpTier, "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5082,13 +5082,14 @@ TEST_F(WebRtcSdpTest, BackfillsDefaultFmtpValues) {
|
||||
"a=setup:actpass\r\n"
|
||||
"a=ice-ufrag:ETEn\r\n"
|
||||
"a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
||||
"m=video 9 UDP/TLS/RTP/SAVPF 96 97\r\n"
|
||||
"m=video 9 UDP/TLS/RTP/SAVPF 96 97 98\r\n"
|
||||
"c=IN IP4 0.0.0.0\r\n"
|
||||
"a=rtcp-mux\r\n"
|
||||
"a=sendonly\r\n"
|
||||
"a=mid:0\r\n"
|
||||
"a=rtpmap:96 H264/90000\r\n"
|
||||
"a=rtpmap:97 VP9/90000\r\n"
|
||||
"a=rtpmap:98 AV1/90000\r\n"
|
||||
"a=ssrc:1234 cname:test\r\n";
|
||||
JsepSessionDescription jdesc(kDummyType);
|
||||
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc));
|
||||
@ -5097,7 +5098,7 @@ TEST_F(WebRtcSdpTest, BackfillsDefaultFmtpValues) {
|
||||
const auto* description = content.media_description();
|
||||
ASSERT_NE(description, nullptr);
|
||||
const std::vector<cricket::Codec> codecs = description->codecs();
|
||||
ASSERT_EQ(codecs.size(), 2u);
|
||||
ASSERT_EQ(codecs.size(), 3u);
|
||||
std::string value;
|
||||
|
||||
EXPECT_EQ(codecs[0].name, "H264");
|
||||
@ -5107,4 +5108,13 @@ TEST_F(WebRtcSdpTest, BackfillsDefaultFmtpValues) {
|
||||
EXPECT_EQ(codecs[1].name, "VP9");
|
||||
EXPECT_TRUE(codecs[1].GetParam("profile-id", &value));
|
||||
EXPECT_EQ(value, "0");
|
||||
|
||||
EXPECT_EQ(codecs[2].name, "AV1");
|
||||
EXPECT_TRUE(codecs[2].GetParam("profile", &value));
|
||||
EXPECT_EQ(value, "0");
|
||||
EXPECT_TRUE(codecs[2].GetParam("level-idx", &value));
|
||||
EXPECT_EQ(value, "5");
|
||||
EXPECT_TRUE(codecs[2].GetParam("tier", &value));
|
||||
EXPECT_EQ(value, "0");
|
||||
RTC_LOG(LS_ERROR) << sdp;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user