Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: media/capture/video/android/video_capture_device_tango_android_unittest.cc

Issue 2983473002: Android Tango depth camera capture support.
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "video_capture_device_tango_android.h"
6 #include "base/android/jni_android.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/sys_info.h"
9 #include "base/test/scoped_task_environment.h"
10 #include "media/capture/video/android/video_capture_device_factory_android.h"
11 #include "media/capture/video/android/video_capture_device_tango_android.h"
12 #include "media/capture/video_capture_types.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace media {
17
18 namespace {
19
20 const int kWidth = 214;
21 const int kHeight = 120;
22 // Projected point cloud values to color frame could be are outside color frame
23 // bounds. kMargin defines how larger is the depth frame area compared to color.
24 const int kMargin = 20;
25
26 bool IsTangoDevice() {
27 const std::string model = base::SysInfo::HardwareModelName();
28 return (model == "Project Tango Tablet Development Kit" ||
29 model == "Lenovo PB2-690M");
mcasas 2017/07/15 00:12:37 Usually these name lists are moved out as static a
30 }
31
32 void createTestTangoPointCloud(float* data,
33 int xstart,
34 int ystart,
35 int xend,
36 int yend,
37 float cx,
38 float cy,
39 float fx,
40 float fy) {
41 float* out = data;
42 for (int i = ystart; i < yend; i++) {
43 for (int j = xstart; j < xend; j++) {
44 // Skip some elements to mimic Tango behavior.
45 if ((j % 3 && (i + j) % 15 == 0) || j % 20 == 0)
46 continue;
47 // Generate depth value based on row and column. Maximum value is 16m.
48 float depth =
49 16.0 / (yend - ystart + xend - xstart) * (j - xstart + i - ystart);
50 float xvalue = depth * (j - cx) / fx;
51 float yvalue = depth * (i - cy) / fy;
52 out[0] = xvalue;
53 out[1] = yvalue;
54 out[2] = depth;
55 out[3] = 1.0;
56 out += 4;
57 }
58 }
59 }
60
61 } // namespace
62
63 class MockVideoCaptureClient : public VideoCaptureDevice::Client {
64 public:
65 MOCK_METHOD2(OnError,
66 void(const tracked_objects::Location& from_here,
67 const std::string& reason));
68 MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
69 MOCK_METHOD0(OnStarted, void(void));
70
71 explicit MockVideoCaptureClient(
72 base::Callback<void(const uint8_t*, int, const VideoCaptureFormat&)>
73 frame_cb)
74 : frame_cb_(frame_cb) {}
75
76 void OnIncomingCapturedData(const uint8_t* data,
77 int length,
78 const VideoCaptureFormat& format,
79 int rotation,
80 base::TimeTicks reference_time,
81 base::TimeDelta timestamp,
82 int frame_feedback_id) override {
83 ASSERT_GT(length, 0);
84 ASSERT_TRUE(data);
85 frame_cb_.Run(data, length, format);
86 }
87
88 // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
89 Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
90 media::VideoPixelFormat format,
91 media::VideoPixelStorage storage,
92 int frame_feedback_id) override {
93 NOTREACHED() << "This should never be called";
94 return Buffer();
95 }
96 void OnIncomingCapturedBuffer(Buffer buffer,
97 const VideoCaptureFormat& format,
98 base::TimeTicks reference_time,
99 base::TimeDelta timestamp) override {
100 NOTREACHED() << "This should never be called";
101 }
102 void OnIncomingCapturedBufferExt(
103 Buffer buffer,
104 const VideoCaptureFormat& format,
105 base::TimeTicks reference_time,
106 base::TimeDelta timestamp,
107 gfx::Rect visible_rect,
108 const VideoFrameMetadata& additional_metadata) override {
109 NOTREACHED() << "This should never be called";
110 }
111 Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
112 media::VideoPixelFormat format,
113 media::VideoPixelStorage storage,
114 int frame_feedback_id) {
115 NOTREACHED() << "This should never be called";
116 return Buffer();
117 }
118
119 private:
120 base::Callback<void(const uint8_t*, int, const VideoCaptureFormat&)>
121 frame_cb_;
122 };
123
124 class VideoCaptureDeviceTangoAndroidTest
125 : public testing::TestWithParam<gfx::Size> {
126 protected:
127 VideoCaptureDeviceTangoAndroidTest()
128 : video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory(
129 base::ThreadTaskRunnerHandle::Get())),
130 device_descriptors_(new VideoCaptureDeviceDescriptors()),
131 video_capture_client_(new MockVideoCaptureClient(
132 base::Bind(&VideoCaptureDeviceTangoAndroidTest::OnFrameCaptured,
133 base::Unretained(this)))) {}
134
135 void SetUp() override {
136 video_capture_device_factory_->GetDeviceDescriptors(
137 device_descriptors_.get());
138 VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
139 base::android::AttachCurrentThread());
140
141 static_cast<VideoCaptureDeviceFactoryAndroid*>(
142 video_capture_device_factory_.get())
143 ->ConfigureForTesting();
144 }
145
146 std::unique_ptr<VideoCaptureDeviceDescriptor> GetTangoDepthDescriptor() {
147 for (const auto& descriptor : *device_descriptors_) {
148 if (descriptor.capture_api == VideoCaptureApi::ANDROID_TANGO) {
149 return std::unique_ptr<VideoCaptureDeviceDescriptor>(
150 new VideoCaptureDeviceDescriptor(descriptor));
151 }
152 }
153 return nullptr;
154 }
155
156 void OnFrameCaptured(const uint8_t* data,
157 int length,
158 const VideoCaptureFormat& format) {
159 memcpy(last_data_, data, length);
160 last_length_ = length;
161 last_format_ = format;
162 }
163
164 static std::unique_ptr<VideoCaptureDeviceTangoAndroid::TangoIntrinsics>
165 GetIntrinsics(const VideoCaptureDeviceTangoAndroid& tango_device) {
166 if (!tango_device.intrinsics_)
167 return nullptr;
168 return std::unique_ptr<VideoCaptureDeviceTangoAndroid::TangoIntrinsics>(
169 new VideoCaptureDeviceTangoAndroid::TangoIntrinsics(
170 *(tango_device.intrinsics_)));
171 }
172
173 static jobject GetJavaCaptureObject(
174 const VideoCaptureDeviceTangoAndroid& tango_device) {
175 return tango_device.j_capture_.obj();
176 }
177
178 base::test::ScopedTaskEnvironment scoped_task_environment_;
179 const std::unique_ptr<VideoCaptureDeviceFactory>
180 video_capture_device_factory_;
181 std::unique_ptr<VideoCaptureDeviceDescriptors> device_descriptors_;
182 std::unique_ptr<MockVideoCaptureClient> video_capture_client_;
183 VideoCaptureFormat last_format_;
184 uint16_t last_data_[kWidth * kHeight] = {0};
185 int last_length_ = 0;
186 };
187
188 TEST_F(VideoCaptureDeviceTangoAndroidTest, OnPointCloudAvailable) {
189 VideoCaptureDeviceFactoryAndroid* android_factory =
190 static_cast<VideoCaptureDeviceFactoryAndroid*>(
191 video_capture_device_factory_.get());
192
193 std::unique_ptr<VideoCaptureDeviceDescriptor> tango_depth_descriptor(
194 GetTangoDepthDescriptor());
195 ASSERT_TRUE(IsTangoDevice() ^ tango_depth_descriptor == nullptr);
196 if (!tango_depth_descriptor) {
197 // Create mock Tango device. Tango depth id value is equal to number of
198 // system cameras; see VideoCaptureFactory.java.
199 tango_depth_descriptor = std::unique_ptr<VideoCaptureDeviceDescriptor>(
200 new VideoCaptureDeviceDescriptor(
201 "Tango Mock Test Depth",
202 base::IntToString(device_descriptors_->size()),
203 VideoCaptureApi::ANDROID_TANGO));
204 }
205 std::unique_ptr<VideoCaptureDevice> device =
206 android_factory->CreateDevice(*tango_depth_descriptor);
207 ASSERT_TRUE(device);
208
209 VideoCaptureDeviceTangoAndroid* tango_device =
210 static_cast<VideoCaptureDeviceTangoAndroid*>(device.get());
211 const auto intrinsics_null = GetIntrinsics(*tango_device);
212 ASSERT_FALSE(intrinsics_null);
213
214 VideoCaptureParams capture_params;
215 capture_params.requested_format.frame_size.SetSize(kWidth, kHeight);
216 capture_params.requested_format.frame_rate = 5;
217 capture_params.requested_format.pixel_format = PIXEL_FORMAT_Y16;
218 tango_device->AllocateAndStart(capture_params,
219 std::move(video_capture_client_));
220
221 JNIEnv* env = base::android::AttachCurrentThread();
222
223 const int length = (kWidth + 2 * kMargin) * (kHeight + 2 * kMargin);
224 float buffer[length * 4] = {0};
225 jobject byte_buffer =
226 env->NewDirectByteBuffer(static_cast<void*>(buffer), sizeof(buffer));
227
228 // Call this once before running with the real values to get tango intrinsics
229 // as they are fetched on first OnPointCloudAvailable call.
230 tango_device->OnPointCloudAvailable(env, GetJavaCaptureObject(*tango_device),
231 byte_buffer, length, 0);
232
233 // Mock values for intrinsics are set in VideoCaptureTango.java.
234 const auto intrinsics = GetIntrinsics(*tango_device);
235 ASSERT_TRUE(intrinsics);
236 EXPECT_NEAR(213.333333, intrinsics->fx, 0.000005);
237 EXPECT_NEAR(213.333333, intrinsics->fy, 0.000005);
238 EXPECT_NEAR(106.666667, intrinsics->cx, 0.000005);
239 EXPECT_EQ(60., intrinsics->cy);
240
241 createTestTangoPointCloud(buffer, -kMargin, -kMargin, kWidth + kMargin,
242 kHeight + kMargin, intrinsics->cx, intrinsics->cy,
243 intrinsics->fx, intrinsics->fy);
244 tango_device->OnPointCloudAvailable(env, GetJavaCaptureObject(*tango_device),
245 byte_buffer, length, 0);
246
247 // Verify the conversion of the generated point cloud to depth buffer.
248 for (int i = 0; i < kHeight; i++) {
249 for (int j = 0; j < kWidth; j++) {
250 // Skip the same elements as in createTestTangoPointCloud.
251 if ((j % 3 && (i + j) % 15 == 0) || j % 20 == 0) {
252 continue;
253 }
254 // Generate depth value based on row and column. Maximum value is 16m.
255 float depth =
256 16.0 / (kWidth + kHeight + 4 * kMargin) * (j + kMargin + i + kMargin);
257 EXPECT_EQ(static_cast<uint16_t>(depth * 4096), last_data_[j + i * kWidth])
258 << "x:" << j << " ,y:" << i;
259 }
260 }
261 tango_device->StopAndDeAllocate();
262 }
263
264 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698