/* * Copyright (c) 2019 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree.
*/
TEST_F(SimpleEncodeTest, ComputeFirstPassStats) {
SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_,
target_bitrate_, num_frames_, target_level_,
in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats();
std::vector<std::vector<double>> frame_stats =
simple_encode.ObserveFirstPassStats();
EXPECT_EQ(frame_stats.size(), static_cast<size_t>(num_frames_)); const size_t data_num = frame_stats[0].size(); // Read ObserveFirstPassStats before changing FIRSTPASS_STATS.
EXPECT_EQ(data_num, static_cast<size_t>(25)); for (size_t i = 0; i < frame_stats.size(); ++i) {
EXPECT_EQ(frame_stats[i].size(), data_num); // FIRSTPASS_STATS's first element is frame
EXPECT_EQ(frame_stats[i][0], i); // FIRSTPASS_STATS's last element is count, and the count is 1 for single // frame stats
EXPECT_EQ(frame_stats[i][data_num - 1], 1);
}
}
// This test encodes the video using EncodeFrame(), where quantize indexes // are selected by vp9 rate control. // Encode stats and the quantize_indexes are collected. // Then the test encodes the video again using EncodeFrameWithQuantizeIndex() // using the quantize indexes collected from the first run. // Then test whether the encode stats of the two encoding runs match.
TEST_F(SimpleEncodeTest, EncodeConsistencyTest) {
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<FrameType> ref_frame_type_list;
std::vector<int> ref_show_idx_list;
{ // The first encode.
SimpleEncode simple_encode(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats(); constint 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);
ref_frame_type_list.push_back(encode_frame_result.frame_type);
ref_show_idx_list.push_back(encode_frame_result.show_idx);
}
simple_encode.EndEncode();
}
{ // The second encode with quantize index got from the first encode.
SimpleEncode simple_encode(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats(); constint 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]);
EXPECT_EQ(encode_frame_result.frame_type, ref_frame_type_list[i]);
EXPECT_EQ(encode_frame_result.show_idx, ref_show_idx_list[i]);
}
simple_encode.EndEncode();
}
}
// Test the information (partition info and motion vector info) stored in // encoder is the same between two encode runs.
TEST_F(SimpleEncodeTest, EncodeConsistencyTest2) { constint num_rows_4x4 = GetNumUnit4x4(width_); constint num_cols_4x4 = GetNumUnit4x4(height_); constint num_units_4x4 = num_rows_4x4 * num_cols_4x4; // The first encode.
SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_,
target_bitrate_, num_frames_, target_level_,
in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats(); constint num_coding_frames = simple_encode.GetCodingFrameNum();
std::vector<PartitionInfo> partition_info_list(num_units_4x4 *
num_coding_frames);
std::vector<MotionVectorInfo> motion_vector_info_list(num_units_4x4 *
num_coding_frames);
simple_encode.StartEncode(); for (int i = 0; i < num_coding_frames; ++i) {
EncodeFrameResult encode_frame_result;
simple_encode.EncodeFrame(&encode_frame_result); for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) {
partition_info_list[i * num_units_4x4 + j] =
encode_frame_result.partition_info[j];
motion_vector_info_list[i * num_units_4x4 + j] =
encode_frame_result.motion_vector_info[j];
}
}
simple_encode.EndEncode(); // The second encode.
SimpleEncode simple_encode_2(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode_2.ComputeFirstPassStats(); constint num_coding_frames_2 = simple_encode_2.GetCodingFrameNum();
simple_encode_2.StartEncode(); for (int i = 0; i < num_coding_frames_2; ++i) {
EncodeFrameResult encode_frame_result;
simple_encode_2.EncodeFrame(&encode_frame_result); for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) {
EXPECT_EQ(encode_frame_result.partition_info[j].row,
partition_info_list[i * num_units_4x4 + j].row);
EXPECT_EQ(encode_frame_result.partition_info[j].column,
partition_info_list[i * num_units_4x4 + j].column);
EXPECT_EQ(encode_frame_result.partition_info[j].row_start,
partition_info_list[i * num_units_4x4 + j].row_start);
EXPECT_EQ(encode_frame_result.partition_info[j].column_start,
partition_info_list[i * num_units_4x4 + j].column_start);
EXPECT_EQ(encode_frame_result.partition_info[j].width,
partition_info_list[i * num_units_4x4 + j].width);
EXPECT_EQ(encode_frame_result.partition_info[j].height,
partition_info_list[i * num_units_4x4 + j].height);
// Test the information stored in encoder is the same between two encode runs.
TEST_F(SimpleEncodeTest, EncodeConsistencyTest3) {
std::vector<int> quantize_index_list; constint num_rows_4x4 = GetNumUnit4x4(width_); constint num_cols_4x4 = GetNumUnit4x4(height_); constint num_units_4x4 = num_rows_4x4 * num_cols_4x4; // The first encode.
SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_,
target_bitrate_, num_frames_, target_level_,
in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats(); constint num_coding_frames = simple_encode.GetCodingFrameNum();
std::vector<PartitionInfo> partition_info_list(num_units_4x4 *
num_coding_frames);
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); for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) {
partition_info_list[i * num_units_4x4 + j] =
encode_frame_result.partition_info[j];
}
}
simple_encode.EndEncode(); // The second encode.
SimpleEncode simple_encode_2(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode_2.ComputeFirstPassStats(); constint num_coding_frames_2 = simple_encode_2.GetCodingFrameNum();
simple_encode_2.StartEncode(); for (int i = 0; i < num_coding_frames_2; ++i) {
EncodeFrameResult encode_frame_result;
simple_encode_2.EncodeFrameWithQuantizeIndex(&encode_frame_result,
quantize_index_list[i]); for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) {
EXPECT_EQ(encode_frame_result.partition_info[j].row,
partition_info_list[i * num_units_4x4 + j].row);
EXPECT_EQ(encode_frame_result.partition_info[j].column,
partition_info_list[i * num_units_4x4 + j].column);
EXPECT_EQ(encode_frame_result.partition_info[j].row_start,
partition_info_list[i * num_units_4x4 + j].row_start);
EXPECT_EQ(encode_frame_result.partition_info[j].column_start,
partition_info_list[i * num_units_4x4 + j].column_start);
EXPECT_EQ(encode_frame_result.partition_info[j].width,
partition_info_list[i * num_units_4x4 + j].width);
EXPECT_EQ(encode_frame_result.partition_info[j].height,
partition_info_list[i * num_units_4x4 + j].height);
}
}
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_F(SimpleEncodeTest, EncodeConsistencySetExternalGroupOfPicturesMap) {
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> gop_map(num_frames_, 0);
{ // The first encode.
SimpleEncode simple_encode(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats();
simple_encode.StartEncode();
int coded_show_frame_count = 0; while (coded_show_frame_count < num_frames_) { const GroupOfPicture group_of_picture =
simple_encode.ObserveGroupOfPicture();
gop_map[coded_show_frame_count] |= kGopMapFlagStart; if (group_of_picture.use_alt_ref) {
gop_map[coded_show_frame_count] |= kGopMapFlagUseAltRef;
} 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);
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);
}
coded_show_frame_count += group_of_picture.show_frame_count;
}
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(width_, height_, frame_rate_num_,
frame_rate_den_, target_bitrate_, num_frames_,
target_level_, in_file_path_str_.c_str());
simple_encode.ComputeFirstPassStats();
simple_encode.SetExternalGroupOfPicturesMap(gop_map.data(), gop_map.size()); constint 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();
}
}
// First gop group. // There is always a key frame at show_idx 0 and key frame should always be // the start of a gop. We expect ObserveExternalGroupOfPicturesMap() will // insert an extra gop start here.
EXPECT_EQ(observed_gop_map[0], kGopMapFlagStart | kGopMapFlagUseAltRef);
// Second gop group with an alt ref.
EXPECT_EQ(observed_gop_map[5], kGopMapFlagStart | kGopMapFlagUseAltRef);
// Third gop group without an alt ref.
EXPECT_EQ(observed_gop_map[10], kGopMapFlagStart);
// Last gop group. The last gop is not supposed to use an alt ref. We expect // ObserveExternalGroupOfPicturesMap() will remove the alt ref flag here.
EXPECT_EQ(observed_gop_map[14], kGopMapFlagStart);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.