Reland "Handle scalability mode in QueryCodecSupport"

This reverts commit 74281bed5350af9c15f83e0b1aec5c5921dbf76f.

Reason for revert: Fixed unit test by removing VP9 profile 2 from encoder factory unit test since this is platform dependent.

Original change's description:
> Revert "Handle scalability mode in QueryCodecSupport"
>
> This reverts commit 715a14811883a642e3acca21fb6017f8a128c0a5.
>
> Reason for revert: Speculative revert. Breaks upstream project http://b/200009579
>
> Original change's description:
> > Handle scalability mode in QueryCodecSupport
> >
> > All valid scalability modes should be supported by the builtin
> > software decoder/encoder.
> >
> > Bug: chromium:1187565
> > Change-Id: If66105d210d5055019f35dae2f80a18ad4a70cdd
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/222642
> > Commit-Queue: Johannes Kron <kron@webrtc.org>
> > Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
> > Reviewed-by: Erik Språng <sprang@webrtc.org>
> > Cr-Commit-Position: refs/heads/main@{#34998}
>
> TBR=danilchap@webrtc.org,sprang@webrtc.org,kron@webrtc.org,webrtc-scoped@luci-project-accounts.iam.gserviceaccount.com
>
> Change-Id: Ibf40d523c50791d73e2afdc3917892b859d2bcb6
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: chromium:1187565
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/232020
> Reviewed-by: Andrey Logvin <landrey@webrtc.org>
> Commit-Queue: Andrey Logvin <landrey@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#35001}


Bug: chromium:1187565
Change-Id: I598a2a530b8fea22997bbb5910eb3b864d1e28a2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/232021
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35003}
diff --git a/media/BUILD.gn b/media/BUILD.gn
index acfa09f..d5aa58c 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -217,7 +217,10 @@
     "../rtc_base/system:rtc_export",
     "../test:fake_video_codecs",
   ]
