shithub: libvpx

Download patch

ref: 757a5e6aa926cd5ee0ad6e7424cfd2968d0a03a4
parent: 38a4e46fd3029c903e124c9f47e88063eb7a4018
author: angiebird <angiebird@google.com>
date: Tue Nov 26 11:40:48 EST 2019

Add GetNextEncodeFrameInfo ObserveGroupOfPicture

GetNextEncodeFrameInfo()
Gets encode_frame_info for the next coding frame.

ObserveGroupOfPicture()
Provides the group of pictures that the next coding frame is in.

Change-Id: Idbc437d32c392f25b06efb2d4e1ec01347d678f2

--- a/test/simple_encode_test.cc
+++ b/test/simple_encode_test.cc
@@ -149,6 +149,24 @@
     simple_encode.EndEncode();
   }
 }
-}  // namespace
 
+TEST(SimpleEncode, GetEncodeFrameInfo) {
+  // Makes sure that the encode_frame_info obtained from GetEncodeFrameInfo()
+  // matches the counterpart in encode_frame_result obtained from EncodeFrame()
+  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) {
+    EncodeFrameInfo encode_frame_info = simple_encode.GetNextEncodeFrameInfo();
+    EncodeFrameResult encode_frame_result;
+    simple_encode.EncodeFrame(&encode_frame_result);
+    EXPECT_EQ(encode_frame_info.show_idx, encode_frame_result.show_idx);
+    EXPECT_EQ(encode_frame_info.frame_type, encode_frame_result.frame_type);
+  }
+  simple_encode.EndEncode();
+}
+
+}  // namespace
 }  // namespace vp9
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -3643,6 +3643,37 @@
 }
 
 #if CONFIG_RATE_CTRL
+void vp9_get_next_group_of_picture(int *first_is_key_frame, int *use_alt_ref,
+                                   int *coding_frame_count, int *first_show_idx,
+                                   const VP9_COMP *cpi) {
+  // We make a copy of rc here because we want to get information from the
+  // encoder without changing its state.
+  // TODO(angiebird): Avoid copying rc here.
+  RATE_CONTROL rc = cpi->rc;
+  const int last_gop_use_alt_ref = rc.source_alt_ref_active;
+  const int multi_layer_arf = 0;
+  const int allow_alt_ref = 1;
+  // We assume that current_video_frame is updated to the show index of the
+  // frame we are about to called. Note that current_video_frame is updated at
+  // the end of encode_frame_to_data_rate().
+  // TODO(angiebird): Avoid this kind of fragile style.
+  *first_show_idx = cpi->common.current_video_frame;
+
+  *first_is_key_frame = 0;
+  if (rc.frames_to_key == 0) {
+    rc.frames_to_key = vp9_get_frames_to_next_key(
+        &cpi->oxcf, &cpi->frame_info, &cpi->twopass.first_pass_info,
+        *first_show_idx, rc.min_gf_interval);
+    rc.frames_since_key = 0;
+    *first_is_key_frame = 1;
+  }
+
+  *coding_frame_count = vp9_get_gop_coding_frame_count(
+      use_alt_ref, &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);
+}
+
 int vp9_get_gop_coding_frame_count(
     int *use_alt_ref, const VP9EncoderConfig *oxcf,
     const FRAME_INFO *frame_info, const FIRST_PASS_INFO *first_pass_info,
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -252,6 +252,16 @@
                                const FIRST_PASS_INFO *first_pass_info,
                                int kf_show_idx, int min_gf_interval);
 #if CONFIG_RATE_CTRL
