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}
diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn
index aaa2a57..5bdd514 100644
--- a/api/video_codecs/BUILD.gn
+++ b/api/video_codecs/BUILD.gn
@@ -85,6 +85,7 @@
     "..:scoped_refptr",
     "../../api:array_view",
     "../../api:rtp_parameters",
+    "../../media:media_constants",
     "../../modules/video_coding:codec_globals_headers",
     "../../rtc_base:checks",
     "../../rtc_base:logging",
diff --git a/api/video_codecs/av1_profile.cc b/api/video_codecs/av1_profile.cc
index 59d7b13..1a953a0 100644
--- a/api/video_codecs/av1_profile.cc
+++ b/api/video_codecs/av1_profile.cc
@@ -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> 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;
diff --git a/api/video_codecs/av1_profile.h b/api/video_codecs/av1_profile.h
index bc97676..4651d93 100644
--- a/api/video_codecs/av1_profile.h
+++ b/api/video_codecs/av1_profile.h
@@ -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.
diff --git a/api/video_codecs/sdp_video_format.cc b/api/video_codecs/sdp_video_format.cc
index 0f313e8..5e311d1 100644
--- a/api/video_codecs/sdp_video_format.cc
+++ b/api/video_codecs/sdp_video_format.cc
@@ -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 {
 
 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;
   }
diff --git a/api/video_codecs/video_decoder_factory_template_dav1d_adapter.h b/api/video_codecs/video_decoder_factory_template_dav1d_adapter.h
index bffbdc4..f38d469 100644
--- a/api/video_codecs/video_decoder_factory_template_dav1d_adapter.h
+++ b/api/video_codecs/video_decoder_factory_template_dav1d_adapter.h
@@ -23,7 +23,7 @@
   static std::vector<SdpVideoFormat> SupportedFormats() {
     return {SdpVideoFormat("AV1"),
             SdpVideoFormat(
-                "AV1", {{kAV1FmtpProfile,
+                "AV1", {{"profile",
                          AV1ProfileToString(AV1Profile::kProfile1).data()}})};
   }
 
diff --git a/media/base/codec_unittest.cc b/media/base/codec_unittest.cc
index 4dc3b18..e1e69eb 100644
--- a/media/base/codec_unittest.cc
+++ b/media/base/codec_unittest.cc
@@ -228,11 +228,11 @@
   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 @@
     // 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 @@
     // 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));
   }
 
diff --git a/media/base/media_constants.cc b/media/base/media_constants.cc
index 2af0295..1a7561a 100644
--- a/media/base/media_constants.cc
+++ b/media/base/media_constants.cc
@@ -124,8 +124,14 @@
 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]
diff --git a/media/base/media_constants.h b/media/base/media_constants.h
index 877cc7a..d5af17e 100644
--- a/media/base/media_constants.h
+++ b/media/base/media_constants.h
@@ -147,8 +147,14 @@
 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;
diff --git a/media/engine/internal_decoder_factory.cc b/media/engine/internal_decoder_factory.cc
index e761fd6..e623aeb 100644
--- a/media/engine/internal_decoder_factory.cc
+++ b/media/engine/internal_decoder_factory.cc
@@ -51,9 +51,10 @@
 
   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;
diff --git a/media/engine/internal_decoder_factory_unittest.cc b/media/engine/internal_decoder_factory_unittest.cc
index 51d6a94..e06b4c3 100644
--- a/media/engine/internal_decoder_factory_unittest.cc
+++ b/media/engine/internal_decoder_factory_unittest.cc
@@ -121,7 +121,7 @@
   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);
 }
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 88f1ce0..a255233 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -2615,6 +2615,17 @@
       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");
+      }
     }
   }
 }
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
index 0238c97..382a496 100644
--- a/pc/webrtc_sdp_unittest.cc
+++ b/pc/webrtc_sdp_unittest.cc
@@ -5082,13 +5082,14 @@
       "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 @@
   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 @@
   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;
 }