-  absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+  absl_deps = [
+    "//third_party/abseil-cpp/absl/strings",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
   sources = [
     "engine/fake_video_codec_factory.cc",
     "engine/fake_video_codec_factory.h",
@@ -614,6 +617,7 @@
         "../modules/video_coding:webrtc_h264",
         "../modules/video_coding:webrtc_vp8",
         "../modules/video_coding/codecs/av1:libaom_av1_decoder",
+        "../modules/video_coding/codecs/av1:libaom_av1_encoder",
         "../p2p:p2p_test_utils",
         "../rtc_base",
         "../rtc_base:checks",
@@ -653,6 +657,7 @@
         "base/video_common_unittest.cc",
         "engine/encoder_simulcast_proxy_unittest.cc",
         "engine/internal_decoder_factory_unittest.cc",
+        "engine/internal_encoder_factory_unittest.cc",
         "engine/multiplex_codec_factory_unittest.cc",
         "engine/null_webrtc_video_engine_unittest.cc",
         "engine/payload_type_mapper_unittest.cc",
diff --git a/media/engine/internal_decoder_factory.cc b/media/engine/internal_decoder_factory.cc
index a8d1f00..c309318 100644
--- a/media/engine/internal_decoder_factory.cc
+++ b/media/engine/internal_decoder_factory.cc
@@ -12,6 +12,7 @@
 
 #include "absl/strings/match.h"
 #include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_codec.h"
 #include "media/base/codec.h"
 #include "media/base/media_constants.h"
 #include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
@@ -36,6 +37,24 @@
   return formats;
 }
 
+VideoDecoderFactory::CodecSupport InternalDecoderFactory::QueryCodecSupport(
+    const SdpVideoFormat& format,
+    bool reference_scaling) const {
+  // Query for supported formats and check if the specified format is supported.
+  // Return unsupported if an invalid combination of format and
+  // reference_scaling is specified.
+  if (reference_scaling) {
+    VideoCodecType codec = PayloadStringToCodecType(format.name);
+    if (codec != kVideoCodecVP9 && codec != kVideoCodecAV1) {
+      return {/*is_supported=*/false, /*is_power_efficient=*/false};
+    }
+  }
+
+  CodecSupport codec_support;
+  codec_support.is_supported = format.IsCodecInList(GetSupportedFormats());
+  return codec_support;
+}
+
 std::unique_ptr<VideoDecoder> InternalDecoderFactory::CreateVideoDecoder(
     const SdpVideoFormat& format) {
   if (!format.IsCodecInList(GetSupportedFormats())) {
diff --git a/media/engine/internal_decoder_factory.h b/media/engine/internal_decoder_factory.h
index 2a580de..0129fb2 100644
--- a/media/engine/internal_decoder_factory.h
+++ b/media/engine/internal_decoder_factory.h
@@ -24,6 +24,8 @@
 class RTC_EXPORT InternalDecoderFactory : public VideoDecoderFactory {
  public:
   std::vector<SdpVideoFormat> GetSupportedFormats() const override;
+  CodecSupport QueryCodecSupport(const SdpVideoFormat& format,
+                                 bool reference_scaling) const override;
   std::unique_ptr<VideoDecoder> CreateVideoDecoder(
       const SdpVideoFormat& format) override;
 };
diff --git a/media/engine/internal_decoder_factory_unittest.cc b/media/engine/internal_decoder_factory_unittest.cc
index 9d3acee..d70390f 100644
--- a/media/engine/internal_decoder_factory_unittest.cc
+++ b/media/engine/internal_decoder_factory_unittest.cc
@@ -19,39 +19,64 @@
 #include "test/gtest.h"
 
 namespace webrtc {
-
+namespace {
 using ::testing::Contains;
 using ::testing::Field;
 using ::testing::Not;
 
-TEST(InternalDecoderFactory, TestVP8) {
+#ifdef RTC_ENABLE_VP9
+constexpr bool kVp9Enabled = true;
+#else
+constexpr bool kVp9Enabled = false;
+#endif
+#ifdef WEBRTC_USE_H264
+constexpr bool kH264Enabled = true;
+#else
+constexpr bool kH264Enabled = false;
+#endif
+constexpr VideoDecoderFactory::CodecSupport kSupported = {
+    /*is_supported=*/true, /*is_power_efficient=*/false};
+constexpr VideoDecoderFactory::CodecSupport kUnsupported = {
+    /*is_supported=*/false, /*is_power_efficient=*/false};
+
+MATCHER_P(Support, expected, "") {
+  return arg.is_supported == expected.is_supported &&
+         arg.is_power_efficient == expected.is_power_efficient;
+}
+
+TEST(InternalDecoderFactoryTest, Vp8) {
   InternalDecoderFactory factory;
   std::unique_ptr<VideoDecoder> decoder =
       factory.CreateVideoDecoder(SdpVideoFormat(cricket::kVp8CodecName));
   EXPECT_TRUE(decoder);
 }
 
-#ifdef RTC_ENABLE_VP9
-TEST(InternalDecoderFactory, TestVP9Profile0) {
+TEST(InternalDecoderFactoryTest, Vp9Profile0) {
   InternalDecoderFactory factory;
   std::unique_ptr<VideoDecoder> decoder =
       factory.CreateVideoDecoder(SdpVideoFormat(
           cricket::kVp9CodecName,
           {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile0)}}));
-  EXPECT_TRUE(decoder);
+  EXPECT_EQ(static_cast<bool>(decoder), kVp9Enabled);
 }
 
-TEST(InternalDecoderFactory, TestVP9Profile1) {
+TEST(InternalDecoderFactoryTest, Vp9Profile1) {
   InternalDecoderFactory factory;
   std::unique_ptr<VideoDecoder> decoder =
       factory.CreateVideoDecoder(SdpVideoFormat(
           cricket::kVp9CodecName,
           {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile1)}}));
-  EXPECT_TRUE(decoder);
+  EXPECT_EQ(static_cast<bool>(decoder), kVp9Enabled);
 }
-#endif  // RTC_ENABLE_VP9
 
-TEST(InternalDecoderFactory, Av1) {
+TEST(InternalDecoderFactoryTest, H264) {
+  InternalDecoderFactory factory;
+  std::unique_ptr<VideoDecoder> decoder =
+      factory.CreateVideoDecoder(SdpVideoFormat(cricket::kH264CodecName));
+  EXPECT_EQ(static_cast<bool>(decoder), kH264Enabled);
+}
+
+TEST(InternalDecoderFactoryTest, Av1) {
   InternalDecoderFactory factory;
   if (kIsLibaomAv1DecoderSupported) {
     EXPECT_THAT(factory.GetSupportedFormats(),
@@ -65,4 +90,45 @@
   }
 }
 
+TEST(InternalDecoderFactoryTest, QueryCodecSupportNoReferenceScaling) {
+  InternalDecoderFactory factory;
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp8CodecName),
+                                        /*reference_scaling=*/false),
+              Support(kSupported));
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp9CodecName),
+                                        /*reference_scaling=*/false),
+              Support(kVp9Enabled ? kSupported : kUnsupported));
+  EXPECT_THAT(factory.QueryCodecSupport(
+                  SdpVideoFormat(cricket::kVp9CodecName,
+                                 {{kVP9FmtpProfileId,
+                                   VP9ProfileToString(VP9Profile::kProfile1)}}),
+                  /*reference_scaling=*/false),
+              Support(kVp9Enabled ? kSupported : kUnsupported));
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kAv1CodecName),
+                                /*reference_scaling=*/false),
+      Support(kIsLibaomAv1DecoderSupported ? kSupported : kUnsupported));
+}
+
+TEST(InternalDecoderFactoryTest, QueryCodecSupportReferenceScaling) {
+  InternalDecoderFactory factory;
+  // VP9 and AV1 support for spatial layers.
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp9CodecName),
+                                        /*reference_scaling=*/true),
+              Support(kVp9Enabled ? kSupported : kUnsupported));
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kAv1CodecName),
+                                /*reference_scaling=*/true),
+      Support(kIsLibaomAv1DecoderSupported ? kSupported : kUnsupported));
+
+  // Invalid config even though VP8 and H264 are supported.
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kH264CodecName),
+                                        /*reference_scaling=*/true),
+              Support(kUnsupported));
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp8CodecName),
+                                        /*reference_scaling=*/true),
+              Support(kUnsupported));
+}
+
+}  // namespace
 }  // namespace webrtc
