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