Move h264_profile_level_id and vp9_profile to api/video_codecs

This is a refactor to simplify a follow-up CL of adding
SdpVideoFormat::IsSameCodec.

The original files media/base/h264_profile_level_id.* and
media/base/vp9_profile.h must be kept until downstream projects
stop using them.

Bug: chroimium:1187565
Change-Id: Ib39eca095a3d61939a914d9bffaf4b891ddd222f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215236
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33782}
diff --git a/api/test/DEPS b/api/test/DEPS
index d97ac49..2784fcb 100644
--- a/api/test/DEPS
+++ b/api/test/DEPS
@@ -35,7 +35,4 @@
   "create_frame_generator\.h": [
     "+system_wrappers/include/clock.h",
   ],
-  "videocodec_test_fixture\.h": [
-    "+media/base/h264_profile_level_id.h"
-  ],
 }
diff --git a/api/test/videocodec_test_fixture.h b/api/test/videocodec_test_fixture.h
index 379d46d..e0f804f 100644
--- a/api/test/videocodec_test_fixture.h
+++ b/api/test/videocodec_test_fixture.h
@@ -59,7 +59,7 @@
   class EncodedFrameChecker {
    public:
     virtual ~EncodedFrameChecker() = default;
-    virtual void CheckEncodedFrame(webrtc::VideoCodecType codec,
+    virtual void CheckEncodedFrame(VideoCodecType codec,
                                    const EncodedImage& encoded_frame) const = 0;
   };
 
@@ -123,16 +123,16 @@
     bool encode_in_real_time = false;
 
     // Codec settings to use.
-    webrtc::VideoCodec codec_settings;
+    VideoCodec codec_settings;
 
     // Name of the codec being tested.
     std::string codec_name;
 
     // H.264 specific settings.
     struct H264CodecSettings {
-      H264::Profile profile = H264::kProfileConstrainedBaseline;
+      H264Profile profile = H264Profile::kProfileConstrainedBaseline;
       H264PacketizationMode packetization_mode =
-          webrtc::H264PacketizationMode::NonInterleaved;
+          H264PacketizationMode::NonInterleaved;
     } h264_codec_settings;
 
     // Custom checker that will be called for each frame.
diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn
index a990276..4e28cd7 100644
--- a/api/video_codecs/BUILD.gn
+++ b/api/video_codecs/BUILD.gn
@@ -15,6 +15,8 @@
 rtc_library("video_codecs_api") {
   visibility = [ "*" ]
   sources = [
+    "h264_profile_level_id.cc",
+    "h264_profile_level_id.h",
     "sdp_video_format.cc",
     "sdp_video_format.h",
     "spatial_layer.cc",
@@ -35,6 +37,8 @@
     "vp8_frame_config.h",
     "vp8_temporal_layers.cc",
     "vp8_temporal_layers.h",
+    "vp9_profile.cc",
+    "vp9_profile.h",
   ]
 
   deps = [
@@ -138,7 +142,6 @@
     ":video_codecs_api",
     "..:fec_controller_api",
     "../../api/video:video_frame",
-    "../../media:rtc_h264_profile_id",
     "../../media:rtc_media_base",
     "../../modules/video_coding:video_codec_interface",
     "../../modules/video_coding:video_coding_utility",
diff --git a/api/video_codecs/h264_profile_level_id.cc b/api/video_codecs/h264_profile_level_id.cc
new file mode 100644
index 0000000..fa47758
--- /dev/null
+++ b/api/video_codecs/h264_profile_level_id.cc
@@ -0,0 +1,252 @@
+/*
+ *  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 "api/video_codecs/h264_profile_level_id.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+const char kProfileLevelId[] = "profile-level-id";
+
+// For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
+// flag specifies if level 1b or level 1.1 is used.
+const uint8_t kConstraintSet3Flag = 0x10;
+
+// Convert a string of 8 characters into a byte where the positions containing
+// character c will have their bit set. For example, c = 'x', str = "x1xx0000"
+// will return 0b10110000. constexpr is used so that the pattern table in
+// kProfilePatterns is statically initialized.
+constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
+  return (str[0] == c) << 7 | (str[1] == c) << 6 | (str[2] == c) << 5 |
+         (str[3] == c) << 4 | (str[4] == c) << 3 | (str[5] == c) << 2 |
+         (str[6] == c) << 1 | (str[7] == c) << 0;
+}
+
+// Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
+// either 0 or 1.
+class BitPattern {
+ public:
+  explicit constexpr BitPattern(const char (&str)[9])
+      : mask_(~ByteMaskString('x', str)),
+        masked_value_(ByteMaskString('1', str)) {}
+
+  bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
+
+ private:
+  const uint8_t mask_;
+  const uint8_t masked_value_;
+};
+
+// Table for converting between profile_idc/profile_iop to H264Profile.
+struct ProfilePattern {
+  const uint8_t profile_idc;
+  const BitPattern profile_iop;
+  const H264Profile profile;
+};
+
+// This is from https://tools.ietf.org/html/rfc6184#section-8.1.
+constexpr ProfilePattern kProfilePatterns[] = {
+    {0x42, BitPattern("x1xx0000"), H264Profile::kProfileConstrainedBaseline},
+    {0x4D, BitPattern("1xxx0000"), H264Profile::kProfileConstrainedBaseline},
+    {0x58, BitPattern("11xx0000"), H264Profile::kProfileConstrainedBaseline},
+    {0x42, BitPattern("x0xx0000"), H264Profile::kProfileBaseline},
+    {0x58, BitPattern("10xx0000"), H264Profile::kProfileBaseline},
+    {0x4D, BitPattern("0x0x0000"), H264Profile::kProfileMain},
+    {0x64, BitPattern("00000000"), H264Profile::kProfileHigh},
+    {0x64, BitPattern("00001100"), H264Profile::kProfileConstrainedHigh}};
+
+struct LevelConstraint {
+  const int max_macroblocks_per_second;
+  const int max_macroblock_frame_size;
+  const H264Level level;
+};
+
+// This is from ITU-T H.264 (02/2016) Table A-1 – Level limits.
+static constexpr LevelConstraint kLevelConstraints[] = {
+    {1485, 99, H264Level::kLevel1},
+    {1485, 99, H264Level::kLevel1_b},
+    {3000, 396, H264Level::kLevel1_1},
+    {6000, 396, H264Level::kLevel1_2},
+    {11880, 396, H264Level::kLevel1_3},
+    {11880, 396, H264Level::kLevel2},
+    {19800, 792, H264Level::kLevel2_1},
+    {20250, 1620, H264Level::kLevel2_2},
+    {40500, 1620, H264Level::kLevel3},
+    {108000, 3600, H264Level::kLevel3_1},
+    {216000, 5120, H264Level::kLevel3_2},
+    {245760, 8192, H264Level::kLevel4},
+    {245760, 8192, H264Level::kLevel4_1},
+    {522240, 8704, H264Level::kLevel4_2},
+    {589824, 22080, H264Level::kLevel5},
+    {983040, 36864, H264Level::kLevel5_1},
+    {2073600, 36864, H264Level::kLevel5_2},
+};
+
+}  // anonymous namespace
+
+absl::optional<H264ProfileLevelId> ParseH264ProfileLevelId(const char* str) {
+  // The string should consist of 3 bytes in hexadecimal format.
+  if (strlen(str) != 6u)
+    return absl::nullopt;
+  const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
+  if (profile_level_id_numeric == 0)
+    return absl::nullopt;
+
+  // Separate into three bytes.
+  const uint8_t level_idc =
+      static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
+  const uint8_t profile_iop =
+      static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
+  const uint8_t profile_idc =
+      static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
+
+  // Parse level based on level_idc and constraint set 3 flag.
+  H264Level level_casted = static_cast<H264Level>(level_idc);
+  H264Level level;
+
+  switch (level_casted) {
+    case H264Level::kLevel1_1:
+      level = (profile_iop & kConstraintSet3Flag) != 0 ? H264Level::kLevel1_b
+                                                       : H264Level::kLevel1_1;
+      break;
+    case H264Level::kLevel1:
+    case H264Level::kLevel1_2:
+    case H264Level::kLevel1_3:
+    case H264Level::kLevel2:
+    case H264Level::kLevel2_1:
+    case H264Level::kLevel2_2:
+    case H264Level::kLevel3:
+    case H264Level::kLevel3_1:
+    case H264Level::kLevel3_2:
+    case H264Level::kLevel4:
+    case H264Level::kLevel4_1:
+    case H264Level::kLevel4_2:
+    case H264Level::kLevel5:
+    case H264Level::kLevel5_1:
+    case H264Level::kLevel5_2:
+      level = level_casted;
+      break;
+    default:
+      // Unrecognized level_idc.
+      return absl::nullopt;
+  }
+
+  // Parse profile_idc/profile_iop into a Profile enum.
+  for (const ProfilePattern& pattern : kProfilePatterns) {
+    if (profile_idc == pattern.profile_idc &&
+        pattern.profile_iop.IsMatch(profile_iop)) {
+      return H264ProfileLevelId(pattern.profile, level);
+    }
+  }
+
+  // Unrecognized profile_idc/profile_iop combination.
+  return absl::nullopt;
+}
+
+absl::optional<H264Level> H264SupportedLevel(int max_frame_pixel_count,
+                                             float max_fps) {
+  static const int kPixelsPerMacroblock = 16 * 16;
+
+  for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
+    const LevelConstraint& level_constraint = kLevelConstraints[i];
+    if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
+            max_frame_pixel_count &&
+        level_constraint.max_macroblocks_per_second <=
+            max_fps * level_constraint.max_macroblock_frame_size) {
+      return level_constraint.level;
+    }
+  }
+
+  // No level supported.
+  return absl::nullopt;
+}
+
+absl::optional<H264ProfileLevelId> ParseSdpForH264ProfileLevelId(
+    const SdpVideoFormat::Parameters& params) {
+  // TODO(magjed): The default should really be kProfileBaseline and kLevel1
+  // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
+  // order to not break backwards compatibility with older versions of WebRTC
+  // where external codecs don't have any parameters, use
+  // kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
+  // done in an interim period to allow external clients to update their code.
+  // http://crbug/webrtc/6337.
+  static const H264ProfileLevelId kDefaultProfileLevelId(
+      H264Profile::kProfileConstrainedBaseline, H264Level::kLevel3_1);
+
+  const auto profile_level_id_it = params.find(kProfileLevelId);
+  return (profile_level_id_it == params.end())
+             ? kDefaultProfileLevelId
+             : ParseH264ProfileLevelId(profile_level_id_it->second.c_str());
+}
+
+absl::optional<std::string> H264ProfileLevelIdToString(
+    const H264ProfileLevelId& profile_level_id) {
+  // Handle special case level == 1b.
+  if (profile_level_id.level == H264Level::kLevel1_b) {
+    switch (profile_level_id.profile) {
+      case H264Profile::kProfileConstrainedBaseline:
+        return {"42f00b"};
+      case H264Profile::kProfileBaseline:
+        return {"42100b"};
+      case H264Profile::kProfileMain:
+        return {"4d100b"};
+      // Level 1b is not allowed for other profiles.
+      default:
+        return absl::nullopt;
+    }
+  }
+
+  const char* profile_idc_iop_string;
+  switch (profile_level_id.profile) {
+    case H264Profile::kProfileConstrainedBaseline:
+      profile_idc_iop_string = "42e0";
+      break;
+    case H264Profile::kProfileBaseline:
+      profile_idc_iop_string = "4200";
+      break;
+    case H264Profile::kProfileMain:
+      profile_idc_iop_string = "4d00";
+      break;
+    case H264Profile::kProfileConstrainedHigh:
+      profile_idc_iop_string = "640c";
+      break;
+    case H264Profile::kProfileHigh:
+      profile_idc_iop_string = "6400";
+      break;
+    // Unrecognized profile.
+    default:
+      return absl::nullopt;
+  }
+
+  char str[7];
+  snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
+  return {str};
+}
+
+bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1,
+                       const SdpVideoFormat::Parameters& params2) {
+  const absl::optional<H264ProfileLevelId> profile_level_id =
+      ParseSdpForH264ProfileLevelId(params1);
+  const absl::optional<H264ProfileLevelId> other_profile_level_id =
+      ParseSdpForH264ProfileLevelId(params2);
+  // Compare H264 profiles, but not levels.
+  return profile_level_id && other_profile_level_id &&
+         profile_level_id->profile == other_profile_level_id->profile;
+}
+
+}  // namespace webrtc
diff --git a/api/video_codecs/h264_profile_level_id.h b/api/video_codecs/h264_profile_level_id.h
new file mode 100644
index 0000000..51d025c
--- /dev/null
+++ b/api/video_codecs/h264_profile_level_id.h
@@ -0,0 +1,91 @@
+/*
+ *  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.
+ */
+
+#ifndef API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_
+#define API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_
+
+#include <string>
+
+#include "absl/types/optional.h"
+#include "api/video_codecs/sdp_video_format.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+enum class H264Profile {
+  kProfileConstrainedBaseline,
+  kProfileBaseline,
+  kProfileMain,
+  kProfileConstrainedHigh,
+  kProfileHigh,
+};
+
+// All values are equal to ten times the level number, except level 1b which is
+// special.
+enum class H264Level {
+  kLevel1_b = 0,
+  kLevel1 = 10,
+  kLevel1_1 = 11,
+  kLevel1_2 = 12,
+  kLevel1_3 = 13,
+  kLevel2 = 20,
+  kLevel2_1 = 21,
+  kLevel2_2 = 22,
+  kLevel3 = 30,
+  kLevel3_1 = 31,
+  kLevel3_2 = 32,
+  kLevel4 = 40,
+  kLevel4_1 = 41,
+  kLevel4_2 = 42,
+  kLevel5 = 50,
+  kLevel5_1 = 51,
+  kLevel5_2 = 52
+};
+
+struct H264ProfileLevelId {
+  constexpr H264ProfileLevelId(H264Profile profile, H264Level level)
+      : profile(profile), level(level) {}
+  H264Profile profile;
+  H264Level level;
+};
+
+// Parse profile level id that is represented as a string of 3 hex bytes.
+// Nothing will be returned if the string is not a recognized H264
+// profile level id.
+absl::optional<H264ProfileLevelId> ParseH264ProfileLevelId(const char* str);
+
+// Parse profile level id that is represented as a string of 3 hex bytes
+// contained in an SDP key-value map. A default profile level id will be
+// returned if the profile-level-id key is missing. Nothing will be returned if
+// the key is present but the string is invalid.
+RTC_EXPORT absl::optional<H264ProfileLevelId> ParseSdpForH264ProfileLevelId(
+    const SdpVideoFormat::Parameters& params);
+
+// Given that a decoder supports up to a given frame size (in pixels) at up to a
+// given number of frames per second, return the highest H.264 level where it
+// can guarantee that it will be able to support all valid encoded streams that
+// are within that level.
+RTC_EXPORT absl::optional<H264Level> H264SupportedLevel(
+    int max_frame_pixel_count,
+    float max_fps);
+
+// Returns canonical string representation as three hex bytes of the profile
+// level id, or returns nothing for invalid profile level ids.
+RTC_EXPORT absl::optional<std::string> H264ProfileLevelIdToString(
+    const H264ProfileLevelId& profile_level_id);
+
+// Returns true if the parameters have the same H264 profile (Baseline, High,
+// etc).
+RTC_EXPORT bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1,
+                                  const SdpVideoFormat::Parameters& params2);
+
+}  // namespace webrtc
+
+#endif  // API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_
diff --git a/api/video_codecs/test/BUILD.gn b/api/video_codecs/test/BUILD.gn
index cb810fc..ea8e6d5 100644
--- a/api/video_codecs/test/BUILD.gn
+++ b/api/video_codecs/test/BUILD.gn
@@ -13,6 +13,7 @@
     testonly = true
     sources = [
       "builtin_video_encoder_factory_unittest.cc",
+      "h264_profile_level_id_unittest.cc",
       "video_decoder_software_fallback_wrapper_unittest.cc",
       "video_encoder_software_fallback_wrapper_unittest.cc",
     ]
