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

Side by Side Diff: media/capture/video/android/video_capture_device_tango_android.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 (c) 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 "media/capture/video/android/video_capture_device_tango_android.h"
6
7 #include <stdint.h>
8 #include <utility>
9
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "jni/VideoCaptureTango_jni.h"
17
18 namespace media {
19
20 VideoCaptureDeviceTangoAndroid::VideoCaptureDeviceTangoAndroid(
21 const VideoCaptureDeviceDescriptor& device_descriptor)
22 : VideoCaptureDeviceAndroid(device_descriptor), weak_ptr_factory_(this) {}
23
24 VideoCaptureDeviceTangoAndroid::~VideoCaptureDeviceTangoAndroid() {}
25
26 void VideoCaptureDeviceTangoAndroid::OnPointCloudAvailable(
27 JNIEnv* env,
28 jobject obj,
29 jobject points_buffer,
30 jint num_points,
31 jdouble timestamp) {
32 if (!IsClientConfiguredForIncomingData())
33 return;
34 if (!intrinsics_ && !(intrinsics_ = GetIntrinsics(env, obj)))
35 return;
36 const base::TimeTicks current_time = base::TimeTicks::Now();
37 ProcessFirstFrameAvailable(current_time);
38
39 const base::TimeDelta capture_time = base::TimeDelta::FromSecondsD(timestamp);
mcasas 2017/07/15 00:12:37 Move this to the vicinity of l.174? Try to allocat
40
41 float* const src =
42 reinterpret_cast<float*>(env->GetDirectBufferAddress(points_buffer));
43 CHECK(src);
44
45 const int width = capture_format_.frame_size.width();
46 const int height = capture_format_.frame_size.height();
47
48 const int buffer_length = width * height * 2;
49 std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_length]);
mcasas 2017/07/15 00:12:36 Since we keep ownership of |buffer|, it might be g
50
51 uint16_t* out = reinterpret_cast<uint16_t*>(buffer.get());
52 memset(out, 0, buffer_length);
53
54 const float fx = intrinsics_->fx;
55 const float fy = intrinsics_->fy;
56 // Add 0.5 to cx and cy to avoid the need for round() in operations bellow.
57 float cx = intrinsics_->cx + 0.5;
58 float cy = intrinsics_->cy + 0.5;
59
60 int current_x = INT_MIN;
61 int current_y = INT_MIN;
62
63 // Optimization: process 4 points at once as they are likely adjacent.
64 // TODO(aleksandar.stojiljkovic): Try optimizing using NEON.
65 // https://crbug.com/674440
66 float* src_end = src + num_points / 4 * 16;
67
68 for (const float* item = src; item < src_end; item += 16) {
69 #define x0 item[0]
70 #define y0 item[1]
71 #define z0 item[2]
72 #define x1 item[4]
73 #define y1 item[5]
74 #define z1 item[6]
75 #define x2 item[8]
76 #define y2 item[9]
77 #define z2 item[10]
78 #define x3 item[12]
79 #define y3 item[13]
80 #define z3 item[14]
81
82 const int row3 = static_cast<int>(fy * y3 / z3 + cy);
83
84 if (row3 < 0 || row3 >= height) {
85 // heuristics: due to radial distortion, early leave as the rest of data
86 // is outside color image. Constant 5 is large enough to compensate the
87 // radial distortion.
88 if (row3 >= height + 5)
89 break;
90 continue;
91 }
92
93 const int column3 = static_cast<int>(fx * x3 / z3 + cx);
94
95 // We know that the cameras are configured to support range < 7 meters but
96 // allow values up to 16m here. Multiplying depth by 4096 gives values with
97 // good exposure in 16-bit unsigned range.
98 uint16_t depth[] = {
99 static_cast<uint16_t>(z0 * 4096), static_cast<uint16_t>(z1 * 4096),
100 static_cast<uint16_t>(z2 * 4096), static_cast<uint16_t>(z3 * 4096)};
101 DCHECK(z0 * 4096 <= 65535 && z1 * 4096 <= 65535 && z2 * 4096 <= 65535 &&
102 z3 * 4096 <= 65535);
103
104 unsigned out_offset3 = row3 * width + column3;
105 if (column3 == current_x + 4 && row3 == current_y) {
106 // All values are packed. We only need to copy depth while there is no
107 // need to calculate x and y.
108 if (column3 - 3 < width)
109 out[out_offset3 - 3] = depth[0];
110 if (column3 - 2 < width)
111 out[out_offset3 - 2] = depth[1];
112 if (column3 - 1 < width)
113 out[out_offset3 - 1] = depth[2];
114 if (column3 < width)
115 out[out_offset3] = depth[3];
116 current_x += 4;
117 continue;
118 }
119
120 int row1 = static_cast<int>(fy * y1 / z1 + cy);
121 int column1 = static_cast<int>(fx * x1 / z1 + cx);
122
123 unsigned out_offset1 = row1 * width + column1;
124 if (column1 == current_x + 2 && row1 == current_y && column1 < width) {
125 if (row1 >= 0 && row1 < height) {
126 out[out_offset1 - 1] = depth[0];
127 out[out_offset1] = depth[1];
128 }
129 } else if (column1 == current_x + 3 && row1 == current_y &&
130 column1 < width) {
131 // This compensates for the radial distortion side effects (vertical lines
132 // with missing values) near the vertical edges.
133 if (row1 >= 0 && row1 < height) {
134 out[out_offset1 - 2] = depth[0];
135 out[out_offset1 - 1] = depth[0];
136 out[out_offset1] = depth[1];
137 }
138 } else {
139 const int row0 = static_cast<int>(fy * y0 / z0 + cy);
140 const int column0 = static_cast<int>(fx * x0 / z0 + cx);
141 if (row0 >= 0 && row0 < height && column0 >= 0 && column0 < width)
142 out[row0 * width + column0] = depth[0];
143 if (row1 >= 0 && row1 < height && column1 >= 0 && column1 < width)
144 out[out_offset1] = depth[1];
145 }
146
147 if (column3 == column1 + 2 && row3 == row1) {
148 if (column3 - 1 >= 0 && column3 - 1 < width)
149 out[out_offset3 - 1] = depth[2];
150 if (column3 >= 0 && column3 < width)
151 out[out_offset3] = depth[3];
152 } else if (column3 == column1 + 3 && row3 == row1) {
153 // This compensates for the radial distortion side effects (vertical lines
154 // with missing values) near the vertical edges.
155 if (column3 - 2 >= 0 && column3 - 2 < width)
156 out[out_offset3 - 2] = depth[2];
157 if (column3 - 1 >= 0 && column3 - 1 < width)
158 out[out_offset3 - 1] = depth[2];
159 if (column3 >= 0 && column3 < width)
160 out[out_offset3] = depth[3];
161 } else {
162 const int row2 = static_cast<int>(fy * y2 / z2 + cy);
163 const int column2 = static_cast<int>(fx * x2 / z2 + cx);
164 if (row2 >= 0 && row2 < height && column2 >= 0 && column2 < width)
165 out[row2 * width + column2] = depth[2];
166 if (row3 >= 0 && column3 >= 0 && column3 < width)
167 out[out_offset3] = depth[3];
168 }
169 current_x = (column3 >= 0) ? column3 : INT_MIN;
170 current_y = row3;
171 }
172
173 if (AdvanceToNextFrameTime(current_time)) {
174 SendIncomingDataToClient(buffer.get(), buffer_length, 0, current_time,
175 capture_time);
176 }
177 }
178
179 std::unique_ptr<VideoCaptureDeviceTangoAndroid::TangoIntrinsics>
180 VideoCaptureDeviceTangoAndroid::GetIntrinsics(JNIEnv* env, jobject obj) {
181 std::unique_ptr<TangoIntrinsics> intrinsics(new TangoIntrinsics);
182 intrinsics->cx = Java_VideoCaptureTango_getPrincipalPointX(env, obj);
183 intrinsics->cy = Java_VideoCaptureTango_getPrincipalPointY(env, obj);
184 intrinsics->fx = Java_VideoCaptureTango_getFocalLengthX(env, obj);
185 intrinsics->fy = Java_VideoCaptureTango_getFocalLengthY(env, obj);
186 return intrinsics;
187 }
188
189 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698