diff --git a/media/engine/internal_encoder_factory.cc b/media/engine/internal_encoder_factory.cc
index 738516e..bb55066 100644
--- a/media/engine/internal_encoder_factory.cc
+++ b/media/engine/internal_encoder_factory.cc
@@ -57,4 +57,38 @@
   return nullptr;
 }
 
+VideoEncoderFactory::CodecSupport InternalEncoderFactory::QueryCodecSupport(
+    const SdpVideoFormat& format,
+    absl::optional<std::string> scalability_mode) const {
+  // Query for supported formats and check if the specified format is supported.
+  // Begin with filtering out unsupported scalability modes.
+  if (scalability_mode) {
+    bool scalability_mode_supported = false;
+    if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) {
+      scalability_mode_supported =
+          VP8Encoder::SupportsScalabilityMode(*scalability_mode);
+    } else if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) {
+      scalability_mode_supported =
+          VP9Encoder::SupportsScalabilityMode(*scalability_mode);
+    } else if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) {
+      scalability_mode_supported =
+          H264Encoder::SupportsScalabilityMode(*scalability_mode);
+    } else if (kIsLibaomAv1EncoderSupported &&
+               absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName)) {
+      scalability_mode_supported =
+          LibaomAv1EncoderSupportsScalabilityMode(*scalability_mode);
+    }
+
+    static constexpr VideoEncoderFactory::CodecSupport kUnsupported = {
+        /*is_supported=*/false, /*is_power_efficient=*/false};
+    if (!scalability_mode_supported) {
+      return kUnsupported;
+    }
+  }
+
+  CodecSupport codec_support;
+  codec_support.is_supported = format.IsCodecInList(GetSupportedFormats());
+  return codec_support;
+}
+
 }  // namespace webrtc