diff --git a/api/video_codecs/test/h264_profile_level_id_unittest.cc b/api/video_codecs/test/h264_profile_level_id_unittest.cc
new file mode 100644
index 0000000..47098d2
--- /dev/null
+++ b/api/video_codecs/test/h264_profile_level_id_unittest.cc
@@ -0,0 +1,171 @@
+/*
+ *  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 "api/video_codecs/h264_profile_level_id.h"
+
+#include <map>
+#include <string>
+
+#include "absl/types/optional.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(H264ProfileLevelId, TestParsingInvalid) {
+  // Malformed strings.
+  EXPECT_FALSE(ParseH264ProfileLevelId(""));
+  EXPECT_FALSE(ParseH264ProfileLevelId(" 42e01f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("4242e01f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("e01f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("gggggg"));
+
+  // Invalid level.
+  EXPECT_FALSE(ParseH264ProfileLevelId("42e000"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("42e00f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("42e0ff"));
+
+  // Invalid profile.
+  EXPECT_FALSE(ParseH264ProfileLevelId("42e11f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("58601f"));
+  EXPECT_FALSE(ParseH264ProfileLevelId("64e01f"));
+}
+
+TEST(H264ProfileLevelId, TestParsingLevel) {
+  EXPECT_EQ(H264Level::kLevel3_1, ParseH264ProfileLevelId("42e01f")->level);
+  EXPECT_EQ(H264Level::kLevel1_1, ParseH264ProfileLevelId("42e00b")->level);
+  EXPECT_EQ(H264Level::kLevel1_b, ParseH264ProfileLevelId("42f00b")->level);
+  EXPECT_EQ(H264Level::kLevel4_2, ParseH264ProfileLevelId("42C02A")->level);
+  EXPECT_EQ(H264Level::kLevel5_2, ParseH264ProfileLevelId("640c34")->level);
+}
+
+TEST(H264ProfileLevelId, TestParsingConstrainedBaseline) {
+  EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
+            ParseH264ProfileLevelId("42e01f")->profile);
+  EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
+            ParseH264ProfileLevelId("42C02A")->profile);
+  EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
+            ParseH264ProfileLevelId("4de01f")->profile);
+  EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
+            ParseH264ProfileLevelId("58f01f")->profile);
+}
+
+TEST(H264ProfileLevelId, TestParsingBaseline) {
+  EXPECT_EQ(H264Profile::kProfileBaseline,
+            ParseH264ProfileLevelId("42a01f")->profile);
+  EXPECT_EQ(H264Profile::kProfileBaseline,
+            ParseH264ProfileLevelId("58A01F")->profile);
+}
+
+TEST(H264ProfileLevelId, TestParsingMain) {
+  EXPECT_EQ(H264Profile::kProfileMain,
+            ParseH264ProfileLevelId("4D401f")->profile);
+}
+
+TEST(H264ProfileLevelId, TestParsingHigh) {
+  EXPECT_EQ(H264Profile::kProfileHigh,
+            ParseH264ProfileLevelId("64001f")->profile);
+}
+
+TEST(H264ProfileLevelId, TestParsingConstrainedHigh) {
+  EXPECT_EQ(H264Profile::kProfileConstrainedHigh,
+            ParseH264ProfileLevelId("640c1f")->profile);
+}
+
+TEST(H264ProfileLevelId, TestSupportedLevel) {
+  EXPECT_EQ(H264Level::kLevel2_1, *H264SupportedLevel(640 * 480, 25));
+  EXPECT_EQ(H264Level::kLevel3_1, *H264SupportedLevel(1280 * 720, 30));
+  EXPECT_EQ(H264Level::kLevel4_2, *H264SupportedLevel(1920 * 1280, 60));
+}
+
+// Test supported level below level 1 requirements.
+TEST(H264ProfileLevelId, TestSupportedLevelInvalid) {
+  EXPECT_FALSE(H264SupportedLevel(0, 0));
+  // All levels support fps > 5.
+  EXPECT_FALSE(H264SupportedLevel(1280 * 720, 5));
+  // All levels support frame sizes > 183 * 137.
+  EXPECT_FALSE(H264SupportedLevel(183 * 137, 30));
+}
+
+TEST(H264ProfileLevelId, TestToString) {
+  EXPECT_EQ("42e01f", *H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileConstrainedBaseline,
+                          H264Level::kLevel3_1)));
+  EXPECT_EQ("42000a", *H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileBaseline, H264Level::kLevel1)));
+  EXPECT_EQ("4d001f", H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileMain, H264Level::kLevel3_1)));
+  EXPECT_EQ("640c2a",
+            *H264ProfileLevelIdToString(H264ProfileLevelId(
+                H264Profile::kProfileConstrainedHigh, H264Level::kLevel4_2)));
+  EXPECT_EQ("64002a", *H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileHigh, H264Level::kLevel4_2)));
+}
+
+TEST(H264ProfileLevelId, TestToStringLevel1b) {
+  EXPECT_EQ("42f00b", *H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileConstrainedBaseline,
+                          H264Level::kLevel1_b)));
+  EXPECT_EQ("42100b",
+            *H264ProfileLevelIdToString(H264ProfileLevelId(
+                H264Profile::kProfileBaseline, H264Level::kLevel1_b)));
+  EXPECT_EQ("4d100b", *H264ProfileLevelIdToString(H264ProfileLevelId(
+                          H264Profile::kProfileMain, H264Level::kLevel1_b)));
+}
+
+TEST(H264ProfileLevelId, TestToStringRoundTrip) {
+  EXPECT_EQ("42e01f",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42e01f")));
+  EXPECT_EQ("42e01f",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42E01F")));
+  EXPECT_EQ("4d100b",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4d100b")));
+  EXPECT_EQ("4d100b",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4D100B")));
+  EXPECT_EQ("640c2a",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640c2a")));
+  EXPECT_EQ("640c2a",
+            *H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640C2A")));
+}
+
+TEST(H264ProfileLevelId, TestToStringInvalid) {
+  EXPECT_FALSE(H264ProfileLevelIdToString(
+      H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1_b)));
+  EXPECT_FALSE(H264ProfileLevelIdToString(H264ProfileLevelId(
+      H264Profile::kProfileConstrainedHigh, H264Level::kLevel1_b)));
+  EXPECT_FALSE(H264ProfileLevelIdToString(
+      H264ProfileLevelId(static_cast<H264Profile>(255), H264Level::kLevel3_1)));
+}
+
+TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) {
+  const absl::optional<H264ProfileLevelId> profile_level_id =
+      ParseSdpForH264ProfileLevelId(SdpVideoFormat::Parameters());
+  EXPECT_TRUE(profile_level_id);
+  EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
+            profile_level_id->profile);
+  EXPECT_EQ(H264Level::kLevel3_1, profile_level_id->level);
+}
+
+TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) {
+  SdpVideoFormat::Parameters params;
+  params["profile-level-id"] = "640c2a";
+  const absl::optional<H264ProfileLevelId> profile_level_id =
+      ParseSdpForH264ProfileLevelId(params);
+  EXPECT_TRUE(profile_level_id);
+  EXPECT_EQ(H264Profile::kProfileConstrainedHigh, profile_level_id->profile);
+  EXPECT_EQ(H264Level::kLevel4_2, profile_level_id->level);
+}
+
+TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdInvalid) {
+  SdpVideoFormat::Parameters params;
+  params["profile-level-id"] = "foobar";
+  EXPECT_FALSE(ParseSdpForH264ProfileLevelId(params));
+}
+
+}  // namespace webrtc
diff --git a/media/base/vp9_profile.cc b/api/video_codecs/vp9_profile.cc
similarity index 91%
rename from media/base/vp9_profile.cc
rename to api/video_codecs/vp9_profile.cc
index abf2502..d69f566 100644
--- a/media/base/vp9_profile.cc
+++ b/api/video_codecs/vp9_profile.cc
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *  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
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "media/base/vp9_profile.h"
+#include "api/video_codecs/vp9_profile.h"
 
 #include <map>
 #include <utility>
@@ -59,7 +59,7 @@
   return StringToVP9Profile(profile_str);
 }
 
-bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
+bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
                       const SdpVideoFormat::Parameters& params2) {
   const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1);
   const absl::optional<VP9Profile> other_profile =
diff --git a/api/video_codecs/vp9_profile.h b/api/video_codecs/vp9_profile.h
new file mode 100644
index 0000000..e632df4
--- /dev/null
+++ b/api/video_codecs/vp9_profile.h
@@ -0,0 +1,53 @@
+/*
+ *  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.
+ */
+
+#ifndef API_VIDEO_CODECS_VP9_PROFILE_H_
+#define API_VIDEO_CODECS_VP9_PROFILE_H_
+
+#include <string>
+
+#include "absl/types/optional.h"
+#include "api/video_codecs/sdp_video_format.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// Profile information for VP9 video.
+extern RTC_EXPORT const char kVP9FmtpProfileId[];
+
+enum class VP9Profile {
+  kProfile0,
+  kProfile1,
+  kProfile2,
+};
+
+// Helper functions to convert VP9Profile to std::string. Returns "0" by
+// default.
+RTC_EXPORT std::string VP9ProfileToString(VP9Profile profile);
+
+// Helper functions to convert std::string to VP9Profile. Returns null if given
+// an invalid profile string.
+absl::optional<VP9Profile> StringToVP9Profile(const std::string& str);
+
+// Parse profile that is represented as a string of single digit contained in an
+// SDP key-value map. A default profile(kProfile0) will be returned if the
+// profile key is missing. Nothing will be returned if the key is present but
+// the string is invalid.
+RTC_EXPORT absl::optional<VP9Profile> ParseSdpForVP9Profile(
+    const SdpVideoFormat::Parameters& params);
+
+// Returns true if the parameters have the same VP9 profile, or neither contains
+// VP9 profile.
+bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
+                      const SdpVideoFormat::Parameters& params2);
+
+}  // namespace webrtc
+
+#endif  // API_VIDEO_CODECS_VP9_PROFILE_H_
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index 2503f7f..8e53767 100644
--- a/common_video/BUILD.gn
+++ b/common_video/BUILD.gn
@@ -21,7 +21,6 @@
     "h264/h264_common.h",
     "h264/pps_parser.cc",
     "h264/pps_parser.h",
-    "h264/profile_level_id.h",
     "h264/sps_parser.cc",
     "h264/sps_parser.h",
     "h264/sps_vui_rewriter.cc",
@@ -52,7 +51,7 @@
     "../api/video:video_frame",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:bitstream_parser_api",
-    "../media:rtc_h264_profile_id",
+    "../api/video_codecs:video_codecs_api",
     "../rtc_base",
     "../rtc_base:checks",
     "../rtc_base:rtc_task_queue",
@@ -90,7 +89,6 @@
       "frame_rate_estimator_unittest.cc",
       "h264/h264_bitstream_parser_unittest.cc",
       "h264/pps_parser_unittest.cc",
-      "h264/profile_level_id_unittest.cc",
       "h264/sps_parser_unittest.cc",
       "h264/sps_vui_rewriter_unittest.cc",
       "libyuv/libyuv_unittest.cc",
@@ -105,7 +103,7 @@
       "../api/video:video_frame",
       "../api/video:video_frame_i010",
       "../api/video:video_rtp_headers",
-      "../media:rtc_h264_profile_id",
+      "../api/video_codecs:video_codecs_api",
       "../rtc_base",
       "../rtc_base:checks",
       "../rtc_base:rtc_base_approved",
