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