diff --git a/media/engine/internal_encoder_factory.h b/media/engine/internal_encoder_factory.h
index 3f43e46..e12810c 100644
--- a/media/engine/internal_encoder_factory.h
+++ b/media/engine/internal_encoder_factory.h
@@ -12,8 +12,10 @@
 #define MEDIA_ENGINE_INTERNAL_ENCODER_FACTORY_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_encoder.h"
 #include "api/video_codecs/video_encoder_factory.h"
@@ -25,7 +27,9 @@
  public:
   static std::vector<SdpVideoFormat> SupportedFormats();
   std::vector<SdpVideoFormat> GetSupportedFormats() const override;
-
+  CodecSupport QueryCodecSupport(
+      const SdpVideoFormat& format,
+      absl::optional<std::string> scalability_mode) const override;
   std::unique_ptr<VideoEncoder> CreateVideoEncoder(
       const SdpVideoFormat& format) override;
 };
diff --git a/media/engine/internal_encoder_factory_unittest.cc b/media/engine/internal_encoder_factory_unittest.cc
new file mode 100644
index 0000000..3365e59
--- /dev/null
+++ b/media/engine/internal_encoder_factory_unittest.cc
@@ -0,0 +1,139 @@
+/*
+ *  Copyright (c) 2021 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/engine/internal_encoder_factory.h"
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/vp9_profile.h"
+#include "media/base/media_constants.h"
+#include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+using ::testing::Contains;
+using ::testing::Field;
+using ::testing::Not;
+
+#ifdef RTC_ENABLE_VP9
+constexpr bool kVp9Enabled = true;
+#else
+constexpr bool kVp9Enabled = false;
+#endif
+#ifdef WEBRTC_USE_H264
+constexpr bool kH264Enabled = true;
+#else
+constexpr bool kH264Enabled = false;
+#endif
+constexpr VideoEncoderFactory::CodecSupport kSupported = {
+    /*is_supported=*/true, /*is_power_efficient=*/false};
+constexpr VideoEncoderFactory::CodecSupport kUnsupported = {
+    /*is_supported=*/false, /*is_power_efficient=*/false};
+
+MATCHER_P(Support, expected, "") {
+  return arg.is_supported == expected.is_supported &&
+         arg.is_power_efficient == expected.is_power_efficient;
+}
+
+TEST(InternalEncoderFactoryTest, Vp8) {
+  InternalEncoderFactory factory;
+  std::unique_ptr<VideoEncoder> encoder =
+      factory.CreateVideoEncoder(SdpVideoFormat(cricket::kVp8CodecName));
+  EXPECT_TRUE(encoder);
+}
+
+TEST(InternalEncoderFactoryTest, Vp9Profile0) {
+  InternalEncoderFactory factory;
+  if (kVp9Enabled) {
+    std::unique_ptr<VideoEncoder> encoder =
+        factory.CreateVideoEncoder(SdpVideoFormat(
+            cricket::kVp9CodecName,
+            {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile0)}}));
+    EXPECT_TRUE(encoder);
+  } else {
+    EXPECT_THAT(
+        factory.GetSupportedFormats(),
+        Not(Contains(Field(&SdpVideoFormat::name, cricket::kVp9CodecName))));
+  }
+}
+
+TEST(InternalEncoderFactoryTest, H264) {
+  InternalEncoderFactory factory;
+  if (kH264Enabled) {
+    std::unique_ptr<VideoEncoder> encoder =
+        factory.CreateVideoEncoder(SdpVideoFormat(cricket::kH264CodecName));
+    EXPECT_TRUE(encoder);
+  } else {
+    EXPECT_THAT(
+        factory.GetSupportedFormats(),
+        Not(Contains(Field(&SdpVideoFormat::name, cricket::kH264CodecName))));
+  }
+}
+
+TEST(InternalEncoderFactoryTest, Av1) {
+  InternalEncoderFactory factory;
+  if (kIsLibaomAv1EncoderSupported) {
+    EXPECT_THAT(factory.GetSupportedFormats(),
+                Contains(Field(&SdpVideoFormat::name, cricket::kAv1CodecName)));
+    EXPECT_TRUE(
+        factory.CreateVideoEncoder(SdpVideoFormat(cricket::kAv1CodecName)));
+  } else {
+    EXPECT_THAT(
+        factory.GetSupportedFormats(),
+        Not(Contains(Field(&SdpVideoFormat::name, cricket::kAv1CodecName))));
+  }
+}
+
+TEST(InternalEncoderFactoryTest, QueryCodecSupportNoScalabilityMode) {
+  InternalEncoderFactory factory;
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp8CodecName),
+                                        /*scalability_mode=*/absl::nullopt),
+              Support(kSupported));
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp9CodecName),
+                                        /*scalability_mode=*/absl::nullopt),
+              Support(kVp9Enabled ? kSupported : kUnsupported));
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kAv1CodecName),
+                                /*scalability_mode=*/absl::nullopt),
+      Support(kIsLibaomAv1EncoderSupported ? kSupported : kUnsupported));
+}
+
+TEST(InternalEncoderFactoryTest, QueryCodecSupportWithScalabilityMode) {
+  InternalEncoderFactory factory;
+  // VP8 and VP9 supported for singles spatial layers.
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp8CodecName), "L1T2"),
+      Support(kSupported));
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp9CodecName), "L1T3"),
+      Support(kVp9Enabled ? kSupported : kUnsupported));
+
+  // VP9 support for spatial layers.
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp9CodecName), "L3T3"),
+      Support(kVp9Enabled ? kSupported : kUnsupported));
+
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kAv1CodecName), "L2T1"),
+      Support(kIsLibaomAv1EncoderSupported ? kSupported : kUnsupported));
+
+  // Invalid scalability modes even though VP8 and H264 are supported.
+  EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat(cricket::kH264CodecName),
+                                        "L2T2"),
+              Support(kUnsupported));
+  EXPECT_THAT(
+      factory.QueryCodecSupport(SdpVideoFormat(cricket::kVp8CodecName), "L3T3"),
+      Support(kUnsupported));
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index 500c87d..129d4ea 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -568,6 +568,7 @@
   ]
   absl_deps = [
     "//third_party/abseil-cpp/absl/algorithm:container",
+    "//third_party/abseil-cpp/absl/strings:strings",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
   if (rtc_build_libvpx) {
diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn
index e7c901c..8162d35 100644
--- a/modules/video_coding/codecs/av1/BUILD.gn
+++ b/modules/video_coding/codecs/av1/BUILD.gn
@@ -60,6 +60,7 @@
   absl_deps = [
     "//third_party/abseil-cpp/absl/algorithm:container",
     "//third_party/abseil-cpp/absl/base:core_headers",
+    "//third_party/abseil-cpp/absl/strings:strings",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
 
diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
index a814c74..9c7cc89 100644
--- a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
+++ b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
@@ -806,4 +806,11 @@
   return std::make_unique<LibaomAv1Encoder>();
 }
 
+bool LibaomAv1EncoderSupportsScalabilityMode(
+    absl::string_view scalability_mode) {
+  // For AV1, the scalability mode is supported if we can create the scalability
+  // structure.
+  return ScalabilityStructureConfig(scalability_mode) != absl::nullopt;
+}
+
 }  // namespace webrtc
diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.h b/modules/video_coding/codecs/av1/libaom_av1_encoder.h
index 4b0ee28..0d81c9c 100644
--- a/modules/video_coding/codecs/av1/libaom_av1_encoder.h
+++ b/modules/video_coding/codecs/av1/libaom_av1_encoder.h
@@ -13,6 +13,7 @@
 #include <memory>
 
 #include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
 #include "api/video_codecs/video_encoder.h"
 
 namespace webrtc {
@@ -20,6 +21,8 @@
 ABSL_CONST_INIT extern const bool kIsLibaomAv1EncoderSupported;
 
 std::unique_ptr<VideoEncoder> CreateLibaomAv1Encoder();
+bool LibaomAv1EncoderSupportsScalabilityMode(
+    absl::string_view scalability_mode);
 
 }  // namespace webrtc
 
diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder_absent.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder_absent.cc
index f394260..fff1dd9 100644
--- a/modules/video_coding/codecs/av1/libaom_av1_encoder_absent.cc
+++ b/modules/video_coding/codecs/av1/libaom_av1_encoder_absent.cc
@@ -21,4 +21,9 @@
   return nullptr;
 }
 
+bool LibaomAv1EncoderSupportsScalabilityMode(
+    absl::string_view scalability_mode) {
+  return false;
+}
+
 }  // namespace webrtc
diff --git a/modules/video_coding/codecs/h264/h264.cc b/modules/video_coding/codecs/h264/h264.cc
index 14e1691..275e634 100644
--- a/modules/video_coding/codecs/h264/h264.cc
+++ b/modules/video_coding/codecs/h264/h264.cc
@@ -44,6 +44,8 @@
 #endif
 }
 
+constexpr absl::string_view kSupportedScalabilityModes[] = {"L1T2", "L1T3"};
+
 }  // namespace
 
 SdpVideoFormat CreateH264Format(H264Profile profile,
@@ -105,6 +107,15 @@
   return IsH264CodecSupported();
 }
 
+bool H264Encoder::SupportsScalabilityMode(absl::string_view scalability_mode) {
+  for (const auto& entry : kSupportedScalabilityModes) {
+    if (entry == scalability_mode) {
+      return true;
+    }
+  }
+  return false;
+}
+
 std::unique_ptr<H264Decoder> H264Decoder::Create() {
   RTC_DCHECK(H264Decoder::IsSupported());
 #if defined(WEBRTC_USE_H264)
diff --git a/modules/video_coding/codecs/h264/include/h264.h b/modules/video_coding/codecs/h264/include/h264.h
index bffd31c..8d1eebc 100644
--- a/modules/video_coding/codecs/h264/include/h264.h
+++ b/modules/video_coding/codecs/h264/include/h264.h
@@ -16,6 +16,7 @@
 #include <string>
 #include <vector>
 
+#include "absl/strings/string_view.h"
 #include "api/video_codecs/h264_profile_level_id.h"
 #include "media/base/codec.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -46,6 +47,7 @@
   static std::unique_ptr<H264Encoder> Create(const cricket::VideoCodec& codec);
   // If H.264 is supported (any implementation).
   static bool IsSupported();
+  static bool SupportsScalabilityMode(absl::string_view scalability_mode);
 
   ~H264Encoder() override {}
 };