diff --git a/common_video/h264/profile_level_id.h b/common_video/h264/profile_level_id.h
deleted file mode 100644
index 07b49e5..0000000
--- a/common_video/h264/profile_level_id.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- *  Copyright (c) 2016 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.
- */
-
-#ifndef COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_
-#define COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_
-
-#include "media/base/h264_profile_level_id.h"
-
-// TODO(zhihuang): Delete this file once dependent applications switch to
-// including "webrtc/media/base/h264_profile_level_id.h" directly.
-
-#endif  // COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_
diff --git a/common_video/h264/profile_level_id_unittest.cc b/common_video/h264/profile_level_id_unittest.cc
deleted file mode 100644
index 957b434..0000000
--- a/common_video/h264/profile_level_id_unittest.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- *  Copyright (c) 2016 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 "common_video/h264/profile_level_id.h"
-
-#include <map>
-#include <string>
-
-#include "absl/types/optional.h"
-#include "media/base/h264_profile_level_id.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace H264 {
-
-TEST(H264ProfileLevelId, TestParsingInvalid) {
-  // Malformed strings.
-  EXPECT_FALSE(ParseProfileLevelId(""));
-  EXPECT_FALSE(ParseProfileLevelId(" 42e01f"));
-  EXPECT_FALSE(ParseProfileLevelId("4242e01f"));
-  EXPECT_FALSE(ParseProfileLevelId("e01f"));
-  EXPECT_FALSE(ParseProfileLevelId("gggggg"));
-
-  // Invalid level.
-  EXPECT_FALSE(ParseProfileLevelId("42e000"));
-  EXPECT_FALSE(ParseProfileLevelId("42e00f"));
-  EXPECT_FALSE(ParseProfileLevelId("42e0ff"));
-
-  // Invalid profile.
-  EXPECT_FALSE(ParseProfileLevelId("42e11f"));
-  EXPECT_FALSE(ParseProfileLevelId("58601f"));
-  EXPECT_FALSE(ParseProfileLevelId("64e01f"));
-}
-
-TEST(H264ProfileLevelId, TestParsingLevel) {
-  EXPECT_EQ(kLevel3_1, ParseProfileLevelId("42e01f")->level);
-  EXPECT_EQ(kLevel1_1, ParseProfileLevelId("42e00b")->level);
-  EXPECT_EQ(kLevel1_b, ParseProfileLevelId("42f00b")->level);
-  EXPECT_EQ(kLevel4_2, ParseProfileLevelId("42C02A")->level);
-  EXPECT_EQ(kLevel5_2, ParseProfileLevelId("640c34")->level);
-}
-
-TEST(H264ProfileLevelId, TestParsingConstrainedBaseline) {
-  EXPECT_EQ(kProfileConstrainedBaseline,
-            ParseProfileLevelId("42e01f")->profile);
-  EXPECT_EQ(kProfileConstrainedBaseline,
-            ParseProfileLevelId("42C02A")->profile);
-  EXPECT_EQ(kProfileConstrainedBaseline,
-            ParseProfileLevelId("4de01f")->profile);
-  EXPECT_EQ(kProfileConstrainedBaseline,
-            ParseProfileLevelId("58f01f")->profile);
-}
-
-TEST(H264ProfileLevelId, TestParsingBaseline) {
-  EXPECT_EQ(kProfileBaseline, ParseProfileLevelId("42a01f")->profile);
-  EXPECT_EQ(kProfileBaseline, ParseProfileLevelId("58A01F")->profile);
-}
-
-TEST(H264ProfileLevelId, TestParsingMain) {
-  EXPECT_EQ(kProfileMain, ParseProfileLevelId("4D401f")->profile);
-}
-
-TEST(H264ProfileLevelId, TestParsingHigh) {
-  EXPECT_EQ(kProfileHigh, ParseProfileLevelId("64001f")->profile);
-}
-
-TEST(H264ProfileLevelId, TestParsingConstrainedHigh) {
-  EXPECT_EQ(kProfileConstrainedHigh, ParseProfileLevelId("640c1f")->profile);
-}
-
-TEST(H264ProfileLevelId, TestSupportedLevel) {
-  EXPECT_EQ(kLevel2_1, *SupportedLevel(640 * 480, 25));
-  EXPECT_EQ(kLevel3_1, *SupportedLevel(1280 * 720, 30));
-  EXPECT_EQ(kLevel4_2, *SupportedLevel(1920 * 1280, 60));
-}
-
-// Test supported level below level 1 requirements.
-TEST(H264ProfileLevelId, TestSupportedLevelInvalid) {
-  EXPECT_FALSE(SupportedLevel(0, 0));
-  // All levels support fps > 5.
-  EXPECT_FALSE(SupportedLevel(1280 * 720, 5));
-  // All levels support frame sizes > 183 * 137.
-  EXPECT_FALSE(SupportedLevel(183 * 137, 30));
-}
-
-TEST(H264ProfileLevelId, TestToString) {
-  EXPECT_EQ("42e01f", *ProfileLevelIdToString(ProfileLevelId(
-                          kProfileConstrainedBaseline, kLevel3_1)));
-  EXPECT_EQ("42000a",
-            *ProfileLevelIdToString(ProfileLevelId(kProfileBaseline, kLevel1)));
-  EXPECT_EQ("4d001f",
-            ProfileLevelIdToString(ProfileLevelId(kProfileMain, kLevel3_1)));
-  EXPECT_EQ("640c2a", *ProfileLevelIdToString(
-                          ProfileLevelId(kProfileConstrainedHigh, kLevel4_2)));
-  EXPECT_EQ("64002a",
-            *ProfileLevelIdToString(ProfileLevelId(kProfileHigh, kLevel4_2)));
-}
-
-TEST(H264ProfileLevelId, TestToStringLevel1b) {
-  EXPECT_EQ("42f00b", *ProfileLevelIdToString(ProfileLevelId(
-                          kProfileConstrainedBaseline, kLevel1_b)));
-  EXPECT_EQ("42100b", *ProfileLevelIdToString(
-                          ProfileLevelId(kProfileBaseline, kLevel1_b)));
-  EXPECT_EQ("4d100b",
-            *ProfileLevelIdToString(ProfileLevelId(kProfileMain, kLevel1_b)));
-}
-
-TEST(H264ProfileLevelId, TestToStringRoundTrip) {
-  EXPECT_EQ("42e01f", *ProfileLevelIdToString(*ParseProfileLevelId("42e01f")));
-  EXPECT_EQ("42e01f", *ProfileLevelIdToString(*ParseProfileLevelId("42E01F")));
-  EXPECT_EQ("4d100b", *ProfileLevelIdToString(*ParseProfileLevelId("4d100b")));
-  EXPECT_EQ("4d100b", *ProfileLevelIdToString(*ParseProfileLevelId("4D100B")));
-  EXPECT_EQ("640c2a", *ProfileLevelIdToString(*ParseProfileLevelId("640c2a")));
-  EXPECT_EQ("640c2a", *ProfileLevelIdToString(*ParseProfileLevelId("640C2A")));
-}
-
-TEST(H264ProfileLevelId, TestToStringInvalid) {
-  EXPECT_FALSE(ProfileLevelIdToString(ProfileLevelId(kProfileHigh, kLevel1_b)));
-  EXPECT_FALSE(ProfileLevelIdToString(
-      ProfileLevelId(kProfileConstrainedHigh, kLevel1_b)));
-  EXPECT_FALSE(ProfileLevelIdToString(
-      ProfileLevelId(static_cast<Profile>(255), kLevel3_1)));
-}
-
-TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) {
-  const absl::optional<ProfileLevelId> profile_level_id =
-      ParseSdpProfileLevelId(CodecParameterMap());
-  EXPECT_TRUE(profile_level_id);
-  EXPECT_EQ(kProfileConstrainedBaseline, profile_level_id->profile);
-  EXPECT_EQ(kLevel3_1, profile_level_id->level);
-}
-
-TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) {
-  CodecParameterMap params;
-  params["profile-level-id"] = "640c2a";
-  const absl::optional<ProfileLevelId> profile_level_id =
-      ParseSdpProfileLevelId(params);
-  EXPECT_TRUE(profile_level_id);
-  EXPECT_EQ(kProfileConstrainedHigh, profile_level_id->profile);
-  EXPECT_EQ(kLevel4_2, profile_level_id->level);
-}
-
-TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdInvalid) {
-  CodecParameterMap params;
-  params["profile-level-id"] = "foobar";
-  EXPECT_FALSE(ParseSdpProfileLevelId(params));
-}
-
-TEST(H264ProfileLevelId, TestGenerateProfileLevelIdForAnswerEmpty) {
-  CodecParameterMap answer_params;
-  GenerateProfileLevelIdForAnswer(CodecParameterMap(), CodecParameterMap(),
-                                  &answer_params);
-  EXPECT_TRUE(answer_params.empty());
-}
-
-TEST(H264ProfileLevelId,
-     TestGenerateProfileLevelIdForAnswerLevelSymmetryCapped) {
-  CodecParameterMap low_level;
-  low_level["profile-level-id"] = "42e015";
-  CodecParameterMap high_level;
-  high_level["profile-level-id"] = "42e01f";
-
-  // Level asymmetry is not allowed; test that answer level is the lower of the
-  // local and remote levels.
-  CodecParameterMap answer_params;
-  GenerateProfileLevelIdForAnswer(low_level /* local_supported */,
-                                  high_level /* remote_offered */,
-                                  &answer_params);
-  EXPECT_EQ("42e015", answer_params["profile-level-id"]);
-
-  CodecParameterMap answer_params2;
-  GenerateProfileLevelIdForAnswer(high_level /* local_supported */,
-                                  low_level /* remote_offered */,
-                                  &answer_params2);
-  EXPECT_EQ("42e015", answer_params2["profile-level-id"]);
-}
-
-TEST(H264ProfileLevelId,
-     TestGenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) {
-  CodecParameterMap local_params;
-  local_params["profile-level-id"] = "42e01f";
-  local_params["level-asymmetry-allowed"] = "1";
-  CodecParameterMap remote_params;
-  remote_params["profile-level-id"] = "42e015";
-  remote_params["level-asymmetry-allowed"] = "1";
-  CodecParameterMap answer_params;
-  GenerateProfileLevelIdForAnswer(local_params, remote_params, &answer_params);
-  // When level asymmetry is allowed, we can answer a higher level than what was
-  // offered.
-  EXPECT_EQ("42e01f", answer_params["profile-level-id"]);
-}
-
-}  // namespace H264
-}  // namespace webrtc
diff --git a/media/BUILD.gn b/media/BUILD.gn
index f487c16..29ba403 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -23,20 +23,15 @@
   defines = [ "HAVE_WEBRTC_VIDEO" ]
 }
 
-rtc_library("rtc_h264_profile_id") {
+# Remove once downstream projects stop depend on this.
+rtc_source_set("rtc_h264_profile_id") {
   visibility = [ "*" ]
   sources = [
     "base/h264_profile_level_id.cc",
     "base/h264_profile_level_id.h",
   ]
-
-  deps = [
-    "../rtc_base",
-    "../rtc_base:checks",
-    "../rtc_base:rtc_base_approved",
-    "../rtc_base/system:rtc_export",
-  ]
-  absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+  public_deps =  # no-presubmit-check TODO(webrtc:8603)
+      [ "../api/video_codecs:video_codecs_api" ]
 }
 
 rtc_source_set("rtc_media_config") {
@@ -44,30 +39,24 @@
   sources = [ "base/media_config.h" ]
 }
 
-rtc_library("rtc_vp9_profile") {
+# Remove once downstream projects stop depend on this.
+rtc_source_set("rtc_vp9_profile") {
   visibility = [ "*" ]
-  sources = [
-    "base/vp9_profile.cc",
-    "base/vp9_profile.h",
-  ]
-
-  deps = [
-    "../api/video_codecs:video_codecs_api",
-    "../rtc_base:rtc_base_approved",
-    "../rtc_base/system:rtc_export",
-  ]
-  absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+  sources = [ "base/vp9_profile.h" ]
+  public_deps =  # no-presubmit-check TODO(webrtc:8603)
+      [ "../api/video_codecs:video_codecs_api" ]
 }
 
-rtc_library("rtc_sdp_fmtp_utils") {
+rtc_library("rtc_sdp_video_format_utils") {
   visibility = [ "*" ]
   sources = [
-    "base/sdp_fmtp_utils.cc",
-    "base/sdp_fmtp_utils.h",
+    "base/sdp_video_format_utils.cc",
+    "base/sdp_video_format_utils.h",
   ]
 
   deps = [
     "../api/video_codecs:video_codecs_api",
+    "../rtc_base:checks",
     "../rtc_base:stringutils",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
@@ -78,9 +67,7 @@
   defines = []
   libs = []
   deps = [
-    ":rtc_h264_profile_id",
     ":rtc_media_config",
-    ":rtc_vp9_profile",
     "../api:array_view",
     "../api:audio_options_api",
     "../api:frame_transformer_interface",
@@ -221,7 +208,6 @@
   libs = []
   deps = [
     ":rtc_encoder_simulcast_proxy",
-    ":rtc_h264_profile_id",
     ":rtc_media_base",
     ":rtc_simulcast_encoder_adapter",
     "../api/video:encoded_image",
@@ -555,9 +541,8 @@
         ":rtc_media_base",
         ":rtc_media_engine_defaults",
         ":rtc_media_tests_utils",
-        ":rtc_sdp_fmtp_utils",
+        ":rtc_sdp_video_format_utils",
         ":rtc_simulcast_encoder_adapter",
-        ":rtc_vp9_profile",
         "../api:create_simulcast_test_fixture_api",
         "../api:libjingle_peerconnection_api",
         "../api:mock_video_bitrate_allocator",
@@ -586,7 +571,6 @@
         "../audio",
         "../call:call_interfaces",
         "../common_video",
-        "../media:rtc_h264_profile_id",
         "../modules/audio_device:mock_audio_device",
         "../modules/audio_processing",
         "../modules/audio_processing:api",
@@ -627,7 +611,7 @@
         "base/codec_unittest.cc",
         "base/media_engine_unittest.cc",
         "base/rtp_utils_unittest.cc",
-        "base/sdp_fmtp_utils_unittest.cc",
+        "base/sdp_video_format_utils_unittest.cc",
         "base/stream_params_unittest.cc",
         "base/turn_utils_unittest.cc",
         "base/video_adapter_unittest.cc",
diff --git a/media/base/codec.cc b/media/base/codec.cc
index ab39592..e8a591e 100644
--- a/media/base/codec.cc
+++ b/media/base/codec.cc
@@ -12,8 +12,8 @@
 
 #include "absl/algorithm/container.h"
 #include "absl/strings/match.h"
-#include "media/base/h264_profile_level_id.h"
-#include "media/base/vp9_profile.h"
+#include "api/video_codecs/h264_profile_level_id.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/string_encode.h"
@@ -51,10 +51,10 @@
            absl::EqualsIgnoreCase(name, name2);
   };
   if (either_name_matches(kH264CodecName))
-    return webrtc::H264::IsSameH264Profile(params1, params2) &&
+    return webrtc::H264IsSameProfile(params1, params2) &&
            IsSameH264PacketizationMode(params1, params2);
   if (either_name_matches(kVp9CodecName))
-    return webrtc::IsSameVP9Profile(params1, params2);
+    return webrtc::VP9IsSameProfile(params1, params2);
   return true;
 }
 
@@ -473,15 +473,16 @@
   for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
        ++it) {
     if (it->name == cricket::kH264CodecName) {
-      const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
-          webrtc::H264::ParseSdpProfileLevelId(it->parameters);
-      if (profile_level_id && profile_level_id->profile !=
-                                  webrtc::H264::kProfileConstrainedBaseline) {
+      const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
+          webrtc::ParseSdpForH264ProfileLevelId(it->parameters);
+      if (profile_level_id &&
+          profile_level_id->profile !=
+              webrtc::H264Profile::kProfileConstrainedBaseline) {
         webrtc::SdpVideoFormat cbp_format = *it;
-        webrtc::H264::ProfileLevelId cbp_profile = *profile_level_id;
-        cbp_profile.profile = webrtc::H264::kProfileConstrainedBaseline;
+        webrtc::H264ProfileLevelId cbp_profile = *profile_level_id;
+        cbp_profile.profile = webrtc::H264Profile::kProfileConstrainedBaseline;
         cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
-            *webrtc::H264::ProfileLevelIdToString(cbp_profile);
+            *webrtc::H264ProfileLevelIdToString(cbp_profile);
         cbr_supported_formats.push_back(cbp_format);
       }
     }
diff --git a/media/base/codec_unittest.cc b/media/base/codec_unittest.cc
index d41ed9b..3586760 100644
--- a/media/base/codec_unittest.cc
+++ b/media/base/codec_unittest.cc
@@ -12,8 +12,8 @@
 
 #include <tuple>
 
-#include "media/base/h264_profile_level_id.h"
-#include "media/base/vp9_profile.h"
+#include "api/video_codecs/h264_profile_level_id.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "modules/video_coding/codecs/h264/include/h264.h"
 #include "rtc_base/gunit.h"
 
@@ -457,10 +457,10 @@
 
 TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
   const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
-      webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
-                               webrtc::H264::kLevel3_1, "1"),
-      webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
-                               webrtc::H264::kLevel3_1, "0")};
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
+                               webrtc::H264Level::kLevel3_1, "1"),
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
+                               webrtc::H264Level::kLevel3_1, "0")};
 
   std::vector<webrtc::SdpVideoFormat> supported_formats =
       kExplicitlySupportedFormats;
@@ -468,11 +468,11 @@
       &supported_formats);
 
   const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 =
-      webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
-                               webrtc::H264::kLevel3_1, "1");
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
+                               webrtc::H264Level::kLevel3_1, "1");
   const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 =
-      webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
-                               webrtc::H264::kLevel3_1, "0");
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
+                               webrtc::H264Level::kLevel3_1, "0");
 
   EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]);
   EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]);
@@ -497,14 +497,14 @@
 
 TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) {
   const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
-      webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
-                               webrtc::H264::kLevel3_1, "1"),
-      webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
-                               webrtc::H264::kLevel3_1, "0"),
-      webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
-                               webrtc::H264::kLevel3_1, "1"),
-      webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
-                               webrtc::H264::kLevel3_1, "0")};
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
+                               webrtc::H264Level::kLevel3_1, "1"),
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
+                               webrtc::H264Level::kLevel3_1, "0"),
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
+                               webrtc::H264Level::kLevel3_1, "1"),
+      webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
+                               webrtc::H264Level::kLevel3_1, "0")};
 
   std::vector<webrtc::SdpVideoFormat> supported_formats =
       kExplicitlySupportedFormats;
