| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/capture/content/smooth_event_sampler.h" | 5 #include "media/capture/content/smooth_event_sampler.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 return sampler->ShouldSample(); | 21 return sampler->ShouldSample(); |
| 22 } | 22 } |
| 23 | 23 |
| 24 void SteadyStateSampleAndAdvance(base::TimeDelta vsync, | 24 void SteadyStateSampleAndAdvance(base::TimeDelta vsync, |
| 25 SmoothEventSampler* sampler, | 25 SmoothEventSampler* sampler, |
| 26 base::TimeTicks* t) { | 26 base::TimeTicks* t) { |
| 27 ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t)); | 27 ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t)); |
| 28 ASSERT_TRUE(sampler->HasUnrecordedEvent()); | 28 ASSERT_TRUE(sampler->HasUnrecordedEvent()); |
| 29 sampler->RecordSample(); | 29 sampler->RecordSample(); |
| 30 ASSERT_FALSE(sampler->HasUnrecordedEvent()); | 30 ASSERT_FALSE(sampler->HasUnrecordedEvent()); |
| 31 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); | |
| 32 *t += vsync; | 31 *t += vsync; |
| 33 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); | |
| 34 } | 32 } |
| 35 | 33 |
| 36 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync, | 34 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync, |
| 37 SmoothEventSampler* sampler, | 35 SmoothEventSampler* sampler, |
| 38 base::TimeTicks* t) { | 36 base::TimeTicks* t) { |
| 39 ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t)); | 37 ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t)); |
| 40 ASSERT_TRUE(sampler->HasUnrecordedEvent()); | 38 ASSERT_TRUE(sampler->HasUnrecordedEvent()); |
| 41 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); | |
| 42 *t += vsync; | 39 *t += vsync; |
| 43 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); | |
| 44 } | 40 } |
| 45 | 41 |
| 46 base::TimeTicks InitialTestTimeTicks() { | 42 base::TimeTicks InitialTestTimeTicks() { |
| 47 return base::TimeTicks() + base::TimeDelta::FromSeconds(1); | 43 return base::TimeTicks() + base::TimeDelta::FromSeconds(1); |
| 48 } | 44 } |
| 49 | 45 |
| 50 void TestRedundantCaptureStrategy(base::TimeDelta capture_period, | |
| 51 int redundant_capture_goal, | |
| 52 SmoothEventSampler* sampler, | |
| 53 base::TimeTicks* t) { | |
| 54 // Before any events have been considered, we're overdue for sampling. | |
| 55 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)); | |
| 56 | |
| 57 // Consider the first event. We want to sample that. | |
| 58 ASSERT_FALSE(sampler->HasUnrecordedEvent()); | |
| 59 ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t)); | |
| 60 ASSERT_TRUE(sampler->HasUnrecordedEvent()); | |
| 61 sampler->RecordSample(); | |
| 62 ASSERT_FALSE(sampler->HasUnrecordedEvent()); | |
| 63 | |
| 64 // After more than 250 ms has passed without considering an event, we should | |
| 65 // repeatedly be overdue for sampling. However, once the redundant capture | |
| 66 // goal is achieved, we should no longer be overdue for sampling. | |
| 67 *t += base::TimeDelta::FromMilliseconds(250); | |
| 68 for (int i = 0; i < redundant_capture_goal; i++) { | |
| 69 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | |
| 70 ASSERT_FALSE(sampler->HasUnrecordedEvent()); | |
| 71 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)) | |
| 72 << "Should sample until redundant capture goal is hit"; | |
| 73 sampler->RecordSample(); | |
| 74 *t += capture_period; // Timer fires once every capture period. | |
| 75 } | |
| 76 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)) | |
| 77 << "Should not be overdue once redundant capture goal achieved."; | |
| 78 } | |
| 79 | 46 |
| 80 } // namespace | 47 } // namespace |
| 81 | 48 |
| 82 // 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains | 49 // 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains |
| 83 // much more comprehensive before/after/edge-case scenarios than the others. | 50 // much more comprehensive before/after/edge-case scenarios than the others. |
| 84 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) { | 51 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) { |
| 85 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | 52 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
| 86 const int redundant_capture_goal = 200; | |
| 87 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; | 53 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; |
| 88 | 54 |
| 89 SmoothEventSampler sampler(capture_period, redundant_capture_goal); | 55 SmoothEventSampler sampler(capture_period); |
| 90 base::TimeTicks t = InitialTestTimeTicks(); | 56 base::TimeTicks t = InitialTestTimeTicks(); |
| 91 | 57 |
| 92 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, &sampler, | |
| 93 &t); | |
| 94 | |
| 95 // Steady state, we should capture every other vsync, indefinitely. | 58 // Steady state, we should capture every other vsync, indefinitely. |
| 96 for (int i = 0; i < 100; i++) { | 59 for (int i = 0; i < 100; i++) { |
| 97 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 60 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 98 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 61 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 99 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 62 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 100 } | 63 } |
| 101 | 64 |
| 102 // Now pretend we're limited by backpressure in the pipeline. In this scenario | 65 // Now pretend we're limited by backpressure in the pipeline. In this scenario |
| 103 // case we are adding events but not sampling them. | 66 // case we are adding events but not sampling them. |
| 104 for (int i = 0; i < 20; i++) { | 67 for (int i = 0; i < 20; i++) { |
| 105 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 68 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 106 ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t)); | |
| 107 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | 69 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
| 108 ASSERT_TRUE(sampler.HasUnrecordedEvent()); | 70 ASSERT_TRUE(sampler.HasUnrecordedEvent()); |
| 109 t += vsync; | 71 t += vsync; |
| 110 } | 72 } |
| 111 | 73 |
| 112 // Now suppose we can sample again. We should be back in the steady state, | 74 // Now suppose we can sample again. We should be back in the steady state, |
| 113 // but at a different phase. | 75 // but at a different phase. |
| 114 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); | |
| 115 for (int i = 0; i < 100; i++) { | 76 for (int i = 0; i < 100; i++) { |
| 116 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 77 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 117 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 78 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 118 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 79 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 119 } | 80 } |
| 120 } | 81 } |
| 121 | 82 |
| 122 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped. | 83 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped. |
| 123 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) { | 84 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) { |
| 124 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | 85 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
| 125 const int redundant_capture_goal = 2; | |
| 126 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50; | 86 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50; |
| 127 | 87 |
| 128 SmoothEventSampler sampler(capture_period, redundant_capture_goal); | 88 SmoothEventSampler sampler(capture_period); |
| 129 base::TimeTicks t = InitialTestTimeTicks(); | 89 base::TimeTicks t = InitialTestTimeTicks(); |
| 130 | 90 |
| 131 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, &sampler, | |
| 132 &t); | |
| 133 | |
| 134 // Steady state, we should capture 1st, 2nd and 4th frames out of every five | 91 // Steady state, we should capture 1st, 2nd and 4th frames out of every five |
| 135 // frames, indefinitely. | 92 // frames, indefinitely. |
| 136 for (int i = 0; i < 100; i++) { | 93 for (int i = 0; i < 100; i++) { |
| 137 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 94 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 138 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 95 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 139 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 96 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 140 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 97 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 141 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 98 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 142 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 99 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 143 } | 100 } |
| 144 | 101 |
| 145 // Now pretend we're limited by backpressure in the pipeline. In this scenario | 102 // Now pretend we're limited by backpressure in the pipeline. In this scenario |
| 146 // case we are adding events but not sampling them. | 103 // case we are adding events but not sampling them. |
| 147 for (int i = 0; i < 20; i++) { | 104 for (int i = 0; i < 20; i++) { |
| 148 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 105 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 149 ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t)); | |
| 150 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | 106 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
| 151 t += vsync; | 107 t += vsync; |
| 152 } | 108 } |
| 153 | 109 |
| 154 // Now suppose we can sample again. We should be back in the steady state | 110 // Now suppose we can sample again. We should be back in the steady state |
| 155 // again. | 111 // again. |
| 156 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); | |
| 157 for (int i = 0; i < 100; i++) { | 112 for (int i = 0; i < 100; i++) { |
| 158 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 113 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 159 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 114 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 160 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 115 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 161 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 116 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 162 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 117 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 163 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 118 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 164 } | 119 } |
| 165 } | 120 } |
| 166 | 121 |
| 167 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped. | 122 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped. |
| 168 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) { | 123 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) { |
| 169 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | 124 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
| 170 const int redundant_capture_goal = 32; | |
| 171 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75; | 125 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75; |
| 172 | 126 |
| 173 SmoothEventSampler sampler(capture_period, redundant_capture_goal); | 127 SmoothEventSampler sampler(capture_period); |
| 174 base::TimeTicks t = InitialTestTimeTicks(); | 128 base::TimeTicks t = InitialTestTimeTicks(); |
| 175 | 129 |
| 176 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, &sampler, | |
| 177 &t); | |
| 178 | |
| 179 // Steady state, we should capture 1st and 3rd frames out of every five | 130 // Steady state, we should capture 1st and 3rd frames out of every five |
| 180 // frames, indefinitely. | 131 // frames, indefinitely. |
| 181 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 132 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 182 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 133 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 183 for (int i = 0; i < 100; i++) { | 134 for (int i = 0; i < 100; i++) { |
| 184 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 135 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 185 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 136 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 186 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 137 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 187 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 138 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 188 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 139 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 189 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 140 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 190 } | 141 } |
| 191 | 142 |
| 192 // Now pretend we're limited by backpressure in the pipeline. In this scenario | 143 // Now pretend we're limited by backpressure in the pipeline. In this scenario |
| 193 // case we are adding events but not sampling them. | 144 // case we are adding events but not sampling them. |
| 194 for (int i = 0; i < 20; i++) { | 145 for (int i = 0; i < 20; i++) { |
| 195 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 146 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 196 ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t)); | |
| 197 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | 147 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
| 198 t += vsync; | 148 t += vsync; |
| 199 } | 149 } |
| 200 | 150 |
| 201 // Now suppose we can sample again. We capture the next frame, and not the one | 151 // Now suppose we can sample again. We capture the next frame, and not the one |
| 202 // after that, and then we're back in the steady state again. | 152 // after that, and then we're back in the steady state again. |
| 203 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); | |
| 204 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 153 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 205 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 154 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 206 for (int i = 0; i < 100; i++) { | 155 for (int i = 0; i < 100; i++) { |
| 207 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 156 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 208 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 157 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 209 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 158 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 210 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 159 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 211 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 160 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 212 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 161 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 213 } | 162 } |
| 214 } | 163 } |
| 215 | 164 |
| 216 // 30Hz sampled at 30Hz should produce 30Hz. | 165 // 30Hz sampled at 30Hz should produce 30Hz. |
| 217 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) { | 166 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) { |
| 218 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | 167 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
| 219 const int redundant_capture_goal = 1; | |
| 220 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30; | 168 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30; |
| 221 | 169 |
| 222 SmoothEventSampler sampler(capture_period, redundant_capture_goal); | 170 SmoothEventSampler sampler(capture_period); |
| 223 base::TimeTicks t = InitialTestTimeTicks(); | 171 base::TimeTicks t = InitialTestTimeTicks(); |
| 224 | 172 |
| 225 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, &sampler, | |
| 226 &t); | |
| 227 | |
| 228 // Steady state, we should capture every vsync, indefinitely. | 173 // Steady state, we should capture every vsync, indefinitely. |
| 229 for (int i = 0; i < 200; i++) { | 174 for (int i = 0; i < 200; i++) { |
| 230 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 175 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 231 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 176 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 232 } | 177 } |
| 233 | 178 |
| 234 // Now pretend we're limited by backpressure in the pipeline. In this scenario | 179 // Now pretend we're limited by backpressure in the pipeline. In this scenario |
| 235 // case we are adding events but not sampling them. | 180 // case we are adding events but not sampling them. |
| 236 for (int i = 0; i < 10; i++) { | 181 for (int i = 0; i < 10; i++) { |
| 237 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 182 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 238 ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t)); | |
| 239 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | 183 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
| 240 t += vsync; | 184 t += vsync; |
| 241 } | 185 } |
| 242 | 186 |
| 243 // Now suppose we can sample again. We should be back in the steady state. | 187 // Now suppose we can sample again. We should be back in the steady state. |
| 244 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); | |
| 245 for (int i = 0; i < 100; i++) { | 188 for (int i = 0; i < 100; i++) { |
| 246 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 189 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 247 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 190 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 248 } | 191 } |
| 249 } | 192 } |
| 250 | 193 |
| 251 // 24Hz sampled at 30Hz should produce 24Hz. | 194 // 24Hz sampled at 30Hz should produce 24Hz. |
| 252 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) { | 195 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) { |
| 253 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | 196 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; |
| 254 const int redundant_capture_goal = 333; | |
| 255 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24; | 197 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24; |
| 256 | 198 |
| 257 SmoothEventSampler sampler(capture_period, redundant_capture_goal); | 199 SmoothEventSampler sampler(capture_period); |
| 258 base::TimeTicks t = InitialTestTimeTicks(); | 200 base::TimeTicks t = InitialTestTimeTicks(); |
| 259 | 201 |
| 260 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, &sampler, | |
| 261 &t); | |
| 262 | |
| 263 // Steady state, we should capture every vsync, indefinitely. | 202 // Steady state, we should capture every vsync, indefinitely. |
| 264 for (int i = 0; i < 200; i++) { | 203 for (int i = 0; i < 200; i++) { |
| 265 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 204 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 266 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 205 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 267 } | 206 } |
| 268 | 207 |
| 269 // Now pretend we're limited by backpressure in the pipeline. In this scenario | 208 // Now pretend we're limited by backpressure in the pipeline. In this scenario |
| 270 // case we are adding events but not sampling them. | 209 // case we are adding events but not sampling them. |
| 271 for (int i = 0; i < 10; i++) { | 210 for (int i = 0; i < 10; i++) { |
| 272 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 211 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 273 ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t)); | |
| 274 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | 212 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); |
| 275 t += vsync; | 213 t += vsync; |
| 276 } | 214 } |
| 277 | 215 |
| 278 // Now suppose we can sample again. We should be back in the steady state. | 216 // Now suppose we can sample again. We should be back in the steady state. |
| 279 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); | |
| 280 for (int i = 0; i < 100; i++) { | 217 for (int i = 0; i < 100; i++) { |
| 281 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 218 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 282 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 219 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 283 } | 220 } |
| 284 } | 221 } |
| 285 | 222 |
| 286 // Tests that changing the minimum capture period during usage results in the | 223 // Tests that changing the minimum capture period during usage results in the |
| 287 // desired behavior. | 224 // desired behavior. |
| 288 TEST(SmoothEventSamplerTest, Sample60HertzWithVariedCapturePeriods) { | 225 TEST(SmoothEventSamplerTest, Sample60HertzWithVariedCapturePeriods) { |
| 289 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; | 226 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; |
| 290 const base::TimeDelta one_to_one_period = vsync; | 227 const base::TimeDelta one_to_one_period = vsync; |
| 291 const base::TimeDelta two_to_one_period = vsync * 2; | 228 const base::TimeDelta two_to_one_period = vsync * 2; |
| 292 const base::TimeDelta two_and_three_to_one_period = | 229 const base::TimeDelta two_and_three_to_one_period = |
| 293 base::TimeDelta::FromSeconds(1) / 24; | 230 base::TimeDelta::FromSeconds(1) / 24; |
| 294 const int redundant_capture_goal = 1; | |
| 295 | 231 |
| 296 SmoothEventSampler sampler(one_to_one_period, redundant_capture_goal); | 232 SmoothEventSampler sampler(one_to_one_period); |
| 297 base::TimeTicks t = InitialTestTimeTicks(); | 233 base::TimeTicks t = InitialTestTimeTicks(); |
| 298 | 234 |
| 299 TestRedundantCaptureStrategy(one_to_one_period, redundant_capture_goal, | |
| 300 &sampler, &t); | |
| 301 | |
| 302 // With the capture rate at 60 Hz, we should capture every vsync. | 235 // With the capture rate at 60 Hz, we should capture every vsync. |
| 303 for (int i = 0; i < 100; i++) { | 236 for (int i = 0; i < 100; i++) { |
| 304 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 237 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 305 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 238 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 306 } | 239 } |
| 307 | 240 |
| 308 // Now change to the capture rate to 30 Hz, and we should capture every other | 241 // Now change to the capture rate to 30 Hz, and we should capture every other |
| 309 // vsync. | 242 // vsync. |
| 310 sampler.SetMinCapturePeriod(two_to_one_period); | 243 sampler.SetMinCapturePeriod(two_to_one_period); |
| 311 for (int i = 0; i < 100; i++) { | 244 for (int i = 0; i < 100; i++) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 328 for (int i = 0; i < 100; i++) { | 261 for (int i = 0; i < 100; i++) { |
| 329 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); | 262 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); |
| 330 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 263 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 331 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 264 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 332 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 265 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 333 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); | 266 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); |
| 334 SteadyStateSampleAndAdvance(vsync, &sampler, &t); | 267 SteadyStateSampleAndAdvance(vsync, &sampler, &t); |
| 335 } | 268 } |
| 336 } | 269 } |
| 337 | 270 |
| 338 TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) { | |
| 339 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; | |
| 340 const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1); | |
| 341 | |
| 342 SmoothEventSampler sampler(capture_period, 1); | |
| 343 base::TimeTicks t = InitialTestTimeTicks(); | |
| 344 | |
| 345 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | |
| 346 sampler.RecordSample(); | |
| 347 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t)) | |
| 348 << "Sampled last event; should not be dirty."; | |
| 349 t += overdue_period; | |
| 350 | |
| 351 // Now simulate 2 events with the same clock value. | |
| 352 ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t)); | |
| 353 sampler.RecordSample(); | |
| 354 ASSERT_FALSE(AddEventAndConsiderSampling(&sampler, t)) | |
| 355 << "Two events at same time -- expected second not to be sampled."; | |
| 356 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period)) | |
| 357 << "Second event should dirty the capture state."; | |
| 358 sampler.RecordSample(); | |
| 359 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period)); | |
| 360 } | |
| 361 | |
| 362 namespace { | 271 namespace { |
| 363 | 272 |
| 364 struct DataPoint { | 273 struct DataPoint { |
| 365 bool should_capture; | 274 bool should_capture; |
| 366 double increment_ms; | 275 double increment_ms; |
| 367 }; | 276 }; |
| 368 | 277 |
| 369 void ReplayCheckingSamplerDecisions(const DataPoint* data_points, | 278 void ReplayCheckingSamplerDecisions(const DataPoint* data_points, |
| 370 size_t num_data_points, | 279 size_t num_data_points, |
| 371 SmoothEventSampler* sampler) { | 280 SmoothEventSampler* sampler) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 {true, 33.44}, | 361 {true, 33.44}, |
| 453 {true, 50.161}, | 362 {true, 50.161}, |
| 454 {true, 33.44}, | 363 {true, 33.44}, |
| 455 {true, 50.161}, | 364 {true, 50.161}, |
| 456 {true, 33.44}, | 365 {true, 33.44}, |
| 457 {true, 83.601}, | 366 {true, 83.601}, |
| 458 {true, 16.72}, | 367 {true, 16.72}, |
| 459 {true, 33.44}, | 368 {true, 33.44}, |
| 460 {false, 0}}; | 369 {false, 0}}; |
| 461 | 370 |
| 462 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); | 371 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30); |
| 463 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); | 372 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
| 464 } | 373 } |
| 465 | 374 |
| 466 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) { | 375 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) { |
| 467 // Actual capturing of timing data: Initial instability as a 30 FPS video was | 376 // Actual capturing of timing data: Initial instability as a 30 FPS video was |
| 468 // started from a still screen, then followed by steady-state. Drawing | 377 // started from a still screen, then followed by steady-state. Drawing |
| 469 // framerate from the video rendering was a bit volatile, but averaged 30 FPS. | 378 // framerate from the video rendering was a bit volatile, but averaged 30 FPS. |
| 470 static const DataPoint data_points[] = {{true, 2407.69}, | 379 static const DataPoint data_points[] = {{true, 2407.69}, |
| 471 {true, 16.733}, | 380 {true, 16.733}, |
| 472 {true, 217.362}, | 381 {true, 217.362}, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 {false, 16.72}, | 470 {false, 16.72}, |
| 562 {true, 66.88}, | 471 {true, 66.88}, |
| 563 {true, 16.721}, | 472 {true, 16.721}, |
| 564 {true, 50.16}, | 473 {true, 50.16}, |
| 565 {true, 33.44}, | 474 {true, 33.44}, |
| 566 {true, 16.72}, | 475 {true, 16.72}, |
| 567 {true, 33.441}, | 476 {true, 33.441}, |
| 568 {true, 33.44}, | 477 {true, 33.44}, |
| 569 {true, 33.44}}; | 478 {true, 33.44}}; |
| 570 | 479 |
| 571 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); | 480 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30); |
| 572 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); | 481 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
| 573 } | 482 } |
| 574 | 483 |
| 575 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) { | 484 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) { |
| 576 // Actual capturing of timing data: WebGL Acquarium demo | 485 // Actual capturing of timing data: WebGL Acquarium demo |
| 577 // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran | 486 // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran |
| 578 // between 55-60 FPS in the steady-state. | 487 // between 55-60 FPS in the steady-state. |
| 579 static const DataPoint data_points[] = {{true, 16.72}, | 488 static const DataPoint data_points[] = {{true, 16.72}, |
| 580 {true, 16.72}, | 489 {true, 16.72}, |
| 581 {true, 4163.29}, | 490 {true, 4163.29}, |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 {true, 50.161}, | 603 {true, 50.161}, |
| 695 {false, 0}, | 604 {false, 0}, |
| 696 {true, 16.72}, | 605 {true, 16.72}, |
| 697 {true, 33.44}, | 606 {true, 33.44}, |
| 698 {false, 0}, | 607 {false, 0}, |
| 699 {true, 33.441}, | 608 {true, 33.441}, |
| 700 {false, 16.72}, | 609 {false, 16.72}, |
| 701 {true, 16.72}, | 610 {true, 16.72}, |
| 702 {true, 50.16}}; | 611 {true, 50.16}}; |
| 703 | 612 |
| 704 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, 3); | 613 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30); |
| 705 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); | 614 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); |
| 706 } | 615 } |
| 707 | 616 |
| 708 } // namespace media | 617 } // namespace media |
| OLD | NEW |