ref: fa370c32e710f2024d998c0bb3f2479d1fc3803f
parent: 9c46931645db1ef28f4f4577a1c222d9432ff148
parent: 2f65eb2a00b8f456ea9718c459ec488d2cd48dac
author: Angie Chiang <angiebird@google.com>
date: Tue Dec 10 19:42:01 EST 2019
Merge changes I54f60f62,Idbc437d3 * changes: Rename parameter two_pass to twopass. Add GetNextEncodeFrameInfo ObserveGroupOfPicture
--- 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
@@ -280,8 +290,8 @@
int multi_layer_arf, int allow_alt_ref);
#endif
-FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *two_pass);
-FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *two_pass);
+FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass);
+FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *twopass);
#ifdef __cplusplus
} // extern "C"
--- 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