diff --git a/media/base/h264_profile_level_id.cc b/media/base/h264_profile_level_id.cc
index 32fa02c..6f9fa46 100644
--- a/media/base/h264_profile_level_id.cc
+++ b/media/base/h264_profile_level_id.cc
@@ -10,301 +10,33 @@
 
 #include "media/base/h264_profile_level_id.h"
 
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-#include "rtc_base/arraysize.h"
-#include "rtc_base/checks.h"
+// TODO(crbug.com/1187565): Remove this file once downstream projects stop
+// depend on it.
 
 namespace webrtc {
 namespace H264 {
 
-namespace {
-
-const char kProfileLevelId[] = "profile-level-id";
-const char kLevelAsymmetryAllowed[] = "level-asymmetry-allowed";
-
-// For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
-// flag specifies if level 1b or level 1.1 is used.
-const uint8_t kConstraintSet3Flag = 0x10;
-
-// Convert a string of 8 characters into a byte where the positions containing
-// character c will have their bit set. For example, c = 'x', str = "x1xx0000"
-// will return 0b10110000. constexpr is used so that the pattern table in
-// kProfilePatterns is statically initialized.
-constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
-  return (str[0] == c) << 7 | (str[1] == c) << 6 | (str[2] == c) << 5 |
-         (str[3] == c) << 4 | (str[4] == c) << 3 | (str[5] == c) << 2 |
-         (str[6] == c) << 1 | (str[7] == c) << 0;
-}
-
-// Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
-// either 0 or 1.
-class BitPattern {
- public:
-  explicit constexpr BitPattern(const char (&str)[9])
-      : mask_(~ByteMaskString('x', str)),
-        masked_value_(ByteMaskString('1', str)) {}
-
-  bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
-
- private:
-  const uint8_t mask_;
-  const uint8_t masked_value_;
-};
-
-// Table for converting between profile_idc/profile_iop to H264::Profile.
-struct ProfilePattern {
-  const uint8_t profile_idc;
-  const BitPattern profile_iop;
-  const Profile profile;
-};
-
-// This is from https://tools.ietf.org/html/rfc6184#section-8.1.
-constexpr ProfilePattern kProfilePatterns[] = {
-    {0x42, BitPattern("x1xx0000"), kProfileConstrainedBaseline},
-    {0x4D, BitPattern("1xxx0000"), kProfileConstrainedBaseline},
-    {0x58, BitPattern("11xx0000"), kProfileConstrainedBaseline},
-    {0x42, BitPattern("x0xx0000"), kProfileBaseline},
-    {0x58, BitPattern("10xx0000"), kProfileBaseline},
-    {0x4D, BitPattern("0x0x0000"), kProfileMain},
-    {0x64, BitPattern("00000000"), kProfileHigh},
-    {0x64, BitPattern("00001100"), kProfileConstrainedHigh}};
-
-// Compare H264 levels and handle the level 1b case.
-bool IsLess(Level a, Level b) {
-  if (a == kLevel1_b)
-    return b != kLevel1 && b != kLevel1_b;
-  if (b == kLevel1_b)
-    return a == kLevel1;
-  return a < b;
-}
-
-Level Min(Level a, Level b) {
-  return IsLess(a, b) ? a : b;
-}
-
-bool IsLevelAsymmetryAllowed(const CodecParameterMap& params) {
-  const auto it = params.find(kLevelAsymmetryAllowed);
-  return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
-}
-
-struct LevelConstraint {
-  const int max_macroblocks_per_second;
-  const int max_macroblock_frame_size;
-  const webrtc::H264::Level level;
-};
-
-// This is from ITU-T H.264 (02/2016) Table A-1 – Level limits.
-static constexpr LevelConstraint kLevelConstraints[] = {
-    {1485, 99, webrtc::H264::kLevel1},
-    {1485, 99, webrtc::H264::kLevel1_b},
-    {3000, 396, webrtc::H264::kLevel1_1},
-    {6000, 396, webrtc::H264::kLevel1_2},
-    {11880, 396, webrtc::H264::kLevel1_3},
-    {11880, 396, webrtc::H264::kLevel2},
-    {19800, 792, webrtc::H264::kLevel2_1},
-    {20250, 1620, webrtc::H264::kLevel2_2},
-    {40500, 1620, webrtc::H264::kLevel3},
-    {108000, 3600, webrtc::H264::kLevel3_1},
-    {216000, 5120, webrtc::H264::kLevel3_2},
-    {245760, 8192, webrtc::H264::kLevel4},
-    {245760, 8192, webrtc::H264::kLevel4_1},
-    {522240, 8704, webrtc::H264::kLevel4_2},
-    {589824, 22080, webrtc::H264::kLevel5},
-    {983040, 36864, webrtc::H264::kLevel5_1},
-    {2073600, 36864, webrtc::H264::kLevel5_2},
-};
-
-}  // anonymous namespace
-
 absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
-  // The string should consist of 3 bytes in hexadecimal format.
-  if (strlen(str) != 6u)
-    return absl::nullopt;
-  const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
-  if (profile_level_id_numeric == 0)
-    return absl::nullopt;
-
-  // Separate into three bytes.
-  const uint8_t level_idc =
-      static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
-  const uint8_t profile_iop =
-      static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
-  const uint8_t profile_idc =
-      static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
-
-  // Parse level based on level_idc and constraint set 3 flag.
-  Level level;
-  switch (level_idc) {
-    case kLevel1_1:
-      level = (profile_iop & kConstraintSet3Flag) != 0 ? kLevel1_b : kLevel1_1;
-      break;
-    case kLevel1:
-    case kLevel1_2:
-    case kLevel1_3:
-    case kLevel2:
-    case kLevel2_1:
-    case kLevel2_2:
-    case kLevel3:
-    case kLevel3_1:
-    case kLevel3_2:
-    case kLevel4:
-    case kLevel4_1:
-    case kLevel4_2:
-    case kLevel5:
-    case kLevel5_1:
-    case kLevel5_2:
-      level = static_cast<Level>(level_idc);
-      break;
-    default:
-      // Unrecognized level_idc.
-      return absl::nullopt;
-  }
-
-  // Parse profile_idc/profile_iop into a Profile enum.
-  for (const ProfilePattern& pattern : kProfilePatterns) {
-    if (profile_idc == pattern.profile_idc &&
-        pattern.profile_iop.IsMatch(profile_iop)) {
-      return ProfileLevelId(pattern.profile, level);
-    }
-  }
-
-  // Unrecognized profile_idc/profile_iop combination.
-  return absl::nullopt;
-}
-
-absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
-  static const int kPixelsPerMacroblock = 16 * 16;
-
-  for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
-    const LevelConstraint& level_constraint = kLevelConstraints[i];
-    if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
-            max_frame_pixel_count &&
-        level_constraint.max_macroblocks_per_second <=
-            max_fps * level_constraint.max_macroblock_frame_size) {
-      return level_constraint.level;
-    }
-  }
-
-  // No level supported.
-  return absl::nullopt;
+  return webrtc::ParseH264ProfileLevelId(str);
 }
 
 absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
-    const CodecParameterMap& params) {
-  // TODO(magjed): The default should really be kProfileBaseline and kLevel1
-  // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
-  // order to not break backwards compatibility with older versions of WebRTC
-  // where external codecs don't have any parameters, use
-  // kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
-  // done in an interim period to allow external clients to update their code.
-  // http://crbug/webrtc/6337.
-  static const ProfileLevelId kDefaultProfileLevelId(
-      kProfileConstrainedBaseline, kLevel3_1);
+    const SdpVideoFormat::Parameters& params) {
+  return webrtc::ParseSdpForH264ProfileLevelId(params);
+}
 
-  const auto profile_level_id_it = params.find(kProfileLevelId);
-  return (profile_level_id_it == params.end())
-             ? kDefaultProfileLevelId
-             : ParseProfileLevelId(profile_level_id_it->second.c_str());
+absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
+  return webrtc::H264SupportedLevel(max_frame_pixel_count, max_fps);
 }
 
 absl::optional<std::string> ProfileLevelIdToString(
     const ProfileLevelId& profile_level_id) {
-  // Handle special case level == 1b.
-  if (profile_level_id.level == kLevel1_b) {
-    switch (profile_level_id.profile) {
-      case kProfileConstrainedBaseline:
-        return {"42f00b"};
-      case kProfileBaseline:
-        return {"42100b"};
-      case kProfileMain:
-        return {"4d100b"};
-      // Level 1b is not allowed for other profiles.
-      default:
-        return absl::nullopt;
-    }
-  }
-
-  const char* profile_idc_iop_string;
-  switch (profile_level_id.profile) {
-    case kProfileConstrainedBaseline:
-      profile_idc_iop_string = "42e0";
-      break;
-    case kProfileBaseline:
-      profile_idc_iop_string = "4200";
-      break;
-    case kProfileMain:
-      profile_idc_iop_string = "4d00";
-      break;
-    case kProfileConstrainedHigh:
-      profile_idc_iop_string = "640c";
-      break;
-    case kProfileHigh:
-      profile_idc_iop_string = "6400";
-      break;
-    // Unrecognized profile.
-    default:
-      return absl::nullopt;
-  }
-
-  char str[7];
-  snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
-  return {str};
+  return webrtc::H264ProfileLevelIdToString(profile_level_id);
 }
 
-// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
-void GenerateProfileLevelIdForAnswer(
-    const CodecParameterMap& local_supported_params,
-    const CodecParameterMap& remote_offered_params,
-    CodecParameterMap* answer_params) {
-  // If both local and remote haven't set profile-level-id, they are both using
-  // the default profile. In this case, don't set profile-level-id in answer
-  // either.
-  if (!local_supported_params.count(kProfileLevelId) &&
-      !remote_offered_params.count(kProfileLevelId)) {
-    return;
-  }
-
-  // Parse profile-level-ids.
-  const absl::optional<ProfileLevelId> local_profile_level_id =
-      ParseSdpProfileLevelId(local_supported_params);
-  const absl::optional<ProfileLevelId> remote_profile_level_id =
-      ParseSdpProfileLevelId(remote_offered_params);
-  // The local and remote codec must have valid and equal H264 Profiles.
-  RTC_DCHECK(local_profile_level_id);
-  RTC_DCHECK(remote_profile_level_id);
-  RTC_DCHECK_EQ(local_profile_level_id->profile,
-                remote_profile_level_id->profile);
-
-  // Parse level information.
-  const bool level_asymmetry_allowed =
-      IsLevelAsymmetryAllowed(local_supported_params) &&
-      IsLevelAsymmetryAllowed(remote_offered_params);
-  const Level local_level = local_profile_level_id->level;
-  const Level remote_level = remote_profile_level_id->level;
-  const Level min_level = Min(local_level, remote_level);
-
-  // Determine answer level. When level asymmetry is not allowed, level upgrade
-  // is not allowed, i.e., the level in the answer must be equal to or lower
-  // than the level in the offer.
-  const Level answer_level = level_asymmetry_allowed ? local_level : min_level;
-
-  // Set the resulting profile-level-id in the answer parameters.
-  (*answer_params)[kProfileLevelId] = *ProfileLevelIdToString(
-      ProfileLevelId(local_profile_level_id->profile, answer_level));
-}
-
-bool IsSameH264Profile(const CodecParameterMap& params1,
-                       const CodecParameterMap& params2) {
-  const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
-      webrtc::H264::ParseSdpProfileLevelId(params1);
-  const absl::optional<webrtc::H264::ProfileLevelId> other_profile_level_id =
-      webrtc::H264::ParseSdpProfileLevelId(params2);
-  // Compare H264 profiles, but not levels.
-  return profile_level_id && other_profile_level_id &&
-         profile_level_id->profile == other_profile_level_id->profile;
+bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
+                       const SdpVideoFormat::Parameters& params2) {
+  return webrtc::H264IsSameProfile(params1, params2);
 }
 
 }  // namespace H264
diff --git a/media/base/h264_profile_level_id.h b/media/base/h264_profile_level_id.h
index f0f7928..c85709f 100644
--- a/media/base/h264_profile_level_id.h
+++ b/media/base/h264_profile_level_id.h
@@ -11,54 +11,45 @@
 #ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
 #define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
 
-#include <map>
 #include <string>
 
-#include "absl/types/optional.h"
-#include "rtc_base/system/rtc_export.h"
+#include "api/video_codecs/h264_profile_level_id.h"
+
+// TODO(crbug.com/1187565): Remove this file once downstream projects stop
+// depend on it.
 
 namespace webrtc {
 namespace H264 {
 
-enum Profile {
-  kProfileConstrainedBaseline,
-  kProfileBaseline,
-  kProfileMain,
-  kProfileConstrainedHigh,
-  kProfileHigh,
-};
+typedef H264Profile Profile;
+typedef H264Level Level;
+typedef H264ProfileLevelId ProfileLevelId;
 
-// Map containting SDP codec parameters.
-typedef std::map<std::string, std::string> CodecParameterMap;
+constexpr H264Profile kProfileConstrainedBaseline =
+    H264Profile::kProfileConstrainedBaseline;
+constexpr H264Profile kProfileBaseline = H264Profile::kProfileBaseline;
+constexpr H264Profile kProfileMain = H264Profile::kProfileMain;
+constexpr H264Profile kProfileConstrainedHigh =
+    H264Profile::kProfileConstrainedHigh;
+constexpr H264Profile kProfileHigh = H264Profile::kProfileHigh;
 
-// All values are equal to ten times the level number, except level 1b which is
-// special.
-enum Level {
-  kLevel1_b = 0,
-  kLevel1 = 10,
-  kLevel1_1 = 11,
-  kLevel1_2 = 12,
-  kLevel1_3 = 13,
-  kLevel2 = 20,
-  kLevel2_1 = 21,
-  kLevel2_2 = 22,
-  kLevel3 = 30,
-  kLevel3_1 = 31,
-  kLevel3_2 = 32,
-  kLevel4 = 40,
-  kLevel4_1 = 41,
-  kLevel4_2 = 42,
-  kLevel5 = 50,
-  kLevel5_1 = 51,
-  kLevel5_2 = 52
-};
-
-struct ProfileLevelId {
-  constexpr ProfileLevelId(Profile profile, Level level)
-      : profile(profile), level(level) {}
-  Profile profile;
-  Level level;
-};
+constexpr H264Level kLevel1_b = H264Level::kLevel1_b;
+constexpr H264Level kLevel1 = H264Level::kLevel1;
+constexpr H264Level kLevel1_1 = H264Level::kLevel1_1;
+constexpr H264Level kLevel1_2 = H264Level::kLevel1_2;
+constexpr H264Level kLevel1_3 = H264Level::kLevel1_3;
+constexpr H264Level kLevel2 = H264Level::kLevel2;
+constexpr H264Level kLevel2_1 = H264Level::kLevel2_1;
+constexpr H264Level kLevel2_2 = H264Level::kLevel2_2;
+constexpr H264Level kLevel3 = H264Level::kLevel3;
+constexpr H264Level kLevel3_1 = H264Level::kLevel3_1;
+constexpr H264Level kLevel3_2 = H264Level::kLevel3_2;
+constexpr H264Level kLevel4 = H264Level::kLevel4;
+constexpr H264Level kLevel4_1 = H264Level::kLevel4_1;
+constexpr H264Level kLevel4_2 = H264Level::kLevel4_2;
+constexpr H264Level kLevel5 = H264Level::kLevel5;
+constexpr H264Level kLevel5_1 = H264Level::kLevel5_1;
+constexpr H264Level kLevel5_2 = H264Level::kLevel5_2;
 
 // Parse profile level id that is represented as a string of 3 hex bytes.
 // Nothing will be returned if the string is not a recognized H264
@@ -70,7 +61,7 @@
 // returned if the profile-level-id key is missing. Nothing will be returned if
 // the key is present but the string is invalid.
 RTC_EXPORT absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
-    const CodecParameterMap& params);
+    const SdpVideoFormat::Parameters& params);
 
 // Given that a decoder supports up to a given frame size (in pixels) at up to a
 // given number of frames per second, return the highest H.264 level where it
@@ -84,33 +75,11 @@
 RTC_EXPORT absl::optional<std::string> ProfileLevelIdToString(
     const ProfileLevelId& profile_level_id);
 
-// Generate codec parameters that will be used as answer in an SDP negotiation
-// based on local supported parameters and remote offered parameters. Both
-// |local_supported_params|, |remote_offered_params|, and |answer_params|
-// represent sendrecv media descriptions, i.e they are a mix of both encode and
-// decode capabilities. In theory, when the profile in |local_supported_params|
-// represent a strict superset of the profile in |remote_offered_params|, we
-// could limit the profile in |answer_params| to the profile in
-// |remote_offered_params|. However, to simplify the code, each supported H264
-// profile should be listed explicitly in the list of local supported codecs,
-// even if they are redundant. Then each local codec in the list should be
-// tested one at a time against the remote codec, and only when the profiles are
-// equal should this function be called. Therefore, this function does not need
-// to handle profile intersection, and the profile of |local_supported_params|
-// and |remote_offered_params| must be equal before calling this function. The
-// parameters that are used when negotiating are the level part of
-// profile-level-id and level-asymmetry-allowed.
-void GenerateProfileLevelIdForAnswer(
-    const CodecParameterMap& local_supported_params,
-    const CodecParameterMap& remote_offered_params,
-    CodecParameterMap* answer_params);
-
 // Returns true if the parameters have the same H264 profile, i.e. the same
 // H264::Profile (Baseline, High, etc).
-bool IsSameH264Profile(const CodecParameterMap& params1,
-                       const CodecParameterMap& params2);
+RTC_EXPORT bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
+                                  const SdpVideoFormat::Parameters& params2);
 
 }  // namespace H264
 }  // namespace webrtc
-
 #endif  // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
