shithub: libvpx

Download patch

ref: 23b070f46ed9d411f547d6481b157efc60e2d5d8
parent: fe8cce2e36ff22d5426afe3271f9c7e32d8dc9ac
author: angiebird <angiebird@google.com>
date: Tue May 26 15:02:33 EDT 2020

Add functions to compute/observe key frame map

Change-Id: I2fc0efb2ac35e64af3350bddaa802a206d1aa13c

--- a/test/simple_encode_test.cc
+++ b/test/simple_encode_test.cc
@@ -106,6 +106,34 @@
   simple_encode.EndEncode();
 }
 
+TEST(SimpleEncode, ObserveKeyFrameMap) {
+  SimpleEncode simple_encode(w, h, frame_rate_num, frame_rate_den,
+                             target_bitrate, num_frames, infile_path);
+  simple_encode.ComputeFirstPassStats();
+  std::vector<int> key_frame_map = simple_encode.ObserveKeyFrameMap();
+  EXPECT_EQ(key_frame_map.size(), static_cast<size_t>(num_frames));
+  simple_encode.StartEncode();
+  int coded_show_frame_count = 0;
+  while (coded_show_frame_count < num_frames) {
+    const GroupOfPicture group_of_picture =
+        simple_encode.ObserveGroupOfPicture();
+    const std::vector<EncodeFrameInfo> &encode_frame_list =
+        group_of_picture.encode_frame_list;
+    for (size_t group_index = 0; group_index < encode_frame_list.size();
+         ++group_index) {
+      EncodeFrameResult encode_frame_result;
+      simple_encode.EncodeFrame(&encode_frame_result);
+      if (encode_frame_result.frame_type == kFrameTypeKey) {
+        EXPECT_EQ(key_frame_map[encode_frame_result.show_idx], 1);
+      } else {
+        EXPECT_EQ(key_frame_map[encode_frame_result.show_idx], 0);
+      }
+    }
+    coded_show_frame_count += group_of_picture.show_frame_count;
+  }
+  simple_encode.EndEncode();
+}
+
 TEST(SimpleEncode, EncodeFrameWithQuantizeIndex) {
   SimpleEncode simple_encode(w, h, frame_rate_num, frame_rate_den,
                              target_bitrate, num_frames, infile_path);
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -3796,6 +3796,30 @@
   }
   return coding_frame_num;
 }
+
+void vp9_get_key_frame_map(const VP9EncoderConfig *oxcf,
+                           const FRAME_INFO *frame_info,
+                           const FIRST_PASS_INFO *first_pass_info,
+                           int *key_frame_map) {
+  int show_idx = 0;
+  RATE_CONTROL rc;
+  vp9_rc_init(oxcf, 1, &rc);
+
+  // key_frame_map points to an int array with size equal to
+  // first_pass_info->num_frames, which is also the number of show frames in the
+  // video.
+  memset(key_frame_map, 0,
+         sizeof(*key_frame_map) * first_pass_info->num_frames);
+  while (show_idx < first_pass_info->num_frames) {
+    int key_frame_group_size;
+    key_frame_map[show_idx] = 1;
+    key_frame_group_size = vp9_get_frames_to_next_key(
+        oxcf, frame_info, first_pass_info, show_idx, rc.min_gf_interval);
+    assert(key_frame_group_size > 0);
+    show_idx += key_frame_group_size;
+  }
+  assert(show_idx == first_pass_info->num_frames);
+}
 #endif  // CONFIG_RATE_CTRL
 
 FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass) {
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -290,6 +290,16 @@
                              const FRAME_INFO *frame_info,
                              const FIRST_PASS_INFO *first_pass_info,
                              int multi_layer_arf, int allow_alt_ref);
+
+/*!\brief Compute a key frame binary map indicates whether key frames appear
+ * in the corresponding positions. The passed in key_frame_map must point to an
+ * integer array with length equal to first_pass_info->num_frames, which is the
+ * number of show frames in the video.
+ */
+void vp9_get_key_frame_map(const struct VP9EncoderConfig *oxcf,
+                           const FRAME_INFO *frame_info,
+                           const FIRST_PASS_INFO *first_pass_info,
+                           int *key_frame_map);
 #endif  // CONFIG_RATE_CTRL
 
 FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass);
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -779,6 +779,9 @@
   free_encoder(cpi);
   rewind(in_file_);
   vpx_img_free(&img);
