Merge "EmulatedFakeCamera2: Add opaque stream output support"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4cdc74e854
@@ -236,6 +236,9 @@ int EmulatedFakeCamera2::allocateStream(
|
||||
ALOGE("%s: Format 0x%x is not supported", __FUNCTION__, format);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
// Emulator's opaque format is RGBA
|
||||
format = HAL_PIXEL_FORMAT_RGBA_8888;
|
||||
}
|
||||
|
||||
const uint32_t *availableSizes;
|
||||
@@ -263,13 +266,12 @@ int EmulatedFakeCamera2::allocateStream(
|
||||
// TODO: Generalize below to work for variable types of streams, etc.
|
||||
// Currently only correct for raw sensor format, sensor resolution.
|
||||
|
||||
ALOG_ASSERT(format == HAL_PIXEL_FORMAT_RAW_SENSOR,
|
||||
"%s: TODO: Only supporting raw sensor format right now", __FUNCTION__);
|
||||
ALOG_ASSERT(width == Sensor::kResolution[0],
|
||||
"%s: TODO: Only supporting raw sensor size right now", __FUNCTION__);
|
||||
ALOG_ASSERT(height == Sensor::kResolution[1],
|
||||
"%s: TODO: Only supporting raw sensor size right now", __FUNCTION__);
|
||||
|
||||
mStreamFormat = format;
|
||||
mRawStreamOps = stream_ops;
|
||||
|
||||
*stream_id = mNextStreamId;
|
||||
@@ -496,7 +498,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
|
||||
ANDROID_REQUEST_FRAME_COUNT,
|
||||
&e);
|
||||
if (res != NO_ERROR) {
|
||||
ALOGE("%s: error reading frame count tag", __FUNCTION__);
|
||||
ALOGE("%s: error reading frame count tag: %s (%d)",
|
||||
__FUNCTION__, strerror(-res), res);
|
||||
mParent->signalError();
|
||||
return false;
|
||||
}
|
||||
@@ -506,7 +509,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
|
||||
ANDROID_SENSOR_EXPOSURE_TIME,
|
||||
&e);
|
||||
if (res != NO_ERROR) {
|
||||
ALOGE("%s: error reading exposure time tag", __FUNCTION__);
|
||||
ALOGE("%s: error reading exposure time tag: %s (%d)",
|
||||
__FUNCTION__, strerror(-res), res);
|
||||
mParent->signalError();
|
||||
return false;
|
||||
}
|
||||
@@ -587,7 +591,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
|
||||
mParent->signalError();
|
||||
return false;
|
||||
}
|
||||
mParent->mSensor->setDestinationBuffer(img, mNextBufferStride);
|
||||
mParent->mSensor->setDestinationBuffer(img, mParent->mStreamFormat,
|
||||
mNextBufferStride);
|
||||
mParent->mReadoutThread->setNextCapture(mRequest, mNextBuffer);
|
||||
|
||||
mRequest = NULL;
|
||||
@@ -1089,8 +1094,15 @@ status_t EmulatedFakeCamera2::constructDefaultRequest(
|
||||
static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_NONE;
|
||||
ADD_OR_SIZE(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1);
|
||||
|
||||
static const int32_t id = 0;
|
||||
ADD_OR_SIZE(ANDROID_REQUEST_ID, &id, 1);
|
||||
|
||||
static const int32_t frameCount = 0;
|
||||
ADD_OR_SIZE(ANDROID_REQUEST_FRAME_COUNT, &frameCount, 1);
|
||||
|
||||
// OUTPUT_STREAMS set by user
|
||||
// FRAME_COUNT set by user
|
||||
entryCount += 1;
|
||||
dataCount += 5; // TODO: Should be maximum stream number
|
||||
|
||||
/** android.lens */
|
||||
|
||||
|
||||
@@ -246,6 +246,7 @@ private:
|
||||
/** Stream manipulation */
|
||||
uint32_t mNextStreamId;
|
||||
const camera2_stream_ops_t *mRawStreamOps;
|
||||
uint32_t mStreamFormat;
|
||||
|
||||
/** Simulated hardware interfaces */
|
||||
sp<Sensor> mSensor;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "EmulatedCamera_Scene"
|
||||
#include <utils/Log.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
@@ -27,17 +28,17 @@ namespace android {
|
||||
|
||||
// Define single-letter shortcuts for scene definition, for directly indexing
|
||||
// mCurrentColors
|
||||
#define G Scene::GRASS*4
|
||||
#define S Scene::GRASS_SHADOW*4
|
||||
#define H Scene::HILL*4
|
||||
#define W Scene::WALL*4
|
||||
#define R Scene::ROOF*4
|
||||
#define D Scene::DOOR*4
|
||||
#define C Scene::CHIMNEY*4
|
||||
#define I Scene::WINDOW*4
|
||||
#define U Scene::SUN*4
|
||||
#define K Scene::SKY*4
|
||||
#define M Scene::MOON*4
|
||||
#define G (Scene::GRASS * Scene::NUM_CHANNELS)
|
||||
#define S (Scene::GRASS_SHADOW * Scene::NUM_CHANNELS)
|
||||
#define H (Scene::HILL * Scene::NUM_CHANNELS)
|
||||
#define W (Scene::WALL * Scene::NUM_CHANNELS)
|
||||
#define R (Scene::ROOF * Scene::NUM_CHANNELS)
|
||||
#define D (Scene::DOOR * Scene::NUM_CHANNELS)
|
||||
#define C (Scene::CHIMNEY * Scene::NUM_CHANNELS)
|
||||
#define I (Scene::WINDOW * Scene::NUM_CHANNELS)
|
||||
#define U (Scene::SUN * Scene::NUM_CHANNELS)
|
||||
#define K (Scene::SKY * Scene::NUM_CHANNELS)
|
||||
#define M (Scene::MOON * Scene::NUM_CHANNELS)
|
||||
|
||||
const int Scene::kSceneWidth = 20;
|
||||
const int Scene::kSceneHeight = 20;
|
||||
@@ -91,9 +92,9 @@ Scene::Scene(
|
||||
{
|
||||
// Map scene to sensor pixels
|
||||
if (mSensorWidth > mSensorHeight) {
|
||||
mMapDiv = (mSensorWidth / kSceneWidth) + 1;
|
||||
mMapDiv = (mSensorWidth / (kSceneWidth + 1) ) + 1;
|
||||
} else {
|
||||
mMapDiv = (mSensorHeight / kSceneHeight) + 1;
|
||||
mMapDiv = (mSensorHeight / (kSceneHeight + 1) ) + 1;
|
||||
}
|
||||
mOffsetX = (kSceneWidth * mMapDiv - mSensorWidth) / 2;
|
||||
mOffsetY = (kSceneHeight * mMapDiv - mSensorHeight) / 2;
|
||||
@@ -103,6 +104,8 @@ Scene::Scene(
|
||||
mFilterGr[0] = -0.9689f; mFilterGr[1] = 1.8758f; mFilterGr[2] = 0.0415f;
|
||||
mFilterGb[0] = -0.9689f; mFilterGb[1] = 1.8758f; mFilterGb[2] = 0.0415f;
|
||||
mFilterB[0] = 0.0557f; mFilterB[1] = -0.2040f; mFilterB[2] = 1.0570f;
|
||||
|
||||
|
||||
}
|
||||
|
||||
Scene::~Scene() {
|
||||
@@ -290,48 +293,53 @@ void Scene::calculateScene(nsecs_t time) {
|
||||
ALOGV("Mat %d XYZ: %f, %f, %f", i, matXYZ[0], matXYZ[1], matXYZ[2]);
|
||||
float luxToElectrons = mSensorSensitivity * mExposureDuration /
|
||||
(kAperture * kAperture);
|
||||
mCurrentColors[i*4 + 0] =
|
||||
mCurrentColors[i*NUM_CHANNELS + 0] =
|
||||
(mFilterR[0] * matXYZ[0] +
|
||||
mFilterR[1] * matXYZ[1] +
|
||||
mFilterR[2] * matXYZ[2])
|
||||
* luxToElectrons;
|
||||
mCurrentColors[i*4 + 1] =
|
||||
mCurrentColors[i*NUM_CHANNELS + 1] =
|
||||
(mFilterGr[0] * matXYZ[0] +
|
||||
mFilterGr[1] * matXYZ[1] +
|
||||
mFilterGr[2] * matXYZ[2])
|
||||
* luxToElectrons;
|
||||
mCurrentColors[i*4 + 2] =
|
||||
mCurrentColors[i*NUM_CHANNELS + 2] =
|
||||
(mFilterGb[0] * matXYZ[0] +
|
||||
mFilterGb[1] * matXYZ[1] +
|
||||
mFilterGb[2] * matXYZ[2])
|
||||
* luxToElectrons;
|
||||
mCurrentColors[i*4 + 3] =
|
||||
mCurrentColors[i*NUM_CHANNELS + 3] =
|
||||
(mFilterB[0] * matXYZ[0] +
|
||||
mFilterB[1] * matXYZ[1] +
|
||||
mFilterB[2] * matXYZ[2])
|
||||
* luxToElectrons;
|
||||
|
||||
ALOGV("Color %d RGGB: %d, %d, %d, %d", i,
|
||||
mCurrentColors[i*4 + 0],
|
||||
mCurrentColors[i*4 + 1],
|
||||
mCurrentColors[i*4 + 2],
|
||||
mCurrentColors[i*4 + 3]);
|
||||
mCurrentColors[i*NUM_CHANNELS + 0],
|
||||
mCurrentColors[i*NUM_CHANNELS + 1],
|
||||
mCurrentColors[i*NUM_CHANNELS + 2],
|
||||
mCurrentColors[i*NUM_CHANNELS + 3]);
|
||||
}
|
||||
// Shake viewpoint
|
||||
mHandshakeX = rand() % mMapDiv/4 - mMapDiv/8;
|
||||
mHandshakeY = rand() % mMapDiv/4 - mMapDiv/8;
|
||||
// Set starting pixel
|
||||
setReadoutPixel(0,0);
|
||||
}
|
||||
|
||||
void Scene::setReadoutPixel(int x, int y) {
|
||||
mCurrentX = x;
|
||||
mCurrentY = y;
|
||||
mSubX = (x + mOffsetY) % mMapDiv;
|
||||
mSubY = (y + mOffsetX) % mMapDiv;
|
||||
mSceneX = (x + mOffsetX) / mMapDiv;
|
||||
mSceneY = (y + mOffsetY) / mMapDiv;
|
||||
mSubX = (x + mOffsetX + mHandshakeX) % mMapDiv;
|
||||
mSubY = (y + mOffsetY + mHandshakeY) % mMapDiv;
|
||||
mSceneX = (x + mOffsetX + mHandshakeX) / mMapDiv;
|
||||
mSceneY = (y + mOffsetY + mHandshakeY) / mMapDiv;
|
||||
mSceneIdx = mSceneY * kSceneWidth + mSceneX;
|
||||
mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
|
||||
}
|
||||
|
||||
uint32_t Scene::getPixelElectrons(int x, int y, int c) {
|
||||
uint32_t e = mCurrentSceneMaterial[c];
|
||||
const uint32_t* Scene::getPixelElectrons() {
|
||||
const uint32_t *pixel = mCurrentSceneMaterial;
|
||||
mCurrentX++;
|
||||
mSubX++;
|
||||
if (mCurrentX >= mSensorWidth) {
|
||||
@@ -345,9 +353,16 @@ uint32_t Scene::getPixelElectrons(int x, int y, int c) {
|
||||
mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
|
||||
mSubX = 0;
|
||||
}
|
||||
return e;
|
||||
return pixel;
|
||||
}
|
||||
|
||||
// RGB->YUV, Jpeg standard
|
||||
const float Scene::kRgb2Yuv[12] = {
|
||||
0.299f, 0.587f, 0.114f, 0.f,
|
||||
-0.16874f, -0.33126f, 0.5f, -128.f,
|
||||
0.5f, -0.41869f, -0.08131f, -128.f,
|
||||
};
|
||||
|
||||
// Aperture of imaging lens
|
||||
const float Scene::kAperture = 2.8;
|
||||
|
||||
|
||||
@@ -67,10 +67,21 @@ class Scene {
|
||||
void setReadoutPixel(int x, int y);
|
||||
|
||||
// Get sensor response in physical units (electrons) for light hitting the
|
||||
// current readout pixel, after passing through color filters. The color
|
||||
// channels are 0=R, 1=Gr, 2=Gb, 3=B. The readout pixel will be
|
||||
// auto-incremented.
|
||||
uint32_t getPixelElectrons(int x, int y, int c);
|
||||
// current readout pixel, after passing through color filters. The readout
|
||||
// pixel will be auto-incremented. The returned array can be indexed with
|
||||
// ColorChannels.
|
||||
const uint32_t* getPixelElectrons();
|
||||
|
||||
enum ColorChannels {
|
||||
R = 0,
|
||||
Gr,
|
||||
Gb,
|
||||
B,
|
||||
Y,
|
||||
Cb,
|
||||
Cr,
|
||||
NUM_CHANNELS
|
||||
};
|
||||
|
||||
private:
|
||||
// Sensor color filtering coefficients in XYZ
|
||||
@@ -82,6 +93,8 @@ class Scene {
|
||||
int mOffsetX, mOffsetY;
|
||||
int mMapDiv;
|
||||
|
||||
int mHandshakeX, mHandshakeY;
|
||||
|
||||
int mSensorWidth;
|
||||
int mSensorHeight;
|
||||
int mCurrentX;
|
||||
@@ -112,12 +125,15 @@ class Scene {
|
||||
NUM_MATERIALS
|
||||
};
|
||||
|
||||
uint32_t mCurrentColors[NUM_MATERIALS*4];
|
||||
uint32_t mCurrentColors[NUM_MATERIALS*NUM_CHANNELS];
|
||||
|
||||
/**
|
||||
* Constants for scene definition. These are various degrees of approximate.
|
||||
*/
|
||||
|
||||
// RGB->YUV conversion
|
||||
static const float kRgb2Yuv[12];
|
||||
|
||||
// Aperture of imaging lens
|
||||
static const float kAperture;
|
||||
|
||||
|
||||
@@ -15,7 +15,15 @@
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
//#define LOG_NNDEBUG 0
|
||||
#define LOG_TAG "EmulatedCamera2_Sensor"
|
||||
|
||||
#ifdef LOG_NNDEBUG
|
||||
#define ALOGVV(...) ALOGV(__VA_ARGS__)
|
||||
#else
|
||||
#define ALOGVV(...) ((void)0)
|
||||
#endif
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "Sensor.h"
|
||||
@@ -108,9 +116,10 @@ Sensor::~Sensor() {
|
||||
}
|
||||
|
||||
status_t Sensor::startUp() {
|
||||
ALOGV("%s: E", __FUNCTION__);
|
||||
|
||||
int res;
|
||||
mCapturedBuffer = NULL;
|
||||
|
||||
res = readyToRun();
|
||||
if (res != OK) {
|
||||
ALOGE("Unable to prepare sensor capture thread to run: %d", res);
|
||||
@@ -126,6 +135,8 @@ status_t Sensor::startUp() {
|
||||
}
|
||||
|
||||
status_t Sensor::shutDown() {
|
||||
ALOGV("%s: E", __FUNCTION__);
|
||||
|
||||
int res;
|
||||
res = requestExitAndWait();
|
||||
if (res != OK) {
|
||||
@@ -140,25 +151,27 @@ Scene &Sensor::getScene() {
|
||||
|
||||
void Sensor::setExposureTime(uint64_t ns) {
|
||||
Mutex::Autolock lock(mControlMutex);
|
||||
ALOGV("Exposure set to %f", ns/1000000.f);
|
||||
ALOGVV("Exposure set to %f", ns/1000000.f);
|
||||
mExposureTime = ns;
|
||||
}
|
||||
|
||||
void Sensor::setFrameDuration(uint64_t ns) {
|
||||
Mutex::Autolock lock(mControlMutex);
|
||||
ALOGV("Frame duration set to %f", ns/1000000.f);
|
||||
ALOGVV("Frame duration set to %f", ns/1000000.f);
|
||||
mFrameDuration = ns;
|
||||
}
|
||||
|
||||
void Sensor::setSensitivity(uint32_t gain) {
|
||||
Mutex::Autolock lock(mControlMutex);
|
||||
ALOGV("Gain set to %d", gain);
|
||||
ALOGVV("Gain set to %d", gain);
|
||||
mGainFactor = gain;
|
||||
}
|
||||
|
||||
void Sensor::setDestinationBuffer(uint8_t *buffer, uint32_t stride) {
|
||||
void Sensor::setDestinationBuffer(uint8_t *buffer,
|
||||
uint32_t format, uint32_t stride) {
|
||||
Mutex::Autolock lock(mControlMutex);
|
||||
mNextBuffer = buffer;
|
||||
mNextBufferFmt = format;
|
||||
mNextStride = stride;
|
||||
}
|
||||
|
||||
@@ -217,6 +230,7 @@ bool Sensor::threadLoop() {
|
||||
uint64_t frameDuration;
|
||||
uint32_t gain;
|
||||
uint8_t *nextBuffer;
|
||||
uint32_t nextBufferFmt;
|
||||
uint32_t stride;
|
||||
{
|
||||
Mutex::Autolock lock(mControlMutex);
|
||||
@@ -224,12 +238,13 @@ bool Sensor::threadLoop() {
|
||||
frameDuration = mFrameDuration;
|
||||
gain = mGainFactor;
|
||||
nextBuffer = mNextBuffer;
|
||||
nextBufferFmt = mNextBufferFmt;
|
||||
stride = mNextStride;
|
||||
// Don't reuse a buffer
|
||||
mNextBuffer = NULL;
|
||||
|
||||
// Signal VSync for start of readout
|
||||
ALOGV("Sensor VSync");
|
||||
ALOGVV("Sensor VSync");
|
||||
mGotVSync = true;
|
||||
mVSync.signal();
|
||||
}
|
||||
@@ -248,7 +263,7 @@ bool Sensor::threadLoop() {
|
||||
kRowReadoutTime * kResolution[1];
|
||||
|
||||
if (mNextCapturedBuffer != NULL) {
|
||||
ALOGV("Sensor starting readout");
|
||||
ALOGVV("Sensor starting readout");
|
||||
// Pretend we're doing readout now; will signal once enough time has elapsed
|
||||
capturedBuffer = mNextCapturedBuffer;
|
||||
captureTime = mNextCaptureTime;
|
||||
@@ -263,66 +278,30 @@ bool Sensor::threadLoop() {
|
||||
mNextCapturedBuffer = nextBuffer;
|
||||
|
||||
if (mNextCapturedBuffer != NULL) {
|
||||
ALOGV("Sensor capturing image (%d x %d) stride %d",
|
||||
ALOGVV("Sensor capturing image (%d x %d) stride %d",
|
||||
kResolution[0], kResolution[1], stride);
|
||||
ALOGV("Exposure: %f ms, gain: %d", (float)exposureDuration/1e6, gain);
|
||||
ALOGVV("Exposure: %f ms, gain: %d", (float)exposureDuration/1e6, gain);
|
||||
mScene.setExposureDuration((float)exposureDuration/1e9);
|
||||
mScene.calculateScene(mNextCaptureTime);
|
||||
|
||||
float totalGain = gain/100.0 * kBaseGainFactor;
|
||||
float noiseVarGain = totalGain * totalGain;
|
||||
float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain
|
||||
+ kReadNoiseVarAfterGain;
|
||||
|
||||
int bayerSelect[4] = {0, 1, 2, 3}; // RGGB
|
||||
|
||||
for (unsigned int y = 0; y < kResolution[1]; y++ ) {
|
||||
int *bayerRow = bayerSelect + (y & 0x1) * 2;
|
||||
uint16_t *px = (uint16_t*)mNextCapturedBuffer + y * stride;
|
||||
for (unsigned int x = 0; x < kResolution[0]; x++) {
|
||||
uint32_t electronCount;
|
||||
electronCount = mScene.getPixelElectrons(x, y, bayerRow[x & 0x1]);
|
||||
|
||||
// TODO: Better pixel saturation curve?
|
||||
electronCount = (electronCount < kSaturationElectrons) ?
|
||||
electronCount : kSaturationElectrons;
|
||||
|
||||
// TODO: Better A/D saturation curve?
|
||||
uint16_t rawCount = electronCount * totalGain;
|
||||
rawCount = (rawCount < kMaxRawValue) ? rawCount : kMaxRawValue;
|
||||
|
||||
// Calculate noise value
|
||||
// TODO: Use more-correct Gaussian instead of uniform noise
|
||||
float photonNoiseVar = electronCount * noiseVarGain;
|
||||
float noiseStddev = sqrtf_approx(readNoiseVar + photonNoiseVar);
|
||||
// Scaled to roughly match gaussian/uniform noise stddev
|
||||
float noiseSample = std::rand() * (2.5 / (1.0 + RAND_MAX)) - 1.25;
|
||||
|
||||
rawCount += kBlackLevel;
|
||||
rawCount += noiseStddev * noiseSample;
|
||||
|
||||
*px++ = rawCount;
|
||||
}
|
||||
simulatedTime += kRowReadoutTime;
|
||||
|
||||
// If enough time has elapsed to complete readout, signal done frame
|
||||
// Only check every so often, though
|
||||
if ((capturedBuffer != NULL) &&
|
||||
((y & 63) == 0) &&
|
||||
(systemTime() >= frameReadoutEndRealTime) ) {
|
||||
ALOGV("Sensor readout complete");
|
||||
Mutex::Autolock lock(mReadoutMutex);
|
||||
mCapturedBuffer = capturedBuffer;
|
||||
mCaptureTime = captureTime;
|
||||
mReadoutComplete.signal();
|
||||
capturedBuffer = NULL;
|
||||
}
|
||||
switch(nextBufferFmt) {
|
||||
case HAL_PIXEL_FORMAT_RAW_SENSOR:
|
||||
captureRaw(gain, stride, &capturedBuffer,
|
||||
captureTime, frameEndRealTime);
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_RGBA_8888:
|
||||
captureRGBA(gain, stride, &capturedBuffer,
|
||||
captureTime, frameEndRealTime);
|
||||
break;
|
||||
default:
|
||||
ALOGE("%s: Unknown format %x, no output", __FUNCTION__,
|
||||
nextBufferFmt);
|
||||
break;
|
||||
}
|
||||
ALOGV("Sensor image captured");
|
||||
}
|
||||
// No capture done, or finished image generation before readout was completed
|
||||
if (capturedBuffer != NULL) {
|
||||
ALOGV("Sensor readout complete");
|
||||
ALOGVV("Sensor readout complete");
|
||||
Mutex::Autolock lock(mReadoutMutex);
|
||||
mCapturedBuffer = capturedBuffer;
|
||||
mCaptureTime = captureTime;
|
||||
@@ -330,7 +309,7 @@ bool Sensor::threadLoop() {
|
||||
capturedBuffer = NULL;
|
||||
}
|
||||
|
||||
ALOGV("Sensor vertical blanking interval");
|
||||
ALOGVV("Sensor vertical blanking interval");
|
||||
nsecs_t workDoneRealTime = systemTime();
|
||||
const nsecs_t timeAccuracy = 2e6; // 2 ms of imprecision is ok
|
||||
if (workDoneRealTime < frameEndRealTime - timeAccuracy) {
|
||||
@@ -344,10 +323,106 @@ bool Sensor::threadLoop() {
|
||||
} while (ret != 0);
|
||||
}
|
||||
nsecs_t endRealTime = systemTime();
|
||||
ALOGV("Frame cycle took %d ms, target %d ms",
|
||||
ALOGVV("Frame cycle took %d ms, target %d ms",
|
||||
(int)((endRealTime - startRealTime)/1000000),
|
||||
(int)(frameDuration / 1000000));
|
||||
return true;
|
||||
};
|
||||
|
||||
void Sensor::captureRaw(uint32_t gain, uint32_t stride,
|
||||
uint8_t **capturedBuffer, nsecs_t captureTime, nsecs_t frameReadoutTime) {
|
||||
float totalGain = gain/100.0 * kBaseGainFactor;
|
||||
float noiseVarGain = totalGain * totalGain;
|
||||
float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain
|
||||
+ kReadNoiseVarAfterGain;
|
||||
|
||||
int bayerSelect[4] = {Scene::R, Scene::Gr, Scene::Gb, Scene::B}; // RGGB
|
||||
|
||||
for (unsigned int y = 0; y < kResolution[1]; y++ ) {
|
||||
int *bayerRow = bayerSelect + (y & 0x1) * 2;
|
||||
uint16_t *px = (uint16_t*)mNextCapturedBuffer + y * stride;
|
||||
for (unsigned int x = 0; x < kResolution[0]; x++) {
|
||||
uint32_t electronCount;
|
||||
electronCount = mScene.getPixelElectrons()[bayerRow[x & 0x1]];
|
||||
|
||||
// TODO: Better pixel saturation curve?
|
||||
electronCount = (electronCount < kSaturationElectrons) ?
|
||||
electronCount : kSaturationElectrons;
|
||||
|
||||
// TODO: Better A/D saturation curve?
|
||||
uint16_t rawCount = electronCount * totalGain;
|
||||
rawCount = (rawCount < kMaxRawValue) ? rawCount : kMaxRawValue;
|
||||
|
||||
// Calculate noise value
|
||||
// TODO: Use more-correct Gaussian instead of uniform noise
|
||||
float photonNoiseVar = electronCount * noiseVarGain;
|
||||
float noiseStddev = sqrtf_approx(readNoiseVar + photonNoiseVar);
|
||||
// Scaled to roughly match gaussian/uniform noise stddev
|
||||
float noiseSample = std::rand() * (2.5 / (1.0 + RAND_MAX)) - 1.25;
|
||||
|
||||
rawCount += kBlackLevel;
|
||||
rawCount += noiseStddev * noiseSample;
|
||||
|
||||
*px++ = rawCount;
|
||||
}
|
||||
// TODO: Handle this better
|
||||
//simulatedTime += kRowReadoutTime;
|
||||
|
||||
// If enough time has elapsed to complete readout, signal done frame
|
||||
// Only check every so often, though
|
||||
if ((*capturedBuffer != NULL) &&
|
||||
((y & 63) == 0) &&
|
||||
(systemTime() >= frameReadoutTime) ) {
|
||||
ALOGV("Sensor readout complete");
|
||||
Mutex::Autolock lock(mReadoutMutex);
|
||||
mCapturedBuffer = *capturedBuffer;
|
||||
mCaptureTime = captureTime;
|
||||
mReadoutComplete.signal();
|
||||
*capturedBuffer = NULL;
|
||||
}
|
||||
}
|
||||
ALOGVV("Raw sensor image captured");
|
||||
}
|
||||
|
||||
void Sensor::captureRGBA(uint32_t gain, uint32_t stride,
|
||||
uint8_t **capturedBuffer, nsecs_t captureTime, nsecs_t frameReadoutTime) {
|
||||
float totalGain = gain/100.0 * kBaseGainFactor;
|
||||
float noiseVarGain = totalGain * totalGain;
|
||||
float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain
|
||||
+ kReadNoiseVarAfterGain;
|
||||
|
||||
for (unsigned int y = 0; y < kResolution[1]; y++ ) {
|
||||
uint8_t *px = (uint8_t*)mNextCapturedBuffer + y * stride * 4;
|
||||
for (unsigned int x = 0; x < kResolution[0]; x++) {
|
||||
uint32_t rCount, gCount, bCount;
|
||||
// TODO: Perfect demosaicing is a cheat
|
||||
const uint32_t *pixel = mScene.getPixelElectrons();
|
||||
rCount = pixel[Scene::R] * totalGain;
|
||||
gCount = pixel[Scene::Gr] * totalGain;
|
||||
bCount = pixel[Scene::B] * totalGain;
|
||||
|
||||
*px++ = rCount / (kMaxRawValue / 255);
|
||||
*px++ = gCount / (kMaxRawValue / 255);
|
||||
*px++ = bCount / (kMaxRawValue / 255);
|
||||
*px++ = 255;
|
||||
}
|
||||
// TODO: Handle this better
|
||||
//simulatedTime += kRowReadoutTime;
|
||||
|
||||
// If enough time has elapsed to complete readout, signal done frame
|
||||
// Only check every so often, though
|
||||
if ((*capturedBuffer != NULL) &&
|
||||
((y & 63) == 0) &&
|
||||
(systemTime() >= frameReadoutTime) ) {
|
||||
ALOGV("Sensor readout complete");
|
||||
Mutex::Autolock lock(mReadoutMutex);
|
||||
mCapturedBuffer = *capturedBuffer;
|
||||
mCaptureTime = captureTime;
|
||||
mReadoutComplete.signal();
|
||||
*capturedBuffer = NULL;
|
||||
}
|
||||
}
|
||||
ALOGVV("RGBA sensor image captured");
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -107,7 +107,7 @@ class Sensor: private Thread, public virtual RefBase {
|
||||
void setFrameDuration(uint64_t ns);
|
||||
void setSensitivity(uint32_t gain);
|
||||
// Buffer must be at least stride*height*2 bytes in size
|
||||
void setDestinationBuffer(uint8_t *buffer, uint32_t stride);
|
||||
void setDestinationBuffer(uint8_t *buffer, uint32_t format, uint32_t stride);
|
||||
|
||||
/*
|
||||
* Controls that cause reconfiguration delay
|
||||
@@ -178,7 +178,9 @@ class Sensor: private Thread, public virtual RefBase {
|
||||
uint64_t mFrameDuration;
|
||||
uint32_t mGainFactor;
|
||||
uint8_t *mNextBuffer;
|
||||
uint32_t mNextBufferFmt;
|
||||
uint32_t mNextStride;
|
||||
|
||||
// End of control parameters
|
||||
|
||||
Mutex mReadoutMutex; // Lock before accessing readout variables
|
||||
@@ -204,6 +206,15 @@ class Sensor: private Thread, public virtual RefBase {
|
||||
uint8_t *mNextCapturedBuffer;
|
||||
|
||||
Scene mScene;
|
||||
|
||||
void captureRaw(uint32_t gain, uint32_t stride,
|
||||
uint8_t **capturedBuffer, nsecs_t captureTime,
|
||||
nsecs_t frameReadoutTime);
|
||||
|
||||
void captureRGBA(uint32_t gain, uint32_t stride,
|
||||
uint8_t **capturedBuffer, nsecs_t captureTime,
|
||||
nsecs_t frameReadoutTime);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user