diff --git a/media/base/sdp_fmtp_utils.cc b/media/base/sdp_fmtp_utils.cc
deleted file mode 100644
index 4ffc3b9..0000000
--- a/media/base/sdp_fmtp_utils.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *  Copyright (c) 2019 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/base/sdp_fmtp_utils.h"
-
-#include <map>
-#include <utility>
-
-#include "rtc_base/string_to_number.h"
-
-namespace webrtc {
-namespace {
-// Max frame rate for VP8 and VP9 video.
-const char kVPxFmtpMaxFrameRate[] = "max-fr";
-// Max frame size for VP8 and VP9 video.
-const char kVPxFmtpMaxFrameSize[] = "max-fs";
-const int kVPxFmtpFrameSizeSubBlockPixels = 256;
-
-absl::optional<int> ParsePositiveNumberFromParams(
-    const SdpVideoFormat::Parameters& params,
-    const char* parameter_name) {
-  const auto max_frame_rate_it = params.find(parameter_name);
-  if (max_frame_rate_it == params.end())
-    return absl::nullopt;
-
-  const absl::optional<int> i =
-      rtc::StringToNumber<int>(max_frame_rate_it->second);
-  if (!i.has_value() || i.value() <= 0)
-    return absl::nullopt;
-  return i;
-}
-
-}  // namespace
-
-absl::optional<int> ParseSdpForVPxMaxFrameRate(
-    const SdpVideoFormat::Parameters& params) {
-  return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate);
-}
-
-absl::optional<int> ParseSdpForVPxMaxFrameSize(
-    const SdpVideoFormat::Parameters& params) {
-  const absl::optional<int> i =
-      ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize);
-  return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels)
-           : absl::nullopt;
-}
-
-}  // namespace webrtc
diff --git a/media/base/sdp_fmtp_utils.h b/media/base/sdp_fmtp_utils.h
deleted file mode 100644
index 04e9183..0000000
--- a/media/base/sdp_fmtp_utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  Copyright (c) 2019 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.
- */
-
-#ifndef MEDIA_BASE_SDP_FMTP_UTILS_H_
-#define MEDIA_BASE_SDP_FMTP_UTILS_H_
-
-#include "absl/types/optional.h"
-#include "api/video_codecs/sdp_video_format.h"
-
-namespace webrtc {
-
-// Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the
-// field is missing or not a number.
-absl::optional<int> ParseSdpForVPxMaxFrameRate(
-    const SdpVideoFormat::Parameters& params);
-
-// Parse max frame size from SDP FMTP line. absl::nullopt is returned if the
-// field is missing or not a number. Please note that the value is stored in sub
-// blocks but the returned value is in total number of pixels.
-absl::optional<int> ParseSdpForVPxMaxFrameSize(
-    const SdpVideoFormat::Parameters& params);
-
-}  // namespace webrtc
-
-#endif  // MEDIA_BASE_SDP_FMTP_UTILS_H__
diff --git a/media/base/sdp_fmtp_utils_unittest.cc b/media/base/sdp_fmtp_utils_unittest.cc
deleted file mode 100644
index 0ff12ff..0000000
--- a/media/base/sdp_fmtp_utils_unittest.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *  Copyright (c) 2019 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/base/sdp_fmtp_utils.h"
-
-#include <string.h>
-#include <map>
-#include <utility>
-
-#include "rtc_base/string_to_number.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace {
-// Max frame rate for VP8 and VP9 video.
-const char kVPxFmtpMaxFrameRate[] = "max-fr";
-// Max frame size for VP8 and VP9 video.
-const char kVPxFmtpMaxFrameSize[] = "max-fs";
-}  // namespace
-
-TEST(SdpFmtpUtilsTest, MaxFrameRateIsMissingOrInvalid) {
-  SdpVideoFormat::Parameters params;
-  absl::optional<int> empty = ParseSdpForVPxMaxFrameRate(params);
-  EXPECT_FALSE(empty);
-  params[kVPxFmtpMaxFrameRate] = "-1";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
-  params[kVPxFmtpMaxFrameRate] = "0";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
-  params[kVPxFmtpMaxFrameRate] = "abcde";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
-}
-
-TEST(SdpFmtpUtilsTest, MaxFrameRateIsSpecified) {
-  SdpVideoFormat::Parameters params;
-  params[kVPxFmtpMaxFrameRate] = "30";
-  EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30);
-  params[kVPxFmtpMaxFrameRate] = "60";
-  EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 60);
-}
-
-TEST(SdpFmtpUtilsTest, MaxFrameSizeIsMissingOrInvalid) {
-  SdpVideoFormat::Parameters params;
-  absl::optional<int> empty = ParseSdpForVPxMaxFrameSize(params);
-  EXPECT_FALSE(empty);
-  params[kVPxFmtpMaxFrameSize] = "-1";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
-  params[kVPxFmtpMaxFrameSize] = "0";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
-  params[kVPxFmtpMaxFrameSize] = "abcde";
-  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
-}
-
-TEST(SdpFmtpUtilsTest, MaxFrameSizeIsSpecified) {
-  SdpVideoFormat::Parameters params;
-  params[kVPxFmtpMaxFrameSize] = "8100";  // 1920 x 1080 / (16^2)
-  EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080);
-  params[kVPxFmtpMaxFrameSize] = "32400";  // 3840 x 2160 / (16^2)
-  EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 3840 * 2160);
-}
-
-}  // namespace webrtc
diff --git a/media/base/sdp_video_format_utils.cc b/media/base/sdp_video_format_utils.cc
new file mode 100644
index 0000000..a156afd
--- /dev/null
+++ b/media/base/sdp_video_format_utils.cc
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (c) 2019 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/base/sdp_video_format_utils.h"
+
+#include <cstring>
+#include <map>
+#include <utility>
+
+#include "api/video_codecs/h264_profile_level_id.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/string_to_number.h"
+
+namespace webrtc {
+namespace {
+const char kProfileLevelId[] = "profile-level-id";
+const char kH264LevelAsymmetryAllowed[] = "level-asymmetry-allowed";
+// Max frame rate for VP8 and VP9 video.
+const char kVPxFmtpMaxFrameRate[] = "max-fr";
+// Max frame size for VP8 and VP9 video.
+const char kVPxFmtpMaxFrameSize[] = "max-fs";
+const int kVPxFmtpFrameSizeSubBlockPixels = 256;
+
+bool IsH264LevelAsymmetryAllowed(const SdpVideoFormat::Parameters& params) {
+  const auto it = params.find(kH264LevelAsymmetryAllowed);
+  return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
+}
+
+// Compare H264 levels and handle the level 1b case.
+bool H264LevelIsLess(H264Level a, H264Level b) {
+  if (a == H264Level::kLevel1_b)
+    return b != H264Level::kLevel1 && b != H264Level::kLevel1_b;
+  if (b == H264Level::kLevel1_b)
+    return a == H264Level::kLevel1;
+  return a < b;
+}
+
+H264Level H264LevelMin(H264Level a, H264Level b) {
+  return H264LevelIsLess(a, b) ? a : b;
+}
+
+absl::optional<int> ParsePositiveNumberFromParams(
+    const SdpVideoFormat::Parameters& params,
+    const char* parameter_name) {
+  const auto max_frame_rate_it = params.find(parameter_name);
+  if (max_frame_rate_it == params.end())
+    return absl::nullopt;
+
+  const absl::optional<int> i =
+      rtc::StringToNumber<int>(max_frame_rate_it->second);
+  if (!i.has_value() || i.value() <= 0)
+    return absl::nullopt;
+  return i;
+}
+
+}  // namespace
+
+// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
+void H264GenerateProfileLevelIdForAnswer(
+    const SdpVideoFormat::Parameters& local_supported_params,
+    const SdpVideoFormat::Parameters& remote_offered_params,
+    SdpVideoFormat::Parameters* answer_params) {
+  // If both local and remote haven't set profile-level-id, they are both using
+  // the default profile. In this case, don't set profile-level-id in answer
+  // either.
+  if (!local_supported_params.count(kProfileLevelId) &&
+      !remote_offered_params.count(kProfileLevelId)) {
+    return;
+  }
+
+  // Parse profile-level-ids.
+  const absl::optional<H264ProfileLevelId> local_profile_level_id =
+      ParseSdpForH264ProfileLevelId(local_supported_params);
+  const absl::optional<H264ProfileLevelId> remote_profile_level_id =
+      ParseSdpForH264ProfileLevelId(remote_offered_params);
+  // The local and remote codec must have valid and equal H264 Profiles.
+  RTC_DCHECK(local_profile_level_id);
+  RTC_DCHECK(remote_profile_level_id);
+  RTC_DCHECK_EQ(local_profile_level_id->profile,
+                remote_profile_level_id->profile);
+
+  // Parse level information.
+  const bool level_asymmetry_allowed =
+      IsH264LevelAsymmetryAllowed(local_supported_params) &&
+      IsH264LevelAsymmetryAllowed(remote_offered_params);
+  const H264Level local_level = local_profile_level_id->level;
+  const H264Level remote_level = remote_profile_level_id->level;
+  const H264Level min_level = H264LevelMin(local_level, remote_level);
+
+  // Determine answer level. When level asymmetry is not allowed, level upgrade
+  // is not allowed, i.e., the level in the answer must be equal to or lower
+  // than the level in the offer.
+  const H264Level answer_level =
+      level_asymmetry_allowed ? local_level : min_level;
+
+  // Set the resulting profile-level-id in the answer parameters.
+  (*answer_params)[kProfileLevelId] = *H264ProfileLevelIdToString(
+      H264ProfileLevelId(local_profile_level_id->profile, answer_level));
+}
+
+absl::optional<int> ParseSdpForVPxMaxFrameRate(
+    const SdpVideoFormat::Parameters& params) {
+  return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate);
+}
+
+absl::optional<int> ParseSdpForVPxMaxFrameSize(
+    const SdpVideoFormat::Parameters& params) {
+  const absl::optional<int> i =
+      ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize);
+  return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels)
+           : absl::nullopt;
+}
+
+}  // namespace webrtc
diff --git a/media/base/sdp_video_format_utils.h b/media/base/sdp_video_format_utils.h
new file mode 100644
index 0000000..6671c18
--- /dev/null
+++ b/media/base/sdp_video_format_utils.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2019 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.
+ */
+
+#ifndef MEDIA_BASE_SDP_VIDEO_FORMAT_UTILS_H_
+#define MEDIA_BASE_SDP_VIDEO_FORMAT_UTILS_H_
+
+#include "absl/types/optional.h"
+#include "api/video_codecs/sdp_video_format.h"
+
+namespace webrtc {
+// Generate codec parameters that will be used as answer in an SDP negotiation
+// based on local supported parameters and remote offered parameters. Both
+// |local_supported_params|, |remote_offered_params|, and |answer_params|
+// represent sendrecv media descriptions, i.e they are a mix of both encode and
+// decode capabilities. In theory, when the profile in |local_supported_params|
+// represent a strict superset of the profile in |remote_offered_params|, we
+// could limit the profile in |answer_params| to the profile in
+// |remote_offered_params|. However, to simplify the code, each supported H264
+// profile should be listed explicitly in the list of local supported codecs,
+// even if they are redundant. Then each local codec in the list should be
+// tested one at a time against the remote codec, and only when the profiles are
+// equal should this function be called. Therefore, this function does not need
+// to handle profile intersection, and the profile of |local_supported_params|
+// and |remote_offered_params| must be equal before calling this function. The
+// parameters that are used when negotiating are the level part of
+// profile-level-id and level-asymmetry-allowed.
+void H264GenerateProfileLevelIdForAnswer(
+    const SdpVideoFormat::Parameters& local_supported_params,
+    const SdpVideoFormat::Parameters& remote_offered_params,
+    SdpVideoFormat::Parameters* answer_params);
+
+// Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the
+// field is missing or not a number.
+absl::optional<int> ParseSdpForVPxMaxFrameRate(
+    const SdpVideoFormat::Parameters& params);
+
+// Parse max frame size from SDP FMTP line. absl::nullopt is returned if the
+// field is missing or not a number. Please note that the value is stored in sub
+// blocks but the returned value is in total number of pixels.
+absl::optional<int> ParseSdpForVPxMaxFrameSize(
+    const SdpVideoFormat::Parameters& params);
+
+}  // namespace webrtc
+
+#endif  // MEDIA_BASE_SDP_VIDEO_FORMAT_UTILS_H_
diff --git a/media/base/sdp_video_format_utils_unittest.cc b/media/base/sdp_video_format_utils_unittest.cc
new file mode 100644
index 0000000..d8ef9ab
--- /dev/null
+++ b/media/base/sdp_video_format_utils_unittest.cc
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (c) 2019 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/base/sdp_video_format_utils.h"
+
+#include <string.h>
+
+#include <map>
+#include <utility>
+
+#include "rtc_base/string_to_number.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+// Max frame rate for VP8 and VP9 video.
+const char kVPxFmtpMaxFrameRate[] = "max-fr";
+// Max frame size for VP8 and VP9 video.
+const char kVPxFmtpMaxFrameSize[] = "max-fs";
+}  // namespace
+
+TEST(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerEmpty) {
+  SdpVideoFormat::Parameters answer_params;
+  H264GenerateProfileLevelIdForAnswer(SdpVideoFormat::Parameters(),
+                                      SdpVideoFormat::Parameters(),
+                                      &answer_params);
+  EXPECT_TRUE(answer_params.empty());
+}
+
+TEST(SdpVideoFormatUtilsTest,
+     TestH264GenerateProfileLevelIdForAnswerLevelSymmetryCapped) {
+  SdpVideoFormat::Parameters low_level;
+  low_level["profile-level-id"] = "42e015";
+  SdpVideoFormat::Parameters high_level;
+  high_level["profile-level-id"] = "42e01f";
+
+  // Level asymmetry is not allowed; test that answer level is the lower of the
+  // local and remote levels.
+  SdpVideoFormat::Parameters answer_params;
+  H264GenerateProfileLevelIdForAnswer(low_level /* local_supported */,
+                                      high_level /* remote_offered */,
+                                      &answer_params);
+  EXPECT_EQ("42e015", answer_params["profile-level-id"]);
+
+  SdpVideoFormat::Parameters answer_params2;
+  H264GenerateProfileLevelIdForAnswer(high_level /* local_supported */,
+                                      low_level /* remote_offered */,
+                                      &answer_params2);
+  EXPECT_EQ("42e015", answer_params2["profile-level-id"]);
+}
+
+TEST(SdpVideoFormatUtilsTest,
+     TestH264GenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) {
+  SdpVideoFormat::Parameters local_params;
+  local_params["profile-level-id"] = "42e01f";
+  local_params["level-asymmetry-allowed"] = "1";
+  SdpVideoFormat::Parameters remote_params;
+  remote_params["profile-level-id"] = "42e015";
+  remote_params["level-asymmetry-allowed"] = "1";
+  SdpVideoFormat::Parameters answer_params;
+  H264GenerateProfileLevelIdForAnswer(local_params, remote_params,
+                                      &answer_params);
+  // When level asymmetry is allowed, we can answer a higher level than what was
+  // offered.
+  EXPECT_EQ("42e01f", answer_params["profile-level-id"]);
+}
+
+TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) {
+  SdpVideoFormat::Parameters params;
+  absl::optional<int> empty = ParseSdpForVPxMaxFrameRate(params);
+  EXPECT_FALSE(empty);
+  params[kVPxFmtpMaxFrameRate] = "-1";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
+  params[kVPxFmtpMaxFrameRate] = "0";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
+  params[kVPxFmtpMaxFrameRate] = "abcde";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params));
+}
+
+TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) {
+  SdpVideoFormat::Parameters params;
+  params[kVPxFmtpMaxFrameRate] = "30";
+  EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30);
+  params[kVPxFmtpMaxFrameRate] = "60";
+  EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 60);
+}
+
+TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) {
+  SdpVideoFormat::Parameters params;
+  absl::optional<int> empty = ParseSdpForVPxMaxFrameSize(params);
+  EXPECT_FALSE(empty);
+  params[kVPxFmtpMaxFrameSize] = "-1";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
+  params[kVPxFmtpMaxFrameSize] = "0";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
+  params[kVPxFmtpMaxFrameSize] = "abcde";
+  EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params));
+}
+
+TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsSpecified) {
+  SdpVideoFormat::Parameters params;
+  params[kVPxFmtpMaxFrameSize] = "8100";  // 1920 x 1080 / (16^2)
+  EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080);
+  params[kVPxFmtpMaxFrameSize] = "32400";  // 3840 x 2160 / (16^2)
+  EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 3840 * 2160);
+}
+
+}  // namespace webrtc
diff --git a/media/base/vp9_profile.h b/media/base/vp9_profile.h
index e47204f..d44a799 100644
--- a/media/base/vp9_profile.h
+++ b/media/base/vp9_profile.h
@@ -11,43 +11,9 @@
 #ifndef MEDIA_BASE_VP9_PROFILE_H_
 #define MEDIA_BASE_VP9_PROFILE_H_
 
-#include <string>
+#include "api/video_codecs/vp9_profile.h"
 
