shithub: libvpx

Download patch

ref: 8a96ad8f478ee1a58f5b86e365df21d23a752347
parent: 08b01d5e05774bea18348e1f282b940f7fcddb98
author: Cheng Chen <chengchen@google.com>
date: Tue Feb 18 07:20:58 EST 2020

Make external arf consistent with vp9

Add a test to ensure that encoding with the external arfs gets the
same result as long as the arfs are the same as the vp9 baseline.

Change-Id: I92c79001018f4df3bc16e9fc56c733509bebb9dc

--- a/test/simple_encode_test.cc
+++ b/test/simple_encode_test.cc
@@ -285,6 +285,66 @@
   simple_encode_2.EndEncode();
 }
 
+// Encode with default VP9 decision first.
+// Get QPs and arf locations from the first encode.
+// Set external arfs and QPs for the second encode.
+// Expect to get matched results.
+TEST(SimpleEncode, EncodeConsistencyTestUseExternalArfs) {
+  std::vector<int> quantize_index_list;
+  std::vector<uint64_t> ref_sse_list;
+  std::vector<double> ref_psnr_list;
+  std::vector<size_t> ref_bit_size_list;
+  std::vector<int> external_arf_indexes(num_frames, 0);
+  {
+    // The first encode.
+    SimpleEncode simple_encode(w, h, frame_rate_num, frame_rate_den,
+                               target_bitrate, num_frames, infile_path);
+    simple_encode.ComputeFirstPassStats();
+    const int num_coding_frames = simple_encode.GetCodingFrameNum();
+    simple_encode.StartEncode();
+    for (int i = 0; i < num_coding_frames; ++i) {
+      EncodeFrameResult encode_frame_result;
+      simple_encode.EncodeFrame(&encode_frame_result);
+      quantize_index_list.push_back(encode_frame_result.quantize_index);
+      ref_sse_list.push_back(encode_frame_result.sse);
+      ref_psnr_list.push_back(encode_frame_result.psnr);
+      ref_bit_size_list.push_back(encode_frame_result.coding_data_bit_size);
+      if (encode_frame_result.frame_type == kFrameTypeKey) {
+        external_arf_indexes[encode_frame_result.show_idx] = 0;
+      } else if (encode_frame_result.frame_type == kFrameTypeAltRef) {
+        external_arf_indexes[encode_frame_result.show_idx] = 1;
+      } else {
+        // This has to be |= because we can't let overlay overwrites the
+        // arf type for the same frame.
+        external_arf_indexes[encode_frame_result.show_idx] |= 0;
+      }
+    }
+    simple_encode.EndEncode();
+  }
+  {
+    // The second encode with quantize index got from the first encode.
+    // The external arfs are the same as the first encode.
+    SimpleEncode simple_encode(w, h, frame_rate_num, frame_rate_den,
+                               target_bitrate, num_frames, infile_path);
+    simple_encode.ComputeFirstPassStats();
+    simple_encode.SetExternalGroupOfPicture(external_arf_indexes);
+    const int num_coding_frames = simple_encode.GetCodingFrameNum();
+    EXPECT_EQ(static_cast<size_t>(num_coding_frames),
+              quantize_index_list.size());
+    simple_encode.StartEncode();
+    for (int i = 0; i < num_coding_frames; ++i) {
+      EncodeFrameResult encode_frame_result;
+      simple_encode.EncodeFrameWithQuantizeIndex(&encode_frame_result,
+                                                 quantize_index_list[i]);
+      EXPECT_EQ(encode_frame_result.quantize_index, quantize_index_list[i]);
+      EXPECT_EQ(encode_frame_result.sse, ref_sse_list[i]);
+      EXPECT_DOUBLE_EQ(encode_frame_result.psnr, ref_psnr_list[i]);
+      EXPECT_EQ(encode_frame_result.coding_data_bit_size, ref_bit_size_list[i]);
+    }
+    simple_encode.EndEncode();
+  }
+}
+
 TEST(SimpleEncode, GetEncodeFrameInfo) {
   // Makes sure that the encode_frame_info obtained from GetEncodeFrameInfo()
   // matches the counterpart in encode_frame_result obtained from EncodeFrame()
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -532,10 +532,24 @@
   int_mv mv[2];
 } MOTION_VECTOR_INFO;
 
