From 757a5e6aa926cd5ee0ad6e7424cfd2968d0a03a4 Mon Sep 17 00:00:00 2001 From: angiebird Date: Tue, 26 Nov 2019 16:40:48 -0800 Subject: [PATCH] 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 --- test/simple_encode_test.cc | 20 +++++++++- vp9/encoder/vp9_firstpass.c | 31 ++++++++++++++++ vp9/encoder/vp9_firstpass.h | 10 +++++ vp9/simple_encode.cc | 73 +++++++++++++++++++++++++++++++++++++ vp9/simple_encode.h | 20 ++++++++++ 5 files changed, 153 insertions(+), 1 deletion(-) diff --git a/test/simple_encode_test.cc b/test/simple_encode_test.cc index e93a1a469..cc5012efd 100644 --- a/test/simple_encode_test.cc +++ b/test/simple_encode_test.cc @@ -149,6 +149,24 @@ TEST(SimpleEncode, EncodeConsistencyTest) { 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 diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 3350cdaf4..48ef8d7ba 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -3643,6 +3643,37 @@ void vp9_twopass_postencode_update(VP9_COMP *cpi) { } #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, diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h index 712a840d5..1c7113488 100644 --- a/vp9/encoder/vp9_firstpass.h +++ b/vp9/encoder/vp9_firstpass.h @@ -252,6 +252,16 @@ int vp9_get_frames_to_next_key(const struct VP9EncoderConfig *oxcf, 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 diff --git a/vp9/simple_encode.cc b/vp9/simple_encode.cc index 6a35eb6bc..3f2f01f79 100644 --- a/vp9/simple_encode.cc +++ b/vp9/simple_encode.cc @@ -102,6 +102,65 @@ static void update_encode_frame_result( 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(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 @@ void SimpleEncode::StartEncode() { 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 @@ int SimpleEncode::GetKeyFrameGroupSize(int key_frame_index) const { 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 @@ void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) { 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( diff --git a/vp9/simple_encode.h b/vp9/simple_encode.h index 471b4e7a8..b8085298b 100644 --- a/vp9/simple_encode.h +++ b/vp9/simple_encode.h @@ -25,6 +25,11 @@ enum FrameType { kAlternateReference, }; +struct EncodeFrameInfo { + int show_idx; + FrameType frame_type; +}; + struct EncodeFrameResult { int show_idx; FrameType frame_type; @@ -38,6 +43,11 @@ struct EncodeFrameResult { int quantize_index; }; +struct GroupOfPicture { + std::vector 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 @@ class SimpleEncode { // 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 @@ class SimpleEncode { int num_frames_; std::FILE *file_; std::unique_ptr impl_ptr_; + + GroupOfPicture group_of_picture_; }; } // namespace vp9 -- 2.40.0