+
+/* 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
+ * the last group of pictures is just finished.
+ */
+void vp9_get_next_group_of_picture(int *first_is_key_frame, int *use_alt_ref,
+                                   int *coding_frame_count, int *first_show_idx,
+                                   const struct VP9_COMP *cpi);
+
 /*!\brief Call this function before coding a new group of pictures to get
  * information about it.
  * \param[in] oxcf                 Encoder config
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -102,6 +102,65 @@
   encode_frame_result->quantize_index = encode_frame_info->quantize_index;
 }
 
+static void IncreaseGroupOfPictureIndex(GroupOfPicture *group_of_picture) {
+  ++group_of_picture->encode_frame_index;
+}
+
+static int IsGroupOfPictureFinished(const GroupOfPicture &group_of_picture) {
+  return static_cast<size_t>(group_of_picture.encode_frame_index) ==
+         group_of_picture.encode_frame_list.size();
+}
+
+static void SetGroupOfPicture(GroupOfPicture *group_of_picture,
+                              int first_is_key_frame, int use_alt_ref,
+                              int coding_frame_count, int first_show_idx) {
+  // Clean up the state of previous group of picture.
+  group_of_picture->encode_frame_list.clear();
+  group_of_picture->encode_frame_index = 0;
+  {
+    // First frame in the group of pictures. It's either key frame or show inter
+    // frame.
+    EncodeFrameInfo encode_frame_info;
+    if (first_is_key_frame) {
+      encode_frame_info.frame_type = kKeyFrame;
+    } else {
+      encode_frame_info.frame_type = kInterFrame;
+    }
+    encode_frame_info.show_idx = first_show_idx;
+    group_of_picture->encode_frame_list.push_back(encode_frame_info);
+  }
+
+  const int show_frame_count = coding_frame_count - use_alt_ref;
+  if (use_alt_ref) {
+    // If there is alternate reference, it is always coded at the second place.
+    // Its show index (or timestamp) is at the last of this group
+    EncodeFrameInfo encode_frame_info;
+    encode_frame_info.frame_type = kAlternateReference;
+    encode_frame_info.show_idx = first_show_idx + show_frame_count;
+    group_of_picture->encode_frame_list.push_back(encode_frame_info);
+  }
+
+  // Encode the rest show inter frames.
+  for (int i = 1; i < show_frame_count; ++i) {
+    EncodeFrameInfo encode_frame_info;
+    encode_frame_info.frame_type = kInterFrame;
+    encode_frame_info.show_idx = first_show_idx + i;
+    group_of_picture->encode_frame_list.push_back(encode_frame_info);
+  }
+}
+
+static void UpdateGroupOfPicture(GroupOfPicture *group_of_picture,
+                                 const VP9_COMP *cpi) {
+  int first_is_key_frame;
+  int use_alt_ref;
+  int coding_frame_count;
+  int first_show_idx;
+  vp9_get_next_group_of_picture(&first_is_key_frame, &use_alt_ref,
+                                &coding_frame_count, &first_show_idx, cpi);
+  SetGroupOfPicture(group_of_picture, first_is_key_frame, use_alt_ref,
+                    coding_frame_count, first_show_idx);
+}
+
 SimpleEncode::SimpleEncode(int frame_width, int frame_height,
                            int frame_rate_num, int frame_rate_den,
                            int target_bitrate, int num_frames,
@@ -211,6 +270,7 @@
   impl_ptr_->cpi = init_encoder(&oxcf, impl_ptr_->img_fmt);
   vpx_img_alloc(&impl_ptr_->tmp_img, impl_ptr_->img_fmt, frame_width_,
                 frame_height_, 1);
+  UpdateGroupOfPicture(&group_of_picture_, impl_ptr_->cpi);
   rewind(file_);
 }
 
@@ -228,6 +288,15 @@
                                     key_frame_index, cpi->rc.min_gf_interval);
 }
 
+GroupOfPicture SimpleEncode::ObserveGroupOfPicture() const {
+  return group_of_picture_;
+}
+
+EncodeFrameInfo SimpleEncode::GetNextEncodeFrameInfo() const {
+  return group_of_picture_
+      .encode_frame_list[group_of_picture_.encode_frame_index];
+}
+
 void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
   VP9_COMP *cpi = impl_ptr_->cpi;
   struct lookahead_ctx *lookahead = cpi->lookahead;
@@ -276,6 +345,10 @@
          max_coding_data_byte_size);
 
   update_encode_frame_result(encode_frame_result, &encode_frame_info);
+  IncreaseGroupOfPictureIndex(&group_of_picture_);
+  if (IsGroupOfPictureFinished(group_of_picture_)) {
+    UpdateGroupOfPicture(&group_of_picture_, impl_ptr_->cpi);
+  }
 }
 
 void SimpleEncode::EncodeFrameWithQuantizeIndex(
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -25,6 +25,11 @@
   kAlternateReference,
 };
 
+struct EncodeFrameInfo {
+  int show_idx;
+  FrameType frame_type;
+};
+
 struct EncodeFrameResult {
   int show_idx;
   FrameType frame_type;
@@ -38,6 +43,11 @@
   int quantize_index;
 };
 
+struct GroupOfPicture {
+  std::vector<EncodeFrameInfo> encode_frame_list;
+  int encode_frame_index;
+};
+
 class SimpleEncode {
  public:
   SimpleEncode(int frame_width, int frame_height, int frame_rate_num,
@@ -72,6 +82,14 @@
   // counted.
   int GetKeyFrameGroupSize(int key_frame_index) const;
 
+  // Provides the group of pictures that the next coding frame is in.
+  // Only call this function between StartEncode() and EndEncode()
+  GroupOfPicture ObserveGroupOfPicture() const;
+
+  // Gets encode_frame_info for the next coding frame.
+  // Only call this function between StartEncode() and EndEncode()
+  EncodeFrameInfo GetNextEncodeFrameInfo() const;
+
   // Encodes a frame
   // This function should be called after StartEncode() and before EndEncode().
   void EncodeFrame(EncodeFrameResult *encode_frame_result);
@@ -97,6 +115,8 @@
   int num_frames_;
   std::FILE *file_;
   std::unique_ptr<EncodeImpl> impl_ptr_;
+
+  GroupOfPicture group_of_picture_;
 };
 
 }  // namespace vp9