OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2008 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2008 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 #include <vector> | 14 #include <vector> |
15 | 15 |
16 #include "webrtc/base/gunit.h" | 16 #include "webrtc/base/gunit.h" |
17 #include "webrtc/base/logging.h" | 17 #include "webrtc/base/logging.h" |
| 18 #include "webrtc/base/random.h" |
18 #include "webrtc/base/thread.h" | 19 #include "webrtc/base/thread.h" |
19 #include "webrtc/media/base/fakevideocapturer.h" | 20 #include "webrtc/media/base/fakevideocapturer.h" |
20 #include "webrtc/media/base/fakevideorenderer.h" | 21 #include "webrtc/media/base/fakevideorenderer.h" |
21 #include "webrtc/media/base/testutils.h" | 22 #include "webrtc/media/base/testutils.h" |
22 #include "webrtc/media/base/videocapturer.h" | 23 #include "webrtc/media/base/videocapturer.h" |
23 | 24 |
24 using cricket::FakeVideoCapturer; | 25 using cricket::FakeVideoCapturer; |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
(...skipping 20 matching lines...) Expand all Loading... |
48 &VideoCapturerTest::OnStateChange); | 49 &VideoCapturerTest::OnStateChange); |
49 capturer_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants()); | 50 capturer_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants()); |
50 } | 51 } |
51 void InitScreencast() { InitCapturer(true); } | 52 void InitScreencast() { InitCapturer(true); } |
52 | 53 |
53 void OnStateChange(cricket::VideoCapturer*, | 54 void OnStateChange(cricket::VideoCapturer*, |
54 cricket::CaptureState capture_state) { | 55 cricket::CaptureState capture_state) { |
55 capture_state_ = capture_state; | 56 capture_state_ = capture_state; |
56 ++num_state_changes_; | 57 ++num_state_changes_; |
57 } | 58 } |
| 59 void TestTimestampFilter(double rel_freq_error); |
| 60 |
58 cricket::CaptureState capture_state() { return capture_state_; } | 61 cricket::CaptureState capture_state() { return capture_state_; } |
59 int num_state_changes() { return num_state_changes_; } | 62 int num_state_changes() { return num_state_changes_; } |
60 | 63 |
61 std::unique_ptr<cricket::FakeVideoCapturer> capturer_; | 64 std::unique_ptr<cricket::FakeVideoCapturer> capturer_; |
62 cricket::CaptureState capture_state_; | 65 cricket::CaptureState capture_state_; |
63 int num_state_changes_; | 66 int num_state_changes_; |
64 cricket::FakeVideoRenderer renderer_; | 67 cricket::FakeVideoRenderer renderer_; |
65 bool expects_rotation_applied_; | 68 bool expects_rotation_applied_; |
66 }; | 69 }; |
67 | 70 |
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 capturer_->set_enable_camera_list(true); | 777 capturer_->set_enable_camera_list(true); |
775 capturer_->ConstrainSupportedFormats(vga_format); | 778 capturer_->ConstrainSupportedFormats(vga_format); |
776 EXPECT_EQ(2u, capturer_->GetSupportedFormats()->size()); | 779 EXPECT_EQ(2u, capturer_->GetSupportedFormats()->size()); |
777 // To make sure it's not just the camera list being broken, add in VGA and | 780 // To make sure it's not just the camera list being broken, add in VGA and |
778 // try again. This time, only the VGA format should be there. | 781 // try again. This time, only the VGA format should be there. |
779 supported_formats.push_back(vga_format); | 782 supported_formats.push_back(vga_format); |
780 capturer_->ResetSupportedFormats(supported_formats); | 783 capturer_->ResetSupportedFormats(supported_formats); |
781 ASSERT_EQ(1u, capturer_->GetSupportedFormats()->size()); | 784 ASSERT_EQ(1u, capturer_->GetSupportedFormats()->size()); |
782 EXPECT_EQ(vga_format.height, capturer_->GetSupportedFormats()->at(0).height); | 785 EXPECT_EQ(vga_format.height, capturer_->GetSupportedFormats()->at(0).height); |
783 } | 786 } |
| 787 |
| 788 namespace { |
| 789 // Computes the difference x_k - mean(x), when x_k is the linear sequence x_k = |
| 790 // k, and the "mean" is plain mean for the first |window_size| samples, followed |
| 791 // by exponential averaging with weight 1/|window_size| for each new sample. |
| 792 // This is needed to predict the effect of camera clock drift on the timestamp |
| 793 // translation. See the comment on VideoCapturer::UpdateOffset for more context. |
| 794 double MeanTimeDifference(int nsamples, int window_size) { |
| 795 if (nsamples <= window_size) { |
| 796 // Plain averaging. |
| 797 return nsamples / 2.0; |
| 798 } else { |
| 799 // Exponential convergence towards |
| 800 // interval_error * (window_size - 1) |
| 801 double alpha = 1.0 - 1.0 / window_size; |
| 802 |
| 803 return ((window_size - 1) - |
| 804 (window_size / 2.0 - 1) * pow(alpha, nsamples - window_size)); |
| 805 } |
| 806 } |
| 807 |
| 808 } // Anonymous namespace |
| 809 |
| 810 void VideoCapturerTest::TestTimestampFilter(double rel_freq_error) { |
| 811 const int kWidth = 800; |
| 812 const int kHeight = 400; |
| 813 |
| 814 const int64_t kEpoch = 10000; |
| 815 const int64_t kJitterUs = 5000; |
| 816 const int64_t kIntervalUs = 33333; // 30 FPS |
| 817 const int kWindowSize = 100; |
| 818 const int kNumFrames = 3 * kWindowSize; |
| 819 |
| 820 int64_t interval_error_us = kIntervalUs * rel_freq_error; |
| 821 int64_t system_start_us = rtc::TimeMicros(); |
| 822 webrtc::Random random(17); |
| 823 |
| 824 int64_t prev_translated_time_us = system_start_us; |
| 825 |
| 826 for (int i = 0; i < kNumFrames; i++) { |
| 827 // Camera time subject to drift. |
| 828 int64_t camera_time_us = kEpoch + i * (kIntervalUs + interval_error_us); |
| 829 int64_t system_time_us = system_start_us + i * kIntervalUs; |
| 830 // And system time readings are subject to jitter. |
| 831 int64_t system_measured_us = system_time_us + random.Rand(kJitterUs); |
| 832 |
| 833 int out_width; |
| 834 int out_height; |
| 835 int crop_width; |
| 836 int crop_height; |
| 837 int crop_x; |
| 838 int crop_y; |
| 839 int64_t translated_time_us; |
| 840 |
| 841 EXPECT_TRUE(capturer_->AdaptFrame(kWidth, kHeight, |
| 842 camera_time_us, system_measured_us, |
| 843 &out_width, &out_height, |
| 844 &crop_width, &crop_height, |
| 845 &crop_x, &crop_y, &translated_time_us)); |
| 846 |
| 847 EXPECT_LE(translated_time_us, system_measured_us); |
| 848 EXPECT_GE(translated_time_us, prev_translated_time_us); |
| 849 |
| 850 // The relative frequency error contributes to the expected error |
| 851 // by a factor which is the difference between the current time |
| 852 // and the average of earlier sample times. |
| 853 int64_t expected_error_us = |
| 854 kJitterUs / 2 + |
| 855 rel_freq_error * kIntervalUs * MeanTimeDifference(i, kWindowSize); |
| 856 |
| 857 int64_t bias_us = capturer_->clip_bias_us(); |
| 858 EXPECT_GE(bias_us, 0); |
| 859 |
| 860 if (i == 0) { |
| 861 EXPECT_EQ(translated_time_us, system_measured_us); |
| 862 } else { |
| 863 EXPECT_NEAR(translated_time_us + bias_us, |
| 864 system_time_us + expected_error_us, |
| 865 2.0 * kJitterUs / sqrt(std::max(i, kWindowSize))); |
| 866 } |
| 867 // If the camera clock runs too fast (rel_freq_error > 0.0), The |
| 868 // bias is expected to roughly cancel the expected error from the |
| 869 // clock drift, as this grows. Otherwise, it reflects the |
| 870 // measurement noise. The tolerances here were selected after some |
| 871 // trial and error. |
| 872 if (i < 10 || rel_freq_error <= 0.0) { |
| 873 EXPECT_LE(bias_us, 3000); |
| 874 } else { |
| 875 EXPECT_NEAR(bias_us, expected_error_us, 1500); |
| 876 } |
| 877 prev_translated_time_us = translated_time_us; |
| 878 } |
| 879 } |
| 880 |
| 881 TEST_F(VideoCapturerTest, AttenuateTimestampJitterNoDrift) { |
| 882 TestTimestampFilter(0.0); |
| 883 } |
| 884 |
| 885 // 100 ppm is a worst case for a reasonable crystal. |
| 886 TEST_F(VideoCapturerTest, AttenuateTimestampJitterSmallPosDrift) { |
| 887 TestTimestampFilter(0.0001); |
| 888 } |
| 889 |
| 890 TEST_F(VideoCapturerTest, AttenuateTimestampJitterSmallNegDrift) { |
| 891 TestTimestampFilter(-0.0001); |
| 892 } |
| 893 |
| 894 // 3000 ppm, 3 ms / s, is the worst observed drift, see |
| 895 // https://bugs.chromium.org/p/webrtc/issues/detail?id=5456 |
| 896 TEST_F(VideoCapturerTest, AttenuateTimestampJitterLargePosDrift) { |
| 897 TestTimestampFilter(0.003); |
| 898 } |
| 899 |
| 900 TEST_F(VideoCapturerTest, AttenuateTimestampJitterLargeNegDrift) { |
| 901 TestTimestampFilter(-0.003); |
| 902 } |
OLD | NEW |