blob: e1c6010cfa6ea5162bfb0d0775656d4ab7541f4f [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Contains implementation of a class EmulatedFakeCamera2 that encapsulates
* functionality of an advanced fake camera.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_FakeCamera2"
#include <utils/Log.h>
#include "EmulatedFakeCamera2.h"
#include "EmulatedCameraFactory.h"
#include <ui/Rect.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
const uint32_t EmulatedFakeCamera2::kAvailableFormats[5] = {
HAL_PIXEL_FORMAT_RAW_SENSOR,
HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_RGBA_8888,
HAL_PIXEL_FORMAT_YV12,
HAL_PIXEL_FORMAT_YCrCb_420_SP
};
const uint32_t EmulatedFakeCamera2::kAvailableRawSizes[2] = {
640, 480
// Sensor::kResolution[0], Sensor::kResolution[1]
};
const uint64_t EmulatedFakeCamera2::kAvailableRawMinDurations[1] = {
Sensor::kFrameDurationRange[0]
};
const uint32_t EmulatedFakeCamera2::kAvailableProcessedSizes[2] = {
640, 480
// Sensor::kResolution[0], Sensor::kResolution[1]
};
const uint64_t EmulatedFakeCamera2::kAvailableProcessedMinDurations[1] = {
Sensor::kFrameDurationRange[0]
};
const uint32_t EmulatedFakeCamera2::kAvailableJpegSizes[2] = {
640, 480
// Sensor::kResolution[0], Sensor::kResolution[1]
};
const uint64_t EmulatedFakeCamera2::kAvailableJpegMinDurations[1] = {
Sensor::kFrameDurationRange[0]
};
EmulatedFakeCamera2::EmulatedFakeCamera2(int cameraId,
bool facingBack,
struct hw_module_t* module)
: EmulatedCamera2(cameraId,module),
mFacingBack(facingBack)
{
ALOGD("Constructing emulated fake camera 2 facing %s",
facingBack ? "back" : "front");
}
EmulatedFakeCamera2::~EmulatedFakeCamera2() {
if (mCameraInfo != NULL) {
free_camera_metadata(mCameraInfo);
}
}
/****************************************************************************
* Public API overrides
***************************************************************************/
status_t EmulatedFakeCamera2::Initialize() {
status_t res;
res = constructStaticInfo(&mCameraInfo, true);
if (res != OK) {
ALOGE("%s: Unable to allocate static info: %s (%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
res = constructStaticInfo(&mCameraInfo, false);
if (res != OK) {
ALOGE("%s: Unable to fill in static info: %s (%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
if (res != OK) return res;
mNextStreamId = 0;
mRawStreamCount = 0;
mProcessedStreamCount = 0;
mJpegStreamCount = 0;
return NO_ERROR;
}
/****************************************************************************
* Camera module API overrides
***************************************************************************/
status_t EmulatedFakeCamera2::connectCamera(hw_device_t** device) {
status_t res;
ALOGV("%s", __FUNCTION__);
mConfigureThread = new ConfigureThread(this);
mReadoutThread = new ReadoutThread(this);
mSensor = new Sensor(this);
mJpegCompressor = new JpegCompressor(this);
mNextStreamId = 0;
res = mSensor->startUp();
if (res != NO_ERROR) return res;
res = mConfigureThread->run("EmulatedFakeCamera2::configureThread");
if (res != NO_ERROR) return res;
res = mReadoutThread->run("EmulatedFakeCamera2::readoutThread");
if (res != NO_ERROR) return res;
return EmulatedCamera2::connectCamera(device);
}
status_t EmulatedFakeCamera2::closeCamera() {
Mutex::Autolock l(mMutex);
status_t res;
ALOGV("%s", __FUNCTION__);
res = mSensor->shutDown();
if (res != NO_ERROR) {
ALOGE("%s: Unable to shut down sensor: %d", __FUNCTION__, res);
return res;
}
mConfigureThread->requestExit();
mReadoutThread->requestExit();
mJpegCompressor->cancel();
mConfigureThread->join();
mReadoutThread->join();
ALOGV("%s exit", __FUNCTION__);
return NO_ERROR;
}
status_t EmulatedFakeCamera2::getCameraInfo(struct camera_info *info) {
info->facing = mFacingBack ? CAMERA_FACING_BACK : CAMERA_FACING_FRONT;
info->orientation = 0;
return EmulatedCamera2::getCameraInfo(info);
}
/****************************************************************************
* Camera device API overrides
***************************************************************************/
/** Request input queue */
int EmulatedFakeCamera2::requestQueueNotify() {
ALOGV("Request queue notification received");
ALOG_ASSERT(mRequestQueueSrc != NULL,
"%s: Request queue src not set, but received queue notification!",
__FUNCTION__);
ALOG_ASSERT(mFrameQueueDst != NULL,
"%s: Request queue src not set, but received queue notification!",
__FUNCTION__);
ALOG_ASSERT(mStreams.size() != 0,
"%s: No streams allocated, but received queue notification!",
__FUNCTION__);
return mConfigureThread->newRequestAvailable();
}
int EmulatedFakeCamera2::getInProgressCount() {
Mutex::Autolock l(mMutex);
int requestCount = 0;
requestCount += mConfigureThread->getInProgressCount();
requestCount += mReadoutThread->getInProgressCount();
requestCount += mJpegCompressor->isBusy() ? 1 : 0;
return requestCount;
}
int EmulatedFakeCamera2::constructDefaultRequest(
int request_template,
camera_metadata_t **request) {
if (request == NULL) return BAD_VALUE;
if (request_template < 0 || request_template >= CAMERA2_TEMPLATE_COUNT) {
return BAD_VALUE;
}
status_t res;
// Pass 1, calculate size and allocate
res = constructDefaultRequest(request_template,
request,
true);
if (res != OK) {
return res;
}
// Pass 2, build request
res = constructDefaultRequest(request_template,
request,
false);
if (res != OK) {
ALOGE("Unable to populate new request for template %d",
request_template);
}
return res;
}
int EmulatedFakeCamera2::allocateStream(
uint32_t width,
uint32_t height,
int format,
const camera2_stream_ops_t *stream_ops,
uint32_t *stream_id,
uint32_t *format_actual,
uint32_t *usage,
uint32_t *max_buffers) {
Mutex::Autolock l(mMutex);
if (format != CAMERA2_HAL_PIXEL_FORMAT_OPAQUE) {
unsigned int numFormats = sizeof(kAvailableFormats) / sizeof(uint32_t);
unsigned int formatIdx = 0;
unsigned int sizeOffsetIdx = 0;
for (; formatIdx < numFormats; formatIdx++) {
if (format == (int)kAvailableFormats[formatIdx]) break;
}
if (formatIdx == numFormats) {
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;
size_t availableSizeCount;
switch (format) {
case HAL_PIXEL_FORMAT_RAW_SENSOR:
availableSizes = kAvailableRawSizes;
availableSizeCount = sizeof(kAvailableRawSizes)/sizeof(uint32_t);
break;
case HAL_PIXEL_FORMAT_BLOB:
availableSizes = kAvailableJpegSizes;
availableSizeCount = sizeof(kAvailableJpegSizes)/sizeof(uint32_t);
break;
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
availableSizes = kAvailableProcessedSizes;
availableSizeCount = sizeof(kAvailableProcessedSizes)/sizeof(uint32_t);
break;
default:
ALOGE("%s: Unknown format 0x%x", __FUNCTION__, format);
return BAD_VALUE;
}
unsigned int resIdx = 0;
for (; resIdx < availableSizeCount; resIdx++) {
if (availableSizes[resIdx * 2] == width &&
availableSizes[resIdx * 2 + 1] == height) break;
}
if (resIdx == availableSizeCount) {
ALOGE("%s: Format 0x%x does not support resolution %d, %d", __FUNCTION__,
format, width, height);
return BAD_VALUE;
}
switch (format) {
case HAL_PIXEL_FORMAT_RAW_SENSOR:
if (mRawStreamCount >= kMaxRawStreamCount) {
ALOGE("%s: Cannot allocate another raw stream (%d already allocated)",
__FUNCTION__, mRawStreamCount);
return INVALID_OPERATION;
}
mRawStreamCount++;
break;
case HAL_PIXEL_FORMAT_BLOB:
if (mJpegStreamCount >= kMaxJpegStreamCount) {
ALOGE("%s: Cannot allocate another JPEG stream (%d already allocated)",
__FUNCTION__, mJpegStreamCount);
return INVALID_OPERATION;
}
mJpegStreamCount++;
break;
default:
if (mProcessedStreamCount >= kMaxProcessedStreamCount) {
ALOGE("%s: Cannot allocate another processed stream (%d already allocated)",
__FUNCTION__, mProcessedStreamCount);
return INVALID_OPERATION;
}
mProcessedStreamCount++;
}
Stream newStream;
newStream.ops = stream_ops;
newStream.width = width;
newStream.height = height;
newStream.format = format;
// TODO: Query stride from gralloc
newStream.stride = width;
mStreams.add(mNextStreamId, newStream);
*stream_id = mNextStreamId;
if (format_actual) *format_actual = format;
*usage = GRALLOC_USAGE_SW_WRITE_OFTEN;
*max_buffers = 4;
ALOGV("Stream allocated: %d, %d x %d, 0x%x. U: %x, B: %d",
*stream_id, width, height, format, *usage, *max_buffers);
mNextStreamId++;
return NO_ERROR;
}
int EmulatedFakeCamera2::registerStreamBuffers(
uint32_t stream_id,
int num_buffers,
buffer_handle_t *buffers) {
// Emulator doesn't need to register these with V4L2, etc.
ALOGV("%s: Stream %d registering %d buffers", __FUNCTION__,
stream_id, num_buffers);
return NO_ERROR;
}
int EmulatedFakeCamera2::releaseStream(uint32_t stream_id) {
Mutex::Autolock l(mMutex);
ssize_t streamIndex = mStreams.indexOfKey(stream_id);
if (streamIndex < 0) {
ALOGE("%s: Unknown stream id %d!", __FUNCTION__, stream_id);
return BAD_VALUE;
}
if (isStreamInUse(stream_id)) {
ALOGE("%s: Cannot release stream %d; in use!", __FUNCTION__,
stream_id);
return BAD_VALUE;
}
switch(mStreams.valueAt(streamIndex).format) {
case HAL_PIXEL_FORMAT_RAW_SENSOR:
mRawStreamCount--;
break;
case HAL_PIXEL_FORMAT_BLOB:
mJpegStreamCount--;
break;
default:
mProcessedStreamCount--;
break;
}
mStreams.removeItemsAt(streamIndex);
return NO_ERROR;
}
/** Custom tag definitions */
// Emulator camera metadata sections
enum {
EMULATOR_SCENE = VENDOR_SECTION,
END_EMULATOR_SECTIONS
};
enum {
EMULATOR_SCENE_START = EMULATOR_SCENE << 16,
};
// Emulator camera metadata tags
enum {
// Hour of day to use for lighting calculations (0-23). Default: 12
EMULATOR_SCENE_HOUROFDAY = EMULATOR_SCENE_START,
EMULATOR_SCENE_END
};
unsigned int emulator_metadata_section_bounds[END_EMULATOR_SECTIONS -
VENDOR_SECTION][2] = {
{ EMULATOR_SCENE_START, EMULATOR_SCENE_END }
};
const char *emulator_metadata_section_names[END_EMULATOR_SECTIONS -
VENDOR_SECTION] = {
"com.android.emulator.scene"
};
typedef struct emulator_tag_info {
const char *tag_name;
uint8_t tag_type;
} emulator_tag_info_t;
emulator_tag_info_t emulator_scene[EMULATOR_SCENE_END - EMULATOR_SCENE_START] = {
{ "hourOfDay", TYPE_INT32 }
};
emulator_tag_info_t *tag_info[END_EMULATOR_SECTIONS -
VENDOR_SECTION] = {
emulator_scene
};
const char* EmulatedFakeCamera2::getVendorSectionName(uint32_t tag) {
ALOGV("%s", __FUNCTION__);
uint32_t section = tag >> 16;
if (section < VENDOR_SECTION || section > END_EMULATOR_SECTIONS) return NULL;
return emulator_metadata_section_names[section - VENDOR_SECTION];
}
const char* EmulatedFakeCamera2::getVendorTagName(uint32_t tag) {
ALOGV("%s", __FUNCTION__);
uint32_t section = tag >> 16;
if (section < VENDOR_SECTION || section > END_EMULATOR_SECTIONS) return NULL;
uint32_t section_index = section - VENDOR_SECTION;
if (tag >= emulator_metadata_section_bounds[section_index][1]) {
return NULL;
}
uint32_t tag_index = tag & 0xFFFF;
return tag_info[section_index][tag_index].tag_name;
}
int EmulatedFakeCamera2::getVendorTagType(uint32_t tag) {
ALOGV("%s", __FUNCTION__);
uint32_t section = tag >> 16;
if (section < VENDOR_SECTION || section > END_EMULATOR_SECTIONS) return -1;
uint32_t section_index = section - VENDOR_SECTION;
if (tag >= emulator_metadata_section_bounds[section_index][1]) {
return -1;
}
uint32_t tag_index = tag & 0xFFFF;
return tag_info[section_index][tag_index].tag_type;
}
/** Shutdown and debug methods */
int EmulatedFakeCamera2::dump(int fd) {
String8 result;
result.appendFormat(" Camera HAL device: EmulatedFakeCamera2\n");
result.appendFormat(" Streams:\n");
for (size_t i = 0; i < mStreams.size(); i++) {
int id = mStreams.keyAt(i);
const Stream& s = mStreams.valueAt(i);
result.appendFormat(
" Stream %d: %d x %d, format 0x%x, stride %d\n",
id, s.width, s.height, s.format, s.stride);
}
write(fd, result.string(), result.size());
return NO_ERROR;
}
void EmulatedFakeCamera2::signalError() {
// TODO: Let parent know so we can shut down cleanly
ALOGE("Worker thread is signaling a serious error");
}
/** Pipeline control worker thread methods */
EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent):
Thread(false),
mParent(parent) {
mRunning = false;
}
EmulatedFakeCamera2::ConfigureThread::~ConfigureThread() {
}
status_t EmulatedFakeCamera2::ConfigureThread::readyToRun() {
Mutex::Autolock lock(mInputMutex);
ALOGV("Starting up ConfigureThread");
mRequest = NULL;
mActive = false;
mRunning = true;
mInputSignal.signal();
return NO_ERROR;
}
status_t EmulatedFakeCamera2::ConfigureThread::waitUntilRunning() {
Mutex::Autolock lock(mInputMutex);
if (!mRunning) {
ALOGV("Waiting for configure thread to start");
mInputSignal.wait(mInputMutex);
}
return OK;
}
status_t EmulatedFakeCamera2::ConfigureThread::newRequestAvailable() {
waitUntilRunning();
Mutex::Autolock lock(mInputMutex);
mActive = true;
mInputSignal.signal();
return OK;
}
bool EmulatedFakeCamera2::ConfigureThread::isStreamInUse(uint32_t id) {
Mutex::Autolock lock(mInternalsMutex);
if (mNextBuffers == NULL) return false;
for (size_t i=0; i < mNextBuffers->size(); i++) {
if ((*mNextBuffers)[i].streamId == (int)id) return true;
}
return false;
}
int EmulatedFakeCamera2::ConfigureThread::getInProgressCount() {
Mutex::Autolock lock(mInternalsMutex);
return mNextBuffers == NULL ? 0 : 1;
}
bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
static const nsecs_t kWaitPerLoop = 10000000L; // 10 ms
status_t res;
// Check if we're currently processing or just waiting
{
Mutex::Autolock lock(mInputMutex);
if (!mActive) {
// Inactive, keep waiting until we've been signaled
status_t res;
res = mInputSignal.waitRelative(mInputMutex, kWaitPerLoop);
if (res != NO_ERROR && res != TIMED_OUT) {
ALOGE("%s: Error waiting for input requests: %d",
__FUNCTION__, res);
return false;
}
if (!mActive) return true;
ALOGV("New request available");
}
// Active
}
if (mRequest == NULL) {
Mutex::Autolock il(mInternalsMutex);
ALOGV("Getting next request");
res = mParent->mRequestQueueSrc->dequeue_request(
mParent->mRequestQueueSrc,
&mRequest);
if (res != NO_ERROR) {
ALOGE("%s: Error dequeuing next request: %d", __FUNCTION__, res);
mParent->signalError();
return false;
}
if (mRequest == NULL) {
ALOGV("Request queue empty, going inactive");
// No requests available, go into inactive mode
Mutex::Autolock lock(mInputMutex);
mActive = false;
return true;
}
// Get necessary parameters for sensor config
sort_camera_metadata(mRequest);
camera_metadata_entry_t streams;
res = find_camera_metadata_entry(mRequest,
ANDROID_REQUEST_OUTPUT_STREAMS,
&streams);
if (res != NO_ERROR) {
ALOGE("%s: error reading output stream tag", __FUNCTION__);
mParent->signalError();
return false;
}
mNextBuffers = new Buffers;
mNextNeedsJpeg = false;
ALOGV("Setting up buffers for capture");
for (size_t i = 0; i < streams.count; i++) {
const Stream &s = mParent->getStreamInfo(streams.data.u8[i]);
StreamBuffer b;
b.streamId = streams.data.u8[i];
b.width = s.width;
b.height = s.height;
b.format = s.format;
b.stride = s.stride;
mNextBuffers->push_back(b);
ALOGV(" Buffer %d: Stream %d, %d x %d, format 0x%x, stride %d",
i, b.streamId, b.width, b.height, b.format, b.stride);
if (b.format == HAL_PIXEL_FORMAT_BLOB) {
mNextNeedsJpeg = true;
}
}
camera_metadata_entry_t e;
res = find_camera_metadata_entry(mRequest,
ANDROID_REQUEST_FRAME_COUNT,
&e);
if (res != NO_ERROR) {
ALOGE("%s: error reading frame count tag: %s (%d)",
__FUNCTION__, strerror(-res), res);
mParent->signalError();
return false;
}
mNextFrameNumber = *e.data.i32;
res = find_camera_metadata_entry(mRequest,
ANDROID_SENSOR_EXPOSURE_TIME,
&e);
if (res != NO_ERROR) {
ALOGE("%s: error reading exposure time tag: %s (%d)",
__FUNCTION__, strerror(-res), res);
mParent->signalError();
return false;
}
mNextExposureTime = *e.data.i64;
res = find_camera_metadata_entry(mRequest,
ANDROID_SENSOR_FRAME_DURATION,
&e);
if (res != NO_ERROR) {
ALOGE("%s: error reading frame duration tag", __FUNCTION__);
mParent->signalError();
return false;
}
mNextFrameDuration = *e.data.i64;
if (mNextFrameDuration <
mNextExposureTime + Sensor::kMinVerticalBlank) {
mNextFrameDuration = mNextExposureTime + Sensor::kMinVerticalBlank;
}
res = find_camera_metadata_entry(mRequest,
ANDROID_SENSOR_SENSITIVITY,
&e);
if (res != NO_ERROR) {
ALOGE("%s: error reading sensitivity tag", __FUNCTION__);
mParent->signalError();
return false;
}
mNextSensitivity = *e.data.i32;
res = find_camera_metadata_entry(mRequest,
EMULATOR_SCENE_HOUROFDAY,
&e);
if (res == NO_ERROR) {
ALOGV("Setting hour: %d", *e.data.i32);
mParent->mSensor->getScene().setHour(*e.data.i32);
}
// Start waiting on sensor or JPEG block
if (mNextNeedsJpeg) {
ALOGV("Waiting for JPEG compressor");
} else {
ALOGV("Waiting for sensor");
}
}
if (mNextNeedsJpeg) {
bool jpegDone;
jpegDone = mParent->mJpegCompressor->waitForDone(kWaitPerLoop);
if (!jpegDone) return true;
ALOGV("Waiting for sensor");
mNextNeedsJpeg = false;
}
bool vsync = mParent->mSensor->waitForVSync(kWaitPerLoop);
if (!vsync) return true;
Mutex::Autolock il(mInternalsMutex);
ALOGV("Configuring sensor for frame %d", mNextFrameNumber);
mParent->mSensor->setExposureTime(mNextExposureTime);
mParent->mSensor->setFrameDuration(mNextFrameDuration);
mParent->mSensor->setSensitivity(mNextSensitivity);
/** Get buffers to fill for this frame */
for (size_t i = 0; i < mNextBuffers->size(); i++) {
StreamBuffer &b = mNextBuffers->editItemAt(i);
Stream s = mParent->getStreamInfo(b.streamId);
res = s.ops->dequeue_buffer(s.ops, &(b.buffer) );
if (res != NO_ERROR || b.buffer == NULL) {
ALOGE("%s: Unable to dequeue buffer from stream %d: %s (%d)",
__FUNCTION__, b.streamId, strerror(-res), res);
mParent->signalError();
return false;
}
/* Lock the buffer from the perspective of the graphics mapper */
uint8_t *img;
const Rect rect(s.width, s.height);
res = GraphicBufferMapper::get().lock(*(b.buffer),
GRALLOC_USAGE_SW_WRITE_OFTEN,
rect, (void**)&(b.img) );
if (res != NO_ERROR) {
ALOGE("%s: grbuffer_mapper.lock failure: %s (%d)",
__FUNCTION__, strerror(-res), res);
s.ops->cancel_buffer(s.ops,
b.buffer);
mParent->signalError();
return false;
}
}
mParent->mReadoutThread->setNextCapture(mRequest, mNextBuffers);
mParent->mSensor->setDestinationBuffers(mNextBuffers);
mRequest = NULL;
mNextBuffers = NULL;
return true;
}
EmulatedFakeCamera2::ReadoutThread::ReadoutThread(EmulatedFakeCamera2 *parent):
Thread(false),
mParent(parent),
mRunning(false),
mActive(false),
mRequest(NULL)
{
mInFlightQueue = new InFlightQueue[kInFlightQueueSize];
mInFlightHead = 0;
mInFlightTail = 0;
}
EmulatedFakeCamera2::ReadoutThread::~ReadoutThread() {
delete mInFlightQueue;
}
status_t EmulatedFakeCamera2::ReadoutThread::readyToRun() {
Mutex::Autolock lock(mInputMutex);
ALOGV("Starting up ReadoutThread");
mRunning = true;
mInputSignal.signal();
return NO_ERROR;
}
status_t EmulatedFakeCamera2::ReadoutThread::waitUntilRunning() {
Mutex::Autolock lock(mInputMutex);
if (!mRunning) {
ALOGV("Waiting for readout thread to start");
mInputSignal.wait(mInputMutex);
}
return OK;
}
void EmulatedFakeCamera2::ReadoutThread::setNextCapture(
camera_metadata_t *request,
Buffers *buffers) {
Mutex::Autolock lock(mInputMutex);
if ( (mInFlightTail + 1) % kInFlightQueueSize == mInFlightHead) {
ALOGE("In flight queue full, dropping captures");
mParent->signalError();
return;
}
mInFlightQueue[mInFlightTail].request = request;
mInFlightQueue[mInFlightTail].buffers = buffers;
mInFlightTail = (mInFlightTail + 1) % kInFlightQueueSize;
if (!mActive) {
mActive = true;
mInputSignal.signal();
}
}
bool EmulatedFakeCamera2::ReadoutThread::isStreamInUse(uint32_t id) {
Mutex::Autolock lock(mInputMutex);
size_t i = mInFlightHead;
while (i != mInFlightTail) {
for (size_t j = 0; j < mInFlightQueue[i].buffers->size(); j++) {
if ( (*(mInFlightQueue[i].buffers))[j].streamId == (int)id )
return true;
}
i = (i + 1) % kInFlightQueueSize;
}
Mutex::Autolock iLock(mInternalsMutex);
if (mBuffers != NULL) {
for (i = 0; i < mBuffers->size(); i++) {
if ( (*mBuffers)[i].streamId == (int)id) return true;
}
}
return false;
}
int EmulatedFakeCamera2::ReadoutThread::getInProgressCount() {
Mutex::Autolock lock(mInputMutex);
Mutex::Autolock iLock(mInternalsMutex);
int requestCount =
((mInFlightTail + kInFlightQueueSize) - mInFlightHead)
% kInFlightQueueSize;
requestCount += (mBuffers == NULL) ? 0 : 1;
return requestCount;
}
bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
static const nsecs_t kWaitPerLoop = 10000000L; // 10 ms
status_t res;
// Check if we're currently processing or just waiting
{
Mutex::Autolock lock(mInputMutex);
if (!mActive) {
// Inactive, keep waiting until we've been signaled
res = mInputSignal.waitRelative(mInputMutex, kWaitPerLoop);
if (res != NO_ERROR && res != TIMED_OUT) {
ALOGE("%s: Error waiting for capture requests: %d",
__FUNCTION__, res);
mParent->signalError();
return false;
}
if (!mActive) return true;
}
// Active, see if we need a new request
if (mRequest == NULL) {
if (mInFlightHead == mInFlightTail) {
// Go inactive
ALOGV("Waiting for sensor data");
mActive = false;
return true;
} else {
Mutex::Autolock iLock(mInternalsMutex);
mRequest = mInFlightQueue[mInFlightHead].request;
mBuffers = mInFlightQueue[mInFlightHead].buffers;
mInFlightQueue[mInFlightHead].request = NULL;
mInFlightQueue[mInFlightHead].buffers = NULL;
mInFlightHead = (mInFlightHead + 1) % kInFlightQueueSize;
ALOGV("Ready to read out request %p, %d buffers",
mRequest, mBuffers->size());
}
}
}
// Active with request, wait on sensor to complete
nsecs_t captureTime;
bool gotFrame;
gotFrame = mParent->mSensor->waitForNewFrame(kWaitPerLoop,
&captureTime);
if (!gotFrame) return true;
// Got sensor data, construct frame and send it out
ALOGV("Readout: Constructing metadata and frames");
Mutex::Autolock iLock(mInternalsMutex);
camera_metadata_entry_t metadataMode;
res = find_camera_metadata_entry(mRequest,
ANDROID_REQUEST_METADATA_MODE,
&metadataMode);
if (*metadataMode.data.u8 == ANDROID_REQUEST_METADATA_FULL) {
ALOGV("Metadata requested, constructing");
camera_metadata_t *frame = NULL;
size_t frame_entries = get_camera_metadata_entry_count(mRequest);
size_t frame_data = get_camera_metadata_data_count(mRequest);
frame_entries += 2;
frame_data += 8;
res = mParent->mFrameQueueDst->dequeue_frame(mParent->mFrameQueueDst,
frame_entries, frame_data, &frame);
if (res != NO_ERROR || frame == NULL) {
ALOGE("%s: Unable to dequeue frame metadata buffer", __FUNCTION__);
mParent->signalError();
return false;
}
res = append_camera_metadata(frame, mRequest);
if (res != NO_ERROR) {
ALOGE("Unable to append request metadata");
}
add_camera_metadata_entry(frame,
ANDROID_SENSOR_TIMESTAMP,
&captureTime,
1);
int32_t hourOfDay = (int32_t)mParent->mSensor->getScene().getHour();
camera_metadata_entry_t requestedHour;
res = find_camera_metadata_entry(frame,
EMULATOR_SCENE_HOUROFDAY,
&requestedHour);
if (res == NAME_NOT_FOUND) {
ALOGV("Adding vendor tag");
res = add_camera_metadata_entry(frame,
EMULATOR_SCENE_HOUROFDAY,
&hourOfDay, 1);
if (res != NO_ERROR) {
ALOGE("Unable to add vendor tag");
}
} else if (res == OK) {
ALOGV("Replacing value in vendor tag");
*requestedHour.data.i32 = hourOfDay;
} else {
ALOGE("Error looking up vendor tag");
}
// TODO: Collect all final values used from sensor in addition to timestamp
mParent->mFrameQueueDst->enqueue_frame(mParent->mFrameQueueDst,
frame);
}
res = mParent->mRequestQueueSrc->free_request(mParent->mRequestQueueSrc, mRequest);
if (res != NO_ERROR) {
ALOGE("%s: Unable to return request buffer to queue: %d",
__FUNCTION__, res);
mParent->signalError();
return false;
}
mRequest = NULL;
int compressedBufferIndex = -1;
ALOGV("Processing %d buffers", mBuffers->size());
for (size_t i = 0; i < mBuffers->size(); i++) {
const StreamBuffer &b = (*mBuffers)[i];
ALOGV(" Buffer %d: Stream %d, %d x %d, format 0x%x, stride %d",
i, b.streamId, b.width, b.height, b.format, b.stride);
if (b.streamId >= 0) {
if (b.format == HAL_PIXEL_FORMAT_BLOB) {
// Assumes only one BLOB buffer type per capture
compressedBufferIndex = i;
} else {
ALOGV("Sending image buffer %d to output stream %d",
i, b.streamId);
GraphicBufferMapper::get().unlock(*(b.buffer));
res = mParent->getStreamInfo(b.streamId).ops->enqueue_buffer(
mParent->getStreamInfo(b.streamId).ops,
captureTime, b.buffer);
if (res != OK) {
ALOGE("Error enqueuing image buffer %p: %s (%d)", b.buffer,
strerror(-res), res);
mParent->signalError();
}
}
}
}
if (compressedBufferIndex == -1) {
delete mBuffers;
mBuffers = NULL;
} else {
ALOGV("Starting JPEG compression for buffer %d, stream %d",
compressedBufferIndex,
(*mBuffers)[compressedBufferIndex].streamId);
mParent->mJpegCompressor->start(mBuffers, captureTime);
mBuffers = NULL;
}
return true;
}
/** Private methods */
status_t EmulatedFakeCamera2::constructStaticInfo(
camera_metadata_t **info,
bool sizeRequest) const {
size_t entryCount = 0;
size_t dataCount = 0;
status_t ret;
#define ADD_OR_SIZE( tag, data, count ) \
if ( ( ret = addOrSize(*info, sizeRequest, &entryCount, &dataCount, \
tag, data, count) ) != OK ) return ret
// android.lens
static const float minFocusDistance = 0;
ADD_OR_SIZE(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE,
&minFocusDistance, 1);
ADD_OR_SIZE(ANDROID_LENS_HYPERFOCAL_DISTANCE,
&minFocusDistance, 1);
static const float focalLength = 3.30f; // mm
ADD_OR_SIZE(ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS,
&focalLength, 1);
static const float aperture = 2.8f;
ADD_OR_SIZE(ANDROID_LENS_AVAILABLE_APERTURES,
&aperture, 1);
static const float filterDensity = 0;
ADD_OR_SIZE(ANDROID_LENS_AVAILABLE_FILTER_DENSITY,
&filterDensity, 1);
static const uint8_t availableOpticalStabilization =
ANDROID_LENS_OPTICAL_STABILIZATION_OFF;
ADD_OR_SIZE(ANDROID_LENS_AVAILABLE_OPTICAL_STABILIZATION,
&availableOpticalStabilization, 1);
static const int32_t lensShadingMapSize[] = {1, 1};
ADD_OR_SIZE(ANDROID_LENS_SHADING_MAP_SIZE, lensShadingMapSize,
sizeof(lensShadingMapSize)/sizeof(int32_t));
static const float lensShadingMap[3 * 1 * 1 ] =
{ 1.f, 1.f, 1.f };
ADD_OR_SIZE(ANDROID_LENS_SHADING_MAP, lensShadingMap,
sizeof(lensShadingMap)/sizeof(float));
// Identity transform
static const int32_t geometricCorrectionMapSize[] = {2, 2};
ADD_OR_SIZE(ANDROID_LENS_GEOMETRIC_CORRECTION_MAP_SIZE,
geometricCorrectionMapSize,
sizeof(geometricCorrectionMapSize)/sizeof(int32_t));
static const float geometricCorrectionMap[2 * 3 * 2 * 2] = {
0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
1.f, 0.f, 1.f, 0.f, 1.f, 0.f,
0.f, 1.f, 0.f, 1.f, 0.f, 1.f,
1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
ADD_OR_SIZE(ANDROID_LENS_GEOMETRIC_CORRECTION_MAP,
geometricCorrectionMap,
sizeof(geometricCorrectionMap)/sizeof(float));
int32_t lensFacing = mFacingBack ?
ANDROID_LENS_FACING_BACK : ANDROID_LENS_FACING_FRONT;
ADD_OR_SIZE(ANDROID_LENS_FACING, &lensFacing, 1);
float lensPosition[3];
if (mFacingBack) {
// Back-facing camera is center-top on device
lensPosition[0] = 0;
lensPosition[1] = 20;
lensPosition[2] = -5;
} else {
// Front-facing camera is center-right on device
lensPosition[0] = 20;
lensPosition[1] = 20;
lensPosition[2] = 0;
}
ADD_OR_SIZE(ANDROID_LENS_POSITION, lensPosition, sizeof(lensPosition)/
sizeof(float));
// android.sensor
ADD_OR_SIZE(ANDROID_SENSOR_EXPOSURE_TIME_RANGE,
Sensor::kExposureTimeRange, 2);
ADD_OR_SIZE(ANDROID_SENSOR_MAX_FRAME_DURATION,
&Sensor::kFrameDurationRange[1], 1);
ADD_OR_SIZE(ANDROID_SENSOR_AVAILABLE_SENSITIVITIES,
Sensor::kAvailableSensitivities,
sizeof(Sensor::kAvailableSensitivities)
/sizeof(uint32_t));
ADD_OR_SIZE(ANDROID_SENSOR_COLOR_FILTER_ARRANGEMENT,
&Sensor::kColorFilterArrangement, 1);
static const float sensorPhysicalSize[2] = {3.20f, 2.40f}; // mm
ADD_OR_SIZE(ANDROID_SENSOR_PHYSICAL_SIZE,
sensorPhysicalSize, 2);
ADD_OR_SIZE(ANDROID_SENSOR_PIXEL_ARRAY_SIZE,
Sensor::kResolution, 2);
ADD_OR_SIZE(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE,
Sensor::kResolution, 2);
ADD_OR_SIZE(ANDROID_SENSOR_WHITE_LEVEL,
&Sensor::kMaxRawValue, 1);
static const int32_t blackLevelPattern[4] = {
Sensor::kBlackLevel, Sensor::kBlackLevel,
Sensor::kBlackLevel, Sensor::kBlackLevel
};
ADD_OR_SIZE(ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
blackLevelPattern, sizeof(blackLevelPattern)/sizeof(int32_t));
//TODO: sensor color calibration fields
// android.flash
static const uint8_t flashAvailable = 0;
ADD_OR_SIZE(ANDROID_FLASH_AVAILABLE, &flashAvailable, 1);
static const int64_t flashChargeDuration = 0;
ADD_OR_SIZE(ANDROID_FLASH_CHARGE_DURATION, &flashChargeDuration, 1);
// android.tonemap
static const int32_t tonemapCurvePoints = 128;
ADD_OR_SIZE(ANDROID_TONEMAP_MAX_CURVE_POINTS, &tonemapCurvePoints, 1);
// android.scaler
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_FORMATS,
kAvailableFormats,
sizeof(kAvailableFormats)/sizeof(uint32_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
kAvailableRawSizes,
sizeof(kAvailableRawSizes)/sizeof(uint32_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
kAvailableRawMinDurations,
sizeof(kAvailableRawMinDurations)/sizeof(uint64_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
kAvailableProcessedSizes,
sizeof(kAvailableProcessedSizes)/sizeof(uint32_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
kAvailableProcessedMinDurations,
sizeof(kAvailableProcessedMinDurations)/sizeof(uint64_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
kAvailableJpegSizes,
sizeof(kAvailableJpegSizes)/sizeof(uint32_t));
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
kAvailableJpegMinDurations,
sizeof(kAvailableJpegMinDurations)/sizeof(uint64_t));
static const float maxZoom = 10;
ADD_OR_SIZE(ANDROID_SCALER_AVAILABLE_MAX_ZOOM,
&maxZoom, 1);
// android.jpeg
static const int32_t jpegThumbnailSizes[] = {
160, 120,
320, 240,
640, 480
};
ADD_OR_SIZE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
jpegThumbnailSizes, sizeof(jpegThumbnailSizes)/sizeof(int32_t));
static const int32_t jpegMaxSize = JpegCompressor::kMaxJpegSize;
ADD_OR_SIZE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
// android.stats
static const uint8_t availableFaceDetectModes[] = {
ANDROID_STATS_FACE_DETECTION_OFF
};
ADD_OR_SIZE(ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES,
availableFaceDetectModes,
sizeof(availableFaceDetectModes));
static const int32_t maxFaceCount = 0;
ADD_OR_SIZE(ANDROID_STATS_MAX_FACE_COUNT,
&maxFaceCount, 1);
static const int32_t histogramSize = 64;
ADD_OR_SIZE(ANDROID_STATS_HISTOGRAM_BUCKET_COUNT,
&histogramSize, 1);
static const int32_t maxHistogramCount = 1000;
ADD_OR_SIZE(ANDROID_STATS_MAX_HISTOGRAM_COUNT,
&maxHistogramCount, 1);
static const int32_t sharpnessMapSize[2] = {64, 64};
ADD_OR_SIZE(ANDROID_STATS_SHARPNESS_MAP_SIZE,
sharpnessMapSize, sizeof(sharpnessMapSize)/sizeof(int32_t));
static const int32_t maxSharpnessMapValue = 1000;
ADD_OR_SIZE(ANDROID_STATS_MAX_SHARPNESS_MAP_VALUE,
&maxSharpnessMapValue, 1);
// android.control
static const uint8_t availableSceneModes[] = {
ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED
};
ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
availableSceneModes, sizeof(availableSceneModes));
static const uint8_t availableEffects[] = {
ANDROID_CONTROL_EFFECT_OFF
};
ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_EFFECTS,
availableEffects, sizeof(availableEffects));
int32_t max3aRegions = 0;
ADD_OR_SIZE(ANDROID_CONTROL_MAX_REGIONS,
&max3aRegions, 1);
static const uint8_t availableAeModes[] = {
ANDROID_CONTROL_AE_OFF,
ANDROID_CONTROL_AE_ON
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_MODES,
availableAeModes, sizeof(availableAeModes));
static const camera_metadata_rational exposureCompensationStep = {
1, 3
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP,
&exposureCompensationStep, 1);
int32_t exposureCompensationRange[] = {-9, 9};
ADD_OR_SIZE(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE,
exposureCompensationRange,
sizeof(exposureCompensationRange)/sizeof(int32_t));
static const int32_t availableTargetFpsRanges[] = {
5, 30
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
availableTargetFpsRanges,
sizeof(availableTargetFpsRanges)/sizeof(int32_t));
static const uint8_t availableAntibandingModes[] = {
ANDROID_CONTROL_AE_ANTIBANDING_OFF,
ANDROID_CONTROL_AE_ANTIBANDING_AUTO
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
availableAntibandingModes, sizeof(availableAntibandingModes));
static const uint8_t availableAwbModes[] = {
ANDROID_CONTROL_AWB_OFF,
ANDROID_CONTROL_AWB_AUTO,
ANDROID_CONTROL_AWB_INCANDESCENT,
ANDROID_CONTROL_AWB_FLUORESCENT,
ANDROID_CONTROL_AWB_DAYLIGHT,
ANDROID_CONTROL_AWB_SHADE
};
ADD_OR_SIZE(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
availableAwbModes, sizeof(availableAwbModes));
static const uint8_t availableAfModes[] = {
ANDROID_CONTROL_AF_OFF
};
ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
availableAfModes, sizeof(availableAfModes));
static const uint8_t availableVstabModes[] = {
ANDROID_CONTROL_VIDEO_STABILIZATION_OFF
};
ADD_OR_SIZE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
availableVstabModes, sizeof(availableVstabModes));
#undef ADD_OR_SIZE
/** Allocate metadata if sizing */
if (sizeRequest) {
ALOGV("Allocating %d entries, %d extra bytes for "
"static camera info",
entryCount, dataCount);
*info = allocate_camera_metadata(entryCount, dataCount);
if (*info == NULL) {
ALOGE("Unable to allocate camera static info"
"(%d entries, %d bytes extra data)",
entryCount, dataCount);
return NO_MEMORY;
}
}
return OK;
}
status_t EmulatedFakeCamera2::constructDefaultRequest(
int request_template,
camera_metadata_t **request,
bool sizeRequest) const {
size_t entryCount = 0;
size_t dataCount = 0;
status_t ret;
#define ADD_OR_SIZE( tag, data, count ) \
if ( ( ret = addOrSize(*request, sizeRequest, &entryCount, &dataCount, \
tag, data, count) ) != OK ) return ret
static const int64_t USEC = 1000LL;
static const int64_t MSEC = USEC * 1000LL;
static const int64_t SEC = MSEC * 1000LL;
/** android.request */
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
entryCount += 1;
dataCount += 5; // TODO: Should be maximum stream number
/** android.lens */
static const float focusDistance = 0;
ADD_OR_SIZE(ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
static const float aperture = 2.8f;
ADD_OR_SIZE(ANDROID_LENS_APERTURE, &aperture, 1);
static const float focalLength = 5.0f;
ADD_OR_SIZE(ANDROID_LENS_FOCAL_LENGTH, &focalLength, 1);
static const float filterDensity = 0;
ADD_OR_SIZE(ANDROID_LENS_FILTER_DENSITY, &filterDensity, 1);
static const uint8_t opticalStabilizationMode =
ANDROID_LENS_OPTICAL_STABILIZATION_OFF;
ADD_OR_SIZE(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
&opticalStabilizationMode, 1);
// FOCUS_RANGE set only in frame
/** android.sensor */
static const int64_t exposureTime = 10 * MSEC;
ADD_OR_SIZE(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1);
static const int64_t frameDuration = 33333333L; // 1/30 s
ADD_OR_SIZE(ANDROID_SENSOR_FRAME_DURATION, &frameDuration, 1);
static const int32_t sensitivity = 100;
ADD_OR_SIZE(ANDROID_SENSOR_SENSITIVITY, &sensitivity, 1);
// TIMESTAMP set only in frame
/** android.flash */
static const uint8_t flashMode = ANDROID_FLASH_OFF;
ADD_OR_SIZE(ANDROID_FLASH_MODE, &flashMode, 1);
static const uint8_t flashPower = 10;
ADD_OR_SIZE(ANDROID_FLASH_FIRING_POWER, &flashPower, 1);
static const int64_t firingTime = 0;
ADD_OR_SIZE(ANDROID_FLASH_FIRING_TIME, &firingTime, 1);
/** Processing block modes */
uint8_t hotPixelMode = 0;
uint8_t demosaicMode = 0;
uint8_t noiseMode = 0;
uint8_t shadingMode = 0;
uint8_t geometricMode = 0;
uint8_t colorMode = 0;
uint8_t tonemapMode = 0;
uint8_t edgeMode = 0;
switch (request_template) {
case CAMERA2_TEMPLATE_PREVIEW:
hotPixelMode = ANDROID_PROCESSING_FAST;
demosaicMode = ANDROID_PROCESSING_FAST;
noiseMode = ANDROID_PROCESSING_FAST;
shadingMode = ANDROID_PROCESSING_FAST;
geometricMode = ANDROID_PROCESSING_FAST;
colorMode = ANDROID_PROCESSING_FAST;
tonemapMode = ANDROID_PROCESSING_FAST;
edgeMode = ANDROID_PROCESSING_FAST;
break;
case CAMERA2_TEMPLATE_STILL_CAPTURE:
hotPixelMode = ANDROID_PROCESSING_HIGH_QUALITY;
demosaicMode = ANDROID_PROCESSING_HIGH_QUALITY;
noiseMode = ANDROID_PROCESSING_HIGH_QUALITY;
shadingMode = ANDROID_PROCESSING_HIGH_QUALITY;
geometricMode = ANDROID_PROCESSING_HIGH_QUALITY;
colorMode = ANDROID_PROCESSING_HIGH_QUALITY;
tonemapMode = ANDROID_PROCESSING_HIGH_QUALITY;
edgeMode = ANDROID_PROCESSING_HIGH_QUALITY;
break;
case CAMERA2_TEMPLATE_VIDEO_RECORD:
hotPixelMode = ANDROID_PROCESSING_FAST;
demosaicMode = ANDROID_PROCESSING_FAST;
noiseMode = ANDROID_PROCESSING_FAST;
shadingMode = ANDROID_PROCESSING_FAST;
geometricMode = ANDROID_PROCESSING_FAST;
colorMode = ANDROID_PROCESSING_FAST;
tonemapMode = ANDROID_PROCESSING_FAST;
edgeMode = ANDROID_PROCESSING_FAST;
break;
case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
hotPixelMode = ANDROID_PROCESSING_HIGH_QUALITY;
demosaicMode = ANDROID_PROCESSING_HIGH_QUALITY;
noiseMode = ANDROID_PROCESSING_HIGH_QUALITY;
shadingMode = ANDROID_PROCESSING_HIGH_QUALITY;
geometricMode = ANDROID_PROCESSING_HIGH_QUALITY;
colorMode = ANDROID_PROCESSING_HIGH_QUALITY;
tonemapMode = ANDROID_PROCESSING_HIGH_QUALITY;
edgeMode = ANDROID_PROCESSING_HIGH_QUALITY;
break;
case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
hotPixelMode = ANDROID_PROCESSING_HIGH_QUALITY;
demosaicMode = ANDROID_PROCESSING_HIGH_QUALITY;
noiseMode = ANDROID_PROCESSING_HIGH_QUALITY;
shadingMode = ANDROID_PROCESSING_HIGH_QUALITY;
geometricMode = ANDROID_PROCESSING_HIGH_QUALITY;
colorMode = ANDROID_PROCESSING_HIGH_QUALITY;
tonemapMode = ANDROID_PROCESSING_HIGH_QUALITY;
edgeMode = ANDROID_PROCESSING_HIGH_QUALITY;
break;
default:
hotPixelMode = ANDROID_PROCESSING_FAST;
demosaicMode = ANDROID_PROCESSING_FAST;
noiseMode = ANDROID_PROCESSING_FAST;
shadingMode = ANDROID_PROCESSING_FAST;
geometricMode = ANDROID_PROCESSING_FAST;
colorMode = ANDROID_PROCESSING_FAST;
tonemapMode = ANDROID_PROCESSING_FAST;
edgeMode = ANDROID_PROCESSING_FAST;
break;
}
ADD_OR_SIZE(ANDROID_HOT_PIXEL_MODE, &hotPixelMode, 1);
ADD_OR_SIZE(ANDROID_DEMOSAIC_MODE, &demosaicMode, 1);
ADD_OR_SIZE(ANDROID_NOISE_MODE, &noiseMode, 1);
ADD_OR_SIZE(ANDROID_SHADING_MODE, &shadingMode, 1);
ADD_OR_SIZE(ANDROID_GEOMETRIC_MODE, &geometricMode, 1);
ADD_OR_SIZE(ANDROID_COLOR_MODE, &colorMode, 1);
ADD_OR_SIZE(ANDROID_TONEMAP_MODE, &tonemapMode, 1);
ADD_OR_SIZE(ANDROID_EDGE_MODE, &edgeMode, 1);
/** android.noise */
static const uint8_t noiseStrength = 5;
ADD_OR_SIZE(ANDROID_NOISE_STRENGTH, &noiseStrength, 1);
/** android.color */
static const float colorTransform[9] = {
1.0f, 0.f, 0.f,
0.f, 1.f, 0.f,
0.f, 0.f, 1.f
};
ADD_OR_SIZE(ANDROID_COLOR_TRANSFORM, colorTransform, 9);
/** android.tonemap */
static const float tonemapCurve[4] = {
0.f, 0.f,
1.f, 1.f
};
ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_RED, tonemapCurve, 4);
ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_GREEN, tonemapCurve, 4);
ADD_OR_SIZE(ANDROID_TONEMAP_CURVE_BLUE, tonemapCurve, 4);
/** android.edge */
static const uint8_t edgeStrength = 5;
ADD_OR_SIZE(ANDROID_EDGE_STRENGTH, &edgeStrength, 1);
/** android.scaler */
static const int32_t cropRegion[3] = {
0, 0, Sensor::kResolution[0]
};
ADD_OR_SIZE(ANDROID_SCALER_CROP_REGION, cropRegion, 3);
/** android.jpeg */
static const int32_t jpegQuality = 80;
ADD_OR_SIZE(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
static const int32_t thumbnailSize[2] = {
640, 480
};
ADD_OR_SIZE(ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
static const int32_t thumbnailQuality = 80;
ADD_OR_SIZE(ANDROID_JPEG_THUMBNAIL_QUALITY, &thumbnailQuality, 1);
static const double gpsCoordinates[2] = {
0, 0
};
ADD_OR_SIZE(ANDROID_JPEG_GPS_COORDINATES, gpsCoordinates, 2);
static const uint8_t gpsProcessingMethod[32] = "None";
ADD_OR_SIZE(ANDROID_JPEG_GPS_PROCESSING_METHOD, gpsProcessingMethod, 32);
static const int64_t gpsTimestamp = 0;
ADD_OR_SIZE(ANDROID_JPEG_GPS_TIMESTAMP, &gpsTimestamp, 1);
static const int32_t jpegOrientation = 0;
ADD_OR_SIZE(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
/** android.stats */
static const uint8_t faceDetectMode = ANDROID_STATS_FACE_DETECTION_OFF;
ADD_OR_SIZE(ANDROID_STATS_FACE_DETECT_MODE, &faceDetectMode, 1);
static const uint8_t histogramMode = ANDROID_STATS_OFF;
ADD_OR_SIZE(ANDROID_STATS_HISTOGRAM_MODE, &histogramMode, 1);
static const uint8_t sharpnessMapMode = ANDROID_STATS_OFF;
ADD_OR_SIZE(ANDROID_STATS_SHARPNESS_MAP_MODE, &sharpnessMapMode, 1);
// faceRectangles, faceScores, faceLandmarks, faceIds, histogram,
// sharpnessMap only in frames
/** android.control */
uint8_t controlIntent = 0;
switch (request_template) {
case CAMERA2_TEMPLATE_PREVIEW:
controlIntent = ANDROID_CONTROL_INTENT_PREVIEW;
break;
case CAMERA2_TEMPLATE_STILL_CAPTURE:
controlIntent = ANDROID_CONTROL_INTENT_STILL_CAPTURE;
break;
case CAMERA2_TEMPLATE_VIDEO_RECORD:
controlIntent = ANDROID_CONTROL_INTENT_VIDEO_RECORD;
break;
case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
controlIntent = ANDROID_CONTROL_INTENT_VIDEO_SNAPSHOT;
break;
case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
controlIntent = ANDROID_CONTROL_INTENT_ZERO_SHUTTER_LAG;
break;
default:
controlIntent = ANDROID_CONTROL_INTENT_CUSTOM;
break;
}
ADD_OR_SIZE(ANDROID_CONTROL_CAPTURE_INTENT, &controlIntent, 1);
static const uint8_t controlMode = ANDROID_CONTROL_AUTO;
ADD_OR_SIZE(ANDROID_CONTROL_MODE, &controlMode, 1);
static const uint8_t effectMode = ANDROID_CONTROL_EFFECT_OFF;
ADD_OR_SIZE(ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
static const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
ADD_OR_SIZE(ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
static const uint8_t aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH;
ADD_OR_SIZE(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
static const int32_t controlRegions[5] = {
0, 0, Sensor::kResolution[0], Sensor::kResolution[1], 1000
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_REGIONS, controlRegions, 5);
static const int32_t aeExpCompensation = 0;
ADD_OR_SIZE(ANDROID_CONTROL_AE_EXP_COMPENSATION, &aeExpCompensation, 1);
static const int32_t aeTargetFpsRange[2] = {
10, 30
};
ADD_OR_SIZE(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeTargetFpsRange, 2);
static const uint8_t aeAntibandingMode =
ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
ADD_OR_SIZE(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1);
static const uint8_t awbMode =
ANDROID_CONTROL_AWB_AUTO;
ADD_OR_SIZE(ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
ADD_OR_SIZE(ANDROID_CONTROL_AWB_REGIONS, controlRegions, 5);
uint8_t afMode = 0;
switch (request_template) {
case CAMERA2_TEMPLATE_PREVIEW:
afMode = ANDROID_CONTROL_AF_AUTO;
break;
case CAMERA2_TEMPLATE_STILL_CAPTURE:
afMode = ANDROID_CONTROL_AF_AUTO;
break;
case CAMERA2_TEMPLATE_VIDEO_RECORD:
afMode = ANDROID_CONTROL_AF_CONTINUOUS_VIDEO;
break;
case CAMERA2_TEMPLATE_VIDEO_SNAPSHOT:
afMode = ANDROID_CONTROL_AF_CONTINUOUS_VIDEO;
break;
case CAMERA2_TEMPLATE_ZERO_SHUTTER_LAG:
afMode = ANDROID_CONTROL_AF_CONTINUOUS_PICTURE;
break;
default:
afMode = ANDROID_CONTROL_AF_AUTO;
break;
}
ADD_OR_SIZE(ANDROID_CONTROL_AF_MODE, &afMode, 1);
ADD_OR_SIZE(ANDROID_CONTROL_AF_REGIONS, controlRegions, 5);
static const uint8_t vstabMode = ANDROID_CONTROL_VIDEO_STABILIZATION_OFF;
ADD_OR_SIZE(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &vstabMode, 1);
// aeState, awbState, afState only in frame
/** Allocate metadata if sizing */
if (sizeRequest) {
ALOGV("Allocating %d entries, %d extra bytes for "
"request template type %d",
entryCount, dataCount, request_template);
*request = allocate_camera_metadata(entryCount, dataCount);
if (*request == NULL) {
ALOGE("Unable to allocate new request template type %d "
"(%d entries, %d bytes extra data)", request_template,
entryCount, dataCount);
return NO_MEMORY;
}
}
return OK;
#undef ADD_OR_SIZE
}
status_t EmulatedFakeCamera2::addOrSize(camera_metadata_t *request,
bool sizeRequest,
size_t *entryCount,
size_t *dataCount,
uint32_t tag,
const void *entryData,
size_t entryDataCount) {
status_t res;
if (!sizeRequest) {
return add_camera_metadata_entry(request, tag, entryData,
entryDataCount);
} else {
int type = get_camera_metadata_tag_type(tag);
if (type < 0 ) return BAD_VALUE;
(*entryCount)++;
(*dataCount) += calculate_camera_metadata_entry_data_size(type,
entryDataCount);
return OK;
}
}
bool EmulatedFakeCamera2::isStreamInUse(uint32_t id) {
// Assumes mMutex is locked; otherwise new requests could enter
// configureThread while readoutThread is being checked
// Order of isStreamInUse calls matters
if (mConfigureThread->isStreamInUse(id) ||
mReadoutThread->isStreamInUse(id) ||
mJpegCompressor->isStreamInUse(id) ) {
ALOGE("%s: Stream %d is in use in active requests!",
__FUNCTION__, id);
return true;
}
return false;
}
const Stream& EmulatedFakeCamera2::getStreamInfo(uint32_t streamId) {
Mutex::Autolock lock(mMutex);
return mStreams.valueFor(streamId);
}
}; /* namespace android */