-#include "absl/types/optional.h"
-#include "api/video_codecs/sdp_video_format.h"
-#include "rtc_base/system/rtc_export.h"
-
-namespace webrtc {
-
-// Profile information for VP9 video.
-extern RTC_EXPORT const char kVP9FmtpProfileId[];
-
-enum class VP9Profile {
-  kProfile0,
-  kProfile1,
-  kProfile2,
-};
-
-// Helper functions to convert VP9Profile to std::string. Returns "0" by
-// default.
-RTC_EXPORT std::string VP9ProfileToString(VP9Profile profile);
-
-// Helper functions to convert std::string to VP9Profile. Returns null if given
-// an invalid profile string.
-absl::optional<VP9Profile> StringToVP9Profile(const std::string& str);
-
-// Parse profile that is represented as a string of single digit contained in an
-// SDP key-value map. A default profile(kProfile0) will be returned if the
-// profile key is missing. Nothing will be returned if the key is present but
-// the string is invalid.
-RTC_EXPORT absl::optional<VP9Profile> ParseSdpForVP9Profile(
-    const SdpVideoFormat::Parameters& params);
-
-// Returns true if the parameters have the same VP9 profile, or neither contains
-// VP9 profile.
-bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
-                      const SdpVideoFormat::Parameters& params2);
-
-}  // namespace webrtc
+// TODO(crbug.com/1187565): Remove this file once downstream projects stop
+// depend on it.
 
 #endif  // MEDIA_BASE_VP9_PROFILE_H_
diff --git a/media/engine/internal_decoder_factory_unittest.cc b/media/engine/internal_decoder_factory_unittest.cc
index 61be5e7..a2a6921 100644
--- a/media/engine/internal_decoder_factory_unittest.cc
+++ b/media/engine/internal_decoder_factory_unittest.cc
@@ -12,8 +12,8 @@
 
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_decoder.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "media/base/media_constants.h"
-#include "media/base/vp9_profile.h"
 #include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index 2fcebe4..4270e27 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -35,12 +35,12 @@
 #include "api/video/video_bitrate_allocation.h"
 #include "api/video_codecs/builtin_video_decoder_factory.h"
 #include "api/video_codecs/builtin_video_encoder_factory.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_decoder_factory.h"
 #include "api/video_codecs/video_encoder.h"
 #include "api/video_codecs/video_encoder_factory.h"
 #include "call/flexfec_receive_stream.h"
-#include "common_video/h264/profile_level_id.h"
 #include "media/base/fake_frame_source.h"
 #include "media/base/fake_network_interface.h"
 #include "media/base/fake_video_renderer.h"
@@ -581,20 +581,21 @@
 // TODO(deadbeef): This test should be updated if/when we start
 // adding RTX codecs for unrecognized codec names.
 TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) {
-  using webrtc::H264::kLevel1;
-  using webrtc::H264::ProfileLevelId;
-  using webrtc::H264::ProfileLevelIdToString;
+  using webrtc::H264Level;
+  using webrtc::H264Profile;
+  using webrtc::H264ProfileLevelId;
+  using webrtc::H264ProfileLevelIdToString;
   webrtc::SdpVideoFormat h264_constrained_baseline("H264");
   h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] =
-      *ProfileLevelIdToString(
-          ProfileLevelId(webrtc::H264::kProfileConstrainedBaseline, kLevel1));
+      *H264ProfileLevelIdToString(H264ProfileLevelId(
+          H264Profile::kProfileConstrainedBaseline, H264Level::kLevel1));
   webrtc::SdpVideoFormat h264_constrained_high("H264");
   h264_constrained_high.parameters[kH264FmtpProfileLevelId] =
-      *ProfileLevelIdToString(
-          ProfileLevelId(webrtc::H264::kProfileConstrainedHigh, kLevel1));
+      *H264ProfileLevelIdToString(H264ProfileLevelId(
+          H264Profile::kProfileConstrainedHigh, H264Level::kLevel1));
   webrtc::SdpVideoFormat h264_high("H264");
-  h264_high.parameters[kH264FmtpProfileLevelId] = *ProfileLevelIdToString(
-      ProfileLevelId(webrtc::H264::kProfileHigh, kLevel1));
+  h264_high.parameters[kH264FmtpProfileLevelId] = *H264ProfileLevelIdToString(
+      H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1));
 
   encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline);
   encoder_factory_->AddSupportedVideoCodec(h264_constrained_high);
@@ -721,10 +722,10 @@
     // The tests only use H264 Constrained Baseline. Make sure we don't return
     // an internal H264 codec from the engine with a different H264 profile.
     if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) {
-      const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
-          webrtc::H264::ParseSdpProfileLevelId(engine_codec.params);
+      const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
+          webrtc::ParseSdpForH264ProfileLevelId(engine_codec.params);
       if (profile_level_id->profile !=
-          webrtc::H264::kProfileConstrainedBaseline) {
+          webrtc::H264Profile::kProfileConstrainedBaseline) {
         continue;
       }
     }
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index fd03ffe..153a4b5 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -592,7 +592,6 @@
     "../../api/video_codecs:video_codecs_api",
     "../../common_video",
     "../../media:rtc_media_base",
-    "../../media:rtc_vp9_profile",
     "../../rtc_base",
     "../../rtc_base:checks",
     "../../rtc_base/experiments:encoder_info_settings",
@@ -814,7 +813,6 @@
       "../../call:video_stream_api",
       "../../common_video",
       "../../media:rtc_audio_video",
-      "../../media:rtc_h264_profile_id",
       "../../media:rtc_internal_video_codecs",
       "../../media:rtc_media_base",
       "../../rtc_base:checks",
@@ -904,11 +902,9 @@
       "../../api/video_codecs:video_codecs_api",
       "../../common_video",
       "../../common_video/test:utilities",
-      "../../media:rtc_h264_profile_id",
       "../../media:rtc_internal_video_codecs",
       "../../media:rtc_media_base",
       "../../media:rtc_simulcast_encoder_adapter",
-      "../../media:rtc_vp9_profile",
       "../../rtc_base",
       "../../test:explicit_key_value_config",
       "../../test:field_trial",
diff --git a/modules/video_coding/codecs/h264/h264.cc b/modules/video_coding/codecs/h264/h264.cc
index be5b031..016d0aa 100644
--- a/modules/video_coding/codecs/h264/h264.cc
+++ b/modules/video_coding/codecs/h264/h264.cc
@@ -45,11 +45,11 @@
 
 }  // namespace
 
-SdpVideoFormat CreateH264Format(H264::Profile profile,
-                                H264::Level level,
+SdpVideoFormat CreateH264Format(H264Profile profile,
+                                H264Level level,
                                 const std::string& packetization_mode) {
   const absl::optional<std::string> profile_string =
-      H264::ProfileLevelIdToString(H264::ProfileLevelId(profile, level));
+      H264ProfileLevelIdToString(H264ProfileLevelId(profile, level));
   RTC_CHECK(profile_string);
   return SdpVideoFormat(
       cricket::kH264CodecName,
@@ -76,12 +76,14 @@
   //
   // We support both packetization modes 0 (mandatory) and 1 (optional,
   // preferred).
-  return {
-      CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "1"),
-      CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "0"),
-      CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1, "1"),
-      CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1,
-                       "0")};
+  return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
+                           "1"),
+          CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
+                           "0"),
+          CreateH264Format(H264Profile::kProfileConstrainedBaseline,
+                           H264Level::kLevel3_1, "1"),
+          CreateH264Format(H264Profile::kProfileConstrainedBaseline,
+                           H264Level::kLevel3_1, "0")};
 }
 
 std::unique_ptr<H264Encoder> H264Encoder::Create(
diff --git a/modules/video_coding/codecs/h264/include/h264.h b/modules/video_coding/codecs/h264/include/h264.h
index 70ca817..1f8f796 100644
--- a/modules/video_coding/codecs/h264/include/h264.h
+++ b/modules/video_coding/codecs/h264/include/h264.h
@@ -27,8 +27,8 @@
 
 // Creates an H264 SdpVideoFormat entry with specified paramters.
 RTC_EXPORT SdpVideoFormat
-CreateH264Format(H264::Profile profile,
-                 H264::Level level,
+CreateH264Format(H264Profile profile,
+                 H264Level level,
                  const std::string& packetization_mode);
 
 // Set to disable the H.264 encoder/decoder implementations that are provided if
diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
index 1031530..4c11f6a 100644
--- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
@@ -25,12 +25,12 @@
 #include "api/array_view.h"
 #include "api/transport/field_trial_based_config.h"
 #include "api/video/video_bitrate_allocation.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_decoder.h"
 #include "api/video_codecs/video_encoder_config.h"
 #include "common_video/h264/h264_common.h"
-#include "media/base/h264_profile_level_id.h"
 #include "media/base/media_constants.h"
 #include "media/engine/internal_decoder_factory.h"
 #include "media/engine/internal_encoder_factory.h"
@@ -302,11 +302,11 @@
     name = CodecTypeToPayloadString(codec_settings.codecType);
   }
   if (codec_settings.codecType == kVideoCodecH264) {
-    if (h264_codec_settings.profile == H264::kProfileConstrainedHigh) {
+    if (h264_codec_settings.profile == H264Profile::kProfileConstrainedHigh) {
       return name + "-CHP";
     } else {
       RTC_DCHECK_EQ(h264_codec_settings.profile,
-                    H264::kProfileConstrainedBaseline);
+                    H264Profile::kProfileConstrainedBaseline);
       return name + "-CBP";
     }
   }
@@ -613,8 +613,8 @@
             ? "1"
             : "0";
     params = {{cricket::kH264FmtpProfileLevelId,
-               *H264::ProfileLevelIdToString(H264::ProfileLevelId(
-                   config_.h264_codec_settings.profile, H264::kLevel3_1))},
+               *H264ProfileLevelIdToString(H264ProfileLevelId(
+                   config_.h264_codec_settings.profile, H264Level::kLevel3_1))},
               {cricket::kH264FmtpPacketizationMode, packetization_mode}};
   } else {
     params = {};
diff --git a/modules/video_coding/codecs/test/videocodec_test_mediacodec.cc b/modules/video_coding/codecs/test/videocodec_test_mediacodec.cc
index 9f88716..978fd88 100644
--- a/modules/video_coding/codecs/test/videocodec_test_mediacodec.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_mediacodec.cc
@@ -95,7 +95,7 @@
   const auto frame_checker =
       std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
 
-  config.h264_codec_settings.profile = H264::kProfileConstrainedHigh;
+  config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
   config.encoded_frame_checker = frame_checker.get();
   config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
                           352, 288);
diff --git a/modules/video_coding/codecs/test/videocodec_test_videotoolbox.cc b/modules/video_coding/codecs/test/videocodec_test_videotoolbox.cc
index 0f02080..6df9743 100644
--- a/modules/video_coding/codecs/test/videocodec_test_videotoolbox.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_videotoolbox.cc
@@ -71,7 +71,7 @@
   const auto frame_checker =
       std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
   auto config = CreateConfig();
-  config.h264_codec_settings.profile = H264::kProfileConstrainedHigh;
+  config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
   config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
                           352, 288);
   config.encoded_frame_checker = frame_checker.get();
diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h
index cf328b2..954c044 100644
--- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h
+++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h
@@ -21,8 +21,8 @@
 #include "api/fec_controller_override.h"
 #include "api/transport/webrtc_key_value_config.h"
 #include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "common_video/include/video_frame_buffer_pool.h"
-#include "media/base/vp9_profile.h"
 #include "modules/video_coding/codecs/interface/libvpx_interface.h"
 #include "modules/video_coding/codecs/vp9/include/vp9.h"
 #include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h"
diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
index 853d2df..e965384 100644
--- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
@@ -15,8 +15,8 @@
 #include "api/video/color_space.h"
 #include "api/video/i420_buffer.h"
 #include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
-#include "media/base/vp9_profile.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/video_coding/codecs/interface/libvpx_interface.h"
 #include "modules/video_coding/codecs/interface/mock_libvpx_interface.h"
diff --git a/modules/video_coding/codecs/vp9/vp9.cc b/modules/video_coding/codecs/vp9/vp9.cc
index 1efb1b4..d9caf0f 100644
--- a/modules/video_coding/codecs/vp9/vp9.cc
+++ b/modules/video_coding/codecs/vp9/vp9.cc
@@ -14,7 +14,7 @@
 
 #include "api/transport/field_trial_based_config.h"
 #include "api/video_codecs/sdp_video_format.h"
-#include "media/base/vp9_profile.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h"
 #include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
 #include "rtc_base/checks.h"
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 18a81b9..2a18414 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -102,6 +102,7 @@
     "../api/video:video_bitrate_allocator_factory",
     "../api/video:video_frame",
     "../api/video:video_rtp_headers",
+    "../api/video_codecs:video_codecs_api",
     "../call:call_interfaces",
     "../call:rtp_interfaces",
     "../call:rtp_receiver",
@@ -109,9 +110,9 @@
     "../common_video:common_video",
     "../logging:ice_log",
     "../media:rtc_data_sctp_transport_internal",
-    "../media:rtc_h264_profile_id",
     "../media:rtc_media_base",
     "../media:rtc_media_config",
+    "../media:rtc_sdp_video_format_utils",
     "../modules/rtp_rtcp:rtp_rtcp",
     "../modules/rtp_rtcp:rtp_rtcp_format",
     "../p2p:rtc_p2p",
diff --git a/pc/media_session.cc b/pc/media_session.cc
index f67d8ea..2e779bd 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -24,9 +24,10 @@
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 #include "api/crypto_params.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "media/base/codec.h"
-#include "media/base/h264_profile_level_id.h"
 #include "media/base/media_constants.h"
+#include "media/base/sdp_video_format_utils.h"
 #include "media/sctp/sctp_transport_internal.h"
 #include "p2p/base/p2p_constants.h"
 #include "pc/channel_manager.h"
@@ -801,8 +802,8 @@
         }
       }
       if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
-        webrtc::H264::GenerateProfileLevelIdForAnswer(
-            ours.params, theirs.params, &negotiated.params);
+        webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs.params,
+                                                    &negotiated.params);
       }
       negotiated.id = theirs.id;
       negotiated.name = theirs.name;
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 942202e..e01ab97 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -1655,6 +1655,7 @@
         ":video_toolbox_cc",
         ":videocodec_objc",
         ":videoframebuffer_objc",
+        "../api/video_codecs:video_codecs_api",
         "../common_video",
         "../modules/video_coding:video_codec_interface",
         "../rtc_base:checks",
diff --git a/sdk/android/src/jni/h264_utils.cc b/sdk/android/src/jni/h264_utils.cc
index 02e3ae1..882df95 100644
--- a/sdk/android/src/jni/h264_utils.cc
+++ b/sdk/android/src/jni/h264_utils.cc
@@ -8,10 +8,9 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "sdk/android/src/jni/video_codec_info.h"
-
-#include "common_video/h264/profile_level_id.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "sdk/android/generated_video_jni/H264Utils_jni.h"
+#include "sdk/android/src/jni/video_codec_info.h"
 
 namespace webrtc {
 namespace jni {
@@ -20,8 +19,8 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& params1,
     const JavaParamRef<jobject>& params2) {
-  return H264::IsSameH264Profile(JavaToNativeStringMap(env, params1),
-                                 JavaToNativeStringMap(env, params2));
+  return H264IsSameProfile(JavaToNativeStringMap(env, params1),
+                           JavaToNativeStringMap(env, params2));
 }
 
 }  // namespace jni
diff --git a/sdk/objc/components/video_codec/RTCH264ProfileLevelId.mm b/sdk/objc/components/video_codec/RTCH264ProfileLevelId.mm
index b985d9d..f0ef3ec 100644
--- a/sdk/objc/components/video_codec/RTCH264ProfileLevelId.mm
+++ b/sdk/objc/components/video_codec/RTCH264ProfileLevelId.mm
@@ -16,7 +16,7 @@
 #import "UIDevice+H264Profile.h"
 #endif
 
