Merge "EmulatedFakeCamera2: Add opaque stream output support"

This commit is contained in:
Eino-Ville Talvala
2012-06-01 10:47:13 -07:00
committed by Android (Google) Code Review
6 changed files with 231 additions and 101 deletions

View File

@@ -236,6 +236,9 @@ int EmulatedFakeCamera2::allocateStream(
ALOGE("%s: Format 0x%x is not supported", __FUNCTION__, format); ALOGE("%s: Format 0x%x is not supported", __FUNCTION__, format);
return BAD_VALUE; return BAD_VALUE;
} }
} else {
// Emulator's opaque format is RGBA
format = HAL_PIXEL_FORMAT_RGBA_8888;
} }
const uint32_t *availableSizes; const uint32_t *availableSizes;
@@ -263,13 +266,12 @@ int EmulatedFakeCamera2::allocateStream(
// TODO: Generalize below to work for variable types of streams, etc. // TODO: Generalize below to work for variable types of streams, etc.
// Currently only correct for raw sensor format, sensor resolution. // 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], ALOG_ASSERT(width == Sensor::kResolution[0],
"%s: TODO: Only supporting raw sensor size right now", __FUNCTION__); "%s: TODO: Only supporting raw sensor size right now", __FUNCTION__);
ALOG_ASSERT(height == Sensor::kResolution[1], ALOG_ASSERT(height == Sensor::kResolution[1],
"%s: TODO: Only supporting raw sensor size right now", __FUNCTION__); "%s: TODO: Only supporting raw sensor size right now", __FUNCTION__);
mStreamFormat = format;
mRawStreamOps = stream_ops; mRawStreamOps = stream_ops;
*stream_id = mNextStreamId; *stream_id = mNextStreamId;
@@ -496,7 +498,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
ANDROID_REQUEST_FRAME_COUNT, ANDROID_REQUEST_FRAME_COUNT,
&e); &e);
if (res != NO_ERROR) { 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(); mParent->signalError();
return false; return false;
} }
@@ -506,7 +509,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
ANDROID_SENSOR_EXPOSURE_TIME, ANDROID_SENSOR_EXPOSURE_TIME,
&e); &e);
if (res != NO_ERROR) { 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(); mParent->signalError();
return false; return false;
} }
@@ -587,7 +591,8 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
mParent->signalError(); mParent->signalError();
return false; return false;
} }
mParent->mSensor->setDestinationBuffer(img, mNextBufferStride); mParent->mSensor->setDestinationBuffer(img, mParent->mStreamFormat,
mNextBufferStride);
mParent->mReadoutThread->setNextCapture(mRequest, mNextBuffer); mParent->mReadoutThread->setNextCapture(mRequest, mNextBuffer);
mRequest = NULL; mRequest = NULL;
@@ -1089,8 +1094,15 @@ status_t EmulatedFakeCamera2::constructDefaultRequest(
static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_NONE; static const uint8_t metadataMode = ANDROID_REQUEST_METADATA_NONE;
ADD_OR_SIZE(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1); 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 // OUTPUT_STREAMS set by user
// FRAME_COUNT set by user entryCount += 1;
dataCount += 5; // TODO: Should be maximum stream number
/** android.lens */ /** android.lens */

View File

@@ -246,6 +246,7 @@ private:
/** Stream manipulation */ /** Stream manipulation */
uint32_t mNextStreamId; uint32_t mNextStreamId;
const camera2_stream_ops_t *mRawStreamOps; const camera2_stream_ops_t *mRawStreamOps;
uint32_t mStreamFormat;
/** Simulated hardware interfaces */ /** Simulated hardware interfaces */
sp<Sensor> mSensor; sp<Sensor> mSensor;

View File

@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_Scene" #define LOG_TAG "EmulatedCamera_Scene"
#include <utils/Log.h> #include <utils/Log.h>
#include <stdlib.h>
#include "Scene.h" #include "Scene.h"
@@ -27,17 +28,17 @@ namespace android {
// Define single-letter shortcuts for scene definition, for directly indexing // Define single-letter shortcuts for scene definition, for directly indexing
// mCurrentColors // mCurrentColors
#define G Scene::GRASS*4 #define G (Scene::GRASS * Scene::NUM_CHANNELS)
#define S Scene::GRASS_SHADOW*4 #define S (Scene::GRASS_SHADOW * Scene::NUM_CHANNELS)
#define H Scene::HILL*4 #define H (Scene::HILL * Scene::NUM_CHANNELS)
#define W Scene::WALL*4 #define W (Scene::WALL * Scene::NUM_CHANNELS)
#define R Scene::ROOF*4 #define R (Scene::ROOF * Scene::NUM_CHANNELS)
#define D Scene::DOOR*4 #define D (Scene::DOOR * Scene::NUM_CHANNELS)
#define C Scene::CHIMNEY*4 #define C (Scene::CHIMNEY * Scene::NUM_CHANNELS)
#define I Scene::WINDOW*4 #define I (Scene::WINDOW * Scene::NUM_CHANNELS)
#define U Scene::SUN*4 #define U (Scene::SUN * Scene::NUM_CHANNELS)
#define K Scene::SKY*4 #define K (Scene::SKY * Scene::NUM_CHANNELS)
#define M Scene::MOON*4 #define M (Scene::MOON * Scene::NUM_CHANNELS)
const int Scene::kSceneWidth = 20; const int Scene::kSceneWidth = 20;
const int Scene::kSceneHeight = 20; const int Scene::kSceneHeight = 20;
@@ -91,9 +92,9 @@ Scene::Scene(
{ {
// Map scene to sensor pixels // Map scene to sensor pixels
if (mSensorWidth > mSensorHeight) { if (mSensorWidth > mSensorHeight) {
mMapDiv = (mSensorWidth / kSceneWidth) + 1; mMapDiv = (mSensorWidth / (kSceneWidth + 1) ) + 1;
} else { } else {
mMapDiv = (mSensorHeight / kSceneHeight) + 1; mMapDiv = (mSensorHeight / (kSceneHeight + 1) ) + 1;
} }
mOffsetX = (kSceneWidth * mMapDiv - mSensorWidth) / 2; mOffsetX = (kSceneWidth * mMapDiv - mSensorWidth) / 2;
mOffsetY = (kSceneHeight * mMapDiv - mSensorHeight) / 2; mOffsetY = (kSceneHeight * mMapDiv - mSensorHeight) / 2;
@@ -103,6 +104,8 @@ Scene::Scene(
mFilterGr[0] = -0.9689f; mFilterGr[1] = 1.8758f; mFilterGr[2] = 0.0415f; mFilterGr[0] = -0.9689f; mFilterGr[1] = 1.8758f; mFilterGr[2] = 0.0415f;
mFilterGb[0] = -0.9689f; mFilterGb[1] = 1.8758f; mFilterGb[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; mFilterB[0] = 0.0557f; mFilterB[1] = -0.2040f; mFilterB[2] = 1.0570f;
} }
Scene::~Scene() { 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]); ALOGV("Mat %d XYZ: %f, %f, %f", i, matXYZ[0], matXYZ[1], matXYZ[2]);
float luxToElectrons = mSensorSensitivity * mExposureDuration / float luxToElectrons = mSensorSensitivity * mExposureDuration /
(kAperture * kAperture); (kAperture * kAperture);
mCurrentColors[i*4 + 0] = mCurrentColors[i*NUM_CHANNELS + 0] =
(mFilterR[0] * matXYZ[0] + (mFilterR[0] * matXYZ[0] +
mFilterR[1] * matXYZ[1] + mFilterR[1] * matXYZ[1] +
mFilterR[2] * matXYZ[2]) mFilterR[2] * matXYZ[2])
* luxToElectrons; * luxToElectrons;
mCurrentColors[i*4 + 1] = mCurrentColors[i*NUM_CHANNELS + 1] =
(mFilterGr[0] * matXYZ[0] + (mFilterGr[0] * matXYZ[0] +
mFilterGr[1] * matXYZ[1] + mFilterGr[1] * matXYZ[1] +
mFilterGr[2] * matXYZ[2]) mFilterGr[2] * matXYZ[2])
* luxToElectrons; * luxToElectrons;
mCurrentColors[i*4 + 2] = mCurrentColors[i*NUM_CHANNELS + 2] =
(mFilterGb[0] * matXYZ[0] + (mFilterGb[0] * matXYZ[0] +
mFilterGb[1] * matXYZ[1] + mFilterGb[1] * matXYZ[1] +
mFilterGb[2] * matXYZ[2]) mFilterGb[2] * matXYZ[2])
* luxToElectrons; * luxToElectrons;
mCurrentColors[i*4 + 3] = mCurrentColors[i*NUM_CHANNELS + 3] =
(mFilterB[0] * matXYZ[0] + (mFilterB[0] * matXYZ[0] +
mFilterB[1] * matXYZ[1] + mFilterB[1] * matXYZ[1] +
mFilterB[2] * matXYZ[2]) mFilterB[2] * matXYZ[2])
* luxToElectrons; * luxToElectrons;
ALOGV("Color %d RGGB: %d, %d, %d, %d", i, ALOGV("Color %d RGGB: %d, %d, %d, %d", i,
mCurrentColors[i*4 + 0], mCurrentColors[i*NUM_CHANNELS + 0],
mCurrentColors[i*4 + 1], mCurrentColors[i*NUM_CHANNELS + 1],
mCurrentColors[i*4 + 2], mCurrentColors[i*NUM_CHANNELS + 2],
mCurrentColors[i*4 + 3]); 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); setReadoutPixel(0,0);
} }
void Scene::setReadoutPixel(int x, int y) { void Scene::setReadoutPixel(int x, int y) {
mCurrentX = x; mCurrentX = x;
mCurrentY = y; mCurrentY = y;
mSubX = (x + mOffsetY) % mMapDiv; mSubX = (x + mOffsetX + mHandshakeX) % mMapDiv;
mSubY = (y + mOffsetX) % mMapDiv; mSubY = (y + mOffsetY + mHandshakeY) % mMapDiv;
mSceneX = (x + mOffsetX) / mMapDiv; mSceneX = (x + mOffsetX + mHandshakeX) / mMapDiv;
mSceneY = (y + mOffsetY) / mMapDiv; mSceneY = (y + mOffsetY + mHandshakeY) / mMapDiv;
mSceneIdx = mSceneY * kSceneWidth + mSceneX; mSceneIdx = mSceneY * kSceneWidth + mSceneX;
mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
} }
uint32_t Scene::getPixelElectrons(int x, int y, int c) { const uint32_t* Scene::getPixelElectrons() {
uint32_t e = mCurrentSceneMaterial[c]; const uint32_t *pixel = mCurrentSceneMaterial;
mCurrentX++; mCurrentX++;
mSubX++; mSubX++;
if (mCurrentX >= mSensorWidth) { if (mCurrentX >= mSensorWidth) {
@@ -345,9 +353,16 @@ uint32_t Scene::getPixelElectrons(int x, int y, int c) {
mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]); mCurrentSceneMaterial = &(mCurrentColors[kScene[mSceneIdx]]);
mSubX = 0; 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 // Aperture of imaging lens
const float Scene::kAperture = 2.8; const float Scene::kAperture = 2.8;

View File

@@ -67,10 +67,21 @@ class Scene {
void setReadoutPixel(int x, int y); void setReadoutPixel(int x, int y);
// Get sensor response in physical units (electrons) for light hitting the // Get sensor response in physical units (electrons) for light hitting the
// current readout pixel, after passing through color filters. The color // current readout pixel, after passing through color filters. The readout
// channels are 0=R, 1=Gr, 2=Gb, 3=B. The readout pixel will be // pixel will be auto-incremented. The returned array can be indexed with
// auto-incremented. // ColorChannels.
uint32_t getPixelElectrons(int x, int y, int c); const uint32_t* getPixelElectrons();
enum ColorChannels {
R = 0,
Gr,
Gb,
B,
Y,
Cb,
Cr,
NUM_CHANNELS
};
private: private:
// Sensor color filtering coefficients in XYZ // Sensor color filtering coefficients in XYZ
@@ -82,6 +93,8 @@ class Scene {
int mOffsetX, mOffsetY; int mOffsetX, mOffsetY;
int mMapDiv; int mMapDiv;
int mHandshakeX, mHandshakeY;
int mSensorWidth; int mSensorWidth;
int mSensorHeight; int mSensorHeight;
int mCurrentX; int mCurrentX;
@@ -112,12 +125,15 @@ class Scene {
NUM_MATERIALS 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. * Constants for scene definition. These are various degrees of approximate.
*/ */
// RGB->YUV conversion
static const float kRgb2Yuv[12];
// Aperture of imaging lens // Aperture of imaging lens
static const float kAperture; static const float kAperture;

View File

@@ -15,7 +15,15 @@
*/ */
//#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0
//#define LOG_NNDEBUG 0
#define LOG_TAG "EmulatedCamera2_Sensor" #define LOG_TAG "EmulatedCamera2_Sensor"
#ifdef LOG_NNDEBUG
#define ALOGVV(...) ALOGV(__VA_ARGS__)
#else
#define ALOGVV(...) ((void)0)
#endif
#include <utils/Log.h> #include <utils/Log.h>
#include "Sensor.h" #include "Sensor.h"
@@ -108,9 +116,10 @@ Sensor::~Sensor() {
} }
status_t Sensor::startUp() { status_t Sensor::startUp() {
ALOGV("%s: E", __FUNCTION__);
int res; int res;
mCapturedBuffer = NULL; mCapturedBuffer = NULL;
res = readyToRun(); res = readyToRun();
if (res != OK) { if (res != OK) {
ALOGE("Unable to prepare sensor capture thread to run: %d", res); ALOGE("Unable to prepare sensor capture thread to run: %d", res);
@@ -126,6 +135,8 @@ status_t Sensor::startUp() {
} }
status_t Sensor::shutDown() { status_t Sensor::shutDown() {
ALOGV("%s: E", __FUNCTION__);
int res; int res;
res = requestExitAndWait(); res = requestExitAndWait();
if (res != OK) { if (res != OK) {
@@ -140,25 +151,27 @@ Scene &Sensor::getScene() {
void Sensor::setExposureTime(uint64_t ns) { void Sensor::setExposureTime(uint64_t ns) {
Mutex::Autolock lock(mControlMutex); Mutex::Autolock lock(mControlMutex);
ALOGV("Exposure set to %f", ns/1000000.f); ALOGVV("Exposure set to %f", ns/1000000.f);
mExposureTime = ns; mExposureTime = ns;
} }
void Sensor::setFrameDuration(uint64_t ns) { void Sensor::setFrameDuration(uint64_t ns) {
Mutex::Autolock lock(mControlMutex); Mutex::Autolock lock(mControlMutex);
ALOGV("Frame duration set to %f", ns/1000000.f); ALOGVV("Frame duration set to %f", ns/1000000.f);
mFrameDuration = ns; mFrameDuration = ns;
} }
void Sensor::setSensitivity(uint32_t gain) { void Sensor::setSensitivity(uint32_t gain) {
Mutex::Autolock lock(mControlMutex); Mutex::Autolock lock(mControlMutex);
ALOGV("Gain set to %d", gain); ALOGVV("Gain set to %d", gain);
mGainFactor = 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); Mutex::Autolock lock(mControlMutex);
mNextBuffer = buffer; mNextBuffer = buffer;
mNextBufferFmt = format;
mNextStride = stride; mNextStride = stride;
} }
@@ -217,6 +230,7 @@ bool Sensor::threadLoop() {
uint64_t frameDuration; uint64_t frameDuration;
uint32_t gain; uint32_t gain;
uint8_t *nextBuffer; uint8_t *nextBuffer;
uint32_t nextBufferFmt;
uint32_t stride; uint32_t stride;
{ {
Mutex::Autolock lock(mControlMutex); Mutex::Autolock lock(mControlMutex);
@@ -224,12 +238,13 @@ bool Sensor::threadLoop() {
frameDuration = mFrameDuration; frameDuration = mFrameDuration;
gain = mGainFactor; gain = mGainFactor;
nextBuffer = mNextBuffer; nextBuffer = mNextBuffer;
nextBufferFmt = mNextBufferFmt;
stride = mNextStride; stride = mNextStride;
// Don't reuse a buffer // Don't reuse a buffer
mNextBuffer = NULL; mNextBuffer = NULL;
// Signal VSync for start of readout // Signal VSync for start of readout
ALOGV("Sensor VSync"); ALOGVV("Sensor VSync");
mGotVSync = true; mGotVSync = true;
mVSync.signal(); mVSync.signal();
} }
@@ -248,7 +263,7 @@ bool Sensor::threadLoop() {
kRowReadoutTime * kResolution[1]; kRowReadoutTime * kResolution[1];
if (mNextCapturedBuffer != NULL) { if (mNextCapturedBuffer != NULL) {
ALOGV("Sensor starting readout"); ALOGVV("Sensor starting readout");
// Pretend we're doing readout now; will signal once enough time has elapsed // Pretend we're doing readout now; will signal once enough time has elapsed
capturedBuffer = mNextCapturedBuffer; capturedBuffer = mNextCapturedBuffer;
captureTime = mNextCaptureTime; captureTime = mNextCaptureTime;
@@ -263,25 +278,72 @@ bool Sensor::threadLoop() {
mNextCapturedBuffer = nextBuffer; mNextCapturedBuffer = nextBuffer;
if (mNextCapturedBuffer != NULL) { 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); 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.setExposureDuration((float)exposureDuration/1e9);
mScene.calculateScene(mNextCaptureTime); mScene.calculateScene(mNextCaptureTime);
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;
}
}
// No capture done, or finished image generation before readout was completed
if (capturedBuffer != NULL) {
ALOGVV("Sensor readout complete");
Mutex::Autolock lock(mReadoutMutex);
mCapturedBuffer = capturedBuffer;
mCaptureTime = captureTime;
mReadoutComplete.signal();
capturedBuffer = NULL;
}
ALOGVV("Sensor vertical blanking interval");
nsecs_t workDoneRealTime = systemTime();
const nsecs_t timeAccuracy = 2e6; // 2 ms of imprecision is ok
if (workDoneRealTime < frameEndRealTime - timeAccuracy) {
timespec t;
t.tv_sec = (frameEndRealTime - workDoneRealTime) / 1000000000L;
t.tv_nsec = (frameEndRealTime - workDoneRealTime) % 1000000000L;
int ret;
do {
ret = nanosleep(&t, &t);
} while (ret != 0);
}
nsecs_t endRealTime = systemTime();
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 totalGain = gain/100.0 * kBaseGainFactor;
float noiseVarGain = totalGain * totalGain; float noiseVarGain = totalGain * totalGain;
float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain float readNoiseVar = kReadNoiseVarBeforeGain * noiseVarGain
+ kReadNoiseVarAfterGain; + kReadNoiseVarAfterGain;
int bayerSelect[4] = {0, 1, 2, 3}; // RGGB int bayerSelect[4] = {Scene::R, Scene::Gr, Scene::Gb, Scene::B}; // RGGB
for (unsigned int y = 0; y < kResolution[1]; y++ ) { for (unsigned int y = 0; y < kResolution[1]; y++ ) {
int *bayerRow = bayerSelect + (y & 0x1) * 2; int *bayerRow = bayerSelect + (y & 0x1) * 2;
uint16_t *px = (uint16_t*)mNextCapturedBuffer + y * stride; uint16_t *px = (uint16_t*)mNextCapturedBuffer + y * stride;
for (unsigned int x = 0; x < kResolution[0]; x++) { for (unsigned int x = 0; x < kResolution[0]; x++) {
uint32_t electronCount; uint32_t electronCount;
electronCount = mScene.getPixelElectrons(x, y, bayerRow[x & 0x1]); electronCount = mScene.getPixelElectrons()[bayerRow[x & 0x1]];
// TODO: Better pixel saturation curve? // TODO: Better pixel saturation curve?
electronCount = (electronCount < kSaturationElectrons) ? electronCount = (electronCount < kSaturationElectrons) ?
@@ -303,51 +365,64 @@ bool Sensor::threadLoop() {
*px++ = rawCount; *px++ = rawCount;
} }
simulatedTime += kRowReadoutTime; // TODO: Handle this better
//simulatedTime += kRowReadoutTime;
// If enough time has elapsed to complete readout, signal done frame // If enough time has elapsed to complete readout, signal done frame
// Only check every so often, though // Only check every so often, though
if ((capturedBuffer != NULL) && if ((*capturedBuffer != NULL) &&
((y & 63) == 0) && ((y & 63) == 0) &&
(systemTime() >= frameReadoutEndRealTime) ) { (systemTime() >= frameReadoutTime) ) {
ALOGV("Sensor readout complete"); ALOGV("Sensor readout complete");
Mutex::Autolock lock(mReadoutMutex); Mutex::Autolock lock(mReadoutMutex);
mCapturedBuffer = capturedBuffer; mCapturedBuffer = *capturedBuffer;
mCaptureTime = captureTime; mCaptureTime = captureTime;
mReadoutComplete.signal(); mReadoutComplete.signal();
capturedBuffer = NULL; *capturedBuffer = NULL;
} }
} }
ALOGV("Sensor image captured"); 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;
} }
// No capture done, or finished image generation before readout was completed // TODO: Handle this better
if (capturedBuffer != NULL) { //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"); ALOGV("Sensor readout complete");
Mutex::Autolock lock(mReadoutMutex); Mutex::Autolock lock(mReadoutMutex);
mCapturedBuffer = capturedBuffer; mCapturedBuffer = *capturedBuffer;
mCaptureTime = captureTime; mCaptureTime = captureTime;
mReadoutComplete.signal(); mReadoutComplete.signal();
capturedBuffer = NULL; *capturedBuffer = NULL;
} }
ALOGV("Sensor vertical blanking interval");
nsecs_t workDoneRealTime = systemTime();
const nsecs_t timeAccuracy = 2e6; // 2 ms of imprecision is ok
if (workDoneRealTime < frameEndRealTime - timeAccuracy) {
timespec t;
t.tv_sec = (frameEndRealTime - workDoneRealTime) / 1000000000L;
t.tv_nsec = (frameEndRealTime - workDoneRealTime) % 1000000000L;
int ret;
do {
ret = nanosleep(&t, &t);
} while (ret != 0);
} }
nsecs_t endRealTime = systemTime(); ALOGVV("RGBA sensor image captured");
ALOGV("Frame cycle took %d ms, target %d ms", }
(int)((endRealTime - startRealTime)/1000000),
(int)(frameDuration / 1000000));
return true;
};
} // namespace android } // namespace android

View File

@@ -107,7 +107,7 @@ class Sensor: private Thread, public virtual RefBase {
void setFrameDuration(uint64_t ns); void setFrameDuration(uint64_t ns);
void setSensitivity(uint32_t gain); void setSensitivity(uint32_t gain);
// Buffer must be at least stride*height*2 bytes in size // 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 * Controls that cause reconfiguration delay
@@ -178,7 +178,9 @@ class Sensor: private Thread, public virtual RefBase {
uint64_t mFrameDuration; uint64_t mFrameDuration;
uint32_t mGainFactor; uint32_t mGainFactor;
uint8_t *mNextBuffer; uint8_t *mNextBuffer;
uint32_t mNextBufferFmt;
uint32_t mNextStride; uint32_t mNextStride;
// End of control parameters // End of control parameters
Mutex mReadoutMutex; // Lock before accessing readout variables Mutex mReadoutMutex; // Lock before accessing readout variables
@@ -204,6 +206,15 @@ class Sensor: private Thread, public virtual RefBase {
uint8_t *mNextCapturedBuffer; uint8_t *mNextCapturedBuffer;
Scene mScene; 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);
}; };
} }