Add function for getting supported H264 level from max resolution and fps

BUG=webrtc:6337

Review-Url: https://codereview.webrtc.org/2470133002
Cr-Commit-Position: refs/heads/master@{#14969}
diff --git a/webrtc/common_video/h264/profile_level_id.cc b/webrtc/common_video/h264/profile_level_id.cc
index c7b7f2c..1b3841d 100644
--- a/webrtc/common_video/h264/profile_level_id.cc
+++ b/webrtc/common_video/h264/profile_level_id.cc
@@ -14,6 +14,8 @@
 #include <cstdlib>
 #include <cstring>
 
+#include "webrtc/base/arraysize.h"
+
 namespace {
 
 // For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
@@ -68,6 +70,33 @@
     {0x64, BitPattern("00000000"), webrtc::H264::kProfileHigh},
     {0x64, BitPattern("00001100"), webrtc::H264::kProfileConstrainedHigh}};
 
+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, 3684, webrtc::H264::kLevel5_1},
+    {2073600, 3684, webrtc::H264::kLevel5_2},
+};
+
 }  // anonymous namespace
 
 namespace webrtc {
@@ -129,6 +158,23 @@
   return rtc::Optional<ProfileLevelId>();
 }
 
+rtc::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 rtc::Optional<Level>(level_constraint.level);
+    }
+  }
+
+  // No level supported.
+  return rtc::Optional<Level>();
+}
+
 rtc::Optional<std::string> ProfileLevelIdToString(
     const ProfileLevelId& profile_level_id) {
   // Handle special case level == 1b.
diff --git a/webrtc/common_video/h264/profile_level_id.h b/webrtc/common_video/h264/profile_level_id.h
index 4429263..f69b7f6 100644
--- a/webrtc/common_video/h264/profile_level_id.h
+++ b/webrtc/common_video/h264/profile_level_id.h
@@ -60,6 +60,12 @@
 // profile level id.
 rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str);
 
+// 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::Optional<Level> SupportedLevel(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::Optional<std::string> ProfileLevelIdToString(
diff --git a/webrtc/common_video/h264/profile_level_id_unittest.cc b/webrtc/common_video/h264/profile_level_id_unittest.cc
index 491fda1..1b3c51b 100644
--- a/webrtc/common_video/h264/profile_level_id_unittest.cc
+++ b/webrtc/common_video/h264/profile_level_id_unittest.cc
@@ -70,6 +70,21 @@
   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)));