blob: f020a99382ced71b4d6f13788fec9fd19848f00f [file] [log] [blame]
Jim Bankoski533470c2012-10-29 19:54:06 -07001/*
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 */
John Koleszar706cafe2013-01-18 11:51:12 -080010#include "third_party/googletest/src/include/gtest/gtest.h"
11#include "test/codec_factory.h"
Jim Bankoski533470c2012-10-29 19:54:06 -070012#include "test/encode_test_driver.h"
13#include "test/i420_video_source.h"
John Koleszar706cafe2013-01-18 11:51:12 -080014#include "test/util.h"
15
Jim Bankoski533470c2012-10-29 19:54:06 -070016namespace {
17
18class DatarateTest : public ::libvpx_test::EncoderTest,
John Koleszar706cafe2013-01-18 11:51:12 -080019 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
20 public:
21 DatarateTest() : EncoderTest(GET_PARAM(0)) {}
22
Jim Bankoski533470c2012-10-29 19:54:06 -070023 protected:
24 virtual void SetUp() {
25 InitializeConfig();
John Koleszar706cafe2013-01-18 11:51:12 -080026 SetMode(GET_PARAM(1));
Jim Bankoski533470c2012-10-29 19:54:06 -070027 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
Jim Bankoski533470c2012-10-29 19:54:06 -070039 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
Marco Paniconicd7f6842012-11-14 15:05:06 -080064 * 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 }
Jim Bankoski533470c2012-10-29 19:54:06 -070071
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.
Yaowu Xuafffa3d2013-09-05 08:45:56 -070078 bits_total_ += frame_size_in_bits;
Jim Bankoski533470c2012-10-29 19:54:06 -070079
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
Marco Paniconicd7f6842012-11-14 15:05:06 -0800134 // 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) {
Jim Bankoski533470c2012-10-29 19:54:06 -0700140 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
John Koleszar706cafe2013-01-18 11:51:12 -0800179VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES);
180
Jim Bankoski533470c2012-10-29 19:54:06 -0700181} // namespace