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

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: third party replaced by dlsym 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/tango_api.h"
11 #include "media/capture/video/android/video_capture_device_factory_android.h"
12 #include "media/capture/video/android/video_capture_device_tango_android.h"
13 #include "media/capture/video_capture_types.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using Intrinsics = media::TangoApi::TangoCameraIntrinsics;
18
19 namespace media {
20
21 namespace {
22
23 const int kWidth = 214;
24 const int kHeight = 120;
25 // Projected point cloud values to color frame could be are outside color frame
26 // bounds. kMargin defines how larger is the depth frame area compared to color.
27 const int kMargin = 20;
28
29 bool IsTangoDevice() {
30 static const char* tango_models[] = {"Project Tango Tablet Development Kit",
31 "Lenovo PB2-690M", "ASUS_A002",
32 "ASUS_A002A"};
33 const std::string model = base::SysInfo::HardwareModelName();
34 const char** result =
35 std::find(tango_models, tango_models + arraysize(tango_models), model);
36 return (result < tango_models + arraysize(tango_models));
37 }
38
39 void OnPointCloudAvailable(void* context,
40 const TangoApi::TangoPointCloud* point_cloud) {}
41
42 void createTestTangoPointCloud(float* data,
43 int xstart,
44 int ystart,
45 int xend,
46 int yend,
47 float cx,
48 float cy,
49 float fx,
50 float fy) {
51 float* out = data;
52 for (int i = ystart; i < yend; i++) {
53 for (int j = xstart; j < xend; j++) {
54 // Skip some elements to mimic Tango behavior.
55 if ((j % 3 && (i + j) % 15 == 0) || j % 20 == 0)
56 continue;
57 // Generate depth value based on row and column. Maximum value is 16m.
58 float depth =
59 16.0 / (yend - ystart + xend - xstart) * (j - xstart + i - ystart);
60 float xvalue = depth * (j - cx) / fx;
61 float yvalue = depth * (i - cy) / fy;
62 out[0] = xvalue;
63 out[1] = yvalue;
64 out[2] = depth;
65 out[3] = 1.0;
66 out += 4;
67 }
68 }
69 }
70
71 } // namespace
72
73 class MockVideoCaptureClient : public VideoCaptureDevice::Client {
74 public:
75 MOCK_METHOD2(OnError,
76 void(const tracked_objects::Location& from_here,
77 const std::string& reason));
78 MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
79 MOCK_METHOD0(OnStarted, void(void));
80
81 explicit MockVideoCaptureClient(
82 base::Callback<void(const uint8_t*, int, const VideoCaptureFormat&)>
83 frame_cb)
84 : frame_cb_(frame_cb) {}
85
86 void OnIncomingCapturedData(const uint8_t* data,
87 int length,
88 const VideoCaptureFormat& format,
89 int rotation,
90 base::TimeTicks reference_time,
91 base::TimeDelta timestamp,
92 int frame_feedback_id) override {
93 ASSERT_GT(length, 0);
94 ASSERT_TRUE(data);
95 frame_cb_.Run(data, length, format);
96 }
97
98 // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
99 Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
100 media::VideoPixelFormat format,
101 media::VideoPixelStorage storage,
102 int frame_feedback_id) override {
103 NOTREACHED() << "This should never be called";
104 return Buffer();
105 }
106 void OnIncomingCapturedBuffer(Buffer buffer,
107 const VideoCaptureFormat& format,
108 base::TimeTicks reference_time,
109 base::TimeDelta timestamp) override {
110 NOTREACHED() << "This should never be called";
111 }
112 void OnIncomingCapturedBufferExt(
113 Buffer buffer,
114 const VideoCaptureFormat& format,
115 base::TimeTicks reference_time,
116 base::TimeDelta timestamp,
117 gfx::Rect visible_rect,
118 const VideoFrameMetadata& additional_metadata) override {
119 NOTREACHED() << "This should never be called";
120 }
121 Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
122 media::VideoPixelFormat format,
123 media::VideoPixelStorage storage,
124 int frame_feedback_id) {
125 NOTREACHED() << "This should never be called";
126 return Buffer();
127 }
128
129 private:
130 base::Callback<void(const uint8_t*, int, const VideoCaptureFormat&)>
131 frame_cb_;
132 };
133
134 class VideoCaptureDeviceTangoAndroidTest
135 : public testing::TestWithParam<gfx::Size> {
136 protected:
137 VideoCaptureDeviceTangoAndroidTest()
138 : video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory(
139 base::ThreadTaskRunnerHandle::Get())),
140 device_descriptors_(new VideoCaptureDeviceDescriptors()),
141 video_capture_client_(new MockVideoCaptureClient(
142 base::Bind(&VideoCaptureDeviceTangoAndroidTest::OnFrameCaptured,
143 base::Unretained(this)))) {}
144
145 void SetUp() override {
146 video_capture_device_factory_->GetDeviceDescriptors(
147 device_descriptors_.get());
148 VideoCaptureDeviceTangoAndroid::RegisterVideoCaptureDevice(
149 base::android::AttachCurrentThread());
150
151 static_cast<VideoCaptureDeviceFactoryAndroid*>(
152 video_capture_device_factory_.get())
153 ->ConfigureForTesting();
154 }
155
156 std::unique_ptr<VideoCaptureDeviceDescriptor> GetTangoDepthDescriptor() {
157 for (const auto& descriptor : *device_descriptors_) {
158 if (descriptor.capture_api == VideoCaptureApi::ANDROID_TANGO) {
159 return std::unique_ptr<VideoCaptureDeviceDescriptor>(
160 new VideoCaptureDeviceDescriptor(descriptor));
161 }
162 }
163 return nullptr;
164 }
165
166 void OnFrameCaptured(const uint8_t* data,
167 int length,
168 const VideoCaptureFormat& format) {
169 memcpy(last_data_, data, length);
170 last_length_ = length;
171 last_format_ = format;
172 }
173
174 void SetIntrinsics(VideoCaptureDeviceTangoAndroid* tango_device,
175 double cx,
176 double cy,
177 double fx,
178 double fy) {
179 tango_device->intrinsics_ = std::unique_ptr<Intrinsics>(new Intrinsics());
180 tango_device->intrinsics_->cx = cx;
181 tango_device->intrinsics_->cy = cy;
182 tango_device->intrinsics_->fx = fx;
183 tango_device->intrinsics_->fy = fy;
184 }
185
186 // Non-Tango devices enter error state and we need to force it to configured
187 // in order to deliver the frame to client.
188 void SetConfiguredState(VideoCaptureDeviceTangoAndroid* tango_device) {
189 tango_device->state_ = VideoCaptureDeviceTangoAndroid::kConfigured;
190 }
191
192 std::unique_ptr<TangoApi> CreateMockTangoApi() {
193 return std::unique_ptr<TangoApi>(new TangoApi(nullptr));
194 }
195
196 base::test::ScopedTaskEnvironment scoped_task_environment_;
197 const std::unique_ptr<VideoCaptureDeviceFactory>
198 video_capture_device_factory_;
199 std::unique_ptr<VideoCaptureDeviceDescriptors> device_descriptors_;
200 std::unique_ptr<MockVideoCaptureClient> video_capture_client_;
201 VideoCaptureFormat last_format_;
202 uint16_t last_data_[kWidth * kHeight] = {0};
203 int last_length_ = 0;
204 };
205
206 TEST_F(VideoCaptureDeviceTangoAndroidTest, OnPointCloudAvailable) {
207 VideoCaptureDeviceFactoryAndroid* android_factory =
208 static_cast<VideoCaptureDeviceFactoryAndroid*>(
209 video_capture_device_factory_.get());
210
211 std::unique_ptr<VideoCaptureDeviceDescriptor> tango_depth_descriptor(
212 GetTangoDepthDescriptor());
213 ASSERT_TRUE(IsTangoDevice() ^ tango_depth_descriptor == nullptr);
214 if (!tango_depth_descriptor) {
215 // Create mock Tango device. Tango depth id value is equal to number of
216 // system cameras; see VideoCaptureFactory.java.
217 tango_depth_descriptor = std::unique_ptr<VideoCaptureDeviceDescriptor>(
218 new VideoCaptureDeviceDescriptor(
219 "Tango Mock Test Depth",
220 base::IntToString(device_descriptors_->size()),
221 VideoCaptureApi::ANDROID_TANGO));
222 }
223 std::unique_ptr<VideoCaptureDevice> device =
224 android_factory->CreateDevice(*tango_depth_descriptor);
225 ASSERT_TRUE(device);
226
227 VideoCaptureDeviceTangoAndroid* tango_device =
228 static_cast<VideoCaptureDeviceTangoAndroid*>(device.get());
229
230 VideoCaptureParams capture_params;
231 capture_params.requested_format.frame_size.SetSize(kWidth, kHeight);
232 capture_params.requested_format.frame_rate = 5;
233 capture_params.requested_format.pixel_format = PIXEL_FORMAT_Y16;
234 tango_device->AllocateAndStart(capture_params,
235 std::move(video_capture_client_));
236 if (!IsTangoDevice())
237 SetConfiguredState(tango_device);
238
239 const int length = (kWidth + 2 * kMargin) * (kHeight + 2 * kMargin);
240 float buffer[length * 4] = {0};
241
242 const double cx = 1920. / 18;
243 const double cy = 1080. / 18;
244 const double fxy = 1920. / 9;
245 SetIntrinsics(tango_device, cx, cy, fxy, fxy);
246
247 createTestTangoPointCloud(buffer, -kMargin, -kMargin, kWidth + kMargin,
248 kHeight + kMargin, cx, cy, fxy, fxy);
249 tango_device->OnPointCloudAvailable(length, buffer, 0);
250
251 // Verify the conversion of the generated point cloud to depth buffer.
252 for (int i = 0; i < kHeight; i++) {
253 for (int j = 0; j < kWidth; j++) {
254 // Skip the same elements as in createTestTangoPointCloud.
255 if ((j % 3 && (i + j) % 15 == 0) || j % 20 == 0) {
256 continue;
257 }
258 // Generate depth value based on row and column. Maximum value is 16m.
259 float depth =
260 16.0 / (kWidth + kHeight + 4 * kMargin) * (j + kMargin + i + kMargin);
261 ASSERT_TRUE(static_cast<uint16_t>(depth * 4096) ==
262 last_data_[j + i * kWidth]);
263 EXPECT_EQ(static_cast<uint16_t>(depth * 4096), last_data_[j + i * kWidth])
264 << "x:" << j << " ,y:" << i;
265 }
266 }
267 tango_device->StopAndDeAllocate();
268 }
269
270 TEST_F(VideoCaptureDeviceTangoAndroidTest, TangoApiNotFound) {
271 std::unique_ptr<TangoApi> api = CreateMockTangoApi();
272 JNIEnv* env = base::android::AttachCurrentThread();
273 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
274 api->TangoService_setBinder(env, nullptr));
275 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
276 api->TangoService_connect(nullptr, nullptr));
277 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
278 api->TangoConfig_setBool(nullptr, "config_enable_depth", true));
279 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
280 api->TangoConfig_setInt32(nullptr, "config_depth_mode", 0));
281 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
282 api->TangoService_connectOnPointCloudAvailable(
283 OnPointCloudAvailable, this));
284 Intrinsics intrinsics;
285 EXPECT_EQ(TangoApi::TANGO_METHOD_NOT_FOUND,
286 api->TangoService_getCameraIntrinsics(TangoApi::TANGO_CAMERA_COLOR,
287 &intrinsics));
288 ASSERT_FALSE(api->TangoService_getConfig(TangoApi::TANGO_CONFIG_DEFAULT));
289 api->TangoService_disconnect();
290 }
291
292 TEST_F(VideoCaptureDeviceTangoAndroidTest, TangoApi) {
293 std::unique_ptr<TangoApi> api = TangoApi::loadAndCreate();
294 ASSERT_TRUE(api || !IsTangoDevice());
295 if (!IsTangoDevice())
296 return; // Skip if not a Tango device.
297
298 // Previous versions of Tango allow calls to some of the methods even without
299 // connecting to service. We want to verify that the methods are resolved and
300 // checking that return error is not TANGO_METHOD_NOT_FOUND is sufficient.
301 JNIEnv* env = base::android::AttachCurrentThread();
302 EXPECT_EQ(TangoApi::TANGO_ERROR, api->TangoService_setBinder(env, nullptr));
303 EXPECT_NE(TangoApi::TANGO_METHOD_NOT_FOUND,
304 api->TangoConfig_setBool(nullptr, "config_enable_depth", true));
305 EXPECT_NE(TangoApi::TANGO_METHOD_NOT_FOUND,
306 api->TangoConfig_setInt32(nullptr, "config_depth_mode", 0));
307 EXPECT_NE(TangoApi::TANGO_METHOD_NOT_FOUND,
308 api->TangoService_connectOnPointCloudAvailable(
309 OnPointCloudAvailable, this));
310 Intrinsics intrinsics;
311 EXPECT_NE(TangoApi::TANGO_METHOD_NOT_FOUND,
312 api->TangoService_getCameraIntrinsics(TangoApi::TANGO_CAMERA_COLOR,
313 &intrinsics));
314 api->TangoService_disconnect();
315 }
316
317 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698