am 819d2aac: Merge "EmulatedFakeCamera2: Add autofocus management" into jb-mr1-dev

* commit '819d2aac43d27100df59ee009c211169787b55dd':
  EmulatedFakeCamera2: Add autofocus management
This commit is contained in:
Eino-Ville Talvala
2012-08-10 12:40:24 -07:00
committed by Android Git Automerger
4 changed files with 479 additions and 21 deletions

View File

@@ -305,6 +305,7 @@ int EmulatedCamera2::trigger_action(const camera2_device_t *d,
int EmulatedCamera2::set_notify_callback(const camera2_device_t *d,
camera2_notify_callback notify_cb, void* user) {
EmulatedCamera2* ec = getInstance(d);
Mutex::Autolock l(ec->mMutex);
ec->mNotifyCb = notify_cb;
ec->mNotifyUserPtr = user;
return NO_ERROR;
@@ -355,6 +356,18 @@ int EmulatedCamera2::close(struct hw_device_t* device) {
return ec->closeCamera();
}
void EmulatedCamera2::sendNotification(int32_t msgType,
int32_t ext1, int32_t ext2, int32_t ext3) {
camera2_notify_callback notifyCb;
{
Mutex::Autolock l(mMutex);
notifyCb = mNotifyCb;
}
if (notifyCb != NULL) {
notifyCb(msgType, ext1, ext2, ext3, mNotifyUserPtr);
}
}
camera2_device_ops_t EmulatedCamera2::sDeviceOps = {
EmulatedCamera2::set_request_queue_src_ops,
EmulatedCamera2::notify_request_queue_not_empty,

View File

@@ -28,6 +28,8 @@
#include "hardware/camera2.h"
#include "system/camera_metadata.h"
#include "EmulatedBaseCamera.h"
#include <utils/Thread.h>
#include <utils/Mutex.h>
namespace android {
@@ -128,7 +130,7 @@ protected:
/** 3A action triggering */
virtual int triggerAction(uint32_t trigger_id,
int ext1, int ext2);
int32_t ext1, int32_t ext2);
/** Custom tag definitions */
virtual const char* getVendorSectionName(uint32_t tag);
@@ -232,21 +234,27 @@ private:
* Data members shared with implementations
***************************************************************************/
protected:
/** Mutex for calls through camera2 device interface */
Mutex mMutex;
const camera2_request_queue_src_ops *mRequestQueueSrc;
const camera2_frame_queue_dst_ops *mFrameQueueDst;
camera2_notify_callback mNotifyCb;
void* mNotifyUserPtr;
struct TagOps : public vendor_tag_query_ops {
EmulatedCamera2 *parent;
};
TagOps mVendorTagOps;
void sendNotification(int32_t msgType,
int32_t ext1, int32_t ext2, int32_t ext3);
/****************************************************************************
* Data members
***************************************************************************/
private:
static camera2_device_ops_t sDeviceOps;
camera2_notify_callback mNotifyCb;
void* mNotifyUserPtr;
};
}; /* namespace android */

View File

@@ -133,6 +133,7 @@ status_t EmulatedFakeCamera2::connectCamera(hw_device_t** device) {
mConfigureThread = new ConfigureThread(this);
mReadoutThread = new ReadoutThread(this);
mControlThread = new ControlThread(this);
mSensor = new Sensor(this);
mJpegCompressor = new JpegCompressor(this);
@@ -147,6 +148,9 @@ status_t EmulatedFakeCamera2::connectCamera(hw_device_t** device) {
res = mReadoutThread->run("EmulatedFakeCamera2::readoutThread");
if (res != NO_ERROR) return res;
res = mControlThread->run("EmulatedFakeCamera2::controlThread");
if (res != NO_ERROR) return res;
return EmulatedCamera2::connectCamera(device);
}
@@ -164,11 +168,12 @@ status_t EmulatedFakeCamera2::closeCamera() {
mConfigureThread->requestExit();
mReadoutThread->requestExit();
mControlThread->requestExit();
mJpegCompressor->cancel();
mConfigureThread->join();
mReadoutThread->join();
mControlThread->join();
ALOGV("%s exit", __FUNCTION__);
return NO_ERROR;
@@ -431,6 +436,14 @@ int EmulatedFakeCamera2::releaseStream(uint32_t stream_id) {
return NO_ERROR;
}
int EmulatedFakeCamera2::triggerAction(uint32_t trigger_id,
int32_t ext1,
int32_t ext2) {
Mutex::Autolock l(mMutex);
return mControlThread->triggerAction(trigger_id,
ext1, ext2);
}
/** Custom tag definitions */
// Emulator camera metadata sections
@@ -535,8 +548,8 @@ void EmulatedFakeCamera2::signalError() {
EmulatedFakeCamera2::ConfigureThread::ConfigureThread(EmulatedFakeCamera2 *parent):
Thread(false),
mParent(parent),
mNextBuffers(NULL),
mRequestCount(0) {
mRequestCount(0),
mNextBuffers(NULL) {
mRunning = false;
}
@@ -635,7 +648,7 @@ bool EmulatedFakeCamera2::ConfigureThread::threadLoop() {
}
// Get necessary parameters for sensor config
sort_camera_metadata(mRequest);
mParent->mControlThread->processRequest(mRequest);
camera_metadata_entry_t streams;
res = find_camera_metadata_entry(mRequest,
@@ -803,10 +816,9 @@ EmulatedFakeCamera2::ReadoutThread::ReadoutThread(EmulatedFakeCamera2 *parent):
mParent(parent),
mRunning(false),
mActive(false),
mRequestCount(0),
mRequest(NULL),
mBuffers(NULL),
mRequestCount(0)
{
mBuffers(NULL) {
mInFlightQueue = new InFlightQueue[kInFlightQueueSize];
mInFlightHead = 0;
mInFlightTail = 0;
@@ -1046,6 +1058,343 @@ bool EmulatedFakeCamera2::ReadoutThread::threadLoop() {
return true;
}
EmulatedFakeCamera2::ControlThread::ControlThread(EmulatedFakeCamera2 *parent):
Thread(false),
mParent(parent) {
mRunning = false;
}
EmulatedFakeCamera2::ControlThread::~ControlThread() {
}
status_t EmulatedFakeCamera2::ControlThread::readyToRun() {
Mutex::Autolock lock(mInputMutex);
ALOGV("Starting up ControlThread");
mRunning = true;
mStartAf = false;
mCancelAf = false;
mStartPrecapture = false;
mControlMode = ANDROID_CONTROL_AUTO;
mEffectMode = ANDROID_CONTROL_EFFECT_OFF;
mSceneMode = ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY;
mAfMode = ANDROID_CONTROL_AF_AUTO;
mAfModeChange = false;
mAeMode = ANDROID_CONTROL_AE_ON;
mAwbMode = ANDROID_CONTROL_AWB_AUTO;
mAfTriggerId = 0;
mPrecaptureTriggerId = 0;
mAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
mAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
mAwbState = ANDROID_CONTROL_AWB_STATE_INACTIVE;
mInputSignal.signal();
return NO_ERROR;
}
status_t EmulatedFakeCamera2::ControlThread::waitUntilRunning() {
Mutex::Autolock lock(mInputMutex);
if (!mRunning) {
ALOGV("Waiting for control thread to start");
mInputSignal.wait(mInputMutex);
}
return OK;
}
status_t EmulatedFakeCamera2::ControlThread::processRequest(camera_metadata_t *request) {
Mutex::Autolock lock(mInputMutex);
// TODO: Add handling for all android.control.* fields here
camera_metadata_entry_t mode;
status_t res;
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_MODE,
&mode);
mControlMode = mode.data.u8[0];
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_EFFECT_MODE,
&mode);
mEffectMode = mode.data.u8[0];
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_SCENE_MODE,
&mode);
mSceneMode = mode.data.u8[0];
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_AF_MODE,
&mode);
if (mAfMode != mode.data.u8[0]) {
ALOGV("AF new mode: %d, old mode %d", mode.data.u8[0], mAfMode);
mAfMode = mode.data.u8[0];
mAfModeChange = true;
mStartAf = false;
mCancelAf = false;
}
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_AE_MODE,
&mode);
mAeMode = mode.data.u8[0];
res = find_camera_metadata_entry(request,
ANDROID_CONTROL_AWB_MODE,
&mode);
mAwbMode = mode.data.u8[0];
// TODO: Override control fields
return OK;
}
status_t EmulatedFakeCamera2::ControlThread::triggerAction(uint32_t msgType,
int32_t ext1, int32_t ext2) {
Mutex::Autolock lock(mInputMutex);
switch (msgType) {
case CAMERA2_TRIGGER_AUTOFOCUS:
mAfTriggerId = ext1;
mStartAf = true;
mCancelAf = false;
break;
case CAMERA2_TRIGGER_CANCEL_AUTOFOCUS:
mAfTriggerId = ext1;
mStartAf = false;
mCancelAf = true;
break;
case CAMERA2_TRIGGER_PRECAPTURE_METERING:
mPrecaptureTriggerId = ext1;
mStartPrecapture = true;
break;
default:
ALOGE("%s: Unknown action triggered: %d (arguments %d %d)",
__FUNCTION__, msgType, ext1, ext2);
return BAD_VALUE;
}
return OK;
}
const nsecs_t EmulatedFakeCamera2::ControlThread::kControlCycleDelay = 100000000;
const nsecs_t EmulatedFakeCamera2::ControlThread::kMinAfDuration = 500000000;
const nsecs_t EmulatedFakeCamera2::ControlThread::kMaxAfDuration = 900000000;
const float EmulatedFakeCamera2::ControlThread::kAfSuccessRate = 0.9;
const float EmulatedFakeCamera2::ControlThread::kContinuousAfStartRate =
kControlCycleDelay / 5000000000.0; // Once every 5 seconds
bool EmulatedFakeCamera2::ControlThread::threadLoop() {
bool afModeChange = false;
bool afTriggered = false;
bool afCancelled = false;
uint8_t afState;
uint8_t afMode;
int32_t afTriggerId;
nsecs_t nextSleep = kControlCycleDelay;
{
Mutex::Autolock lock(mInputMutex);
if (mStartAf) {
afTriggered = true;
mStartAf = false;
} else if (mCancelAf) {
afCancelled = true;
mCancelAf = false;
}
afState = mAfState;
afMode = mAfMode;
afModeChange = mAfModeChange;
mAfModeChange = false;
afTriggerId = mAfTriggerId;
}
if (afCancelled || afModeChange) {
ALOGV("Resetting AF state due to cancel/mode change");
afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
updateAfState(afState, afTriggerId);
mAfScanDuration = 0;
mLockAfterPassiveScan = false;
}
uint8_t oldAfState = afState;
if (afTriggered) {
afState = processAfTrigger(afMode, afState);
}
afState = maybeStartAfScan(afMode, afState);
afState = updateAfScan(afMode, afState, &nextSleep);
updateAfState(afState, afTriggerId);
int ret;
timespec t;
t.tv_sec = 0;
t.tv_nsec = nextSleep;
do {
ret = nanosleep(&t, &t);
} while (ret != 0);
return true;
}
int EmulatedFakeCamera2::ControlThread::processAfTrigger(uint8_t afMode,
uint8_t afState) {
switch (afMode) {
case ANDROID_CONTROL_AF_OFF:
case ANDROID_CONTROL_AF_EDOF:
// Do nothing
break;
case ANDROID_CONTROL_AF_MACRO:
case ANDROID_CONTROL_AF_AUTO:
switch (afState) {
case ANDROID_CONTROL_AF_STATE_INACTIVE:
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
// Start new focusing cycle
mAfScanDuration = ((double)rand() / RAND_MAX) *
(kMaxAfDuration - kMinAfDuration) + kMinAfDuration;
afState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
ALOGV("%s: AF scan start, duration %lld ms",
__FUNCTION__, mAfScanDuration / 1000000);
break;
case ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN:
// Ignore new request, already scanning
break;
default:
ALOGE("Unexpected AF state in AUTO/MACRO AF mode: %d",
afState);
}
break;
case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
switch (afState) {
// Picture mode waits for passive scan to complete
case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
mLockAfterPassiveScan = true;
break;
case ANDROID_CONTROL_AF_STATE_INACTIVE:
afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
break;
case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
break;
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
// Must cancel to get out of these states
break;
default:
ALOGE("Unexpected AF state in CONTINUOUS_PICTURE AF mode: %d",
afState);
}
break;
case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
switch (afState) {
// Video mode does not wait for passive scan to complete
case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
case ANDROID_CONTROL_AF_STATE_INACTIVE:
afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
break;
case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
break;
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
// Must cancel to get out of these states
break;
default:
ALOGE("Unexpected AF state in CONTINUOUS_VIDEO AF mode: %d",
afState);
}
break;
default:
break;
}
return afState;
}
int EmulatedFakeCamera2::ControlThread::maybeStartAfScan(uint8_t afMode,
uint8_t afState) {
if ((afMode == ANDROID_CONTROL_AF_CONTINUOUS_VIDEO ||
afMode == ANDROID_CONTROL_AF_CONTINUOUS_PICTURE) &&
(afState == ANDROID_CONTROL_AF_STATE_INACTIVE ||
afState == ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)) {
bool startScan = ((double)rand() / RAND_MAX) < kContinuousAfStartRate;
if (startScan) {
// Start new passive focusing cycle
mAfScanDuration = ((double)rand() / RAND_MAX) *
(kMaxAfDuration - kMinAfDuration) + kMinAfDuration;
afState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
ALOGV("%s: AF passive scan start, duration %lld ms",
__FUNCTION__, mAfScanDuration / 1000000);
}
}
return afState;
}
int EmulatedFakeCamera2::ControlThread::updateAfScan(uint8_t afMode,
uint8_t afState, nsecs_t *maxSleep) {
if (! (afState == ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN ||
afState == ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN ) ) {
return afState;
}
if (mAfScanDuration == 0) {
ALOGV("%s: AF scan done", __FUNCTION__);
switch (afMode) {
case ANDROID_CONTROL_AF_MACRO:
case ANDROID_CONTROL_AF_AUTO: {
bool success = ((double)rand() / RAND_MAX) < kAfSuccessRate;
if (success) {
afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
} else {
afState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
}
break;
}
case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
if (mLockAfterPassiveScan) {
afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
mLockAfterPassiveScan = false;
} else {
afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
}
break;
case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
afState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
break;
default:
ALOGE("Unexpected AF mode in scan state");
}
} else {
if (mAfScanDuration <= *maxSleep) {
*maxSleep = mAfScanDuration;
mAfScanDuration = 0;
} else {
mAfScanDuration -= *maxSleep;
}
}
return afState;
}
void EmulatedFakeCamera2::ControlThread::updateAfState(uint8_t newState,
int32_t triggerId) {
Mutex::Autolock lock(mInputMutex);
if (mAfState != newState) {
ALOGV("%s: Autofocus state now %d, id %d", __FUNCTION__,
newState, triggerId);
mAfState = newState;
mParent->sendNotification(CAMERA2_MSG_AUTOFOCUS,
newState, triggerId, 0);
}
}
/** Private methods */
status_t EmulatedFakeCamera2::constructStaticInfo(
@@ -1062,9 +1411,12 @@ status_t EmulatedFakeCamera2::constructStaticInfo(
// android.lens
static const float minFocusDistance = 0;
// 5 cm min focus distance for back camera, infinity (fixed focus) for front
const float minFocusDistance = mFacingBack ? 1.0/0.05 : 0.0;
ADD_OR_SIZE(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE,
&minFocusDistance, 1);
// 5 m hyperfocal distance for back camera, infinity (fixed focus) for front
const float hyperFocalDistance = mFacingBack ? 1.0/5.0 : 0.0;
ADD_OR_SIZE(ANDROID_LENS_HYPERFOCAL_DISTANCE,
&minFocusDistance, 1);
@@ -1323,11 +1675,25 @@ status_t EmulatedFakeCamera2::constructStaticInfo(
ADD_OR_SIZE(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
availableAwbModes, sizeof(availableAwbModes));
static const uint8_t availableAfModes[] = {
static const uint8_t availableAfModesBack[] = {
ANDROID_CONTROL_AF_OFF,
ANDROID_CONTROL_AF_AUTO,
ANDROID_CONTROL_AF_MACRO,
ANDROID_CONTROL_AF_CONTINUOUS_VIDEO,
ANDROID_CONTROL_AF_CONTINUOUS_PICTURE
};
static const uint8_t availableAfModesFront[] = {
ANDROID_CONTROL_AF_OFF
};
ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
availableAfModes, sizeof(availableAfModes));
if (mFacingBack) {
ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
availableAfModesBack, sizeof(availableAfModesBack));
} else {
ADD_OR_SIZE(ANDROID_CONTROL_AF_AVAILABLE_MODES,
availableAfModesFront, sizeof(availableAfModesFront));
}
static const uint8_t availableVstabModes[] = {
ANDROID_CONTROL_VIDEO_STABILIZATION_OFF

View File

@@ -31,7 +31,6 @@
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/Thread.h>
namespace android {
@@ -113,9 +112,9 @@ protected:
// virtual int releaseReprocessStream(uint32_t stream_id);
// virtual int triggerAction(uint32_t trigger_id,
// int ext1,
// int ext2);
virtual int triggerAction(uint32_t trigger_id,
int32_t ext1,
int32_t ext2);
/** Custom tag definitions */
virtual const char* getVendorSectionName(uint32_t tag);
@@ -245,6 +244,80 @@ private:
};
// 3A management thread (auto-exposure, focus, white balance)
class ControlThread: public Thread {
public:
ControlThread(EmulatedFakeCamera2 *parent);
~ControlThread();
status_t readyToRun();
status_t waitUntilRunning();
// Interpret request's control parameters and override
// capture settings as needed
status_t processRequest(camera_metadata_t *request);
status_t triggerAction(uint32_t msgType,
int32_t ext1, int32_t ext2);
private:
ControlThread(const ControlThread &t);
ControlThread& operator=(const ControlThread &t);
// Constants controlling fake 3A behavior
static const nsecs_t kControlCycleDelay;
static const nsecs_t kMinAfDuration;
static const nsecs_t kMaxAfDuration;
static const float kAfSuccessRate;
static const float kContinuousAfStartRate;
EmulatedFakeCamera2 *mParent;
bool mRunning;
bool threadLoop();
Mutex mInputMutex; // Protects input methods
Condition mInputSignal;
// Trigger notifications
bool mStartAf;
bool mCancelAf;
bool mStartPrecapture;
// Latest state for 3A request fields
uint8_t mControlMode;
uint8_t mEffectMode;
uint8_t mSceneMode;
uint8_t mAfMode;
bool mAfModeChange;
uint8_t mAwbMode;
uint8_t mAeMode;
// Latest trigger IDs
int32_t mAfTriggerId;
int32_t mPrecaptureTriggerId;
// Current state for 3A algorithms
uint8_t mAfState;
uint8_t mAeState;
uint8_t mAwbState;
// Private to threadLoop and its utility methods
nsecs_t mAfScanDuration;
bool mLockAfterPassiveScan;
// Utility methods
int processAfTrigger(uint8_t afMode, uint8_t afState);
int maybeStartAfScan(uint8_t afMode, uint8_t afState);
int updateAfScan(uint8_t afMode, uint8_t afState, nsecs_t *maxSleep);
void updateAfState(uint8_t newState, int32_t triggerId);
};
/****************************************************************************
* Static configuration information
***************************************************************************/
@@ -271,9 +344,6 @@ protected:
bool mFacingBack;
private:
/** Mutex for calls through camera2 device interface */
Mutex mMutex;
/** Stream manipulation */
uint32_t mNextStreamId;
uint32_t mRawStreamCount;
@@ -289,6 +359,7 @@ private:
/** Pipeline control threads */
sp<ConfigureThread> mConfigureThread;
sp<ReadoutThread> mReadoutThread;
sp<ControlThread> mControlThread;
};
}; /* namespace android */