1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 //#define LOG_NNDEBUG 0 19 #define LOG_TAG "EmulatedCamera2_Sensor" 20 21 #ifdef LOG_NNDEBUG 22 #define ALOGVV(...) ALOGV(__VA_ARGS__) 23 #else 24 #define ALOGVV(...) ((void)0) 25 #endif 26 27 #include <utils/Log.h> 28 29 #include "../EmulatedFakeCamera2.h" 30 #include "Sensor.h" 31 #include <cmath> 32 #include <cstdlib> 33 #include "system/camera_metadata.h" 34 35 namespace android { 36 37 const unsigned int Sensor::kResolution[2] = {640, 480}; 38 const unsigned int Sensor::kActiveArray[4] = {0, 0, 640, 480}; 39 40 //const nsecs_t Sensor::kExposureTimeRange[2] = 41 // {1000L, 30000000000L} ; // 1 us - 30 sec 42 //const nsecs_t Sensor::kFrameDurationRange[2] = 43 // {33331760L, 30000000000L}; // ~1/30 s - 30 sec 44 const nsecs_t Sensor::kExposureTimeRange[2] = 45 {1000L, 300000000L} ; // 1 us - 0.3 sec 46 const nsecs_t Sensor::kFrameDurationRange[2] = 47 {33331760L, 300000000L}; // ~1/30 s - 0.3 sec 48 49 const nsecs_t Sensor::kMinVerticalBlank = 10000L; 50 51 const uint8_t Sensor::kColorFilterArrangement = 52 ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB; 53 54 // Output image data characteristics 55 const uint32_t Sensor::kMaxRawValue = 4000; 56 const uint32_t Sensor::kBlackLevel = 1000; 57 58 // Sensor sensitivity 59 const float Sensor::kSaturationVoltage = 0.520f; 60 const uint32_t Sensor::kSaturationElectrons = 2000; 61 const float Sensor::kVoltsPerLuxSecond = 0.100f; 62 63 const float Sensor::kElectronsPerLuxSecond = 64 Sensor::kSaturationElectrons / Sensor::kSaturationVoltage 65 * Sensor::kVoltsPerLuxSecond; 66 67 const float Sensor::kBaseGainFactor = (float)Sensor::kMaxRawValue / 68 Sensor::kSaturationElectrons; 69 70 const float Sensor::kReadNoiseStddevBeforeGain = 1.177; // in electrons 71 const float Sensor::kReadNoiseStddevAfterGain = 2.100; // in digital counts 72 const float Sensor::kReadNoiseVarBeforeGain = 73 Sensor::kReadNoiseStddevBeforeGain * 74 Sensor::kReadNoiseStddevBeforeGain; 75 const float Sensor::kReadNoiseVarAfterGain = 76 Sensor::kReadNoiseStddevAfterGain * 77 Sensor::kReadNoiseStddevAfterGain; 78 79 // While each row has to read out, reset, and then expose, the (reset + 80 // expose) sequence can be overlapped by other row readouts, so the final 81 // minimum frame duration is purely a function of row readout time, at least 82 // if there's a reasonable number of rows. 83 const nsecs_t Sensor::kRowReadoutTime = 84 Sensor::kFrameDurationRange[0] / Sensor::kResolution[1]; 85 86 const int32_t Sensor::kSensitivityRange[2] = {100, 1600}; 87 const uint32_t Sensor::kDefaultSensitivity = 100; 88 89 /** A few utility functions for math, normal distributions */ 90 91 // Take advantage of IEEE floating-point format to calculate an approximate 92 // square root. Accurate to within +-3.6% 93 float sqrtf_approx(float r) { 94 // Modifier is based on IEEE floating-point representation; the 95 // manipulations boil down to finding approximate log2, dividing by two, and 96 // then inverting the log2. A bias is added to make the relative error 97 // symmetric about the real answer. 98 const int32_t modifier = 0x1FBB4000; 99 100 int32_t r_i = *(int32_t*)(&r); 101 r_i = (r_i >> 1) + modifier; 102 103 return *(float*)(&r_i); 104 } 105 106 107 108 Sensor::Sensor(): 109 Thread(false), 110 mGotVSync(false), 111 mExposureTime(kFrameDurationRange[0]-kMinVerticalBlank), 112 mFrameDuration(kFrameDurationRange[0]), 113 mGainFactor(kDefaultSensitivity), 114 mNextBuffers(NULL), 115 mFrameNumber(0), 116 mCapturedBuffers(NULL), 117 mListener(NULL), 118 mScene(kResolution[0], kResolution[1], kElectronsPerLuxSecond) 119 { 120 121 } 122 123 Sensor::~Sensor() { 124 shutDown(); 125 } 126 127 status_t Sensor::startUp() { 128 ALOGV("%s: E", __FUNCTION__); 129 130 int res; 131 mCapturedBuffers = NULL; 132 res = run("EmulatedFakeCamera2::Sensor", 133 ANDROID_PRIORITY_URGENT_DISPLAY); 134 135 if (res != OK) { 136 ALOGE("Unable to start up sensor capture thread: %d", res); 137 } 138 return res; 139 } 140 141 status_t Sensor::shutDown() { 142 ALOGV("%s: E", __FUNCTION__); 143 144 int res; 145 res = requestExitAndWait(); 146 if (res != OK) { 147 ALOGE("Unable to shut down sensor capture thread: %d", res); 148 } 149 return res; 150 } 151 152 Scene &Sensor::getScene() { 153 return mScene; 154 } 155 156 void Sensor::setExposureTime(uint64_t ns) { 157 Mutex::Autolock lock(mControlMutex); 158 ALOGVV("Exposure set to %f", ns/1000000.f); 159 mExposureTime = ns; 160 } 161 162 void Sensor::setFrameDuration(uint64_t ns) { 163 Mutex::Autolock lock(mControlMutex); 164 ALOGVV("Frame duration set to %f", ns/1000000.f); 165 mFrameDuration = ns; 166 } 167 168 void Sensor::setSensitivity(uint32_t gain) { 169 Mutex::Autolock lock(mControlMutex); 170 ALOGVV("Gain set to %d", gain); 171 mGainFactor = gain; 172 } 173 174 void Sensor::setDestinationBuffers(Buffers *buffers) { 175 Mutex::Autolock lock(mControlMutex); 176 mNextBuffers = buffers; 177 } 178 179 void Sensor::setFrameNumber(uint32_t frameNumber) { 180 Mutex::Autolock lock(mControlMutex); 181 mFrameNumber = frameNumber; 182 } 183 184 bool Sensor::waitForVSync(nsecs_t reltime) { 185 int res; 186 Mutex::Autolock lock(mControlMutex); 187 188 mGotVSync = false; 189 res = mVSync.waitRelative(mControlMutex, reltime); 190 if (res != OK && res != TIMED_OUT) { 191 ALOGE("%s: Error waiting for VSync signal: %d", __FUNCTION__, res); 192 return false; 193 } 194 return mGotVSync; 195 } 196 197 bool Sensor::waitForNewFrame(nsecs_t reltime, 198 nsecs_t *captureTime) { 199 Mutex::Autolock lock(mReadoutMutex); 200 uint8_t *ret; 201 if (mCapturedBuffers == NULL) { 202 int res; 203 res = mReadoutAvailable.waitRelative(mReadoutMutex, reltime); 204 if (res == TIMED_OUT) { 205 return false; 206 } else if (res != OK || mCapturedBuffers == NULL) { 207 ALOGE("Error waiting for sensor readout signal: %d", res); 208 return false; 209 } 210 } else { 211 mReadoutComplete.signal(); 212 } 213 214 *captureTime = mCaptureTime; 215 mCapturedBuffers = NULL; 216 return true; 217 } 218 219 Sensor::SensorListener::~SensorListener() { 220 } 221 222 void Sensor::setSensorListener(SensorListener *listener) { 223 Mutex::Autolock lock(mControlMutex); 224 mListener = listener; 225 } 226 227 status_t Sensor::readyToRun() { 228 ALOGV("Starting up sensor thread"); 229 mStartupTime = systemTime(); 230 mNextCaptureTime = 0; 231 mNextCapturedBuffers = NULL; 232 return OK; 233 } 234 235 bool Sensor::threadLoop() { 236 /** 237 * Sensor capture operation main loop. 238 * 239 * Stages are out-of-order relative to a single frame's processing, but 240 * in-order in time. 241 */ 242 243 /** 244 * Stage 1: Read in latest control parameters 245 */ 246 uint64_t exposureDuration; 247 uint64_t frameDuration; 248 uint32_t gain; 249 Buffers *nextBuffers; 250 uint32_t frameNumber; 251 SensorListener *listener = NULL; 252 { 253 Mutex::Autolock lock(mControlMutex); 254 exposureDuration = mExposureTime; 255 frameDuration = mFrameDuration; 256 gain = mGainFactor; 257 nextBuffers = mNextBuffers; 258 frameNumber = mFrameNumber; 259 listener = mListener; 260 // Don't reuse a buffer set 261 mNextBuffers = NULL; 262 263 // Signal VSync for start of readout 264 ALOGVV("Sensor VSync"); 265 mGotVSync = true; 266 mVSync.signal(); 267 } 268 269 /** 270 * Stage 3: Read out latest captured image 271 */ 272 273 Buffers *capturedBuffers = NULL; 274 nsecs_t captureTime = 0; 275 276 nsecs_t startRealTime = systemTime(); 277 // Stagefright cares about system time for timestamps, so base simulated 278 // time on that. 279 nsecs_t simulatedTime = startRealTime; 280 nsecs_t frameEndRealTime = startRealTime + frameDuration; 281 nsecs_t frameReadoutEndRealTime = startRealTime + 282 kRowReadoutTime * kResolution[1]; 283 284 if (mNextCapturedBuffers != NULL) { 285 ALOGVV("Sensor starting readout"); 286 // Pretend we're doing readout now; will signal once enough time has elapsed 287 capturedBuffers = mNextCapturedBuffers; 288 captureTime = mNextCaptureTime; 289 } 290 simulatedTime += kRowReadoutTime + kMinVerticalBlank; 291 292 // TODO: Move this signal to another thread to simulate readout 293 // time properly 294 if (capturedBuffers != NULL) { 295 ALOGVV("Sensor readout complete"); 296 Mutex::Autolock lock(mReadoutMutex); 297 if (mCapturedBuffers != NULL) { 298 ALOGV("Waiting for readout thread to catch up!"); 299 mReadoutComplete.wait(mReadoutMutex); 300 } 301 302 mCapturedBuffers = capturedBuffers; 303 mCaptureTime = captureTime; 304 mReadoutAvailable.signal(); 305 capturedBuffers = NULL; 306 } 307 308 /** 309 * Stage 2: Capture new image 310 */ 311 mNextCaptureTime = simulatedTime; 312 mNextCapturedBuffers = nextBuffers; 313 314 if (mNextCapturedBuffers != NULL) { 315 if (listener != NULL) { 316 listener->onSensorEvent(frameNumber, SensorListener::EXPOSURE_START, 317 mNextCaptureTime); 318 } 319 ALOGVV("Starting next capture: Exposure: %f ms, gain: %d", 320 (float)exposureDuration/1e6, gain); 321 mScene.setExposureDuration((float)exposureDuration/1e9); 322 mScene.calculateScene(mNextCaptureTime); 323 324 // Might be adding more buffers, so size isn't constant 325 for (size_t i = 0; i < mNextCapturedBuffers->size(); i++) { 326 const StreamBuffer &b = (*mNextCapturedBuffers)[i]; 327 ALOGVV("Sensor capturing buffer %d: stream %d," 328 " %d x %d, format %x, stride %d, buf %p, img %p", 329 i, b.streamId, b.width, b.height, b.format, b.stride, 330 b.buffer, b.img); 331 switch(b.format) { 332 case HAL_PIXEL_FORMAT_RAW16: 333 captureRaw(b.img, gain, b.stride); 334 break; 335 case HAL_PIXEL_FORMAT_RGB_888: 336 captureRGB(b.img, gain, b.stride); 337 break; 338 case HAL_PIXEL_FORMAT_RGBA_8888: 339 captureRGBA(b.img, gain, b.stride); 340 break; 341 case HAL_PIXEL_FORMAT_BLOB: 342 if (b.dataSpace != HAL_DATASPACE_DEPTH) { 343 // Add auxillary buffer of the right size 344 // Assumes only one BLOB (JPEG) buffer in 345 // mNextCapturedBuffers 346 StreamBuffer bAux; 347 bAux.streamId = 0; 348 bAux.width = b.width; 349 bAux.height = b.height; 350 bAux.format = HAL_PIXEL_FORMAT_RGB_888; 351 bAux.stride = b.width; 352 bAux.buffer = NULL; 353 // TODO: Reuse these 354 bAux.img = new uint8_t[b.width * b.height * 3]; 355 mNextCapturedBuffers->push_back(bAux); 356 } else { 357 captureDepthCloud(b.img); 358 } 359 break; 360 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 361 captureNV21(b.img, gain, b.stride); 362 break; 363 case HAL_PIXEL_FORMAT_YV12: 364 // TODO: 365 ALOGE("%s: Format %x is TODO", __FUNCTION__, b.format); 366 break; 367 case HAL_PIXEL_FORMAT_Y16: 368 captureDepth(b.img, gain, b.stride); 369 break; 370 default: 371 ALOGE("%s: Unknown format %x, no output", __FUNCTION__, 372 b.format); 373 break; 374 } 375 } 376 } 377 378 ALOGVV("Sensor vertical blanking interval"); 379 nsecs_t workDoneRealTime = systemTime(); 380 const nsecs_t timeAccuracy = 2e6; // 2 ms of imprecision is ok 381 if (workDoneRealTime < frameEndRealTime - timeAccuracy) { 382 timespec t; 383 t.tv_sec = (frameEndRealTime - workDoneRealTime) / 1000000000L; 384 t.tv_nsec = (frameEndRealTime - workDoneRealTime) % 1000000000L; 385 386 int ret; 387 do { 388 ret = nanosleep(&t, &t); 389 } while (ret != 0); 390 } 391 nsecs_t endRealTime = systemTime(); 392 ALOGVV("Frame cycle took %d ms, target %d ms", 393 (int)((endRealTime - startRealTime)/1000000), 394 (int)(frameDuration / 1000000)); 395 return true; 396 }; 397 398 void Sensor::captureRaw(uint8_t *img, uint32_t gain, uint32_t stride) { 399 float totalGain = gain/100.0 * kBaseGainFactor; 400 float noiseVarGain = totalGain * totalGain; 401 float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain 402 + kReadNoiseVarAfterGain; 403 404 int bayerSelect[4] = {Scene::R, Scene::Gr, Scene::Gb, Scene::B}; // RGGB 405 mScene.setReadoutPixel(0,0); 406 for (unsigned int y = 0; y < kResolution[1]; y++ ) { 407 int *bayerRow = bayerSelect + (y & 0x1) * 2; 408 uint16_t *px = (uint16_t*)img + y * stride; 409 for (unsigned int x = 0; x < kResolution[0]; x++) { 410 uint32_t electronCount; 411 electronCount = mScene.getPixelElectrons()[bayerRow[x & 0x1]]; 412 413 // TODO: Better pixel saturation curve? 414 electronCount = (electronCount < kSaturationElectrons) ? 415 electronCount : kSaturationElectrons; 416 417 // TODO: Better A/D saturation curve? 418 uint16_t rawCount = electronCount * totalGain; 419 rawCount = (rawCount < kMaxRawValue) ? rawCount : kMaxRawValue; 420 421 // Calculate noise value 422 // TODO: Use more-correct Gaussian instead of uniform noise 423 float photonNoiseVar = electronCount * noiseVarGain; 424 float noiseStddev = sqrtf_approx(readNoiseVar + photonNoiseVar); 425 // Scaled to roughly match gaussian/uniform noise stddev 426 float noiseSample = std::rand() * (2.5 / (1.0 + RAND_MAX)) - 1.25; 427 428 rawCount += kBlackLevel; 429 rawCount += noiseStddev * noiseSample; 430 431 *px++ = rawCount; 432 } 433 // TODO: Handle this better 434 //simulatedTime += kRowReadoutTime; 435 } 436 ALOGVV("Raw sensor image captured"); 437 } 438 439 void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) { 440 float totalGain = gain/100.0 * kBaseGainFactor; 441 // In fixed-point math, calculate total scaling from electrons to 8bpp 442 int scale64x = 64 * totalGain * 255 / kMaxRawValue; 443 uint32_t inc = kResolution[0] / stride; 444 445 for (unsigned int y = 0, outY = 0; y < kResolution[1]; y+=inc, outY++ ) { 446 uint8_t *px = img + outY * stride * 4; 447 mScene.setReadoutPixel(0, y); 448 for (unsigned int x = 0; x < kResolution[0]; x+=inc) { 449 uint32_t rCount, gCount, bCount; 450 // TODO: Perfect demosaicing is a cheat 451 const uint32_t *pixel = mScene.getPixelElectrons(); 452 rCount = pixel[Scene::R] * scale64x; 453 gCount = pixel[Scene::Gr] * scale64x; 454 bCount = pixel[Scene::B] * scale64x; 455 456 *px++ = rCount < 255*64 ? rCount / 64 : 255; 457 *px++ = gCount < 255*64 ? gCount / 64 : 255; 458 *px++ = bCount < 255*64 ? bCount / 64 : 255; 459 *px++ = 255; 460 for (unsigned int j = 1; j < inc; j++) 461 mScene.getPixelElectrons(); 462 } 463 // TODO: Handle this better 464 //simulatedTime += kRowReadoutTime; 465 } 466 ALOGVV("RGBA sensor image captured"); 467 } 468 469 void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) { 470 float totalGain = gain/100.0 * kBaseGainFactor; 471 // In fixed-point math, calculate total scaling from electrons to 8bpp 472 int scale64x = 64 * totalGain * 255 / kMaxRawValue; 473 uint32_t inc = kResolution[0] / stride; 474 475 for (unsigned int y = 0, outY = 0; y < kResolution[1]; y += inc, outY++ ) { 476 mScene.setReadoutPixel(0, y); 477 uint8_t *px = img + outY * stride * 3; 478 for (unsigned int x = 0; x < kResolution[0]; x += inc) { 479 uint32_t rCount, gCount, bCount; 480 // TODO: Perfect demosaicing is a cheat 481 const uint32_t *pixel = mScene.getPixelElectrons(); 482 rCount = pixel[Scene::R] * scale64x; 483 gCount = pixel[Scene::Gr] * scale64x; 484 bCount = pixel[Scene::B] * scale64x; 485 486 *px++ = rCount < 255*64 ? rCount / 64 : 255; 487 *px++ = gCount < 255*64 ? gCount / 64 : 255; 488 *px++ = bCount < 255*64 ? bCount / 64 : 255; 489 for (unsigned int j = 1; j < inc; j++) 490 mScene.getPixelElectrons(); 491 } 492 // TODO: Handle this better 493 //simulatedTime += kRowReadoutTime; 494 } 495 ALOGVV("RGB sensor image captured"); 496 } 497 498 void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) { 499 float totalGain = gain/100.0 * kBaseGainFactor; 500 // Using fixed-point math with 6 bits of fractional precision. 501 // In fixed-point math, calculate total scaling from electrons to 8bpp 502 const int scale64x = 64 * totalGain * 255 / kMaxRawValue; 503 // In fixed-point math, saturation point of sensor after gain 504 const int saturationPoint = 64 * 255; 505 // Fixed-point coefficients for RGB-YUV transform 506 // Based on JFIF RGB->YUV transform. 507 // Cb/Cr offset scaled by 64x twice since they're applied post-multiply 508 const int rgbToY[] = {19, 37, 7}; 509 const int rgbToCb[] = {-10,-21, 32, 524288}; 510 const int rgbToCr[] = {32,-26, -5, 524288}; 511 // Scale back to 8bpp non-fixed-point 512 const int scaleOut = 64; 513 const int scaleOutSq = scaleOut * scaleOut; // after multiplies 514 515 uint32_t inc = kResolution[0] / stride; 516 uint32_t outH = kResolution[1] / inc; 517 for (unsigned int y = 0, outY = 0; 518 y < kResolution[1]; y+=inc, outY++) { 519 uint8_t *pxY = img + outY * stride; 520 uint8_t *pxVU = img + (outH + outY / 2) * stride; 521 mScene.setReadoutPixel(0,y); 522 for (unsigned int outX = 0; outX < stride; outX++) { 523 int32_t rCount, gCount, bCount; 524 // TODO: Perfect demosaicing is a cheat 525 const uint32_t *pixel = mScene.getPixelElectrons(); 526 rCount = pixel[Scene::R] * scale64x; 527 rCount = rCount < saturationPoint ? rCount : saturationPoint; 528 gCount = pixel[Scene::Gr] * scale64x; 529 gCount = gCount < saturationPoint ? gCount : saturationPoint; 530 bCount = pixel[Scene::B] * scale64x; 531 bCount = bCount < saturationPoint ? bCount : saturationPoint; 532 533 *pxY++ = (rgbToY[0] * rCount + 534 rgbToY[1] * gCount + 535 rgbToY[2] * bCount) / scaleOutSq; 536 if (outY % 2 == 0 && outX % 2 == 0) { 537 *pxVU++ = (rgbToCr[0] * rCount + 538 rgbToCr[1] * gCount + 539 rgbToCr[2] * bCount + 540 rgbToCr[3]) / scaleOutSq; 541 *pxVU++ = (rgbToCb[0] * rCount + 542 rgbToCb[1] * gCount + 543 rgbToCb[2] * bCount + 544 rgbToCb[3]) / scaleOutSq; 545 } 546 for (unsigned int j = 1; j < inc; j++) 547 mScene.getPixelElectrons(); 548 } 549 } 550 ALOGVV("NV21 sensor image captured"); 551 } 552 553 void Sensor::captureDepth(uint8_t *img, uint32_t gain, uint32_t stride) { 554 float totalGain = gain/100.0 * kBaseGainFactor; 555 // In fixed-point math, calculate scaling factor to 13bpp millimeters 556 int scale64x = 64 * totalGain * 8191 / kMaxRawValue; 557 uint32_t inc = kResolution[0] / stride; 558 559 for (unsigned int y = 0, outY = 0; y < kResolution[1]; y += inc, outY++ ) { 560 mScene.setReadoutPixel(0, y); 561 uint16_t *px = ((uint16_t*)img) + outY * stride; 562 for (unsigned int x = 0; x < kResolution[0]; x += inc) { 563 uint32_t depthCount; 564 // TODO: Make up real depth scene instead of using green channel 565 // as depth 566 const uint32_t *pixel = mScene.getPixelElectrons(); 567 depthCount = pixel[Scene::Gr] * scale64x; 568 569 *px++ = depthCount < 8191*64 ? depthCount / 64 : 0; 570 for (unsigned int j = 1; j < inc; j++) 571 mScene.getPixelElectrons(); 572 } 573 // TODO: Handle this better 574 //simulatedTime += kRowReadoutTime; 575 } 576 ALOGVV("Depth sensor image captured"); 577 } 578 579 void Sensor::captureDepthCloud(uint8_t *img) { 580 581 android_depth_points *cloud = reinterpret_cast<android_depth_points*>(img); 582 583 cloud->num_points = 16; 584 585 // TODO: Create point cloud values that match RGB scene 586 const int FLOATS_PER_POINT = 4; 587 const float JITTER_STDDEV = 0.1f; 588 for (size_t y = 0, i = 0; y < 4; y++) { 589 for (size_t x = 0; x < 4; x++, i++) { 590 float randSampleX = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f; 591 randSampleX *= JITTER_STDDEV; 592 593 float randSampleY = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f; 594 randSampleY *= JITTER_STDDEV; 595 596 float randSampleZ = std::rand() * (2.5f / (1.0f + RAND_MAX)) - 1.25f; 597 randSampleZ *= JITTER_STDDEV; 598 599 cloud->xyzc_points[i * FLOATS_PER_POINT + 0] = x - 1.5f + randSampleX; 600 cloud->xyzc_points[i * FLOATS_PER_POINT + 1] = y - 1.5f + randSampleY; 601 cloud->xyzc_points[i * FLOATS_PER_POINT + 2] = 3.f + randSampleZ; 602 cloud->xyzc_points[i * FLOATS_PER_POINT + 3] = 0.8f; 603 } 604 } 605 606 ALOGVV("Depth point cloud captured"); 607 608 } 609 610 } // namespace android 611