diff --git a/modules/video_coding/codecs/vp8/include/vp8.h b/modules/video_coding/codecs/vp8/include/vp8.h
index d05c3a6..22f8de6 100644
--- a/modules/video_coding/codecs/vp8/include/vp8.h
+++ b/modules/video_coding/codecs/vp8/include/vp8.h
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
 #include "api/video_codecs/video_encoder.h"
 #include "api/video_codecs/vp8_frame_buffer_controller.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -39,6 +40,7 @@
 
   static std::unique_ptr<VideoEncoder> Create();
   static std::unique_ptr<VideoEncoder> Create(Settings settings);
+  static bool SupportsScalabilityMode(absl::string_view scalability_mode);
 
   ABSL_DEPRECATED("")
   static std::unique_ptr<VideoEncoder> Create(
diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
index 1f70569..88b840c 100644
--- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
+++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
@@ -49,6 +49,8 @@
 constexpr char kVP8IosMaxNumberOfThreadFieldTrialParameter[] = "max_thread";
 #endif
 
+constexpr absl::string_view kSupportedScalabilityModes[] = {"L1T2", "L1T3"};
+
 constexpr char kVp8ForcePartitionResilience[] =
     "WebRTC-VP8-ForcePartitionResilience";
 
@@ -230,6 +232,15 @@
                                             std::move(settings));
 }
 
