Merge changes I4a874650,Icb32e4b8,I3ea56bca

* changes:
  Camera2: Use lower resolutions for front fake camera
  Camera2: Fix deadlock issues with getInProgressCount
  EmulatedFakeCamera2: Add features needed for recording support for 320x240, NV21
This commit is contained in:
Eino-Ville Talvala
2012-07-26 08:52:56 -07:00
committed by Android (Google) Code Review
6 changed files with 184 additions and 53 deletions

View File

@@ -39,6 +39,7 @@ LOCAL_C_INCLUDES += external/jpeg \
external/skia/include/core/ \ external/skia/include/core/ \
frameworks/native/include/media/hardware \ frameworks/native/include/media/hardware \
frameworks/base/core/jni/android/graphics \ frameworks/base/core/jni/android/graphics \
$(LOCAL_PATH)/../../opengl/system/OpenglSystemCommon \
$(call include-path-for, camera) $(call include-path-for, camera)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \

View File

@@ -27,6 +27,7 @@
#include "EmulatedCameraFactory.h" #include "EmulatedCameraFactory.h"
#include <ui/Rect.h> #include <ui/Rect.h>
#include <ui/GraphicBufferMapper.h> #include <ui/GraphicBufferMapper.h>
#include "gralloc_cb.h"
namespace android { namespace android {
@@ -47,8 +48,13 @@ const uint64_t EmulatedFakeCamera2::kAvailableRawMinDurations[1] = {
Sensor::kFrameDurationRange[0] Sensor::kFrameDurationRange[0]
}; };
const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizes[2] = { const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesBack[4] = {
640, 480 640, 480, 320, 240
// Sensor::kResolution[0], Sensor::kResolution[1]
};
const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizesFront[4] = {
320, 240, 160, 120
// Sensor::kResolution[0], Sensor::kResolution[1] // Sensor::kResolution[0], Sensor::kResolution[1]
}; };
@@ -56,11 +62,17 @@ const uint64_t EmulatedFakeCamera2::kAvailableProcessedMinDurations[1] = {
Sensor::kFrameDurationRange[0] Sensor::kFrameDurationRange[0]
}; };
const uint32_t EmulatedFakeCamera2::kAvailableJpegSizes[2] = { const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesBack[2] = {
640, 480 640, 480
// Sensor::kResolution[0], Sensor::kResolution[1] // Sensor::kResolution[0], Sensor::kResolution[1]
}; };
const uint32_t EmulatedFakeCamera2::kAvailableJpegSizesFront[2] = {
320, 240
// Sensor::kResolution[0], Sensor::kResolution[1]
};
const uint64_t EmulatedFakeCamera2::kAvailableJpegMinDurations[1] = { const uint64_t EmulatedFakeCamera2::kAvailableJpegMinDurations[1] = {
Sensor::kFrameDurationRange[0] Sensor::kFrameDurationRange[0]
}; };
@@ -251,8 +263,9 @@ int EmulatedFakeCamera2::allocateStream(
return BAD_VALUE; return BAD_VALUE;
} }
} else { } else {
// Emulator's opaque format is RGBA // Translate to emulator's magic format.
format = HAL_PIXEL_FORMAT_RGBA_8888; // Note: It is assumed that this is a processed format (not raw or JPEG).
format = GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO;
} }
const uint32_t *availableSizes; const uint32_t *availableSizes;
@@ -263,14 +276,21 @@ int EmulatedFakeCamera2::allocateStream(
availableSizeCount = sizeof(kAvailableRawSizes)/sizeof(uint32_t); availableSizeCount = sizeof(kAvailableRawSizes)/sizeof(uint32_t);
break; break;
case HAL_PIXEL_FORMAT_BLOB: case HAL_PIXEL_FORMAT_BLOB:
availableSizes = kAvailableJpegSizes; availableSizes = mFacingBack ?
availableSizeCount = sizeof(kAvailableJpegSizes)/sizeof(uint32_t); kAvailableJpegSizesBack : kAvailableJpegSizesFront;
availableSizeCount = mFacingBack ?
sizeof(kAvailableJpegSizesBack)/sizeof(uint32_t) :
sizeof(kAvailableJpegSizesFront)/sizeof(uint32_t);
break; break;
case GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO:
case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP:
availableSizes = kAvailableProcessedSizes; availableSizes = mFacingBack ?
availableSizeCount = sizeof(kAvailableProcessedSizes)/sizeof(uint32_t); kAvailableProcessedSizesBack : kAvailableProcessedSizesFront;
availableSizeCount = mFacingBack ?
sizeof(kAvailableProcessedSizesBack)/sizeof(uint32_t) :
sizeof(kAvailableProcessedSizesFront)/sizeof(uint32_t);
break; break;
default: default:
ALOGE("%s: Unknown format 0x%x", __FUNCTION__, format); ALOGE("%s: Unknown format 0x%x", __FUNCTION__, format);
@@ -326,7 +346,7 @@ int EmulatedFakeCamera2::allocateStream(
*stream_id = mNextStreamId; *stream_id = mNextStreamId;
if (format_actual) *format_actual = format; if (format_actual) *format_actual = format;
*usage = GRALLOC_USAGE_SW_WRITE_OFTEN; *usage = GRALLOC_USAGE_HW_CAMERA_WRITE;
*max_buffers = 4; *max_buffers = 4;
ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d", ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d",
@@ -340,9 +360,42 @@ int EmulatedFakeCamera2::registerStreamBuffers(
uint32_t stream_id, uint32_t stream_id,
int num_buffers, int num_buffers,
buffer_handle_t *buffers) { buffer_handle_t *buffers) {
// Emulator doesn't need to register these with V4L2, etc. Mutex::Autolock l(mMutex);
ALOGV("%s: Stream %d registering %d buffers", __FUNCTION__, ALOGV("%s: Stream %d registering %d buffers", __FUNCTION__,
stream_id, num_buffers); stream_id, num_buffers);
// Need to find out what the final concrete pixel format for our stream is
// Assumes that all buffers have the same format.
if (num_buffers < 1) {
ALOGE("%s: Stream %d only has %d buffers!",
__FUNCTION__, stream_id, num_buffers);
return BAD_VALUE;
}
const cb_handle_t *streamBuffer =
reinterpret_cast<const cb_handle_t*>(buffers[0]);
int finalFormat = streamBuffer->format;
if (finalFormat == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) {
ALOGE("%s: Stream %d: Bad final pixel format "
"GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO; "
"concrete pixel format required!", __FUNCTION__, stream_id);
return BAD_VALUE;
}
ssize_t streamIndex = mStreams.indexOfKey(stream_id);
if (streamIndex < 0) {
ALOGE("%s: Unknown stream id %d!", __FUNCTION__, stream_id);
return BAD_VALUE;
}
Stream &stream = mStreams.editValueAt(streamIndex);
ALOGV("%s: Stream %d format set to %x, previously %x",
__FUNCTION__, stream_id, finalFormat, stream.format);
stream.format = finalFormat;
return NO_ERROR; return NO_ERROR;
} }
@@ -481,7 +534,9 @@ void EmulatedFakeCamera2::signalError() {
EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent): EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent):
Thread(false), Thread(false),
mParent(parent) { mParent(parent),
mNextBuffers(NULL),
mRequestCount(0) {
mRunning = false; mRunning = false;
} }
@@ -531,8 +586,8 @@ bool EmulatedFakeCamera2::ConfigureThread::isStreamInUse(uint32_t id) {
} }
int EmulatedFakeCamera2::ConfigureThread::getInProgressCount() { int EmulatedFakeCamera2::ConfigureThread::getInProgressCount() {
Mutex::Autolock lock(mInternalsMutex); Mutex::Autolock lock(mInputMutex);
return mNextBuffers == NULL ? 0 : 1; return mRequestCount;
} }
bool EmulatedFakeCamera2::ConfigureThread::threadLoop() { bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
@@ -574,6 +629,9 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
Mutex::Autolock lock(mInputMutex); Mutex::Autolock lock(mInputMutex);
mActive = false; mActive = false;
return true; return true;
} else {
Mutex::Autolock lock(mInputMutex);
mRequestCount++;
} }
// Get necessary parameters for sensor config // Get necessary parameters for sensor config
@@ -593,7 +651,14 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
mNextNeedsJpeg = false; mNextNeedsJpeg = false;
ALOGV("Setting up buffers for capture"); ALOGV("Setting up buffers for capture");
for (size_t i = 0; i < streams.count; i++) { for (size_t i = 0; i < streams.count; i++) {
const Stream &s = mParent->getStreamInfo(streams.data.u8[i]); int streamId = streams.data.u8[i];
const Stream &s = mParent->getStreamInfo(streamId);
if (s.format == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) {
ALOGE("%s: Stream %d does not have a concrete pixel format, but "
"is included in a request!", __FUNCTION__, streamId);
mParent->signalError();
return false;
}
StreamBuffer b; StreamBuffer b;
b.streamId = streams.data.u8[i]; b.streamId = streams.data.u8[i];
b.width = s.width; b.width = s.width;
@@ -708,7 +773,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
const Rect rect(s.width, s.height); const Rect rect(s.width, s.height);
res = GraphicBufferMapper::get().lock(*(b.buffer), res = GraphicBufferMapper::get().lock(*(b.buffer),
GRALLOC_USAGE_SW_WRITE_OFTEN, GRALLOC_USAGE_HW_CAMERA_WRITE,
rect, (void**)&(b.img) ); rect, (void**)&(b.img) );
if (res != NO_ERROR) { if (res != NO_ERROR) {
@@ -727,6 +792,9 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
mRequest = NULL; mRequest = NULL;
mNextBuffers = NULL; mNextBuffers = NULL;
Mutex::Autolock lock(mInputMutex);
mRequestCount--;
return true; return true;
} }
@@ -735,7 +803,9 @@ EmulatedFakeCamera2::ReadoutThread::ReadoutThread(EmulatedFakeCamera2 *parent):
mParent(parent), mParent(parent),
mRunning(false), mRunning(false),
mActive(false), mActive(false),
mRequest(NULL) mRequest(NULL),
mBuffers(NULL),
mRequestCount(0)
{ {
mInFlightQueue = new InFlightQueue[kInFlightQueueSize]; mInFlightQueue = new InFlightQueue[kInFlightQueueSize];
mInFlightHead = 0; mInFlightHead = 0;
@@ -775,6 +845,7 @@ void EmulatedFakeCamera2::ReadoutThread::setNextCapture(
mInFlightQueue[mInFlightTail].request = request; mInFlightQueue[mInFlightTail].request = request;
mInFlightQueue[mInFlightTail].buffers = buffers; mInFlightQueue[mInFlightTail].buffers = buffers;
mInFlightTail = (mInFlightTail + 1) % kInFlightQueueSize; mInFlightTail = (mInFlightTail + 1) % kInFlightQueueSize;
mRequestCount++;
if (!mActive) { if (!mActive) {
mActive = true; mActive = true;
@@ -807,14 +878,8 @@ bool EmulatedFakeCamera2::ReadoutThread::isStreamInUse(uint32_t id) {
int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() { int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() {
Mutex::Autolock lock(mInputMutex); Mutex::Autolock lock(mInputMutex);
Mutex::Autolock iLock(mInternalsMutex);
int requestCount = return mRequestCount;
((mInFlightTail + kInFlightQueueSize) - mInFlightHead)
% kInFlightQueueSize;
requestCount += (mBuffers == NULL) ? 0 : 1;
return requestCount;
} }
bool EmulatedFakeCamera2::ReadoutThread::threadLoop() { bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
@@ -953,9 +1018,8 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
ALOGV("Sending image buffer %d to output stream %d", ALOGV("Sending image buffer %d to output stream %d",
i, b.streamId); i, b.streamId);
GraphicBufferMapper::get().unlock(*(b.buffer)); GraphicBufferMapper::get().unlock(*(b.buffer));
res = mParent->getStreamInfo(b.streamId).ops->enqueue_buffer( const Stream &s = mParent->getStreamInfo(b.streamId);
mParent->getStreamInfo(b.streamId).ops, res = s.ops->enqueue_buffer(s.ops, captureTime, b.buffer);
captureTime, b.buffer);
if (res != OK) { if (res != OK) {
ALOGE("Error enqueuing image buffer %p: %s (%d)", b.buffer, ALOGE("Error enqueuing image buffer %p: %s (%d)", b.buffer,
strerror(-res), res); strerror(-res), res);
@@ -964,6 +1028,7 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
} }
} }
} }
if (compressedBufferIndex == -1) { if (compressedBufferIndex == -1) {
delete mBuffers; delete mBuffers;
mBuffers = NULL; mBuffers = NULL;
@@ -975,6 +1040,9 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
mBuffers = NULL; mBuffers = NULL;
} }
Mutex::Autolock l(mInputMutex);
mRequestCount--;
return true; return true;
} }
@@ -1121,17 +1189,29 @@ status_t EmulatedFakeCamera2::constructStaticInfo(
kAvailableRawMinDurations, kAvailableRawMinDurations,
sizeof(kAvailableRawMinDurations)/sizeof(uint64_t)); sizeof(kAvailableRawMinDurations)/sizeof(uint64_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, if (mFacingBack) {
kAvailableProcessedSizes, ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
sizeof(kAvailableProcessedSizes)/sizeof(uint32_t)); kAvailableProcessedSizesBack,
sizeof(kAvailableProcessedSizesBack)/sizeof(uint32_t));
} else {
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
kAvailableProcessedSizesFront,
sizeof(kAvailableProcessedSizesFront)/sizeof(uint32_t));
}
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS, ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
kAvailableProcessedMinDurations, kAvailableProcessedMinDurations,
sizeof(kAvailableProcessedMinDurations)/sizeof(uint64_t)); sizeof(kAvailableProcessedMinDurations)/sizeof(uint64_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, if (mFacingBack) {
kAvailableJpegSizes, ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
sizeof(kAvailableJpegSizes)/sizeof(uint32_t)); kAvailableJpegSizesBack,
sizeof(kAvailableJpegSizesBack)/sizeof(uint32_t));
} else {
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
kAvailableJpegSizesFront,
sizeof(kAvailableJpegSizesFront)/sizeof(uint32_t));
}
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS, ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
kAvailableJpegMinDurations, kAvailableJpegMinDurations,
@@ -1145,9 +1225,8 @@ status_t EmulatedFakeCamera2::constructStaticInfo(
static const int32_t jpegThumbnailSizes[] = { static const int32_t jpegThumbnailSizes[] = {
160, 120, 160, 120,
320, 240, 320, 240
640, 480 };
};
ADD_OR_SIZE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, ADD_OR_SIZE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
jpegThumbnailSizes, sizeof(jpegThumbnailSizes)/sizeof(int32_t)); jpegThumbnailSizes, sizeof(jpegThumbnailSizes)/sizeof(int32_t));
@@ -1220,7 +1299,7 @@ status_t EmulatedFakeCamera2::constructStaticInfo(
sizeof(exposureCompensationRange)/sizeof(int32_t)); sizeof(exposureCompensationRange)/sizeof(int32_t));
static const int32_t availableTargetFpsRanges[] = { static const int32_t availableTargetFpsRanges[] = {
5, 30 5, 30, 15, 30
}; };
ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
availableTargetFpsRanges, availableTargetFpsRanges,

