From 50c59cdae9cf59fbe248013fff5c4ad6c0c54138 Mon Sep 17 00:00:00 2001 From: Deb Mukherjee Date: Wed, 15 Oct 2014 16:40:12 -0700 Subject: [PATCH] Adds a set of end-to-end encode tests Covers all profiles and input formats. The tests check if the encode succeeds and if the psnr is sane. Change-Id: I195a5330debf92562846121819b6eaf961e27c01 --- test/i420_video_source.h | 94 ++-------------------- test/test-data.mk | 3 + test/test-data.sha1 | 3 + test/test.mk | 2 + test/vp9_end_to_end_test.cc | 155 ++++++++++++++++++++++++++++++++++++ test/yuv_video_source.h | 151 +++++++++++++++++++++++++++++++++++ 6 files changed, 320 insertions(+), 88 deletions(-) create mode 100644 test/vp9_end_to_end_test.cc create mode 100644 test/yuv_video_source.h diff --git a/test/i420_video_source.h b/test/i420_video_source.h index c3315f9ce..0a184805c 100644 --- a/test/i420_video_source.h +++ b/test/i420_video_source.h @@ -13,104 +13,22 @@ #include #include -#include "test/video_source.h" +#include "test/yuv_video_source.h" namespace libvpx_test { // This class extends VideoSource to allow parsing of raw yv12 // so that we can do actual file encodes. -class I420VideoSource : public VideoSource { +class I420VideoSource : public YUVVideoSource { public: I420VideoSource(const std::string &file_name, unsigned int width, unsigned int height, int rate_numerator, int rate_denominator, unsigned int start, int limit) - : file_name_(file_name), - input_file_(NULL), - img_(NULL), - start_(start), - limit_(limit), - frame_(0), - width_(0), - height_(0), - framerate_numerator_(rate_numerator), - framerate_denominator_(rate_denominator) { - // This initializes raw_sz_, width_, height_ and allocates an img. - SetSize(width, height); - } - - virtual ~I420VideoSource() { - vpx_img_free(img_); - if (input_file_) - fclose(input_file_); - } - - virtual void Begin() { - if (input_file_) - fclose(input_file_); - input_file_ = OpenTestDataFile(file_name_); - ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: " - << file_name_; - if (start_) { - fseek(input_file_, static_cast(raw_sz_) * start_, SEEK_SET); - } - - frame_ = start_; - FillFrame(); - } - - virtual void Next() { - ++frame_; - FillFrame(); - } - - virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; } - - // Models a stream where Timebase = 1/FPS, so pts == frame. - virtual vpx_codec_pts_t pts() const { return frame_; } - - virtual unsigned long duration() const { return 1; } - - virtual vpx_rational_t timebase() const { - const vpx_rational_t t = { framerate_denominator_, framerate_numerator_ }; - return t; - } - - virtual unsigned int frame() const { return frame_; } - - virtual unsigned int limit() const { return limit_; } - - void SetSize(unsigned int width, unsigned int height) { - if (width != width_ || height != height_) { - vpx_img_free(img_); - img_ = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, width, height, 1); - ASSERT_TRUE(img_ != NULL); - width_ = width; - height_ = height; - raw_sz_ = width * height * 3 / 2; - } - } - - virtual void FillFrame() { - ASSERT_TRUE(input_file_ != NULL); - // Read a frame from input_file. - if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) { - limit_ = frame_; - } - } - - protected: - std::string file_name_; - FILE *input_file_; - vpx_image_t *img_; - size_t raw_sz_; - unsigned int start_; - unsigned int limit_; - unsigned int frame_; - unsigned int width_; - unsigned int height_; - int framerate_numerator_; - int framerate_denominator_; + : YUVVideoSource(file_name, VPX_IMG_FMT_I420, + width, height, + rate_numerator, rate_denominator, + start, limit) {} }; } // namespace libvpx_test diff --git a/test/test-data.mk b/test/test-data.mk index c50b1c746..e4dae3a95 100644 --- a/test/test-data.mk +++ b/test/test-data.mk @@ -7,12 +7,15 @@ LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_odd.yuv LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_420.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_422.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_444.y4m +LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_440.yuv LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_420.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_422.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_444.y4m +LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_440.yuv LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_420.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_422.y4m LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_444.y4m +LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_440.yuv LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m diff --git a/test/test-data.sha1 b/test/test-data.sha1 index 2dc64d334..69d1d2f25 100644 --- a/test/test-data.sha1 +++ b/test/test-data.sha1 @@ -17,12 +17,15 @@ d637297561dd904eb2c97a9015deeb31c4a1e8d2 invalid-vp90-2-08-tile_1x4_frame_paral a432f96ff0a787268e2f94a8092ab161a18d1b06 park_joy_90p_10_420.y4m 0b194cc312c3a2e84d156a221b0a5eb615dfddc5 park_joy_90p_10_422.y4m ff0e0a21dc2adc95b8c1b37902713700655ced17 park_joy_90p_10_444.y4m +c934da6fb8cc54ee2a8c17c54cf6076dac37ead0 park_joy_90p_10_440.yuv 614c32ae1eca391e867c70d19974f0d62664dd99 park_joy_90p_12_420.y4m c92825f1ea25c5c37855083a69faac6ac4641a9e park_joy_90p_12_422.y4m b592189b885b6cc85db55cc98512a197d73d3b34 park_joy_90p_12_444.y4m +82c1bfcca368c2f22bad7d693d690d5499ecdd11 park_joy_90p_12_440.yuv 4e0eb61e76f0684188d9bc9f3ce61f6b6b77bb2c park_joy_90p_8_420.y4m 7a193ff7dfeb96ba5f82b2afd7afa9e1fe83d947 park_joy_90p_8_422.y4m bdb7856e6bc93599bdda05c2e773a9f22b6c6d03 park_joy_90p_8_444.y4m +81e1f3843748438b8f2e71db484eb22daf72e939 park_joy_90p_8_440.yuv b1f1c3ec79114b9a0651af24ce634afb44a9a419 rush_hour_444.y4m 5184c46ddca8b1fadd16742e8500115bc8f749da vp80-00-comprehensive-001.ivf 65bf1bbbced81b97bd030f376d1b7f61a224793f vp80-00-comprehensive-002.ivf diff --git a/test/test.mk b/test/test.mk index 1bd732d51..30c13a1d5 100644 --- a/test/test.mk +++ b/test/test.mk @@ -23,6 +23,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += datarate_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += error_resilience_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += i420_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += y4m_video_source.h +LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += yuv_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += altref_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += config_test.cc @@ -38,6 +39,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += cpu_speed_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += frame_size_tests.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += resize_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_lossless_test.cc +LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_end_to_end_test.cc LIBVPX_TEST_SRCS-yes += decode_test_driver.cc LIBVPX_TEST_SRCS-yes += decode_test_driver.h diff --git a/test/vp9_end_to_end_test.cc b/test/vp9_end_to_end_test.cc new file mode 100644 index 000000000..a8f679342 --- /dev/null +++ b/test/vp9_end_to_end_test.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014 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. + */ + +#include "test/codec_factory.h" +#include "test/encode_test_driver.h" +#include "test/y4m_video_source.h" +#include "test/yuv_video_source.h" +#include "test/util.h" +#include "third_party/googletest/src/include/gtest/gtest.h" + +namespace { + +const unsigned int kWidth = 160; +const unsigned int kHeight = 90; +const unsigned int kFramerate = 50; +const unsigned int kFrames = 10; +const int kBitrate = 500; +const int kCpuUsed = 2; +const double psnr_threshold = 35.0; + +typedef struct { + const char *filename; + unsigned int input_bit_depth; + vpx_img_fmt fmt; + vpx_bit_depth_t bit_depth; + unsigned int profile; +} TestVideoParam; + +const TestVideoParam TestVectors[] = { + {"park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0}, + {"park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422, VPX_BITS_8, 1}, + {"park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444, VPX_BITS_8, 1}, + {"park_joy_90p_8_440.yuv", 8, VPX_IMG_FMT_I440, VPX_BITS_8, 1}, +#if CONFIG_VP9_HIGHBITDEPTH + {"park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016, VPX_BITS_10, 2}, + {"park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216, VPX_BITS_10, 3}, + {"park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416, VPX_BITS_10, 3}, + {"park_joy_90p_10_440.yuv", 10, VPX_IMG_FMT_I44016, VPX_BITS_10, 3}, + {"park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016, VPX_BITS_12, 2}, + {"park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216, VPX_BITS_12, 3}, + {"park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416, VPX_BITS_12, 3}, + {"park_joy_90p_12_440.yuv", 12, VPX_IMG_FMT_I44016, VPX_BITS_12, 3}, +#endif // CONFIG_VP9_HIGHBITDEPTH +}; + +int is_extension_y4m(const char *filename) { + const char *dot = strrchr(filename, '.'); + if (!dot || dot == filename) + return 0; + else + return !strcmp(dot, ".y4m"); +} + +class EndToEndTestLarge + : public ::libvpx_test::EncoderTest, + public ::libvpx_test::CodecTestWith2Params { + protected: + EndToEndTestLarge() + : EncoderTest(GET_PARAM(0)), + psnr_(0.0), + nframes_(0), + encoding_mode_(GET_PARAM(1)) { + } + + virtual ~EndToEndTestLarge() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + if (encoding_mode_ != ::libvpx_test::kRealTime) { + cfg_.g_lag_in_frames = 5; + cfg_.rc_end_usage = VPX_VBR; + } else { + cfg_.g_lag_in_frames = 0; + cfg_.rc_end_usage = VPX_CBR; + } + test_video_param_ = GET_PARAM(2); + } + + virtual void BeginPassHook(unsigned int) { + psnr_ = 0.0; + nframes_ = 0; + } + + virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { + psnr_ += pkt->data.psnr.psnr[0]; + nframes_++; + } + + virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, + ::libvpx_test::Encoder *encoder) { + if (video->frame() == 1) { + encoder->Control(VP8E_SET_CPUUSED, kCpuUsed); + if (encoding_mode_ != ::libvpx_test::kRealTime) { + encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); + encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7); + encoder->Control(VP8E_SET_ARNR_STRENGTH, 5); + encoder->Control(VP8E_SET_ARNR_TYPE, 3); + } + } + } + + double GetAveragePsnr() const { + if (nframes_) + return psnr_ / nframes_; + return 0.0; + } + + TestVideoParam test_video_param_; + + private: + double psnr_; + unsigned int nframes_; + libvpx_test::TestMode encoding_mode_; +}; + +TEST_P(EndToEndTestLarge, EndtoEndPSNRTest) { + cfg_.rc_target_bitrate = kBitrate; + cfg_.g_error_resilient = 0; + cfg_.g_profile = test_video_param_.profile; + cfg_.g_input_bit_depth = test_video_param_.input_bit_depth; + cfg_.g_bit_depth = test_video_param_.bit_depth; + init_flags_ = VPX_CODEC_USE_PSNR; + + libvpx_test::VideoSource *video; + if (is_extension_y4m(test_video_param_.filename)) { + video = new libvpx_test::Y4mVideoSource(test_video_param_.filename, + 0, kFrames); + } else { + video = new libvpx_test::YUVVideoSource(test_video_param_.filename, + test_video_param_.fmt, + kWidth, kHeight, + kFramerate, 1, 0, kFrames); + } + + ASSERT_NO_FATAL_FAILURE(RunLoop(video)); + const double psnr = GetAveragePsnr(); + EXPECT_GT(psnr, psnr_threshold); + delete(video); +} + +VP9_INSTANTIATE_TEST_CASE( + EndToEndTestLarge, + ::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood), + ::testing::ValuesIn(TestVectors)); + +} // namespace diff --git a/test/yuv_video_source.h b/test/yuv_video_source.h new file mode 100644 index 000000000..3c852b242 --- /dev/null +++ b/test/yuv_video_source.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2014 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. + */ +#ifndef TEST_YUV_VIDEO_SOURCE_H_ +#define TEST_YUV_VIDEO_SOURCE_H_ + +#include +#include +#include + +#include "test/video_source.h" +#include "vpx/vpx_image.h" + +namespace libvpx_test { + +// This class extends VideoSource to allow parsing of raw YUV +// formats of various color sampling and bit-depths so that we can +// do actual file encodes. +class YUVVideoSource : public VideoSource { + public: + YUVVideoSource(const std::string &file_name, vpx_img_fmt format, + unsigned int width, unsigned int height, + int rate_numerator, int rate_denominator, + unsigned int start, int limit) + : file_name_(file_name), + input_file_(NULL), + img_(NULL), + start_(start), + limit_(limit), + frame_(0), + width_(0), + height_(0), + format_(VPX_IMG_FMT_NONE), + framerate_numerator_(rate_numerator), + framerate_denominator_(rate_denominator) { + // This initializes format_, raw_size_, width_, height_ and allocates img. + SetSize(width, height, format); + } + + virtual ~YUVVideoSource() { + vpx_img_free(img_); + if (input_file_) + fclose(input_file_); + } + + virtual void Begin() { + if (input_file_) + fclose(input_file_); + input_file_ = OpenTestDataFile(file_name_); + ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: " + << file_name_; + if (start_) + fseek(input_file_, static_cast(raw_size_) * start_, SEEK_SET); + + frame_ = start_; + FillFrame(); + } + + virtual void Next() { + ++frame_; + FillFrame(); + } + + virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; } + + // Models a stream where Timebase = 1/FPS, so pts == frame. + virtual vpx_codec_pts_t pts() const { return frame_; } + + virtual unsigned long duration() const { return 1; } + + virtual vpx_rational_t timebase() const { + const vpx_rational_t t = { framerate_denominator_, framerate_numerator_ }; + return t; + } + + virtual unsigned int frame() const { return frame_; } + + virtual unsigned int limit() const { return limit_; } + + virtual void SetSize(unsigned int width, unsigned int height, + vpx_img_fmt format) { + if (width != width_ || height != height_ || format != format_) { + vpx_img_free(img_); + img_ = vpx_img_alloc(NULL, format, width, height, 1); + ASSERT_TRUE(img_ != NULL); + width_ = width; + height_ = height; + format_ = format; + switch (format) { + case VPX_IMG_FMT_I420: + raw_size_ = width * height * 3 / 2; + break; + case VPX_IMG_FMT_I422: + raw_size_ = width * height * 2; + break; + case VPX_IMG_FMT_I440: + raw_size_ = width * height * 2; + break; + case VPX_IMG_FMT_I444: + raw_size_ = width * height * 3; + break; + case VPX_IMG_FMT_I42016: + raw_size_ = width * height * 3; + break; + case VPX_IMG_FMT_I42216: + raw_size_ = width * height * 4; + break; + case VPX_IMG_FMT_I44016: + raw_size_ = width * height * 4; + break; + case VPX_IMG_FMT_I44416: + raw_size_ = width * height * 6; + break; + default: + ASSERT_TRUE(0); + } + } + } + + virtual void FillFrame() { + ASSERT_TRUE(input_file_ != NULL); + // Read a frame from input_file. + if (fread(img_->img_data, raw_size_, 1, input_file_) == 0) { + limit_ = frame_; + } + } + + protected: + std::string file_name_; + FILE *input_file_; + vpx_image_t *img_; + size_t raw_size_; + unsigned int start_; + unsigned int limit_; + unsigned int frame_; + unsigned int width_; + unsigned int height_; + vpx_img_fmt format_; + int framerate_numerator_; + int framerate_denominator_; +}; + +} // namespace libvpx_test + +#endif // TEST_YUV_VIDEO_SOURCE_H_ -- 2.40.0