Define `ProfileVersion` at the API and internal conversions.

PiperOrigin-RevId: 745735786
diff --git a/iamf/api/conversion/BUILD b/iamf/api/conversion/BUILD
index dd0f82f..53c5fce 100644
--- a/iamf/api/conversion/BUILD
+++ b/iamf/api/conversion/BUILD
@@ -1,3 +1,5 @@
+load("@rules_cc//cc:cc_library.bzl", "cc_library")
+
 package(default_visibility = [
     "//iamf/api/conversion/tests:__pkg__",
     "//iamf/api/decoder:__pkg__",
@@ -17,4 +19,19 @@
         "@com_google_absl//absl/strings",
     ],
 )
+
+cc_library(
+    name = "profile_conversion",
+    srcs = ["profile_conversion.cc"],
+    hdrs = ["profile_conversion.h"],
+    deps = [
+        "//iamf/api:iamf_tools_api_types",
+        "//iamf/obu:ia_sequence_header",
+        "@com_google_absl//absl/log",
+        "@com_google_absl//absl/status",
+        "@com_google_absl//absl/status:statusor",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
 # keep-sorted end
diff --git a/iamf/api/conversion/profile_conversion.cc b/iamf/api/conversion/profile_conversion.cc
new file mode 100644
index 0000000..cd6fda3
--- /dev/null
+++ b/iamf/api/conversion/profile_conversion.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2025, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 3-Clause Clear License
+ * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
+ * License was not distributed with this source code in the LICENSE file, you
+ * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
+ * Alliance for Open Media Patent License 1.0 was not distributed with this
+ * source code in the PATENTS file, you can obtain it at
+ * www.aomedia.org/license/patent.
+ */
+
+#include "iamf/api/conversion/profile_conversion.h"
+
+#include "absl/log/log.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
+#include "iamf/api/iamf_tools_api_types.h"
+#include "iamf/obu/ia_sequence_header.h"
+
+namespace iamf_tools {
+
+typedef ::iamf_tools::ProfileVersion InternalProfileVersion;
+
+InternalProfileVersion ApiToInternalType(
+    api::ProfileVersion api_profile_version) {
+  switch (api_profile_version) {
+    case api::ProfileVersion::kIamfSimpleProfile:
+      return InternalProfileVersion::kIamfSimpleProfile;
+    case api::ProfileVersion::kIamfBaseProfile:
+      return InternalProfileVersion::kIamfBaseProfile;
+    case api::ProfileVersion::kIamfBaseEnhancedProfile:
+      return InternalProfileVersion::kIamfBaseEnhancedProfile;
+  }
+  // Switch above is exhaustive.
+  LOG(FATAL) << "Invalid profile version= "
+             << static_cast<int>(api_profile_version);
+}
+
+absl::StatusOr<api::ProfileVersion> InternalToApiType(
+    InternalProfileVersion profile_version) {
+  switch (profile_version) {
+    case InternalProfileVersion::kIamfSimpleProfile:
+      return api::ProfileVersion::kIamfSimpleProfile;
+    case InternalProfileVersion::kIamfBaseProfile:
+      return api::ProfileVersion::kIamfBaseProfile;
+    case InternalProfileVersion::kIamfBaseEnhancedProfile:
+      return api::ProfileVersion::kIamfBaseEnhancedProfile;
+    default:
+      // Some internal profiles are not intended for use in the API.
+      return absl::InvalidArgumentError(
+          absl::StrCat("Invalid profile version= ", profile_version));
+  }
+}
+
+}  // namespace iamf_tools
diff --git a/iamf/api/conversion/profile_conversion.h b/iamf/api/conversion/profile_conversion.h
new file mode 100644
index 0000000..2c102e3
--- /dev/null
+++ b/iamf/api/conversion/profile_conversion.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2025, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 3-Clause Clear License
+ * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
+ * License was not distributed with this source code in the LICENSE file, you
+ * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
+ * Alliance for Open Media Patent License 1.0 was not distributed with this
+ * source code in the PATENTS file, you can obtain it at
+ * www.aomedia.org/license/patent.
+ */
+
+#ifndef API_CONVERSION_PROFILE_CONVERSION_H_
+#define API_CONVERSION_PROFILE_CONVERSION_H_
+
+#include "absl/status/statusor.h"
+#include "iamf/api/iamf_tools_api_types.h"
+#include "iamf/obu/ia_sequence_header.h"
+
+namespace iamf_tools {
+
+/*!\brief Converts the API ProfileVersion to an internal ProfileVersion.
+ *
+ * \param api_profile_version API-requested profile version.
+ * \return Internal profile version.
+ */
+iamf_tools::ProfileVersion ApiToInternalType(
+    api::ProfileVersion api_profile_version);
+
+/*!\brief Converts the internal IAMF ProfileVersion to the API ProfileVersion.
+ *
+ * \param profile_version Internal profile version.
+ * \return API profile version, or an error if the internal profile version is
+ *         not intended for use in the API.
+ */
+absl::StatusOr<iamf_tools::api::ProfileVersion> InternalToApiType(
+    iamf_tools::ProfileVersion profile_version);
+
+}  // namespace iamf_tools
+
+#endif  // API_CONVERSION_PROFILE_CONVERSION_H_
diff --git a/iamf/api/conversion/tests/BUILD b/iamf/api/conversion/tests/BUILD
index 53af4b1..3e6520a 100644
--- a/iamf/api/conversion/tests/BUILD
+++ b/iamf/api/conversion/tests/BUILD
@@ -1,3 +1,5 @@
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
+
 # keep-sorted start block=yes prefix_order=cc_test newline_separated=yes
 cc_test(
     name = "mix_presentation_conversion_test",
@@ -10,4 +12,17 @@
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "profile_conversion_test",
+    srcs = ["profile_conversion_test.cc"],
+    deps = [
+        "//iamf/api:iamf_tools_api_types",
+        "//iamf/api/conversion:profile_conversion",
+        "//iamf/obu:ia_sequence_header",
+        "@com_google_absl//absl/status:status_matchers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 # keep-sorted end
diff --git a/iamf/api/conversion/tests/profile_conversion_test.cc b/iamf/api/conversion/tests/profile_conversion_test.cc
new file mode 100644
index 0000000..8ac5036
--- /dev/null
+++ b/iamf/api/conversion/tests/profile_conversion_test.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2025, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 3-Clause Clear License
+ * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
+ * License was not distributed with this source code in the LICENSE file, you
+ * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
+ * Alliance for Open Media Patent License 1.0 was not distributed with this
+ * source code in the PATENTS file, you can obtain it at
+ * www.aomedia.org/license/patent.
+ */
+
+#include "iamf/api/conversion/profile_conversion.h"
+
+#include <utility>
+
+#include "absl/status/status_matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "iamf/api/iamf_tools_api_types.h"
+#include "iamf/obu/ia_sequence_header.h"
+
+namespace iamf_tools {
+namespace {
+
+using ::absl_testing::IsOk;
+using ::absl_testing::IsOkAndHolds;
+using ::testing::Not;
+using ::testing::TestWithParam;
+
+using ProfileVersionPair =
+    std::pair<api::ProfileVersion, iamf_tools::ProfileVersion>;
+using ApiToInternalType_ProfileVersion = TestWithParam<ProfileVersionPair>;
+
+auto kApiOutputToInternalProfileVersionPairs = ::testing::Values(
+    ProfileVersionPair(api::ProfileVersion::kIamfSimpleProfile,
+                       ProfileVersion::kIamfSimpleProfile),
+    ProfileVersionPair(api::ProfileVersion::kIamfBaseProfile,
+                       ProfileVersion::kIamfBaseProfile),
+    ProfileVersionPair(api::ProfileVersion::kIamfBaseEnhancedProfile,
+                       ProfileVersion::kIamfBaseEnhancedProfile));
+
+TEST_P(ApiToInternalType_ProfileVersion,
+       ConvertsOutputProfileVersionToInternalProfileVersion) {
+  const auto& [api_profile_version, expected_profile_version] = GetParam();
+
+  const ProfileVersion resulting_profile_version =
+      ApiToInternalType(api_profile_version);
+
+  EXPECT_EQ(resulting_profile_version, expected_profile_version);
+}
+
+INSTANTIATE_TEST_SUITE_P(ApiToInternalType_ProfileVersion_Instantiation,
+                         ApiToInternalType_ProfileVersion,
+                         kApiOutputToInternalProfileVersionPairs);
+
+using InternalTypeToApi_ProfileVersion = TestWithParam<ProfileVersionPair>;
+
+TEST_P(InternalTypeToApi_ProfileVersion,
+       ConvertsInternalProfileVersionToOutputProfileVersion) {
+  const auto& [expected_api_output_layout, internal_profile_version] =
+      GetParam();
+
+  const auto api_output_layout = InternalToApiType(internal_profile_version);
+
+  EXPECT_THAT(api_output_layout, IsOkAndHolds(expected_api_output_layout));
+}
+
+INSTANTIATE_TEST_SUITE_P(InternalTypeToApi_ProfileVersion_Instantiation,
+                         InternalTypeToApi_ProfileVersion,
+                         kApiOutputToInternalProfileVersionPairs);
+
+TEST(InternalToApiType_InvalidProfileVersion, ReturnsError) {
+  // Some special reserved internal types have no corresponding API type.
+  EXPECT_THAT(InternalToApiType(ProfileVersion::kIamfReserved255Profile),
+              Not(IsOk()));
+}
+
+}  // namespace
+}  // namespace iamf_tools
diff --git a/iamf/api/decoder/iamf_decoder.cc b/iamf/api/decoder/iamf_decoder.cc
index 1f20e2e..245136f 100644
--- a/iamf/api/decoder/iamf_decoder.cc
+++ b/iamf/api/decoder/iamf_decoder.cc
@@ -104,14 +104,16 @@
 //                                 support for v1.1 via
 //                                 `kIamfBaseEnhancedProfile`.
 // Only permit profiles defined in v1.0.0-errata, for now.
-const absl::flat_hash_set<ProfileVersion> kSimpleAndBaseProfiles = {
-    ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile};
+const absl::flat_hash_set<::iamf_tools::ProfileVersion> kSimpleAndBaseProfiles =
+    {::iamf_tools::ProfileVersion::kIamfSimpleProfile,
+     ::iamf_tools::ProfileVersion::kIamfBaseProfile};
 
 // Creates an ObuProcessor; an ObuProcessor is only created once all descriptor
 // OBUs have been processed. Contracted to only return a resource exhausted
 // error if there is not enough data to process the descriptor OBUs.
 absl::StatusOr<std::unique_ptr<ObuProcessor>> CreateObuProcessor(
-    const absl::flat_hash_set<ProfileVersion>& desired_profile_versions,
+    const absl::flat_hash_set<::iamf_tools::ProfileVersion>&
+        desired_profile_versions,
     bool contains_all_descriptor_obus,
     StreamBasedReadBitBuffer* read_bit_buffer, Layout& in_out_layout,
     std::vector<uint8_t>& output_descriptor_obus) {
diff --git a/iamf/api/iamf_tools_api_types.h b/iamf/api/iamf_tools_api_types.h
index d933a2c..039bdc3 100644
--- a/iamf/api/iamf_tools_api_types.h
+++ b/iamf/api/iamf_tools_api_types.h
@@ -42,6 +42,20 @@
 
 std::ostream& operator<<(std::ostream& os, const IamfStatus& status);
 
+/*!\brief Indicates the profile version to decode.
+ *
+ * Profiles are defined in the IAMF spec:
+ * https://aomediacodec.github.io/iamf/#obu-iasequenceheader.
+ */
+enum class ProfileVersion {
+  // Simple profile as defined in IAMF v1.0.0-errata.
+  kIamfSimpleProfile = 0,
+  // Base profile as defined in IAMF v1.0.0-errata.
+  kIamfBaseProfile = 1,
+  // Base-Enhanced profile as defined in IAMF v1.1.0.
+  kIamfBaseEnhancedProfile = 2,
+};
+
 /*!\brief Determines the layout of the output file.
  *
  * Typically these correspond with `sound_system`s in the IAMF spec