+bool VP8Encoder::SupportsScalabilityMode(absl::string_view scalability_mode) {
+  for (const auto& entry : kSupportedScalabilityModes) {
+    if (entry == scalability_mode) {
+      return true;
+    }
+  }
+  return false;
+}
+
 vpx_enc_frame_flags_t LibvpxVp8Encoder::EncodeFlags(
     const Vp8FrameConfig& references) {
   RTC_DCHECK(!references.drop_frame);
diff --git a/modules/video_coding/codecs/vp9/include/vp9.h b/modules/video_coding/codecs/vp9/include/vp9.h
index 7294de2..829680a 100644
--- a/modules/video_coding/codecs/vp9/include/vp9.h
+++ b/modules/video_coding/codecs/vp9/include/vp9.h
@@ -15,6 +15,7 @@
 #include <memory>
 #include <vector>
 
+#include "absl/strings/string_view.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "media/base/codec.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -36,6 +37,7 @@
   static std::unique_ptr<VP9Encoder> Create();
   // Parses VP9 Profile from `codec` and returns the appropriate implementation.
   static std::unique_ptr<VP9Encoder> Create(const cricket::VideoCodec& codec);
+  static bool SupportsScalabilityMode(absl::string_view scalability_mode);
 
   ~VP9Encoder() override {}
 };
diff --git a/modules/video_coding/codecs/vp9/vp9.cc b/modules/video_coding/codecs/vp9/vp9.cc
index d9caf0f..9570e53 100644
--- a/modules/video_coding/codecs/vp9/vp9.cc
+++ b/modules/video_coding/codecs/vp9/vp9.cc
@@ -23,6 +23,13 @@
 #include "vpx/vpx_codec.h"
 
 namespace webrtc {
+namespace {
+constexpr absl::string_view kSupportedScalabilityModes[] = {
+    "L1T2",     "L1T3",     "L2T1",    "L2T2",  "L2T3",     "L3T1",
+    "L3T2",     "L3T3",     "L1T2h",   "L1T3h", "L2T1h",    "L2T2h",
+    "L2T3h",    "L3T1h",    "L3T2h",   "L3T3h", "L2T2_KEY", "L2T3_KEY",
+    "L3T1_KEY", "L3T2_KEY", "L3T3_KEY"};
+}  // namespace
 
 std::vector<SdpVideoFormat> SupportedVP9Codecs() {
 #ifdef RTC_ENABLE_VP9
@@ -86,6 +93,15 @@
 #endif
 }
 
+bool VP9Encoder::SupportsScalabilityMode(absl::string_view scalability_mode) {
+  for (const auto& entry : kSupportedScalabilityModes) {
+    if (entry == scalability_mode) {
+      return true;
+    }
+  }
+  return false;
+}
+
 std::unique_ptr<VP9Decoder> VP9Decoder::Create() {
 #ifdef RTC_ENABLE_VP9
   return std::make_unique<LibvpxVp9Decoder>();