datarate_test.cc revision 91037db265ecdd914a26e056cf69207b4f50924e
1/* 2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10#include "third_party/googletest/src/include/gtest/gtest.h" 11#include "test/codec_factory.h" 12#include "test/encode_test_driver.h" 13#include "test/i420_video_source.h" 14#include "test/util.h" 15 16namespace { 17 18class DatarateTest : public ::libvpx_test::EncoderTest, 19 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> { 20 public: 21 DatarateTest() : EncoderTest(GET_PARAM(0)) {} 22 23 protected: 24 virtual void SetUp() { 25 InitializeConfig(); 26 SetMode(GET_PARAM(1)); 27 ResetModel(); 28 } 29 30 virtual void ResetModel() { 31 last_pts_ = 0; 32 bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz; 33 frame_number_ = 0; 34 first_drop_ = 0; 35 bits_total_ = 0; 36 duration_ = 0.0; 37 } 38 39 virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, 40 ::libvpx_test::Encoder *encoder) { 41 const vpx_rational_t tb = video->timebase(); 42 timebase_ = static_cast<double>(tb.num) / tb.den; 43 duration_ = 0; 44 } 45 46 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { 47 // Time since last timestamp = duration. 48 vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; 49 50 // TODO(jimbankoski): Remove these lines when the issue: 51 // http://code.google.com/p/webm/issues/detail?id=496 is fixed. 52 // For now the codec assumes buffer starts at starting buffer rate 53 // plus one frame's time. 54 if (last_pts_ == 0) 55 duration = 1; 56 57 // Add to the buffer the bits we'd expect from a constant bitrate server. 58 bits_in_buffer_model_ += duration * timebase_ * cfg_.rc_target_bitrate 59 * 1000; 60 61 /* Test the buffer model here before subtracting the frame. Do so because 62 * the way the leaky bucket model works in libvpx is to allow the buffer to 63 * empty - and then stop showing frames until we've got enough bits to 64 * show one. As noted in comment below (issue 495), this does not currently 65 * apply to key frames. For now exclude key frames in condition below. */ 66 bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true: false; 67 if (!key_frame) { 68 ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame " 69 << pkt->data.frame.pts; 70 } 71 72 const int frame_size_in_bits = pkt->data.frame.sz * 8; 73 74 // Subtract from the buffer the bits associated with a played back frame. 75 bits_in_buffer_model_ -= frame_size_in_bits; 76 77 // Update the running total of bits for end of test datarate checks. 78 bits_total_ += frame_size_in_bits ; 79 80 // If first drop not set and we have a drop set it to this time. 81 if (!first_drop_ && duration > 1) 82 first_drop_ = last_pts_ + 1; 83 84 // Update the most recent pts. 85 last_pts_ = pkt->data.frame.pts; 86 87 // We update this so that we can calculate the datarate minus the last 88 // frame encoded in the file. 89 bits_in_last_frame_ = frame_size_in_bits; 90 91 ++frame_number_; 92 } 93 94 virtual void EndPassHook(void) { 95 if (bits_total_) { 96 const double file_size_in_kb = bits_total_ / 1000; /* bits per kilobit */ 97 98 duration_ = (last_pts_ + 1) * timebase_; 99 100 // Effective file datarate includes the time spent prebuffering. 101 effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0 102 / (cfg_.rc_buf_initial_sz / 1000.0 + duration_); 103 104 file_datarate_ = file_size_in_kb / duration_; 105 } 106 } 107 108 vpx_codec_pts_t last_pts_; 109 int bits_in_buffer_model_; 110 double timebase_; 111 int frame_number_; 112 vpx_codec_pts_t first_drop_; 113 int64_t bits_total_; 114 double duration_; 115 double file_datarate_; 116 double effective_datarate_; 117 int bits_in_last_frame_; 118}; 119 120TEST_P(DatarateTest, BasicBufferModel) { 121 cfg_.rc_buf_initial_sz = 500; 122 cfg_.rc_dropframe_thresh = 1; 123 cfg_.rc_max_quantizer = 56; 124 cfg_.rc_end_usage = VPX_CBR; 125 // 2 pass cbr datarate control has a bug hidden by the small # of 126 // frames selected in this encode. The problem is that even if the buffer is 127 // negative we produce a keyframe on a cutscene. Ignoring datarate 128 // constraints 129 // TODO(jimbankoski): ( Fix when issue 130 // http://code.google.com/p/webm/issues/detail?id=495 is addressed. ) 131 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 132 30, 1, 0, 140); 133 134 // There is an issue for low bitrates in real-time mode, where the 135 // effective_datarate slightly overshoots the target bitrate. 136 // This is same the issue as noted about (#495). 137 // TODO(jimbankoski/marpan): Update test to run for lower bitrates (< 100), 138 // when the issue is resolved. 139 for (int i = 100; i < 800; i += 200) { 140 cfg_.rc_target_bitrate = i; 141 ResetModel(); 142 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 143 ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_) 144 << " The datarate for the file exceeds the target!"; 145 146 ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3) 147 << " The datarate for the file missed the target!"; 148 } 149} 150 151TEST_P(DatarateTest, ChangingDropFrameThresh) { 152 cfg_.rc_buf_initial_sz = 500; 153 cfg_.rc_max_quantizer = 36; 154 cfg_.rc_end_usage = VPX_CBR; 155 cfg_.rc_target_bitrate = 200; 156 cfg_.kf_mode = VPX_KF_DISABLED; 157 158 const int frame_count = 40; 159 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 160 30, 1, 0, frame_count); 161 162 // Here we check that the first dropped frame gets earlier and earlier 163 // as the drop frame threshold is increased. 164 165 const int kDropFrameThreshTestStep = 30; 166 vpx_codec_pts_t last_drop = frame_count; 167 for (int i = 1; i < 91; i += kDropFrameThreshTestStep) { 168 cfg_.rc_dropframe_thresh = i; 169 ResetModel(); 170 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 171 ASSERT_LE(first_drop_, last_drop) 172 << " The first dropped frame for drop_thresh " << i 173 << " > first dropped frame for drop_thresh " 174 << i - kDropFrameThreshTestStep; 175 last_drop = first_drop_; 176 } 177} 178 179VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES); 180 181} // namespace 182