Extract CreateH264ConstrainedBaselineProfile Extracts the logic for generating H.264 Constrained Baseline Profile (CBP) SDP formats into a standalone method. This is a preparatory refactoring for an upcoming Chromium CL (crrev.com/c/7929853), which will reuse this logic to retain the highest supported H.264 level when deduplicating video encoder capabilities. Bug: webrtc:521921838 Change-Id: Ibe05d6a807ec148ffe37e475ce19e9f1bacef3d1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/482340 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Johannes Kron <kron@webrtc.org> Cr-Commit-Position: refs/heads/main@{#48008}
diff --git a/media/base/codec.cc b/media/base/codec.cc index 480f74b..8b7da35 100644 --- a/media/base/codec.cc +++ b/media/base/codec.cc
@@ -15,6 +15,7 @@ #include <iterator> #include <optional> #include <string> +#include <utility> #include <vector> #include "absl/algorithm/container.h" @@ -367,34 +368,43 @@ return result; } +std::optional<SdpVideoFormat> CreateH264ConstrainedBaselineProfile( + const SdpVideoFormat& format) { + if (format.name != kH264CodecName) { + return std::nullopt; + } + const std::optional<H264ProfileLevelId> profile_level_id = + ParseSdpForH264ProfileLevelId(format.parameters); + if (!profile_level_id || + profile_level_id->profile == H264Profile::kProfileConstrainedBaseline) { + return std::nullopt; + } + SdpVideoFormat cbp_format = format; + H264ProfileLevelId cbp_profile = *profile_level_id; + cbp_profile.profile = H264Profile::kProfileConstrainedBaseline; + cbp_format.parameters[kH264FmtpProfileLevelId] = + *H264ProfileLevelIdToString(cbp_profile); + return cbp_format; +} + // If a decoder supports any H264 profile, it is implicitly assumed to also // support constrained base line even though it's not explicitly listed. void AddH264ConstrainedBaselineProfileToSupportedFormats( std::vector<SdpVideoFormat>* supported_formats) { - std::vector<SdpVideoFormat> cbr_supported_formats; + std::vector<SdpVideoFormat> cbp_supported_formats; // For any H264 supported profile, add the corresponding constrained baseline // profile. - for (auto it = supported_formats->cbegin(); it != supported_formats->cend(); - ++it) { - if (it->name == kH264CodecName) { - const std::optional<H264ProfileLevelId> profile_level_id = - ParseSdpForH264ProfileLevelId(it->parameters); - if (profile_level_id && profile_level_id->profile != - H264Profile::kProfileConstrainedBaseline) { - SdpVideoFormat cbp_format = *it; - H264ProfileLevelId cbp_profile = *profile_level_id; - cbp_profile.profile = H264Profile::kProfileConstrainedBaseline; - cbp_format.parameters[kH264FmtpProfileLevelId] = - *H264ProfileLevelIdToString(cbp_profile); - cbr_supported_formats.push_back(cbp_format); - } + for (const SdpVideoFormat& format : *supported_formats) { + if (std::optional<SdpVideoFormat> cbp_format = + CreateH264ConstrainedBaselineProfile(format)) { + cbp_supported_formats.push_back(std::move(*cbp_format)); } } size_t original_size = supported_formats->size(); // ...if it's not already in the list. - std::copy_if(cbr_supported_formats.begin(), cbr_supported_formats.end(), + std::copy_if(cbp_supported_formats.begin(), cbp_supported_formats.end(), std::back_inserter(*supported_formats), [supported_formats](const SdpVideoFormat& format) { return !format.IsCodecInList(*supported_formats);
diff --git a/media/base/codec.h b/media/base/codec.h index 31f5999..6d5f23e 100644 --- a/media/base/codec.h +++ b/media/base/codec.h
@@ -272,6 +272,12 @@ const std::vector<Codec>& supported_codecs, const Codec& codec); +// Returns a copy of `format` modified to be H.264 Constrained Baseline Profile +// (CBP) if `format` is H.264, has a valid profile-level-id, and is not already +// CBP. Otherwise, returns std::nullopt. +RTC_EXPORT std::optional<SdpVideoFormat> CreateH264ConstrainedBaselineProfile( + const SdpVideoFormat& format); + RTC_EXPORT void AddH264ConstrainedBaselineProfileToSupportedFormats( std::vector<SdpVideoFormat>* supported_formats);
diff --git a/media/base/codec_unittest.cc b/media/base/codec_unittest.cc index 231198d..0e5973e 100644 --- a/media/base/codec_unittest.cc +++ b/media/base/codec_unittest.cc
@@ -333,6 +333,34 @@ EXPECT_EQ(supported_formats.size(), kExplicitlySupportedFormats.size()); } +TEST(CodecTest, CreateH264ConstrainedBaselineProfileReturnsCbpForBaseline) { + SdpVideoFormat baseline_format = CreateH264Format( + H264Profile::kProfileBaseline, H264Level::kLevel3_1, "1"); + SdpVideoFormat expected_cbp_format = CreateH264Format( + H264Profile::kProfileConstrainedBaseline, H264Level::kLevel3_1, "1"); + + std::optional<SdpVideoFormat> cbp_format = + CreateH264ConstrainedBaselineProfile(baseline_format); + + ASSERT_TRUE(cbp_format.has_value()); + EXPECT_EQ(*cbp_format, expected_cbp_format); +} + +TEST(CodecTest, CreateH264ConstrainedBaselineProfileReturnsNulloptForCbp) { + SdpVideoFormat cbp_format = CreateH264Format( + H264Profile::kProfileConstrainedBaseline, H264Level::kLevel3_1, "1"); + + EXPECT_FALSE(CreateH264ConstrainedBaselineProfile(cbp_format).has_value()); +} + +TEST(CodecTest, CreateH264ConstrainedBaselineProfileReturnsNulloptForVp9) { + SdpVideoFormat vp9_format = { + kVp9CodecName, + {{kVP9FmtpProfileId, VP9ProfileToString(VP9Profile::kProfile0)}}}; + + EXPECT_FALSE(CreateH264ConstrainedBaselineProfile(vp9_format).has_value()); +} + TEST(CodecTest, AbslStringify) { Codec codec = CreateAudioCodec(47, "custom-audio", 48000, 2); EXPECT_EQ(absl::StrCat(codec), "[47:audio/custom-audio/48000/2]");