+
+  // Generate key_frame_map based on impl_ptr_->first_pass_stats.
+  key_frame_map_ = ComputeKeyFrameMap();
 }
 
 std::vector<std::vector<double>> SimpleEncode::ObserveFirstPassStats() {
@@ -1063,6 +1066,28 @@
                            num_frames_);
   return vp9_get_coding_frame_num(&oxcf, &frame_info, &first_pass_info,
                                   multi_layer_arf, allow_alt_ref);
+}
+
+std::vector<int> SimpleEncode::ComputeKeyFrameMap() const {
+  assert(impl_ptr_->first_pass_stats.size() == num_frames_);
+  vpx_rational_t frame_rate =
+      make_vpx_rational(frame_rate_num_, frame_rate_den_);
+  const VP9EncoderConfig oxcf =
+      vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
+                             target_bitrate_, VPX_RC_LAST_PASS);
+  FRAME_INFO frame_info = vp9_get_frame_info(&oxcf);
+  FIRST_PASS_INFO first_pass_info;
+  fps_init_first_pass_info(&first_pass_info,
+                           GetVectorData(impl_ptr_->first_pass_stats),
+                           num_frames_);
+  std::vector<int> key_frame_map(num_frames_, 0);
+  vp9_get_key_frame_map(&oxcf, &frame_info, &first_pass_info,
+                        GetVectorData(key_frame_map));
+  return key_frame_map;
+}
+
+std::vector<int> SimpleEncode::ObserveKeyFrameMap() const {
+  return key_frame_map_;
 }
 
 uint64_t SimpleEncode::GetFramePixelCount() const {
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -304,8 +304,9 @@
   SimpleEncode(SimpleEncode &) = delete;
   SimpleEncode &operator=(const SimpleEncode &) = delete;
 
-  // Makes encoder compute the first pass stats and store it internally for
-  // future encode.
+  // Makes encoder compute the first pass stats and store it at
+  // impl_ptr_->first_pass_stats. key_frame_map_ is also computed based on the
+  // first pass stats.
   void ComputeFirstPassStats();
 
   // Outputs the first pass stats represented by a 2-D vector.
@@ -314,8 +315,14 @@
   // values. For details, please check FIRSTPASS_STATS in vp9_firstpass.h
   std::vector<std::vector<double>> ObserveFirstPassStats();
 
+  // Ouputs a copy of key_frame_map_, a binary vector with size equal to the
+  // number of show frames in the video. For each entry in the vector, 1
+  // indicates the position is a key frame and 0 indicates it's not a key frame.
+  // This function should be called after ComputeFirstPassStats()
+  std::vector<int> ObserveKeyFrameMap() const;
+
   // Sets group of pictures map for coding the entire video.
-  // Each entry in the gop_map corresponds to a show frame in the video.
+  // Each entry in the gop_map is corresponding to a show frame in the video.
   // Therefore, the size of gop_map should equal to the number of show frames in
   // the entire video.
   // If a given entry's kGopMapFlagStart is set, it means this is the start of a
@@ -366,6 +373,12 @@
   uint64_t GetFramePixelCount() const;
 
  private:
+  // Compute the key frame locations of the video based on first pass stats.
+  // The results are returned as a binary vector with 1s indicating keyframes
+  // and 0s indicating non keyframes.
+  // It has to be called after impl_ptr_->first_pass_stats is computed.
+  std::vector<int> ComputeKeyFrameMap() const;
+
   // Updates key_frame_group_size_, reset key_frame_group_index_ and init
   // ref_frame_info_.
   void UpdateKeyFrameGroup(int key_frame_show_index);
@@ -388,6 +401,7 @@
   std::FILE *out_file_;
   std::unique_ptr<EncodeImpl> impl_ptr_;
 
+  std::vector<int> key_frame_map_;
   std::vector<int> gop_map_;
   GroupOfPicture group_of_picture_;