-#include "media/base/h264_profile_level_id.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "media/base/media_constants.h"
 
 namespace {
@@ -38,13 +38,12 @@
 
 #if defined(WEBRTC_IOS)
 
-using namespace webrtc::H264;
-
-NSString *MaxSupportedLevelForProfile(Profile profile) {
-  const absl::optional<ProfileLevelId> profileLevelId = [UIDevice maxSupportedH264Profile];
+NSString *MaxSupportedLevelForProfile(webrtc::H264Profile profile) {
+  const absl::optional<webrtc::H264ProfileLevelId> profileLevelId =
+      [UIDevice maxSupportedH264Profile];
   if (profileLevelId && profileLevelId->profile >= profile) {
     const absl::optional<std::string> profileString =
-        ProfileLevelIdToString(ProfileLevelId(profile, profileLevelId->level));
+        H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(profile, profileLevelId->level));
     if (profileString) {
       return [NSString stringForStdString:*profileString];
     }
@@ -55,7 +54,7 @@
 
 NSString *MaxSupportedProfileLevelConstrainedBaseline() {
 #if defined(WEBRTC_IOS)
-  NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedBaseline);
+  NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedBaseline);
   if (profile != nil) {
     return profile;
   }
@@ -65,7 +64,7 @@
 
 NSString *MaxSupportedProfileLevelConstrainedHigh() {
 #if defined(WEBRTC_IOS)
-  NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedHigh);
+  NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedHigh);
   if (profile != nil) {
     return profile;
   }
@@ -94,8 +93,8 @@
   if (self = [super init]) {
     self.hexString = hexString;
 
-    absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
-        webrtc::H264::ParseProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
+    absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
+        webrtc::ParseH264ProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
     if (profile_level_id.has_value()) {
       self.profile = static_cast<RTCH264Profile>(profile_level_id->profile);
       self.level = static_cast<RTCH264Level>(profile_level_id->level);
@@ -110,8 +109,8 @@
     self.level = level;
 
     absl::optional<std::string> hex_string =
-        webrtc::H264::ProfileLevelIdToString(webrtc::H264::ProfileLevelId(
-            static_cast<webrtc::H264::Profile>(profile), static_cast<webrtc::H264::Level>(level)));
+        webrtc::H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(
+            static_cast<webrtc::H264Profile>(profile), static_cast<webrtc::H264Level>(level)));
     self.hexString =
         [NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding];
   }
diff --git a/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm b/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm
index 01d48c1..e64f619 100644
--- a/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm
+++ b/sdk/objc/components/video_codec/RTCVideoEncoderH264.mm
@@ -28,8 +28,8 @@
 #import "components/video_frame_buffer/RTCCVPixelBuffer.h"
 #import "helpers.h"
 
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "common_video/h264/h264_bitstream_parser.h"
-#include "common_video/h264/profile_level_id.h"
 #include "common_video/include/bitrate_adjuster.h"
 #include "modules/video_coding/include/video_error_codes.h"
 #include "rtc_base/buffer.h"
@@ -173,100 +173,100 @@
 // no specific VideoToolbox profile for the specified level, AutoLevel will be
 // returned. The user must initialize the encoder with a resolution and
 // framerate conforming to the selected H264 level regardless.
-CFStringRef ExtractProfile(const webrtc::H264::ProfileLevelId &profile_level_id) {
+CFStringRef ExtractProfile(const webrtc::H264ProfileLevelId &profile_level_id) {
   switch (profile_level_id.profile) {
-    case webrtc::H264::kProfileConstrainedBaseline:
-    case webrtc::H264::kProfileBaseline:
+    case webrtc::H264Profile::kProfileConstrainedBaseline:
+    case webrtc::H264Profile::kProfileBaseline:
       switch (profile_level_id.level) {
-        case webrtc::H264::kLevel3:
+        case webrtc::H264Level::kLevel3:
           return kVTProfileLevel_H264_Baseline_3_0;
-        case webrtc::H264::kLevel3_1:
+        case webrtc::H264Level::kLevel3_1:
           return kVTProfileLevel_H264_Baseline_3_1;
-        case webrtc::H264::kLevel3_2:
+        case webrtc::H264Level::kLevel3_2:
           return kVTProfileLevel_H264_Baseline_3_2;
-        case webrtc::H264::kLevel4:
+        case webrtc::H264Level::kLevel4:
           return kVTProfileLevel_H264_Baseline_4_0;
-        case webrtc::H264::kLevel4_1:
+        case webrtc::H264Level::kLevel4_1:
           return kVTProfileLevel_H264_Baseline_4_1;
-        case webrtc::H264::kLevel4_2:
+        case webrtc::H264Level::kLevel4_2:
           return kVTProfileLevel_H264_Baseline_4_2;
-        case webrtc::H264::kLevel5:
+        case webrtc::H264Level::kLevel5:
           return kVTProfileLevel_H264_Baseline_5_0;
-        case webrtc::H264::kLevel5_1:
+        case webrtc::H264Level::kLevel5_1:
           return kVTProfileLevel_H264_Baseline_5_1;
-        case webrtc::H264::kLevel5_2:
+        case webrtc::H264Level::kLevel5_2:
           return kVTProfileLevel_H264_Baseline_5_2;
-        case webrtc::H264::kLevel1:
-        case webrtc::H264::kLevel1_b:
-        case webrtc::H264::kLevel1_1:
-        case webrtc::H264::kLevel1_2:
-        case webrtc::H264::kLevel1_3:
-        case webrtc::H264::kLevel2:
-        case webrtc::H264::kLevel2_1:
-        case webrtc::H264::kLevel2_2:
+        case webrtc::H264Level::kLevel1:
+        case webrtc::H264Level::kLevel1_b:
+        case webrtc::H264Level::kLevel1_1:
+        case webrtc::H264Level::kLevel1_2:
+        case webrtc::H264Level::kLevel1_3:
+        case webrtc::H264Level::kLevel2:
+        case webrtc::H264Level::kLevel2_1:
+        case webrtc::H264Level::kLevel2_2:
           return kVTProfileLevel_H264_Baseline_AutoLevel;
       }
 
-    case webrtc::H264::kProfileMain:
+    case webrtc::H264Profile::kProfileMain:
       switch (profile_level_id.level) {
-        case webrtc::H264::kLevel3:
+        case webrtc::H264Level::kLevel3:
           return kVTProfileLevel_H264_Main_3_0;
-        case webrtc::H264::kLevel3_1:
+        case webrtc::H264Level::kLevel3_1:
           return kVTProfileLevel_H264_Main_3_1;
-        case webrtc::H264::kLevel3_2:
+        case webrtc::H264Level::kLevel3_2:
           return kVTProfileLevel_H264_Main_3_2;
-        case webrtc::H264::kLevel4:
+        case webrtc::H264Level::kLevel4:
           return kVTProfileLevel_H264_Main_4_0;
-        case webrtc::H264::kLevel4_1:
+        case webrtc::H264Level::kLevel4_1:
           return kVTProfileLevel_H264_Main_4_1;
-        case webrtc::H264::kLevel4_2:
+        case webrtc::H264Level::kLevel4_2:
           return kVTProfileLevel_H264_Main_4_2;
-        case webrtc::H264::kLevel5:
+        case webrtc::H264Level::kLevel5:
           return kVTProfileLevel_H264_Main_5_0;
-        case webrtc::H264::kLevel5_1:
+        case webrtc::H264Level::kLevel5_1:
           return kVTProfileLevel_H264_Main_5_1;
-        case webrtc::H264::kLevel5_2:
+        case webrtc::H264Level::kLevel5_2:
           return kVTProfileLevel_H264_Main_5_2;
-        case webrtc::H264::kLevel1:
-        case webrtc::H264::kLevel1_b:
-        case webrtc::H264::kLevel1_1:
-        case webrtc::H264::kLevel1_2:
-        case webrtc::H264::kLevel1_3:
-        case webrtc::H264::kLevel2:
-        case webrtc::H264::kLevel2_1:
-        case webrtc::H264::kLevel2_2:
+        case webrtc::H264Level::kLevel1:
+        case webrtc::H264Level::kLevel1_b:
+        case webrtc::H264Level::kLevel1_1:
+        case webrtc::H264Level::kLevel1_2:
+        case webrtc::H264Level::kLevel1_3:
+        case webrtc::H264Level::kLevel2:
+        case webrtc::H264Level::kLevel2_1:
+        case webrtc::H264Level::kLevel2_2:
           return kVTProfileLevel_H264_Main_AutoLevel;
       }
 
-    case webrtc::H264::kProfileConstrainedHigh:
-    case webrtc::H264::kProfileHigh:
+    case webrtc::H264Profile::kProfileConstrainedHigh:
+    case webrtc::H264Profile::kProfileHigh:
       switch (profile_level_id.level) {
-        case webrtc::H264::kLevel3:
+        case webrtc::H264Level::kLevel3:
           return kVTProfileLevel_H264_High_3_0;
-        case webrtc::H264::kLevel3_1:
+        case webrtc::H264Level::kLevel3_1:
           return kVTProfileLevel_H264_High_3_1;
-        case webrtc::H264::kLevel3_2:
+        case webrtc::H264Level::kLevel3_2:
           return kVTProfileLevel_H264_High_3_2;
-        case webrtc::H264::kLevel4:
+        case webrtc::H264Level::kLevel4:
           return kVTProfileLevel_H264_High_4_0;
-        case webrtc::H264::kLevel4_1:
+        case webrtc::H264Level::kLevel4_1:
           return kVTProfileLevel_H264_High_4_1;
-        case webrtc::H264::kLevel4_2:
+        case webrtc::H264Level::kLevel4_2:
           return kVTProfileLevel_H264_High_4_2;
-        case webrtc::H264::kLevel5:
+        case webrtc::H264Level::kLevel5:
           return kVTProfileLevel_H264_High_5_0;
-        case webrtc::H264::kLevel5_1:
+        case webrtc::H264Level::kLevel5_1:
           return kVTProfileLevel_H264_High_5_1;
-        case webrtc::H264::kLevel5_2:
+        case webrtc::H264Level::kLevel5_2:
           return kVTProfileLevel_H264_High_5_2;
-        case webrtc::H264::kLevel1:
-        case webrtc::H264::kLevel1_b:
-        case webrtc::H264::kLevel1_1:
-        case webrtc::H264::kLevel1_2:
-        case webrtc::H264::kLevel1_3:
-        case webrtc::H264::kLevel2:
-        case webrtc::H264::kLevel2_1:
-        case webrtc::H264::kLevel2_2:
+        case webrtc::H264Level::kLevel1:
+        case webrtc::H264Level::kLevel1_b:
+        case webrtc::H264Level::kLevel1_1:
+        case webrtc::H264Level::kLevel1_2:
+        case webrtc::H264Level::kLevel1_3:
+        case webrtc::H264Level::kLevel2:
+        case webrtc::H264Level::kLevel2_1:
+        case webrtc::H264Level::kLevel2_2:
           return kVTProfileLevel_H264_High_AutoLevel;
       }
   }
@@ -276,33 +276,33 @@
 // can be processed by given encoder with |profile_level_id|.
 // See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items
 // for details.
-NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id) {
+NSUInteger GetMaxSampleRate(const webrtc::H264ProfileLevelId &profile_level_id) {
   switch (profile_level_id.level) {
-    case webrtc::H264::kLevel3:
+    case webrtc::H264Level::kLevel3:
       return 10368000;
-    case webrtc::H264::kLevel3_1:
+    case webrtc::H264Level::kLevel3_1:
       return 27648000;
-    case webrtc::H264::kLevel3_2:
+    case webrtc::H264Level::kLevel3_2:
       return 55296000;
-    case webrtc::H264::kLevel4:
-    case webrtc::H264::kLevel4_1:
+    case webrtc::H264Level::kLevel4:
+    case webrtc::H264Level::kLevel4_1:
       return 62914560;
-    case webrtc::H264::kLevel4_2:
+    case webrtc::H264Level::kLevel4_2:
       return 133693440;
-    case webrtc::H264::kLevel5:
+    case webrtc::H264Level::kLevel5:
       return 150994944;
-    case webrtc::H264::kLevel5_1:
+    case webrtc::H264Level::kLevel5_1:
       return 251658240;
-    case webrtc::H264::kLevel5_2:
+    case webrtc::H264Level::kLevel5_2:
       return 530841600;
-    case webrtc::H264::kLevel1:
-    case webrtc::H264::kLevel1_b:
-    case webrtc::H264::kLevel1_1:
-    case webrtc::H264::kLevel1_2:
-    case webrtc::H264::kLevel1_3:
-    case webrtc::H264::kLevel2:
-    case webrtc::H264::kLevel2_1:
-    case webrtc::H264::kLevel2_2:
+    case webrtc::H264Level::kLevel1:
+    case webrtc::H264Level::kLevel1_b:
+    case webrtc::H264Level::kLevel1_1:
+    case webrtc::H264Level::kLevel1_2:
+    case webrtc::H264Level::kLevel1_3:
+    case webrtc::H264Level::kLevel2:
+    case webrtc::H264Level::kLevel2_1:
+    case webrtc::H264Level::kLevel2_2:
       // Zero means auto rate setting.
       return 0;
   }
@@ -317,7 +317,7 @@
   uint32_t _encoderFrameRate;
   uint32_t _maxAllowedFrameRate;
   RTCH264PacketizationMode _packetizationMode;
-  absl::optional<webrtc::H264::ProfileLevelId> _profile_level_id;
+  absl::optional<webrtc::H264ProfileLevelId> _profile_level_id;
   RTCVideoEncoderCallback _callback;
   int32_t _width;
   int32_t _height;
@@ -342,7 +342,7 @@
     _bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
     _packetizationMode = RTCH264PacketizationModeNonInterleaved;
     _profile_level_id =
-        webrtc::H264::ParseSdpProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
+        webrtc::ParseSdpForH264ProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
     RTC_DCHECK(_profile_level_id);
     RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id));
     RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);
diff --git a/sdk/objc/components/video_codec/UIDevice+H264Profile.h b/sdk/objc/components/video_codec/UIDevice+H264Profile.h
index bb6f6ce..a51debb 100644
--- a/sdk/objc/components/video_codec/UIDevice+H264Profile.h
+++ b/sdk/objc/components/video_codec/UIDevice+H264Profile.h
@@ -10,10 +10,10 @@
 
 #import <UIKit/UIKit.h>
 
-#include "media/base/h264_profile_level_id.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 
 @interface UIDevice (H264Profile)
 
-+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile;
++ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile;
 
 @end
diff --git a/sdk/objc/components/video_codec/UIDevice+H264Profile.mm b/sdk/objc/components/video_codec/UIDevice+H264Profile.mm
index bfbdfa0..42ebadf 100644
--- a/sdk/objc/components/video_codec/UIDevice+H264Profile.mm
+++ b/sdk/objc/components/video_codec/UIDevice+H264Profile.mm
@@ -15,99 +15,156 @@
 
 namespace {
 
-using namespace webrtc::H264;
+using namespace webrtc;
 
 struct SupportedH264Profile {
   const RTCDeviceType deviceType;
-  const ProfileLevelId profile;
+  const H264ProfileLevelId profile;
 };
 
 constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = {
     // iPhones with at least iOS 9
-    {RTCDeviceTypeIPhone12ProMax, {kProfileHigh, kLevel5_2}},  // https://support.apple.com/kb/SP832
-    {RTCDeviceTypeIPhone12Pro, {kProfileHigh, kLevel5_2}},     // https://support.apple.com/kb/SP831
-    {RTCDeviceTypeIPhone12, {kProfileHigh, kLevel5_2}},        // https://support.apple.com/kb/SP830
-    {RTCDeviceTypeIPhone12Mini, {kProfileHigh, kLevel5_2}},    // https://support.apple.com/kb/SP829
-    {RTCDeviceTypeIPhone11ProMax, {kProfileHigh, kLevel5_2}},  // https://support.apple.com/kb/SP806
-    {RTCDeviceTypeIPhone11Pro, {kProfileHigh, kLevel5_2}},     // https://support.apple.com/kb/SP805
-    {RTCDeviceTypeIPhone11, {kProfileHigh, kLevel5_2}},        // https://support.apple.com/kb/SP804
-    {RTCDeviceTypeIPhoneXS, {kProfileHigh, kLevel5_2}},        // https://support.apple.com/kb/SP779
-    {RTCDeviceTypeIPhoneXSMax, {kProfileHigh, kLevel5_2}},     // https://support.apple.com/kb/SP780
-    {RTCDeviceTypeIPhoneXR, {kProfileHigh, kLevel5_2}},        // https://support.apple.com/kb/SP781
-    {RTCDeviceTypeIPhoneX, {kProfileHigh, kLevel5_2}},         // https://support.apple.com/kb/SP770
-    {RTCDeviceTypeIPhone8, {kProfileHigh, kLevel5_2}},         // https://support.apple.com/kb/SP767
-    {RTCDeviceTypeIPhone8Plus, {kProfileHigh, kLevel5_2}},     // https://support.apple.com/kb/SP768
-    {RTCDeviceTypeIPhone7, {kProfileHigh, kLevel5_1}},         // https://support.apple.com/kb/SP743
-    {RTCDeviceTypeIPhone7Plus, {kProfileHigh, kLevel5_1}},     // https://support.apple.com/kb/SP744
-    {RTCDeviceTypeIPhoneSE, {kProfileHigh, kLevel4_2}},        // https://support.apple.com/kb/SP738
-    {RTCDeviceTypeIPhone6S, {kProfileHigh, kLevel4_2}},        // https://support.apple.com/kb/SP726
-    {RTCDeviceTypeIPhone6SPlus, {kProfileHigh, kLevel4_2}},    // https://support.apple.com/kb/SP727
-    {RTCDeviceTypeIPhone6, {kProfileHigh, kLevel4_2}},         // https://support.apple.com/kb/SP705
-    {RTCDeviceTypeIPhone6Plus, {kProfileHigh, kLevel4_2}},     // https://support.apple.com/kb/SP706
-    {RTCDeviceTypeIPhone5SGSM, {kProfileHigh, kLevel4_2}},     // https://support.apple.com/kb/SP685
+    {RTCDeviceTypeIPhone12ProMax,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP832
+    {RTCDeviceTypeIPhone12Pro,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP831
+    {RTCDeviceTypeIPhone12,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP830
+    {RTCDeviceTypeIPhone12Mini,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP829
+    {RTCDeviceTypeIPhone11ProMax,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP806
+    {RTCDeviceTypeIPhone11Pro,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP805
+    {RTCDeviceTypeIPhone11,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP804
+    {RTCDeviceTypeIPhoneXS,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP779
+    {RTCDeviceTypeIPhoneXSMax,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP780
+    {RTCDeviceTypeIPhoneXR,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP781
+    {RTCDeviceTypeIPhoneX,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP770
+    {RTCDeviceTypeIPhone8,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP767
+    {RTCDeviceTypeIPhone8Plus,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP768
+    {RTCDeviceTypeIPhone7,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_1}},  // https://support.apple.com/kb/SP743
+    {RTCDeviceTypeIPhone7Plus,
+     {H264Profile::kProfileHigh, H264Level::kLevel5_1}},  // https://support.apple.com/kb/SP744
+    {RTCDeviceTypeIPhoneSE,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP738
+    {RTCDeviceTypeIPhone6S,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP726
+    {RTCDeviceTypeIPhone6SPlus,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP727
+    {RTCDeviceTypeIPhone6,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP705
+    {RTCDeviceTypeIPhone6Plus,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP706
+    {RTCDeviceTypeIPhone5SGSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP685
     {RTCDeviceTypeIPhone5SGSM_CDMA,
-     {kProfileHigh, kLevel4_2}},                           // https://support.apple.com/kb/SP685
-    {RTCDeviceTypeIPhone5GSM, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP655
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP685
+    {RTCDeviceTypeIPhone5GSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP655
     {RTCDeviceTypeIPhone5GSM_CDMA,
-     {kProfileHigh, kLevel4_1}},                            // https://support.apple.com/kb/SP655
-    {RTCDeviceTypeIPhone5CGSM, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP684
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP655
+    {RTCDeviceTypeIPhone5CGSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP684
     {RTCDeviceTypeIPhone5CGSM_CDMA,
-     {kProfileHigh, kLevel4_1}},                         // https://support.apple.com/kb/SP684
-    {RTCDeviceTypeIPhone4S, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP643
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP684
+    {RTCDeviceTypeIPhone4S,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP643
 
     // iPods with at least iOS 9
-    {RTCDeviceTypeIPodTouch7G, {kProfileMain, kLevel4_1}},  // https://support.apple.com/kb/SP796
-    {RTCDeviceTypeIPodTouch6G, {kProfileMain, kLevel4_1}},  // https://support.apple.com/kb/SP720
-    {RTCDeviceTypeIPodTouch5G, {kProfileMain, kLevel3_1}},  // https://support.apple.com/kb/SP657
+    {RTCDeviceTypeIPodTouch7G,
+     {H264Profile::kProfileMain, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP796
+    {RTCDeviceTypeIPodTouch6G,
+     {H264Profile::kProfileMain, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP720
+    {RTCDeviceTypeIPodTouch5G,
+     {H264Profile::kProfileMain, H264Level::kLevel3_1}},  // https://support.apple.com/kb/SP657
 
     // iPads with at least iOS 9
-    {RTCDeviceTypeIPadAir4Gen, {kProfileHigh, kLevel4_1}},   // https://support.apple.com/kb/SP828
-    {RTCDeviceTypeIPad8, {kProfileHigh, kLevel4_1}},   // https://support.apple.com/kb/SP822
-    {RTCDeviceTypeIPadPro4Gen12Inch, {kProfileHigh, kLevel4_1}},   // https://support.apple.com/kb/SP815
-    {RTCDeviceTypeIPadPro4Gen11Inch, {kProfileHigh, kLevel4_1}},   // https://support.apple.com/kb/SP814
-    {RTCDeviceTypeIPadAir3Gen, {kProfileHigh, kLevel4_1}},   // https://support.apple.com/kb/SP787
-    {RTCDeviceTypeIPadMini5Gen, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP788
+    {RTCDeviceTypeIPadAir4Gen,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP828
+    {RTCDeviceTypeIPad8,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP822
+    {RTCDeviceTypeIPadPro4Gen12Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP815
+    {RTCDeviceTypeIPadPro4Gen11Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP814
+    {RTCDeviceTypeIPadAir3Gen,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP787
+    {RTCDeviceTypeIPadMini5Gen,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP788
     {RTCDeviceTypeIPadPro3Gen12Inch,
-     {kProfileHigh, kLevel5_2}},  // https://support.apple.com/kb/SP785
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP785
     {RTCDeviceTypeIPadPro3Gen11Inch,
-     {kProfileHigh, kLevel5_2}},                               // https://support.apple.com/kb/SP784
-    {RTCDeviceTypeIPad7Gen10Inch, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP807
-    {RTCDeviceTypeIPad2Wifi, {kProfileHigh, kLevel4_1}},       // https://support.apple.com/kb/SP622
-    {RTCDeviceTypeIPad2GSM, {kProfileHigh, kLevel4_1}},        // https://support.apple.com/kb/SP622
-    {RTCDeviceTypeIPad2CDMA, {kProfileHigh, kLevel4_1}},       // https://support.apple.com/kb/SP622
-    {RTCDeviceTypeIPad2Wifi2, {kProfileHigh, kLevel4_1}},      // https://support.apple.com/kb/SP622
-    {RTCDeviceTypeIPadMiniWifi, {kProfileHigh, kLevel4_1}},    // https://support.apple.com/kb/SP661
-    {RTCDeviceTypeIPadMiniGSM, {kProfileHigh, kLevel4_1}},     // https://support.apple.com/kb/SP661
+     {H264Profile::kProfileHigh, H264Level::kLevel5_2}},  // https://support.apple.com/kb/SP784
+    {RTCDeviceTypeIPad7Gen10Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP807
+    {RTCDeviceTypeIPad2Wifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP622
+    {RTCDeviceTypeIPad2GSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP622
+    {RTCDeviceTypeIPad2CDMA,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP622
+    {RTCDeviceTypeIPad2Wifi2,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP622
+    {RTCDeviceTypeIPadMiniWifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP661
+    {RTCDeviceTypeIPadMiniGSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP661
     {RTCDeviceTypeIPadMiniGSM_CDMA,
-     {kProfileHigh, kLevel4_1}},                              // https://support.apple.com/kb/SP661
-    {RTCDeviceTypeIPad3Wifi, {kProfileHigh, kLevel4_1}},      // https://support.apple.com/kb/SP647
-    {RTCDeviceTypeIPad3GSM_CDMA, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP647
-    {RTCDeviceTypeIPad3GSM, {kProfileHigh, kLevel4_1}},       // https://support.apple.com/kb/SP647
-    {RTCDeviceTypeIPad4Wifi, {kProfileHigh, kLevel4_1}},      // https://support.apple.com/kb/SP662
-    {RTCDeviceTypeIPad4GSM, {kProfileHigh, kLevel4_1}},       // https://support.apple.com/kb/SP662
-    {RTCDeviceTypeIPad4GSM_CDMA, {kProfileHigh, kLevel4_1}},  // https://support.apple.com/kb/SP662
-    {RTCDeviceTypeIPad5, {kProfileHigh, kLevel4_2}},          // https://support.apple.com/kb/SP751
-    {RTCDeviceTypeIPad6, {kProfileHigh, kLevel4_2}},          // https://support.apple.com/kb/SP774
-    {RTCDeviceTypeIPadAirWifi, {kProfileHigh, kLevel4_2}},    // https://support.apple.com/kb/SP692
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP661
+    {RTCDeviceTypeIPad3Wifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP647
+    {RTCDeviceTypeIPad3GSM_CDMA,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP647
+    {RTCDeviceTypeIPad3GSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP647
+    {RTCDeviceTypeIPad4Wifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP662
+    {RTCDeviceTypeIPad4GSM,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP662
+    {RTCDeviceTypeIPad4GSM_CDMA,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_1}},  // https://support.apple.com/kb/SP662
+    {RTCDeviceTypeIPad5,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP751
+    {RTCDeviceTypeIPad6,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP774
+    {RTCDeviceTypeIPadAirWifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP692
     {RTCDeviceTypeIPadAirCellular,
-     {kProfileHigh, kLevel4_2}},  // https://support.apple.com/kb/SP692
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP692
     {RTCDeviceTypeIPadAirWifiCellular,
-     {kProfileHigh, kLevel4_2}},                               // https://support.apple.com/kb/SP692
-    {RTCDeviceTypeIPadAir2, {kProfileHigh, kLevel4_2}},        // https://support.apple.com/kb/SP708
-    {RTCDeviceTypeIPadMini2GWifi, {kProfileHigh, kLevel4_2}},  // https://support.apple.com/kb/SP693
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP692
+    {RTCDeviceTypeIPadAir2,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP708
+    {RTCDeviceTypeIPadMini2GWifi,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP693
     {RTCDeviceTypeIPadMini2GCellular,
-     {kProfileHigh, kLevel4_2}},  // https://support.apple.com/kb/SP693
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP693
     {RTCDeviceTypeIPadMini2GWifiCellular,
-     {kProfileHigh, kLevel4_2}},                               // https://support.apple.com/kb/SP693
-    {RTCDeviceTypeIPadMini3, {kProfileHigh, kLevel4_2}},       // https://support.apple.com/kb/SP709
-    {RTCDeviceTypeIPadMini4, {kProfileHigh, kLevel4_2}},       // https://support.apple.com/kb/SP725
-    {RTCDeviceTypeIPadPro9Inch, {kProfileHigh, kLevel4_2}},    // https://support.apple.com/kb/SP739
-    {RTCDeviceTypeIPadPro12Inch, {kProfileHigh, kLevel4_2}},   // https://support.apple.com/kb/sp723
-    {RTCDeviceTypeIPadPro12Inch2, {kProfileHigh, kLevel4_2}},  // https://support.apple.com/kb/SP761
-    {RTCDeviceTypeIPadPro10Inch, {kProfileHigh, kLevel4_2}},   // https://support.apple.com/kb/SP762
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP693
+    {RTCDeviceTypeIPadMini3,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP709
+    {RTCDeviceTypeIPadMini4,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP725
+    {RTCDeviceTypeIPadPro9Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP739
+    {RTCDeviceTypeIPadPro12Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/sp723
+    {RTCDeviceTypeIPadPro12Inch2,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP761
+    {RTCDeviceTypeIPadPro10Inch,
+     {H264Profile::kProfileHigh, H264Level::kLevel4_2}},  // https://support.apple.com/kb/SP762
 };
 
-absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) {
+absl::optional<H264ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) {
   const auto* result = std::find_if(std::begin(kH264MaxSupportedProfiles),
                                     std::end(kH264MaxSupportedProfiles),
                                     [deviceType](const SupportedH264Profile& supportedProfile) {
@@ -123,7 +180,7 @@
 
 @implementation UIDevice (H264Profile)
 
-+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile {
++ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile {
   return FindMaxSupportedProfileForDevice([self deviceType]);
 }
 
diff --git a/video/BUILD.gn b/video/BUILD.gn
index 35ad044..c524212 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -84,7 +84,6 @@
     "../call:rtp_sender",
     "../call:video_stream_api",
     "../common_video",
-    "../media:rtc_h264_profile_id",
     "../modules:module_api",
     "../modules:module_api_public",
     "../modules/pacing",
@@ -175,7 +174,6 @@
     "../call:rtp_receiver",  # For RtxReceiveStream.
     "../call:video_stream_api",
     "../common_video",
-    "../media:rtc_h264_profile_id",
     "../modules:module_api",
     "../modules/pacing",
     "../modules/remote_bitrate_estimator",
@@ -431,7 +429,6 @@
         "../api:test_dependency_factory",
         "../api:video_quality_test_fixture_api",
         "../api/video_codecs:video_codecs_api",
-        "../media:rtc_vp9_profile",
         "../modules/pacing",
         "../modules/video_coding:webrtc_vp9",
         "../rtc_base/experiments:alr_experiment",
@@ -463,8 +460,8 @@
         "../api:peer_connection_quality_test_fixture_api",
         "../api:simulated_network_api",
         "../api:time_controller",
+        "../api/video_codecs:video_codecs_api",
         "../call:simulated_network",
-        "../media:rtc_vp9_profile",
         "../modules/video_coding:webrtc_vp9",
         "../system_wrappers:field_trial",
         "../test:field_trial",
diff --git a/video/full_stack_tests.cc b/video/full_stack_tests.cc
index ece756b..3831fdf 100644
--- a/video/full_stack_tests.cc
+++ b/video/full_stack_tests.cc
@@ -21,7 +21,7 @@
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_encoder_config.h"
-#include "media/base/vp9_profile.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "modules/video_coding/codecs/vp9/include/vp9.h"
 #include "system_wrappers/include/field_trial.h"
 #include "test/field_trial.h"
diff --git a/video/pc_full_stack_tests.cc b/video/pc_full_stack_tests.cc
index cca3353..5cebf41 100644
--- a/video/pc_full_stack_tests.cc
+++ b/video/pc_full_stack_tests.cc
@@ -21,8 +21,8 @@
 #include "api/test/peerconnection_quality_test_fixture.h"
 #include "api/test/simulated_network.h"
 #include "api/test/time_controller.h"
+#include "api/video_codecs/vp9_profile.h"
 #include "call/simulated_network.h"
-#include "media/base/vp9_profile.h"
 #include "modules/video_coding/codecs/vp9/include/vp9.h"
 #include "system_wrappers/include/field_trial.h"
 #include "test/field_trial.h"
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 12cb01d..8f51a8a 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -24,6 +24,7 @@
 #include "api/array_view.h"
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/video/encoded_image.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_decoder_factory.h"
@@ -31,7 +32,6 @@
 #include "call/rtp_stream_receiver_controller_interface.h"
 #include "call/rtx_receive_stream.h"
 #include "common_video/include/incoming_video_stream.h"
-#include "media/base/h264_profile_level_id.h"
 #include "modules/utility/include/process_thread.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/include/video_coding_defines.h"
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index 4821f3c..2c7461a 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -24,6 +24,7 @@
 #include "api/array_view.h"
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/video/encoded_image.h"
+#include "api/video_codecs/h264_profile_level_id.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_decoder_factory.h"
@@ -31,7 +32,6 @@
 #include "call/rtp_stream_receiver_controller_interface.h"
 #include "call/rtx_receive_stream.h"
 #include "common_video/include/incoming_video_stream.h"
-#include "media/base/h264_profile_level_id.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/include/video_coding_defines.h"
 #include "modules/video_coding/include/video_error_codes.h"