+typedef struct ENCODE_COMMAND {
+  int use_external_quantize_index;
+  int external_quantize_index;
+  // A list of binary flags set from the external controller.
+  // Each binary flag indicates whether the frame is an arf or not.
+  const int *external_arf_indexes;
+} ENCODE_COMMAND;
+
 static INLINE void encode_command_init(ENCODE_COMMAND *encode_command) {
   vp9_zero(*encode_command);
   encode_command->use_external_quantize_index = 0;
   encode_command->external_quantize_index = -1;
+  encode_command->external_arf_indexes = NULL;
+}
+
+static INLINE void encode_command_set_external_arf_indexes(
+    ENCODE_COMMAND *encode_command, const int *external_arf_indexes) {
+  encode_command->external_arf_indexes = external_arf_indexes;
 }
 
 static INLINE void encode_command_set_external_quantize_index(
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -2479,7 +2479,7 @@
  */
 static int get_gop_coding_frame_num(
 #if CONFIG_RATE_CTRL
-    const ENCODE_COMMAND *encode_command,
+    const int *external_arf_indexes,
 #endif
     int *use_alt_ref, const FRAME_INFO *frame_info,
     const FIRST_PASS_INFO *first_pass_info, const RATE_CONTROL *rc,
@@ -2501,7 +2501,7 @@
   (void)active_gf_interval;
   (void)gop_intra_factor;
 
-  if (encode_command != NULL && encode_command->use_external_arf) {
+  if (external_arf_indexes != NULL && rc->frames_to_key > 1) {
     // gop_coding_frames = 1 is necessary to filter out the overlay frame,
     // since the arf is in this group of picture and its overlay is in the next.
     gop_coding_frames = 1;
@@ -2509,7 +2509,7 @@
     while (gop_coding_frames < rc->frames_to_key) {
       const int frame_index = gf_start_show_idx + gop_coding_frames;
       ++gop_coding_frames;
-      if (encode_command->external_arf_indexes[frame_index] == 1) break;
+      if (external_arf_indexes[frame_index] == 1) break;
     }
     return gop_coding_frames;
   }
@@ -2743,7 +2743,7 @@
   {
     gop_coding_frames = get_gop_coding_frame_num(
 #if CONFIG_RATE_CTRL
-        &cpi->encode_command,
+        cpi->encode_command.external_arf_indexes,
 #endif
         &use_alt_ref, frame_info, first_pass_info, rc, gf_start_show_idx,
         &active_gf_interval, gop_intra_factor, cpi->oxcf.lag_in_frames);
@@ -3697,12 +3697,12 @@
   }
 
   *coding_frame_count = vp9_get_gop_coding_frame_count(
-      &cpi->encode_command, &cpi->oxcf, &cpi->frame_info,
+      cpi->encode_command.external_arf_indexes, &cpi->oxcf, &cpi->frame_info,
       &cpi->twopass.first_pass_info, &rc, *first_show_idx, multi_layer_arf,
       allow_alt_ref, *first_is_key_frame, *last_gop_use_alt_ref, use_alt_ref);
 }
 
-int vp9_get_gop_coding_frame_count(const ENCODE_COMMAND *encode_command,
+int vp9_get_gop_coding_frame_count(const int *external_arf_indexes,
                                    const VP9EncoderConfig *oxcf,
                                    const FRAME_INFO *frame_info,
                                    const FIRST_PASS_INFO *first_pass_info,
@@ -3727,7 +3727,7 @@
 
   frame_count = get_gop_coding_frame_num(
 #if CONFIG_RATE_CTRL
-      encode_command,
+      external_arf_indexes,
 #endif
       use_alt_ref, frame_info, first_pass_info, rc, show_idx,
       &active_gf_interval, gop_intra_factor, oxcf->lag_in_frames);
@@ -3737,7 +3737,7 @@
 
 // Under CONFIG_RATE_CTRL, once the first_pass_info is ready, the number of
 // coding frames (including show frame and alt ref) can be determined.
-int vp9_get_coding_frame_num(const ENCODE_COMMAND *encode_command,
+int vp9_get_coding_frame_num(const int *external_arf_indexes,
                              const VP9EncoderConfig *oxcf,
                              const FRAME_INFO *frame_info,
                              const FIRST_PASS_INFO *first_pass_info,
@@ -3762,7 +3762,7 @@
     }
 
     gop_coding_frame_count = vp9_get_gop_coding_frame_count(
-        encode_command, oxcf, frame_info, first_pass_info, &rc, show_idx,
+        external_arf_indexes, oxcf, frame_info, first_pass_info, &rc, show_idx,
         multi_layer_arf, allow_alt_ref, first_is_key_frame,
         last_gop_use_alt_ref, &use_alt_ref);
 
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -252,15 +252,6 @@
                                const FIRST_PASS_INFO *first_pass_info,
                                int kf_show_idx, int min_gf_interval);
 #if CONFIG_RATE_CTRL
-typedef struct ENCODE_COMMAND {
-  int use_external_quantize_index;
-  int external_quantize_index;
-  int use_external_arf;
-  // A list of binary flags set from the external controller.
-  // Each binary flag indicates whether the frame is an arf or not.
-  const int *external_arf_indexes;
-} ENCODE_COMMAND;
-
 /* Call this function to get info about the next group of pictures.
  * This function should be called after vp9_create_compressor() when encoding
  * starts or after vp9_get_compressed_data() when the encoding process of
@@ -273,7 +264,7 @@
 
 /*!\brief Call this function before coding a new group of pictures to get
  * information about it.
- * \param[in] encode_command       Encode command
+ * \param[in] external_arf_indexes External arf indexs passed in
  * \param[in] oxcf                 Encoder config
  * \param[in] frame_info           Frame info
  * \param[in] first_pass_info      First pass stats
@@ -288,7 +279,7 @@
  *
  * \return Returns coding frame count
  */
-int vp9_get_gop_coding_frame_count(const ENCODE_COMMAND *encode_command,
+int vp9_get_gop_coding_frame_count(const int *external_arf_indexes,
                                    const struct VP9EncoderConfig *oxcf,
                                    const FRAME_INFO *frame_info,
                                    const FIRST_PASS_INFO *first_pass_info,
@@ -297,7 +288,7 @@
                                    int first_is_key_frame,
                                    int last_gop_use_alt_ref, int *use_alt_ref);
 
-int vp9_get_coding_frame_num(const ENCODE_COMMAND *encode_command,
+int vp9_get_coding_frame_num(const int *external_arf_indexes,
                              const struct VP9EncoderConfig *oxcf,
                              const FRAME_INFO *frame_info,
                              const FIRST_PASS_INFO *first_pass_info,
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -691,10 +691,9 @@
   return output_stats;
 }
 
-void SimpleEncode::SetExternalGroupOfPicture(const bool use_external_arf,
-                                             const int *external_arf_indexes) {
-  impl_ptr_->cpi->encode_command.use_external_arf = use_external_arf;
-  impl_ptr_->cpi->encode_command.external_arf_indexes = external_arf_indexes;
+void SimpleEncode::SetExternalGroupOfPicture(
+    std::vector<int> external_arf_indexes) {
+  external_arf_indexes_ = external_arf_indexes;
 }
 
 void SimpleEncode::StartEncode() {
@@ -715,6 +714,8 @@
   vpx_img_alloc(&impl_ptr_->tmp_img, impl_ptr_->img_fmt, frame_width_,
                 frame_height_, 1);
   frame_coding_index_ = 0;
+  encode_command_set_external_arf_indexes(&impl_ptr_->cpi->encode_command,
+                                          external_arf_indexes_.data());
   UpdateGroupOfPicture(impl_ptr_->cpi, frame_coding_index_, &group_of_picture_);
   rewind(in_file_);
 
@@ -851,7 +852,7 @@
   FIRST_PASS_INFO first_pass_info;
   fps_init_first_pass_info(&first_pass_info, impl_ptr_->first_pass_stats.data(),
                            num_frames_);
-  return vp9_get_coding_frame_num(/*encode_command=*/nullptr, &oxcf,
+  return vp9_get_coding_frame_num(external_arf_indexes_.data(), &oxcf,
                                   &frame_info, &first_pass_info,
                                   multi_layer_arf, allow_alt_ref);
 }
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -276,9 +276,9 @@
   // The arf index determines whether a frame is arf or not.
   // Therefore it also determines the group of picture size.
   // If set, VP9 will use the external arf index to make decision.
-  // This function is called only once before StartEncde().
-  void SetExternalGroupOfPicture(bool use_external_arf,
-                                 const int *external_arf_indexes);
+  // This function should be called only once after ComputeFirstPassStats(),
+  // before StartEncde().
+  void SetExternalGroupOfPicture(std::vector<int> external_arf_indexes);
 
   // Initializes the encoder for actual encoding.
   // This function should be called after ComputeFirstPassStats().
@@ -334,6 +334,7 @@
   std::FILE *out_file_;
   std::unique_ptr<EncodeImpl> impl_ptr_;
 
+  std::vector<int> external_arf_indexes_;
   GroupOfPicture group_of_picture_;
 
   // Each show or no show frame is assigned with a coding index based on its