AV1 levels: add check for min compression ratio

BUG=aomedia:2332

Change-Id: Iabb549c27f679213bcfd98ee90ddb0f83b6d4e6c
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 592e6df..b4381cb 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2551,11 +2551,13 @@
 static void init_level_info(AV1LevelInfo *level_info) {
   memset(level_info, 0, MAX_NUM_OPERATING_POINTS * sizeof(*level_info));
   for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) {
-    AV1LevelSpec *level_spec = &level_info[i].level_spec;
+    AV1LevelSpec *const level_spec = &level_info[i].level_spec;
     level_spec->level = SEQ_LEVEL_MAX;
     level_spec->min_cropped_tile_width = INT_MAX;
     level_spec->min_cropped_tile_height = INT_MAX;
     level_spec->tile_width_is_valid = 1;
+    AV1LevelStats *const level_stats = &level_info[i].level_stats;
+    level_stats->min_cr = 1e8;
   }
 }
 
diff --git a/av1/encoder/level.c b/av1/encoder/level.c
index 911924f..1746267 100644
--- a/av1/encoder/level.c
+++ b/av1/encoder/level.c
@@ -230,6 +230,7 @@
   FRAME_HEADER_RATE_TOO_HIGH,
   DISPLAY_RATE_TOO_HIGH,
   DECODE_RATE_TOO_HIGH,
+  CR_TOO_SMALL,
 
   TARGET_LEVEL_FAIL_IDS
 } TARGET_LEVEL_FAIL_ID;
@@ -247,19 +248,35 @@
   "The frame header rate is too high",
   "The display luma sample rate is too high",
   "The decoded luma sample rate is too high",
+  "The compression ratio is too small",
 };
 
+static double get_min_cr(const AV1LevelSpec *const level_spec, int tier,
+                         int is_still_picture, int64_t decoded_sample_rate) {
+  if (is_still_picture) return 0.8;
+  const double min_cr_basis = tier ? level_spec->high_cr : level_spec->main_cr;
+  const double speed_adj =
+      (double)decoded_sample_rate / level_spec->max_display_rate;
+  return AOMMAX(min_cr_basis * speed_adj, 0.8);
+}
+
 static void check_level_constraints(AV1_COMP *cpi, int operating_point_idx,
-                                    const AV1LevelSpec *level_spec) {
+                                    const AV1LevelSpec *const level_spec,
+                                    const AV1LevelStats *const level_stats) {
   const AV1_LEVEL target_seq_level_idx =
       cpi->target_seq_level_idx[operating_point_idx];
   if (target_seq_level_idx >= SEQ_LEVELS) return;
   TARGET_LEVEL_FAIL_ID fail_id = TARGET_LEVEL_FAIL_IDS;
+  const AV1LevelSpec *const target_level_spec =
+      av1_level_defs + target_seq_level_idx;
+  const SequenceHeader *const seq_params = &cpi->common.seq_params;
+  const double min_cr =
+      get_min_cr(target_level_spec, seq_params->tier[operating_point_idx],
+                 seq_params->still_picture, level_spec->max_decode_rate);
   // Check level conformance
   // TODO(kyslov@) implement all constraints
+
   do {
-    const AV1LevelSpec *const target_level_spec =
-        av1_level_defs + target_seq_level_idx;
     if (level_spec->max_picture_size > target_level_spec->max_picture_size) {
       fail_id = LUMA_PIC_SIZE_TOO_LARGE;
       break;
@@ -319,6 +336,11 @@
       fail_id = DECODE_RATE_TOO_HIGH;
       break;
     }
+
+    if (level_stats->min_cr < min_cr) {
+      fail_id = CR_TOO_SMALL;
+      break;
+    }
   } while (0);
 
   if (fail_id != TARGET_LEVEL_FAIL_IDS) {
@@ -517,6 +539,7 @@
 
     level_stats->total_compressed_size += frame_compressed_size;
     if (show_frame) level_stats->total_time_encoded = total_time_encoded;
+    level_stats->min_cr = AOMMIN(level_stats->min_cr, compression_ratio);
 
     // update level_spec
     // TODO(kyslov@) update all spec fields
@@ -540,12 +563,7 @@
       scan_past_frames(buffer, encoded_frames_in_last_second, level_spec);
     }
 
-    // TODO(kyslov@) These are needed for further level stat calculations
-    (void)compression_ratio;
-    (void)ts_start;
-    (void)ts_end;
-
-    check_level_constraints(cpi, i, level_spec);
+    check_level_constraints(cpi, i, level_spec, level_stats);
   }
 }
 
diff --git a/av1/encoder/level.h b/av1/encoder/level.h
index 1692fad..9178e12 100644
--- a/av1/encoder/level.h
+++ b/av1/encoder/level.h
@@ -58,6 +58,7 @@
 typedef struct {
   uint64_t total_compressed_size;
   double total_time_encoded;
+  double min_cr;
 } AV1LevelStats;
 
 typedef struct {