View File

@@ -185,10 +185,11 @@ private:
bool mRunning; bool mRunning;
bool threadLoop(); bool threadLoop();
Mutex mInputMutex; // Protects mActive Mutex mInputMutex; // Protects mActive, mRequestCount
Condition mInputSignal; Condition mInputSignal;
bool mActive; // Whether we're waiting for input requests or actively bool mActive; // Whether we're waiting for input requests or actively
// working on them // working on them
size_t mRequestCount;
camera_metadata_t *mRequest; camera_metadata_t *mRequest;
@@ -222,7 +223,7 @@ private:
bool threadLoop(); bool threadLoop();
// Inputs // Inputs
Mutex mInputMutex; // Protects mActive, mInFlightQueue Mutex mInputMutex; // Protects mActive, mInFlightQueue, mRequestCount
Condition mInputSignal; Condition mInputSignal;
bool mActive; bool mActive;
@@ -235,6 +236,8 @@ private:
size_t mInFlightHead; size_t mInFlightHead;
size_t mInFlightTail; size_t mInFlightTail;
size_t mRequestCount;
// Internals // Internals
Mutex mInternalsMutex; Mutex mInternalsMutex;
camera_metadata_t *mRequest; camera_metadata_t *mRequest;
@@ -252,9 +255,11 @@ private:
static const uint32_t kAvailableFormats[]; static const uint32_t kAvailableFormats[];
static const uint32_t kAvailableRawSizes[]; static const uint32_t kAvailableRawSizes[];
static const uint64_t kAvailableRawMinDurations[]; static const uint64_t kAvailableRawMinDurations[];
static const uint32_t kAvailableProcessedSizes[]; static const uint32_t kAvailableProcessedSizesBack[];
static const uint32_t kAvailableProcessedSizesFront[];
static const uint64_t kAvailableProcessedMinDurations[]; static const uint64_t kAvailableProcessedMinDurations[];
static const uint32_t kAvailableJpegSizes[]; static const uint32_t kAvailableJpegSizesBack[];
static const uint32_t kAvailableJpegSizesFront[];
static const uint64_t kAvailableJpegMinDurations[]; static const uint64_t kAvailableJpegMinDurations[];
/**************************************************************************** /****************************************************************************

View File

@@ -43,7 +43,7 @@ typedef Vector<StreamBuffer> Buffers;
struct Stream { struct Stream {
const camera2_stream_ops_t *ops; const camera2_stream_ops_t *ops;
uint32_t width, height; uint32_t width, height;
uint32_t format; int32_t format;
uint32_t stride; uint32_t stride;
}; };

View File

@@ -247,7 +247,9 @@ bool Sensor::threadLoop() {
nsecs_t captureTime = 0; nsecs_t captureTime = 0;
nsecs_t startRealTime = systemTime(); nsecs_t startRealTime = systemTime();
nsecs_t simulatedTime = startRealTime - mStartupTime; // Stagefright cares about system time for timestamps, so base simulated
// time on that.
nsecs_t simulatedTime = startRealTime;
nsecs_t frameEndRealTime = startRealTime + frameDuration; nsecs_t frameEndRealTime = startRealTime + frameDuration;
nsecs_t frameReadoutEndRealTime = startRealTime + nsecs_t frameReadoutEndRealTime = startRealTime +
kRowReadoutTime * kResolution[1]; kRowReadoutTime * kResolution[1];
@@ -312,8 +314,10 @@ bool Sensor::threadLoop() {
captureRGB(bAux.img, gain, b.stride); captureRGB(bAux.img, gain, b.stride);
mNextCapturedBuffers->push_back(bAux); mNextCapturedBuffers->push_back(bAux);
break; break;
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP:
captureNV21(b.img, gain, b.stride);
break;
case HAL_PIXEL_FORMAT_YV12:
// TODO: // TODO:
ALOGE("%s: Format %x is TODO", __FUNCTION__, b.format); ALOGE("%s: Format %x is TODO", __FUNCTION__, b.format);
break; break;
@@ -390,11 +394,12 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) {
float totalGain = gain/100.0 * kBaseGainFactor; float totalGain = gain/100.0 * kBaseGainFactor;
// In fixed-point math, calculate total scaling from electrons to 8bpp // In fixed-point math, calculate total scaling from electrons to 8bpp
int scale64x = 64 * totalGain * 255 / kMaxRawValue; int scale64x = 64 * totalGain * 255 / kMaxRawValue;
mScene.setReadoutPixel(0,0); uint32_t inc = kResolution[0] / stride;
for (unsigned int y = 0; y < kResolution[1]; y++ ) { for (unsigned int y = 0, outY = 0; y < kResolution[1]; y+=inc, outY++ ) {
uint8_t *px = img + y * stride * 4; uint8_t *px = img + outY * stride * 4;
for (unsigned int x = 0; x < kResolution[0]; x++) { mScene.setReadoutPixel(0, y);
for (unsigned int x = 0; x < kResolution[0]; x+=inc) {
uint32_t rCount, gCount, bCount; uint32_t rCount, gCount, bCount;
// TODO: Perfect demosaicing is a cheat // TODO: Perfect demosaicing is a cheat
const uint32_t *pixel = mScene.getPixelElectrons(); const uint32_t *pixel = mScene.getPixelElectrons();
@@ -406,6 +411,8 @@ void Sensor::captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride) {
*px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255;
*px++ = bCount < 255*64 ? bCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255;
*px++ = 255; *px++ = 255;
for (unsigned int j = 1; j < inc; j++)
mScene.getPixelElectrons();
} }
// TODO: Handle this better // TODO: Handle this better
//simulatedTime += kRowReadoutTime; //simulatedTime += kRowReadoutTime;
@@ -417,11 +424,12 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
float totalGain = gain/100.0 * kBaseGainFactor; float totalGain = gain/100.0 * kBaseGainFactor;
// In fixed-point math, calculate total scaling from electrons to 8bpp // In fixed-point math, calculate total scaling from electrons to 8bpp
int scale64x = 64 * totalGain * 255 / kMaxRawValue; int scale64x = 64 * totalGain * 255 / kMaxRawValue;
mScene.setReadoutPixel(0,0); uint32_t inc = kResolution[0] / stride;
for (unsigned int y = 0; y < kResolution[1]; y++ ) { for (unsigned int y = 0, outY = 0; y < kResolution[1]; y += inc, outY++ ) {
uint8_t *px = img + y * stride * 3; mScene.setReadoutPixel(0, y);
for (unsigned int x = 0; x < kResolution[0]; x++) { uint8_t *px = img + outY * stride * 3;
for (unsigned int x = 0; x < kResolution[0]; x += inc) {
uint32_t rCount, gCount, bCount; uint32_t rCount, gCount, bCount;
// TODO: Perfect demosaicing is a cheat // TODO: Perfect demosaicing is a cheat
const uint32_t *pixel = mScene.getPixelElectrons(); const uint32_t *pixel = mScene.getPixelElectrons();
@@ -432,6 +440,8 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
*px++ = rCount < 255*64 ? rCount / 64 : 255; *px++ = rCount < 255*64 ? rCount / 64 : 255;
*px++ = gCount < 255*64 ? gCount / 64 : 255; *px++ = gCount < 255*64 ? gCount / 64 : 255;
*px++ = bCount < 255*64 ? bCount / 64 : 255; *px++ = bCount < 255*64 ? bCount / 64 : 255;
for (unsigned int j = 1; j < inc; j++)
mScene.getPixelElectrons();
} }
// TODO: Handle this better // TODO: Handle this better
//simulatedTime += kRowReadoutTime; //simulatedTime += kRowReadoutTime;
@@ -439,4 +449,40 @@ void Sensor::captureRGB(uint8_t *img, uint32_t gain, uint32_t stride) {
ALOGVV("RGB sensor image captured"); ALOGVV("RGB sensor image captured");
} }
void Sensor::captureNV21(uint8_t *img, uint32_t gain, uint32_t stride) {
float totalGain = gain/100.0 * kBaseGainFactor;
// In fixed-point math, calculate total scaling from electrons to 8bpp
int scale64x = 64 * totalGain * 255 / kMaxRawValue;
// TODO: Make full-color
uint32_t inc = kResolution[0] / stride;
uint32_t outH = kResolution[1] / inc;
for (unsigned int y = 0, outY = 0, outUV = outH;
y < kResolution[1]; y+=inc, outY++, outUV ) {
uint8_t *pxY = img + outY * stride;
mScene.setReadoutPixel(0,y);
for (unsigned int x = 0; x < kResolution[0]; x+=inc) {
uint32_t rCount, gCount, bCount;
// TODO: Perfect demosaicing is a cheat
const uint32_t *pixel = mScene.getPixelElectrons();
rCount = pixel[Scene::R] * scale64x;
gCount = pixel[Scene::Gr] * scale64x;
bCount = pixel[Scene::B] * scale64x;
uint32_t avg = (rCount + gCount + bCount) / 3;
*pxY++ = avg < 255*64 ? avg / 64 : 255;
for (unsigned int j = 1; j < inc; j++)
mScene.getPixelElectrons();
}
}
for (unsigned int y = 0, outY = outH; y < kResolution[1]/2; y+=inc, outY++) {
uint8_t *px = img + outY * stride;
for (unsigned int x = 0; x < kResolution[0]; x+=inc) {
// UV to neutral
*px++ = 128;
*px++ = 128;
}
}
ALOGVV("NV21 sensor image captured");
}
} // namespace android } // namespace android

View File

@@ -212,7 +212,7 @@ class Sensor: private Thread, public virtual RefBase {
void captureRaw(uint8_t *img, uint32_t gain, uint32_t stride); void captureRaw(uint8_t *img, uint32_t gain, uint32_t stride);
void captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride); void captureRGBA(uint8_t *img, uint32_t gain, uint32_t stride);
void captureRGB(uint8_t *img, uint32_t gain, uint32_t stride); void captureRGB(uint8_t *img, uint32_t gain, uint32_t stride);
void captureNV21(uint8_t *img, uint32_t gain, uint32_t stride);
}; };
} }