Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |