diff --git a/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.cpp b/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.cpp index 60d939d34..ac19f6ec3 100644 --- a/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.cpp +++ b/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.cpp @@ -38,20 +38,23 @@ namespace webrtc { 2073600, 36864, 240000, H264Level::kLevel5_2 }, }; - static const int kPixelsPerMacroblock = 16 * 16; + static const int kPixelsPerMacroblockSide = 16; static const int kUnitMaxBRWithNAL = 1200; - absl::optional H264SupportedLevel(int maxFramePixelCount, int maxFramerate, int maxBitrate) + absl::optional H264SupportedLevel(int maxFrameWidthPixelCount, int maxFrameHeightPixelCount, int maxFramerate, int maxBitrate) { - if (maxFramePixelCount <= 0 || maxFramerate <= 0 || maxBitrate <= 0) + if (maxFrameWidthPixelCount <= 0 || maxFrameHeightPixelCount <= 0 || maxFramerate <= 0 || maxBitrate <= 0) return absl::nullopt; + int maxFrameMacroblockCount = + ((maxFrameWidthPixelCount + kPixelsPerMacroblockSide - 1) / kPixelsPerMacroblockSide) * + ((maxFrameHeightPixelCount + kPixelsPerMacroblockSide - 1) / kPixelsPerMacroblockSide); + for (size_t i = 0; i < arraysize(kLevelConstraints); i++) { const LevelConstraint& level_constraint = kLevelConstraints[i]; - if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock >= maxFramePixelCount && - level_constraint.max_macroblocks_per_second >= - maxFramerate * maxFramePixelCount / kPixelsPerMacroblock && + if (level_constraint.max_macroblock_frame_size >= maxFrameMacroblockCount && + level_constraint.max_macroblocks_per_second >= maxFramerate * maxFrameMacroblockCount && level_constraint.max_video_bitrate * kUnitMaxBRWithNAL >= maxBitrate) { return level_constraint.level; @@ -62,14 +65,18 @@ namespace webrtc return absl::nullopt; } - int SupportedMaxFramerate(H264Level level, int maxFramePixelCount) + int SupportedMaxFramerate(H264Level level, int maxFrameWidthPixelCount, int maxFrameHeightPixelCount) { + int maxFrameMacroblockCount = + ((maxFrameWidthPixelCount + kPixelsPerMacroblockSide - 1) / kPixelsPerMacroblockSide) * + ((maxFrameHeightPixelCount + kPixelsPerMacroblockSide - 1) / kPixelsPerMacroblockSide); + for (size_t i = 0; i < arraysize(kLevelConstraints); i++) { const LevelConstraint& level_constraint = kLevelConstraints[i]; if (level_constraint.level == level) { - return level_constraint.max_macroblocks_per_second * kPixelsPerMacroblock / maxFramePixelCount; + return level_constraint.max_macroblocks_per_second / maxFrameMacroblockCount; } } diff --git a/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.h b/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.h index 128951887..3055676b1 100644 --- a/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.h +++ b/Plugin~/WebRTCPlugin/Codec/H264ProfileLevelId.h @@ -11,10 +11,10 @@ namespace webrtc // Returns the minumum level which can supports given parameters. // webrtc::H264SupportedLevel function is defined in libwebrtc, but that is for decoder. - absl::optional H264SupportedLevel(int maxFramePixelCount, int maxFramerate, int maxBitrate); + absl::optional H264SupportedLevel(int maxFrameWidthPixelCount, int maxFrameHeightPixelCount, int maxFramerate, int maxBitrate); - // Returns the max framerate that calclated by maxFramePixelCount. - int SupportedMaxFramerate(H264Level level, int maxFramePixelCount); + // Returns the max framerate that calclated by maxFrameWidthPixelCount and maxFrameHeightPixelCount. + int SupportedMaxFramerate(H264Level level, int maxFrameWidthPixelCount, int maxFrameHeightPixelCount); } // end namespace webrtc } // end namespace unity diff --git a/Plugin~/WebRTCPlugin/Codec/NvCodec/NvEncoderImpl.cpp b/Plugin~/WebRTCPlugin/Codec/NvCodec/NvEncoderImpl.cpp index 84b7b5c61..805ec8add 100644 --- a/Plugin~/WebRTCPlugin/Codec/NvCodec/NvEncoderImpl.cpp +++ b/Plugin~/WebRTCPlugin/Codec/NvCodec/NvEncoderImpl.cpp @@ -60,9 +60,8 @@ namespace webrtc inline absl::optional NvEncRequiredLevel(const VideoCodec& codec, std::vector& formats, const GUID& guid) { - int pixelCount = codec.width * codec.height; auto requiredLevel = unity::webrtc::H264SupportedLevel( - pixelCount, static_cast(codec.maxFramerate), static_cast(codec.maxBitrate)); + codec.width, codec.height, static_cast(codec.maxFramerate), static_cast(codec.maxBitrate)); if (!requiredLevel) { @@ -223,7 +222,7 @@ namespace webrtc // workaround // Use supported max framerate that calculated by h264 level define. m_codec.maxFramerate = static_cast( - SupportedMaxFramerate(s_maxSupportedH264Level.value(), m_codec.width * m_codec.height)); + SupportedMaxFramerate(s_maxSupportedH264Level.value(), m_codec.width, m_codec.height)); requiredLevel = NvEncRequiredLevel(m_codec, s_formats, m_profileGuid); if (!requiredLevel) { @@ -567,7 +566,7 @@ namespace webrtc // workaround // Use supported max framerate that calculated by h264 level define. m_codec.maxFramerate = static_cast( - SupportedMaxFramerate(s_maxSupportedH264Level.value(), m_codec.width * m_codec.height)); + SupportedMaxFramerate(s_maxSupportedH264Level.value(), m_codec.width, m_codec.height)); requiredLevel = NvEncRequiredLevel(m_codec, s_formats, m_profileGuid); if (!requiredLevel) { diff --git a/Plugin~/WebRTCPluginTest/H264ProfileLevelIdTest.cpp b/Plugin~/WebRTCPluginTest/H264ProfileLevelIdTest.cpp index a5c82ddb6..d8ebd7289 100644 --- a/Plugin~/WebRTCPluginTest/H264ProfileLevelIdTest.cpp +++ b/Plugin~/WebRTCPluginTest/H264ProfileLevelIdTest.cpp @@ -9,25 +9,25 @@ namespace webrtc TEST(H264ProfileLevelId, TestSupportedLevel) { - EXPECT_EQ(H264Level::kLevel2_1, *H264SupportedLevel(320 * 240, 25, 4000 * 1200)); - EXPECT_EQ(H264Level::kLevel3_1, *H264SupportedLevel(1280 * 720, 30, 14000 * 1200)); - EXPECT_EQ(H264Level::kLevel4_2, *H264SupportedLevel(1920 * 1080, 60, 50000 * 1200)); - EXPECT_EQ(H264Level::kLevel5_2, *H264SupportedLevel(3840 * 2160, 60, 50000 * 1200)); + EXPECT_EQ(H264Level::kLevel2_1, *H264SupportedLevel(320, 240, 25, 4000 * 1200)); + EXPECT_EQ(H264Level::kLevel3_1, *H264SupportedLevel(1280, 720, 30, 14000 * 1200)); + EXPECT_EQ(H264Level::kLevel4_2, *H264SupportedLevel(1920, 1080, 60, 50000 * 1200)); + EXPECT_EQ(H264Level::kLevel5_2, *H264SupportedLevel(3840, 2160, 60, 50000 * 1200)); } TEST(H264ProfileLevelId, TestSupportedLevelInvalid) { - EXPECT_FALSE(H264SupportedLevel(0, 0, 0)); - EXPECT_FALSE(H264SupportedLevel(3840 * 2160, 90, 50000 * 1200)); + EXPECT_FALSE(H264SupportedLevel(0, 0, 0, 0)); + EXPECT_FALSE(H264SupportedLevel(3840, 2160, 90, 50000 * 1200)); } TEST(H264ProfileLevelId, TestSupportedFramerate) { - EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel2_1, 320 * 240), 25); - EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel3_1, 1280 * 720), 30); - EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel4_2, 1920 * 1080), 60); - EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel5_2, 2560 * 1440), 90); - EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel5_2, 3840 * 2160), 60); + EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel2_1, 320, 240), 25); + EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel3_1, 1280, 720), 30); + EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel4_2, 1920, 1080), 60); + EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel5_2, 2560, 1440), 90); + EXPECT_GE(SupportedMaxFramerate(H264Level::kLevel5_2, 3840, 2160), 60); } const char kProfileLevelId[] = "profile-level-id";