17ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian/* 27ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * Copyright (c) 2014 The WebM project authors. All Rights Reserved. 37ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * 47ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * Use of this source code is governed by a BSD-style license 57ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * that can be found in the LICENSE file in the root of the source 67ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * tree. An additional intellectual property rights grant can be found 77ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * in the file PATENTS. All contributing project authors may 87ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian * be found in the AUTHORS file in the root of the source tree. 97ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian */ 107ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 117ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include <string> 127ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include <vector> 137ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "third_party/googletest/src/include/gtest/gtest.h" 147ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "test/codec_factory.h" 157ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "test/encode_test_driver.h" 167ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "test/md5_helper.h" 177ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "test/util.h" 187ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#include "test/y4m_video_source.h" 190a39d0a697ff3603e8c100300fda363658e10b23James Zern#include "vp9/encoder/vp9_firstpass.h" 207ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 217ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramaniannamespace { 220a39d0a697ff3603e8c100300fda363658e10b23James Zern// FIRSTPASS_STATS struct: 230a39d0a697ff3603e8c100300fda363658e10b23James Zern// { 240a39d0a697ff3603e8c100300fda363658e10b23James Zern// 25 double members; 250a39d0a697ff3603e8c100300fda363658e10b23James Zern// 1 int64_t member; 260a39d0a697ff3603e8c100300fda363658e10b23James Zern// } 270a39d0a697ff3603e8c100300fda363658e10b23James Zern// Whenever FIRSTPASS_STATS struct is modified, the following constants need to 280a39d0a697ff3603e8c100300fda363658e10b23James Zern// be revisited. 290a39d0a697ff3603e8c100300fda363658e10b23James Zernconst int kDbl = 25; 300a39d0a697ff3603e8c100300fda363658e10b23James Zernconst int kInt = 1; 310a39d0a697ff3603e8c100300fda363658e10b23James Zernconst size_t kFirstPassStatsSz = kDbl * sizeof(double) + kInt * sizeof(int64_t); 320a39d0a697ff3603e8c100300fda363658e10b23James Zern 330a39d0a697ff3603e8c100300fda363658e10b23James Zernclass VPxFirstPassEncoderThreadTest 340a39d0a697ff3603e8c100300fda363658e10b23James Zern : public ::libvpx_test::EncoderTest, 350a39d0a697ff3603e8c100300fda363658e10b23James Zern public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> { 360a39d0a697ff3603e8c100300fda363658e10b23James Zern protected: 370a39d0a697ff3603e8c100300fda363658e10b23James Zern VPxFirstPassEncoderThreadTest() 380a39d0a697ff3603e8c100300fda363658e10b23James Zern : EncoderTest(GET_PARAM(0)), encoder_initialized_(false), tiles_(0), 390a39d0a697ff3603e8c100300fda363658e10b23James Zern encoding_mode_(GET_PARAM(1)), set_cpu_used_(GET_PARAM(2)) { 400a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 410a39d0a697ff3603e8c100300fda363658e10b23James Zern 420a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 430a39d0a697ff3603e8c100300fda363658e10b23James Zern first_pass_only_ = true; 440a39d0a697ff3603e8c100300fda363658e10b23James Zern firstpass_stats_.buf = NULL; 450a39d0a697ff3603e8c100300fda363658e10b23James Zern firstpass_stats_.sz = 0; 460a39d0a697ff3603e8c100300fda363658e10b23James Zern } 470a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual ~VPxFirstPassEncoderThreadTest() { free(firstpass_stats_.buf); } 480a39d0a697ff3603e8c100300fda363658e10b23James Zern 490a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void SetUp() { 500a39d0a697ff3603e8c100300fda363658e10b23James Zern InitializeConfig(); 510a39d0a697ff3603e8c100300fda363658e10b23James Zern SetMode(encoding_mode_); 520a39d0a697ff3603e8c100300fda363658e10b23James Zern 530a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_end_usage = VPX_VBR; 540a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_2pass_vbr_minsection_pct = 5; 550a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_2pass_vbr_maxsection_pct = 2000; 560a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_max_quantizer = 56; 570a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_min_quantizer = 0; 580a39d0a697ff3603e8c100300fda363658e10b23James Zern } 590a39d0a697ff3603e8c100300fda363658e10b23James Zern 600a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void BeginPassHook(unsigned int /*pass*/) { 610a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder_initialized_ = false; 620a39d0a697ff3603e8c100300fda363658e10b23James Zern abort_ = false; 630a39d0a697ff3603e8c100300fda363658e10b23James Zern } 640a39d0a697ff3603e8c100300fda363658e10b23James Zern 650a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void EndPassHook() { 660a39d0a697ff3603e8c100300fda363658e10b23James Zern // For first pass stats test, only run first pass encoder. 670a39d0a697ff3603e8c100300fda363658e10b23James Zern if (first_pass_only_ && cfg_.g_pass == VPX_RC_FIRST_PASS) 680a39d0a697ff3603e8c100300fda363658e10b23James Zern abort_ |= first_pass_only_; 690a39d0a697ff3603e8c100300fda363658e10b23James Zern } 700a39d0a697ff3603e8c100300fda363658e10b23James Zern 710a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void PreEncodeFrameHook(::libvpx_test::VideoSource * /*video*/, 720a39d0a697ff3603e8c100300fda363658e10b23James Zern ::libvpx_test::Encoder *encoder) { 730a39d0a697ff3603e8c100300fda363658e10b23James Zern if (!encoder_initialized_) { 740a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode in 2-pass mode. 750a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP9E_SET_TILE_COLUMNS, tiles_); 760a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); 770a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); 780a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7); 790a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP8E_SET_ARNR_STRENGTH, 5); 800a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP8E_SET_ARNR_TYPE, 3); 810a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 0); 820a39d0a697ff3603e8c100300fda363658e10b23James Zern 830a39d0a697ff3603e8c100300fda363658e10b23James Zern if (encoding_mode_ == ::libvpx_test::kTwoPassGood) 840a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP9E_SET_ROW_MT, row_mt_mode_); 850a39d0a697ff3603e8c100300fda363658e10b23James Zern 860a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder_initialized_ = true; 870a39d0a697ff3603e8c100300fda363658e10b23James Zern } 880a39d0a697ff3603e8c100300fda363658e10b23James Zern } 890a39d0a697ff3603e8c100300fda363658e10b23James Zern 900a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void StatsPktHook(const vpx_codec_cx_pkt_t *pkt) { 910a39d0a697ff3603e8c100300fda363658e10b23James Zern const uint8_t *const pkt_buf = 920a39d0a697ff3603e8c100300fda363658e10b23James Zern reinterpret_cast<uint8_t *>(pkt->data.twopass_stats.buf); 930a39d0a697ff3603e8c100300fda363658e10b23James Zern const size_t pkt_size = pkt->data.twopass_stats.sz; 940a39d0a697ff3603e8c100300fda363658e10b23James Zern 950a39d0a697ff3603e8c100300fda363658e10b23James Zern // First pass stats size equals sizeof(FIRSTPASS_STATS) 960a39d0a697ff3603e8c100300fda363658e10b23James Zern EXPECT_EQ(pkt_size, kFirstPassStatsSz) 970a39d0a697ff3603e8c100300fda363658e10b23James Zern << "Error: First pass stats size doesn't equal kFirstPassStatsSz"; 980a39d0a697ff3603e8c100300fda363658e10b23James Zern 990a39d0a697ff3603e8c100300fda363658e10b23James Zern firstpass_stats_.buf = 1000a39d0a697ff3603e8c100300fda363658e10b23James Zern realloc(firstpass_stats_.buf, firstpass_stats_.sz + pkt_size); 1010a39d0a697ff3603e8c100300fda363658e10b23James Zern memcpy((uint8_t *)firstpass_stats_.buf + firstpass_stats_.sz, pkt_buf, 1020a39d0a697ff3603e8c100300fda363658e10b23James Zern pkt_size); 1030a39d0a697ff3603e8c100300fda363658e10b23James Zern firstpass_stats_.sz += pkt_size; 1040a39d0a697ff3603e8c100300fda363658e10b23James Zern } 1050a39d0a697ff3603e8c100300fda363658e10b23James Zern 1060a39d0a697ff3603e8c100300fda363658e10b23James Zern bool encoder_initialized_; 1070a39d0a697ff3603e8c100300fda363658e10b23James Zern int tiles_; 1080a39d0a697ff3603e8c100300fda363658e10b23James Zern ::libvpx_test::TestMode encoding_mode_; 1090a39d0a697ff3603e8c100300fda363658e10b23James Zern int set_cpu_used_; 1100a39d0a697ff3603e8c100300fda363658e10b23James Zern int row_mt_mode_; 1110a39d0a697ff3603e8c100300fda363658e10b23James Zern bool first_pass_only_; 1120a39d0a697ff3603e8c100300fda363658e10b23James Zern vpx_fixed_buf_t firstpass_stats_; 1130a39d0a697ff3603e8c100300fda363658e10b23James Zern}; 1140a39d0a697ff3603e8c100300fda363658e10b23James Zern 1150a39d0a697ff3603e8c100300fda363658e10b23James Zernstatic void compare_fp_stats(vpx_fixed_buf_t *fp_stats, double factor) { 1160a39d0a697ff3603e8c100300fda363658e10b23James Zern // fp_stats consists of 2 set of first pass encoding stats. These 2 set of 1170a39d0a697ff3603e8c100300fda363658e10b23James Zern // stats are compared to check if the stats match or at least are very close. 1180a39d0a697ff3603e8c100300fda363658e10b23James Zern FIRSTPASS_STATS *stats1 = reinterpret_cast<FIRSTPASS_STATS *>(fp_stats->buf); 1190a39d0a697ff3603e8c100300fda363658e10b23James Zern int nframes_ = (int)(fp_stats->sz / sizeof(FIRSTPASS_STATS)); 1200a39d0a697ff3603e8c100300fda363658e10b23James Zern FIRSTPASS_STATS *stats2 = stats1 + nframes_ / 2; 1210a39d0a697ff3603e8c100300fda363658e10b23James Zern int i, j; 1220a39d0a697ff3603e8c100300fda363658e10b23James Zern 1230a39d0a697ff3603e8c100300fda363658e10b23James Zern // The total stats are also output and included in the first pass stats. Here 1240a39d0a697ff3603e8c100300fda363658e10b23James Zern // ignore that in the comparison. 1250a39d0a697ff3603e8c100300fda363658e10b23James Zern for (i = 0; i < (nframes_ / 2 - 1); ++i) { 1260a39d0a697ff3603e8c100300fda363658e10b23James Zern const double *frame_stats1 = reinterpret_cast<double *>(stats1); 1270a39d0a697ff3603e8c100300fda363658e10b23James Zern const double *frame_stats2 = reinterpret_cast<double *>(stats2); 1280a39d0a697ff3603e8c100300fda363658e10b23James Zern 1290a39d0a697ff3603e8c100300fda363658e10b23James Zern for (j = 0; j < kDbl; ++j) { 130df37111358d02836cb29bbcb9c6e4c95dff90a16Johann ASSERT_LE(fabs(*frame_stats1 - *frame_stats2), 131df37111358d02836cb29bbcb9c6e4c95dff90a16Johann fabs(*frame_stats1) / factor) 132df37111358d02836cb29bbcb9c6e4c95dff90a16Johann << "First failure @ frame #" << i << " stat #" << j << " (" 133df37111358d02836cb29bbcb9c6e4c95dff90a16Johann << *frame_stats1 << " vs. " << *frame_stats2 << ")"; 1340a39d0a697ff3603e8c100300fda363658e10b23James Zern frame_stats1++; 1350a39d0a697ff3603e8c100300fda363658e10b23James Zern frame_stats2++; 1360a39d0a697ff3603e8c100300fda363658e10b23James Zern } 1370a39d0a697ff3603e8c100300fda363658e10b23James Zern 1380a39d0a697ff3603e8c100300fda363658e10b23James Zern stats1++; 1390a39d0a697ff3603e8c100300fda363658e10b23James Zern stats2++; 1400a39d0a697ff3603e8c100300fda363658e10b23James Zern } 1410a39d0a697ff3603e8c100300fda363658e10b23James Zern 1420a39d0a697ff3603e8c100300fda363658e10b23James Zern // Reset firstpass_stats_ to 0. 1430a39d0a697ff3603e8c100300fda363658e10b23James Zern memset((uint8_t *)fp_stats->buf, 0, fp_stats->sz); 1440a39d0a697ff3603e8c100300fda363658e10b23James Zern fp_stats->sz = 0; 1450a39d0a697ff3603e8c100300fda363658e10b23James Zern} 1460a39d0a697ff3603e8c100300fda363658e10b23James Zern 1470a39d0a697ff3603e8c100300fda363658e10b23James Zernstatic void compare_fp_stats_md5(vpx_fixed_buf_t *fp_stats) { 1480a39d0a697ff3603e8c100300fda363658e10b23James Zern // fp_stats consists of 2 set of first pass encoding stats. These 2 set of 1490a39d0a697ff3603e8c100300fda363658e10b23James Zern // stats are compared to check if the stats match. 1500a39d0a697ff3603e8c100300fda363658e10b23James Zern uint8_t *stats1 = reinterpret_cast<uint8_t *>(fp_stats->buf); 1510a39d0a697ff3603e8c100300fda363658e10b23James Zern uint8_t *stats2 = stats1 + fp_stats->sz / 2; 1520a39d0a697ff3603e8c100300fda363658e10b23James Zern ::libvpx_test::MD5 md5_row_mt_0, md5_row_mt_1; 1530a39d0a697ff3603e8c100300fda363658e10b23James Zern 1540a39d0a697ff3603e8c100300fda363658e10b23James Zern md5_row_mt_0.Add(stats1, fp_stats->sz / 2); 1550a39d0a697ff3603e8c100300fda363658e10b23James Zern const char *md5_row_mt_0_str = md5_row_mt_0.Get(); 1560a39d0a697ff3603e8c100300fda363658e10b23James Zern 1570a39d0a697ff3603e8c100300fda363658e10b23James Zern md5_row_mt_1.Add(stats2, fp_stats->sz / 2); 1580a39d0a697ff3603e8c100300fda363658e10b23James Zern const char *md5_row_mt_1_str = md5_row_mt_1.Get(); 1590a39d0a697ff3603e8c100300fda363658e10b23James Zern 1600a39d0a697ff3603e8c100300fda363658e10b23James Zern // Check md5 match. 1610a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_STREQ(md5_row_mt_0_str, md5_row_mt_1_str) 1620a39d0a697ff3603e8c100300fda363658e10b23James Zern << "MD5 checksums don't match"; 1630a39d0a697ff3603e8c100300fda363658e10b23James Zern 1640a39d0a697ff3603e8c100300fda363658e10b23James Zern // Reset firstpass_stats_ to 0. 1650a39d0a697ff3603e8c100300fda363658e10b23James Zern memset((uint8_t *)fp_stats->buf, 0, fp_stats->sz); 1660a39d0a697ff3603e8c100300fda363658e10b23James Zern fp_stats->sz = 0; 1670a39d0a697ff3603e8c100300fda363658e10b23James Zern} 1680a39d0a697ff3603e8c100300fda363658e10b23James Zern 1690a39d0a697ff3603e8c100300fda363658e10b23James ZernTEST_P(VPxFirstPassEncoderThreadTest, FirstPassStatsTest) { 1700a39d0a697ff3603e8c100300fda363658e10b23James Zern ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); 1710a39d0a697ff3603e8c100300fda363658e10b23James Zern 1720a39d0a697ff3603e8c100300fda363658e10b23James Zern first_pass_only_ = true; 1730a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.rc_target_bitrate = 1000; 1740a39d0a697ff3603e8c100300fda363658e10b23James Zern 1750a39d0a697ff3603e8c100300fda363658e10b23James Zern // Test row_mt_mode: 0 vs 1 at single thread case(threads = 1, tiles_ = 0) 1760a39d0a697ff3603e8c100300fda363658e10b23James Zern tiles_ = 0; 1770a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 1; 1780a39d0a697ff3603e8c100300fda363658e10b23James Zern 1790a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 0; 1800a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 1810a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1820a39d0a697ff3603e8c100300fda363658e10b23James Zern 1830a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 1840a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1850a39d0a697ff3603e8c100300fda363658e10b23James Zern 1860a39d0a697ff3603e8c100300fda363658e10b23James Zern // Compare to check if using or not using row-mt generates close stats. 187df37111358d02836cb29bbcb9c6e4c95dff90a16Johann ASSERT_NO_FATAL_FAILURE(compare_fp_stats(&firstpass_stats_, 1000.0)); 1880a39d0a697ff3603e8c100300fda363658e10b23James Zern 1890a39d0a697ff3603e8c100300fda363658e10b23James Zern // Test single thread vs multiple threads 1900a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 1910a39d0a697ff3603e8c100300fda363658e10b23James Zern tiles_ = 0; 1920a39d0a697ff3603e8c100300fda363658e10b23James Zern 1930a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 1; 1940a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 1950a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1960a39d0a697ff3603e8c100300fda363658e10b23James Zern 1970a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 4; 1980a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1990a39d0a697ff3603e8c100300fda363658e10b23James Zern 2000a39d0a697ff3603e8c100300fda363658e10b23James Zern // Compare to check if single-thread and multi-thread stats are close enough. 201df37111358d02836cb29bbcb9c6e4c95dff90a16Johann ASSERT_NO_FATAL_FAILURE(compare_fp_stats(&firstpass_stats_, 1000.0)); 2020a39d0a697ff3603e8c100300fda363658e10b23James Zern 2030a39d0a697ff3603e8c100300fda363658e10b23James Zern // Bit exact test in row_mt mode. 2040a39d0a697ff3603e8c100300fda363658e10b23James Zern // When row_mt_mode_=1 and using >1 threads, the encoder generates bit exact 2050a39d0a697ff3603e8c100300fda363658e10b23James Zern // result. 2060a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 2070a39d0a697ff3603e8c100300fda363658e10b23James Zern tiles_ = 2; 2080a39d0a697ff3603e8c100300fda363658e10b23James Zern 2090a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 2; 2100a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 2110a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 2120a39d0a697ff3603e8c100300fda363658e10b23James Zern 2130a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 8; 2140a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 2150a39d0a697ff3603e8c100300fda363658e10b23James Zern 2160a39d0a697ff3603e8c100300fda363658e10b23James Zern // Compare to check if stats match with row-mt=0/1. 2170a39d0a697ff3603e8c100300fda363658e10b23James Zern compare_fp_stats_md5(&firstpass_stats_); 2180a39d0a697ff3603e8c100300fda363658e10b23James Zern} 2190a39d0a697ff3603e8c100300fda363658e10b23James Zern 2207ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanianclass VPxEncoderThreadTest 2217ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian : public ::libvpx_test::EncoderTest, 2227bc9febe8749e98a3812a0dc4380ceae75c29450Johann public ::libvpx_test::CodecTestWith4Params<libvpx_test::TestMode, int, 2237bc9febe8749e98a3812a0dc4380ceae75c29450Johann int, int> { 2247ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian protected: 2257ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian VPxEncoderThreadTest() 2267bc9febe8749e98a3812a0dc4380ceae75c29450Johann : EncoderTest(GET_PARAM(0)), encoder_initialized_(false), 2277bc9febe8749e98a3812a0dc4380ceae75c29450Johann tiles_(GET_PARAM(3)), threads_(GET_PARAM(4)), 2287bc9febe8749e98a3812a0dc4380ceae75c29450Johann encoding_mode_(GET_PARAM(1)), set_cpu_used_(GET_PARAM(2)) { 2297ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian init_flags_ = VPX_CODEC_USE_PSNR; 2307ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian md5_.clear(); 2310a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 2320a39d0a697ff3603e8c100300fda363658e10b23James Zern psnr_ = 0.0; 2330a39d0a697ff3603e8c100300fda363658e10b23James Zern nframes_ = 0; 2347ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 23568e1c830ade592be74773e249bf94e2bbfb50de7Johann virtual ~VPxEncoderThreadTest() {} 2367ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 2377ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian virtual void SetUp() { 2387ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian InitializeConfig(); 2397ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian SetMode(encoding_mode_); 2407ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 2417ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian if (encoding_mode_ != ::libvpx_test::kRealTime) { 2427ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_end_usage = VPX_VBR; 2437ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_2pass_vbr_minsection_pct = 5; 24468e1c830ade592be74773e249bf94e2bbfb50de7Johann cfg_.rc_2pass_vbr_maxsection_pct = 2000; 2457ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } else { 2467ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.g_lag_in_frames = 0; 2477ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_end_usage = VPX_CBR; 2487ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.g_error_resilient = 1; 2497ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2507ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_max_quantizer = 56; 2517ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_min_quantizer = 0; 2527ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2537ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 2547ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian virtual void BeginPassHook(unsigned int /*pass*/) { 2557ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder_initialized_ = false; 2560a39d0a697ff3603e8c100300fda363658e10b23James Zern psnr_ = 0.0; 2570a39d0a697ff3603e8c100300fda363658e10b23James Zern nframes_ = 0; 2587ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2597ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 26068e1c830ade592be74773e249bf94e2bbfb50de7Johann virtual void PreEncodeFrameHook(::libvpx_test::VideoSource * /*video*/, 2617ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ::libvpx_test::Encoder *encoder) { 2627ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian if (!encoder_initialized_) { 2637ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian // Encode 4 column tiles. 2647ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP9E_SET_TILE_COLUMNS, tiles_); 2657ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); 2667ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian if (encoding_mode_ != ::libvpx_test::kRealTime) { 2677ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); 2687ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7); 2697ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_ARNR_STRENGTH, 5); 2707ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_ARNR_TYPE, 3); 2717bc9febe8749e98a3812a0dc4380ceae75c29450Johann encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 0); 2727ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } else { 2737ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 0); 2747ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder->Control(VP9E_SET_AQ_MODE, 3); 2757ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2760a39d0a697ff3603e8c100300fda363658e10b23James Zern encoder->Control(VP9E_SET_ROW_MT, row_mt_mode_); 2770a39d0a697ff3603e8c100300fda363658e10b23James Zern 2787ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian encoder_initialized_ = true; 2797ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2807ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 2817ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 2820a39d0a697ff3603e8c100300fda363658e10b23James Zern virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { 2830a39d0a697ff3603e8c100300fda363658e10b23James Zern psnr_ += pkt->data.psnr.psnr[0]; 2840a39d0a697ff3603e8c100300fda363658e10b23James Zern nframes_++; 2850a39d0a697ff3603e8c100300fda363658e10b23James Zern } 2860a39d0a697ff3603e8c100300fda363658e10b23James Zern 28768e1c830ade592be74773e249bf94e2bbfb50de7Johann virtual void DecompressedFrameHook(const vpx_image_t &img, 28868e1c830ade592be74773e249bf94e2bbfb50de7Johann vpx_codec_pts_t /*pts*/) { 28968e1c830ade592be74773e249bf94e2bbfb50de7Johann ::libvpx_test::MD5 md5_res; 29068e1c830ade592be74773e249bf94e2bbfb50de7Johann md5_res.Add(&img); 29168e1c830ade592be74773e249bf94e2bbfb50de7Johann md5_.push_back(md5_res.Get()); 29268e1c830ade592be74773e249bf94e2bbfb50de7Johann } 29368e1c830ade592be74773e249bf94e2bbfb50de7Johann 29468e1c830ade592be74773e249bf94e2bbfb50de7Johann virtual bool HandleDecodeResult(const vpx_codec_err_t res, 2957bc9febe8749e98a3812a0dc4380ceae75c29450Johann const libvpx_test::VideoSource & /*video*/, 29668e1c830ade592be74773e249bf94e2bbfb50de7Johann libvpx_test::Decoder * /*decoder*/) { 2977ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian if (res != VPX_CODEC_OK) { 29868e1c830ade592be74773e249bf94e2bbfb50de7Johann EXPECT_EQ(VPX_CODEC_OK, res); 29968e1c830ade592be74773e249bf94e2bbfb50de7Johann return false; 3007ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 3017ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 30268e1c830ade592be74773e249bf94e2bbfb50de7Johann return true; 3037ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian } 3047ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3050a39d0a697ff3603e8c100300fda363658e10b23James Zern double GetAveragePsnr() const { return nframes_ ? (psnr_ / nframes_) : 0.0; } 3060a39d0a697ff3603e8c100300fda363658e10b23James Zern 3077ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian bool encoder_initialized_; 3087ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian int tiles_; 3097bc9febe8749e98a3812a0dc4380ceae75c29450Johann int threads_; 3107ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ::libvpx_test::TestMode encoding_mode_; 3117ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian int set_cpu_used_; 3120a39d0a697ff3603e8c100300fda363658e10b23James Zern int row_mt_mode_; 3130a39d0a697ff3603e8c100300fda363658e10b23James Zern double psnr_; 3140a39d0a697ff3603e8c100300fda363658e10b23James Zern unsigned int nframes_; 3157ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian std::vector<std::string> md5_; 3167ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian}; 3177ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3187ce0a1d1337c01056ba24006efab21f00e179e04Vignesh VenkatasubramanianTEST_P(VPxEncoderThreadTest, EncoderResultTest) { 3197ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 15, 20); 3207ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.rc_target_bitrate = 1000; 3217ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3220a39d0a697ff3603e8c100300fda363658e10b23James Zern // Part 1: Bit exact test for row_mt_mode_ = 0. 3230a39d0a697ff3603e8c100300fda363658e10b23James Zern // This part keeps original unit tests done before row-mt code is checked in. 3240a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 0; 3250a39d0a697ff3603e8c100300fda363658e10b23James Zern 3267ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian // Encode using single thread. 3277ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian cfg_.g_threads = 1; 3287ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian init_flags_ = VPX_CODEC_USE_PSNR; 3297ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3300a39d0a697ff3603e8c100300fda363658e10b23James Zern const std::vector<std::string> single_thr_md5 = md5_; 3317ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian md5_.clear(); 3327ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3337ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian // Encode using multiple threads. 3347bc9febe8749e98a3812a0dc4380ceae75c29450Johann cfg_.g_threads = threads_; 3357ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3360a39d0a697ff3603e8c100300fda363658e10b23James Zern const std::vector<std::string> multi_thr_md5 = md5_; 3377ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian md5_.clear(); 3387ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3397ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian // Compare to check if two vectors are equal. 3407ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian ASSERT_EQ(single_thr_md5, multi_thr_md5); 3410a39d0a697ff3603e8c100300fda363658e10b23James Zern 3420a39d0a697ff3603e8c100300fda363658e10b23James Zern // Part 2: row_mt_mode_ = 0 vs row_mt_mode_ = 1 single thread bit exact test. 3430a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 3440a39d0a697ff3603e8c100300fda363658e10b23James Zern 3450a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode using single thread 3460a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 1; 3470a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 3480a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3490a39d0a697ff3603e8c100300fda363658e10b23James Zern std::vector<std::string> row_mt_single_thr_md5 = md5_; 3500a39d0a697ff3603e8c100300fda363658e10b23James Zern md5_.clear(); 3510a39d0a697ff3603e8c100300fda363658e10b23James Zern 3520a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_EQ(single_thr_md5, row_mt_single_thr_md5); 3530a39d0a697ff3603e8c100300fda363658e10b23James Zern 3540a39d0a697ff3603e8c100300fda363658e10b23James Zern // Part 3: Bit exact test with row-mt on 3550a39d0a697ff3603e8c100300fda363658e10b23James Zern // When row_mt_mode_=1 and using >1 threads, the encoder generates bit exact 3560a39d0a697ff3603e8c100300fda363658e10b23James Zern // result. 3570a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 3580a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_single_thr_md5.clear(); 3590a39d0a697ff3603e8c100300fda363658e10b23James Zern 3600a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode using 2 threads. 3610a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 2; 3620a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 3630a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3640a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_single_thr_md5 = md5_; 3650a39d0a697ff3603e8c100300fda363658e10b23James Zern md5_.clear(); 3660a39d0a697ff3603e8c100300fda363658e10b23James Zern 3670a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode using multiple threads. 3680a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = threads_; 3690a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3700a39d0a697ff3603e8c100300fda363658e10b23James Zern const std::vector<std::string> row_mt_multi_thr_md5 = md5_; 3710a39d0a697ff3603e8c100300fda363658e10b23James Zern md5_.clear(); 3720a39d0a697ff3603e8c100300fda363658e10b23James Zern 3730a39d0a697ff3603e8c100300fda363658e10b23James Zern // Compare to check if two vectors are equal. 3740a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_EQ(row_mt_single_thr_md5, row_mt_multi_thr_md5); 3750a39d0a697ff3603e8c100300fda363658e10b23James Zern 3760a39d0a697ff3603e8c100300fda363658e10b23James Zern // Part 4: PSNR test with bit_match_mode_ = 0 3770a39d0a697ff3603e8c100300fda363658e10b23James Zern row_mt_mode_ = 1; 3780a39d0a697ff3603e8c100300fda363658e10b23James Zern 3790a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode using single thread. 3800a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = 1; 3810a39d0a697ff3603e8c100300fda363658e10b23James Zern init_flags_ = VPX_CODEC_USE_PSNR; 3820a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3830a39d0a697ff3603e8c100300fda363658e10b23James Zern const double single_thr_psnr = GetAveragePsnr(); 3840a39d0a697ff3603e8c100300fda363658e10b23James Zern 3850a39d0a697ff3603e8c100300fda363658e10b23James Zern // Encode using multiple threads. 3860a39d0a697ff3603e8c100300fda363658e10b23James Zern cfg_.g_threads = threads_; 3870a39d0a697ff3603e8c100300fda363658e10b23James Zern ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 3880a39d0a697ff3603e8c100300fda363658e10b23James Zern const double multi_thr_psnr = GetAveragePsnr(); 3890a39d0a697ff3603e8c100300fda363658e10b23James Zern 3900a39d0a697ff3603e8c100300fda363658e10b23James Zern EXPECT_NEAR(single_thr_psnr, multi_thr_psnr, 0.1); 3917ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian} 3927ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian 3930a39d0a697ff3603e8c100300fda363658e10b23James ZernINSTANTIATE_TEST_CASE_P( 3940a39d0a697ff3603e8c100300fda363658e10b23James Zern VP9, VPxFirstPassEncoderThreadTest, 3950a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Combine( 3960a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Values( 3970a39d0a697ff3603e8c100300fda363658e10b23James Zern static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)), 3980a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Values(::libvpx_test::kTwoPassGood), 3990a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Range(0, 4))); // cpu_used 4000a39d0a697ff3603e8c100300fda363658e10b23James Zern 4017bc9febe8749e98a3812a0dc4380ceae75c29450Johann// Split this into two instantiations so that we can distinguish 4027bc9febe8749e98a3812a0dc4380ceae75c29450Johann// between very slow runs ( ie cpu_speed 0 ) vs ones that can be 4037bc9febe8749e98a3812a0dc4380ceae75c29450Johann// run nightly by adding Large to the title. 4047bc9febe8749e98a3812a0dc4380ceae75c29450JohannINSTANTIATE_TEST_CASE_P( 4057bc9febe8749e98a3812a0dc4380ceae75c29450Johann VP9, VPxEncoderThreadTest, 4067bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Combine( 4077bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Values( 4087bc9febe8749e98a3812a0dc4380ceae75c29450Johann static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)), 4097bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Values(::libvpx_test::kTwoPassGood, 4107bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::libvpx_test::kOnePassGood, 4117bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::libvpx_test::kRealTime), 4120a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Range(3, 9), // cpu_used 4137bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Range(0, 3), // tile_columns 4147bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Range(2, 5))); // threads 4157bc9febe8749e98a3812a0dc4380ceae75c29450Johann 4167bc9febe8749e98a3812a0dc4380ceae75c29450JohannINSTANTIATE_TEST_CASE_P( 4177bc9febe8749e98a3812a0dc4380ceae75c29450Johann VP9Large, VPxEncoderThreadTest, 4187bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Combine( 4197bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Values( 4207bc9febe8749e98a3812a0dc4380ceae75c29450Johann static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)), 4217bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Values(::libvpx_test::kTwoPassGood, 4227bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::libvpx_test::kOnePassGood, 4237bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::libvpx_test::kRealTime), 4240a39d0a697ff3603e8c100300fda363658e10b23James Zern ::testing::Range(0, 3), // cpu_used 4257bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Range(0, 3), // tile_columns 4267bc9febe8749e98a3812a0dc4380ceae75c29450Johann ::testing::Range(2, 5))); // threads 4277bc9febe8749e98a3812a0dc4380ceae75c29450Johann 4287ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian} // namespace 429