summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/CameraMetadata.cpp117
-rw-r--r--include/camera/CameraMetadata.h20
-rw-r--r--services/camera/libcameraservice/Camera3Device.cpp820
-rw-r--r--services/camera/libcameraservice/Camera3Device.h163
4 files changed, 1058 insertions, 62 deletions
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index fdd0610..6c3e233 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -23,19 +23,22 @@
namespace android {
CameraMetadata::CameraMetadata() :
- mBuffer(NULL) {
+ mBuffer(NULL), mLocked(false) {
}
-CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity)
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
+ mLocked(false)
{
mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
}
-CameraMetadata::CameraMetadata(const CameraMetadata &other) {
+CameraMetadata::CameraMetadata(const CameraMetadata &other) :
+ mLocked(false) {
mBuffer = clone_camera_metadata(other.mBuffer);
}
-CameraMetadata::CameraMetadata(camera_metadata_t *buffer) : mBuffer(NULL) {
+CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
+ mBuffer(NULL), mLocked(false) {
acquire(buffer);
}
@@ -44,6 +47,11 @@ CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
}
CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
+ return *this;
+ }
+
if (CC_LIKELY(buffer != mBuffer)) {
camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
clear();
@@ -53,16 +61,44 @@ CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
}
CameraMetadata::~CameraMetadata() {
+ mLocked = false;
clear();
}
+const camera_metadata_t* CameraMetadata::getAndLock() {
+ mLocked = true;
+ return mBuffer;
+}
+
+status_t CameraMetadata::unlock(const camera_metadata_t *buffer) {
+ if (!mLocked) {
+ ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (buffer != mBuffer) {
+ ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ mLocked = false;
+ return OK;
+}
+
camera_metadata_t* CameraMetadata::release() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return NULL;
+ }
camera_metadata_t *released = mBuffer;
mBuffer = NULL;
return released;
}
void CameraMetadata::clear() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
if (mBuffer) {
free_camera_metadata(mBuffer);
mBuffer = NULL;
@@ -70,15 +106,27 @@ void CameraMetadata::clear() {
}
void CameraMetadata::acquire(camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
clear();
mBuffer = buffer;
}
void CameraMetadata::acquire(CameraMetadata &other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
acquire(other.release());
}
status_t CameraMetadata::append(const CameraMetadata &other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
return append_camera_metadata(mBuffer, other.mBuffer);
}
@@ -92,6 +140,10 @@ bool CameraMetadata::isEmpty() const {
}
status_t CameraMetadata::sort() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
return sort_camera_metadata(mBuffer);
}
@@ -115,69 +167,101 @@ status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
status_t CameraMetadata::update(uint32_t tag,
const int32_t *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_INT32)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const uint8_t *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const float *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const int64_t *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_INT64)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const double *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const camera_metadata_rational_t *data, size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
return res;
}
- return update(tag, (const void*)data, data_count);
+ return updateImpl(tag, (const void*)data, data_count);
}
status_t CameraMetadata::update(uint32_t tag,
const String8 &string) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
return res;
}
- return update(tag, (const void*)string.string(), string.size());
+ return updateImpl(tag, (const void*)string.string(), string.size());
}
-status_t CameraMetadata::update(uint32_t tag, const void *data,
+status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
size_t data_count) {
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
int type = get_camera_metadata_tag_type(tag);
if (type == -1) {
ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
@@ -216,6 +300,11 @@ bool CameraMetadata::exists(uint32_t tag) const {
camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
status_t res;
camera_metadata_entry entry;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ entry.count = 0;
+ return entry;
+ }
res = find_camera_metadata_entry(mBuffer, tag, &entry);
if (CC_UNLIKELY( res != OK )) {
entry.count = 0;
@@ -238,6 +327,10 @@ camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
status_t CameraMetadata::erase(uint32_t tag) {
camera_metadata_entry_t entry;
status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
res = find_camera_metadata_entry(mBuffer, tag, &entry);
if (res == NAME_NOT_FOUND) {
return OK;
diff --git a/include/camera/CameraMetadata.h b/include/camera/CameraMetadata.h
index 4289126..8eeb2e7 100644
--- a/include/camera/CameraMetadata.h
+++ b/include/camera/CameraMetadata.h
@@ -49,6 +49,23 @@ class CameraMetadata {
CameraMetadata &operator=(const camera_metadata_t *buffer);
/**
+ * Get reference to the underlying metadata buffer. Ownership remains with
+ * the CameraMetadata object, but non-const CameraMetadata methods will not
+ * work until unlock() is called. Note that the lock has nothing to do with
+ * thread-safety, it simply prevents the camera_metadata_t pointer returned
+ * here from being accidentally invalidated by CameraMetadata operations.
+ */
+ const camera_metadata_t* getAndLock();
+
+ /**
+ * Unlock the CameraMetadata for use again. After this unlock, the pointer
+ * given from getAndLock() may no longer be used. The pointer passed out
+ * from getAndLock must be provided to guarantee that the right object is
+ * being unlocked.
+ */
+ status_t unlock(const camera_metadata_t *buffer);
+
+ /**
* Release a raw metadata buffer to the caller. After this call,
* CameraMetadata no longer references the buffer, and the caller takes
* responsibility for freeing the raw metadata buffer (using
@@ -154,6 +171,7 @@ class CameraMetadata {
private:
camera_metadata_t *mBuffer;
+ bool mLocked;
/**
* Check if tag has a given type
@@ -163,7 +181,7 @@ class CameraMetadata {
/**
* Base update entry method
*/
- status_t update(uint32_t tag, const void *data, size_t data_count);
+ status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
/**
* Resize metadata buffer if needed by reallocating it and copying it over.
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 04a6e6a..e6fb33e 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -29,13 +29,16 @@
#include <utils/Trace.h>
#include <utils/Timers.h>
#include "Camera3Device.h"
+#include "camera3/Camera3OutputStream.h"
-namespace android {
+using namespace android::camera3;
+namespace android {
Camera3Device::Camera3Device(int id):
mId(id),
- mHal3Device(NULL)
+ mHal3Device(NULL),
+ mStatus(STATUS_UNINITIALIZED)
{
ATRACE_CALL();
camera3_callback_ops::notify = &sNotify;
@@ -54,11 +57,17 @@ int Camera3Device::getId() const {
return mId;
}
+/**
+ * CameraDeviceBase interface
+ */
+
status_t Camera3Device::initialize(camera_module_t *module)
{
ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+
ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
- if (mHal3Device != NULL) {
+ if (mStatus != STATUS_UNINITIALIZED) {
ALOGE("%s: Already initialized!", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -76,6 +85,7 @@ status_t Camera3Device::initialize(camera_module_t *module)
if (res != OK) {
ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
mId, strerror(-res), res);
+ mStatus = STATUS_ERROR;
return res;
}
@@ -87,6 +97,7 @@ status_t Camera3Device::initialize(camera_module_t *module)
__FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_3_0,
device->common.version);
device->common.close(&device->common);
+ mStatus = STATUS_ERROR;
return BAD_VALUE;
}
@@ -99,6 +110,7 @@ status_t Camera3Device::initialize(camera_module_t *module)
" and device version (%x).", __FUNCTION__,
device->common.version, info.device_version);
device->common.close(&device->common);
+ mStatus = STATUS_ERROR;
return BAD_VALUE;
}
@@ -109,6 +121,7 @@ status_t Camera3Device::initialize(camera_module_t *module)
ALOGE("%s: Camera %d: Unable to initialize HAL device: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
device->common.close(&device->common);
+ mStatus = STATUS_ERROR;
return BAD_VALUE;
}
@@ -124,18 +137,21 @@ status_t Camera3Device::initialize(camera_module_t *module)
ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
device->common.close(&device->common);
+ mStatus = STATUS_ERROR;
return res;
}
}
/** Start up request queue thread */
- requestThread = new RequestThread(this);
- res = requestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
+ mRequestThread = new RequestThread(this, device);
+ res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
if (res != OK) {
ALOGE("%s: Camera %d: Unable to start request queue thread: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
device->common.close(&device->common);
+ mRequestThread.clear();
+ mStatus = STATUS_ERROR;
return res;
}
@@ -143,54 +159,205 @@ status_t Camera3Device::initialize(camera_module_t *module)
mDeviceInfo = info.static_camera_characteristics;
mHal3Device = device;
+ mStatus = STATUS_IDLE;
+ mNextStreamId = 0;
return OK;
}
status_t Camera3Device::disconnect() {
ATRACE_CALL();
+ Mutex::Autolock l(mLock);
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ ALOGV("%s: E", __FUNCTION__);
+
+ status_t res;
+ if (mStatus == STATUS_UNINITIALIZED) return OK;
+
+ if (mStatus == STATUS_ACTIVE ||
+ (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
+ res = mRequestThread->clearRepeatingRequests();
+ if (res != OK) {
+ ALOGE("%s: Can't stop streaming", __FUNCTION__);
+ return res;
+ }
+ res = waitUntilDrainedLocked();
+ if (res != OK) {
+ ALOGE("%s: Timeout waiting for HAL to drain", __FUNCTION__);
+ return res;
+ }
+ }
+ assert(mStatus == STATUS_IDLE || mStatus == STATUS_ERROR);
+
+ if (mRequestThread != NULL) {
+ mRequestThread->requestExit();
+ }
+
+ mOutputStreams.clear();
+ mInputStream.clear();
+
+ if (mRequestThread != NULL) {
+ mRequestThread->join();
+ mRequestThread.clear();
+ }
+
+ if (mHal3Device != NULL) {
+ mHal3Device->common.close(&mHal3Device->common);
+ mHal3Device = NULL;
+ }
+
+ mStatus = STATUS_UNINITIALIZED;
+
+ ALOGV("%s: X", __FUNCTION__);
+ return OK;
}
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
(void)args;
+ String8 lines;
+
+ const char *status =
+ mStatus == STATUS_ERROR ? "ERROR" :
+ mStatus == STATUS_UNINITIALIZED ? "UNINITIALIZED" :
+ mStatus == STATUS_IDLE ? "IDLE" :
+ mStatus == STATUS_ACTIVE ? "ACTIVE" :
+ "Unknown";
+ lines.appendFormat(" Device status: %s\n", status);
+ lines.appendFormat(" Stream configuration:\n");
+
+ if (mInputStream != NULL) {
+ write(fd, lines.string(), lines.size());
+ mInputStream->dump(fd, args);
+ } else {
+ lines.appendFormat(" No input stream.\n");
+ write(fd, lines.string(), lines.size());
+ }
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ mOutputStreams[i]->dump(fd,args);
+ }
- mHal3Device->ops->dump(mHal3Device, fd);
+ if (mHal3Device != NULL) {
+ lines = String8(" HAL device dump:\n");
+ write(fd, lines.string(), lines.size());
+ mHal3Device->ops->dump(mHal3Device, fd);
+ }
return OK;
}
const CameraMetadata& Camera3Device::info() const {
ALOGVV("%s: E", __FUNCTION__);
-
+ if (CC_UNLIKELY(mStatus == STATUS_UNINITIALIZED ||
+ mStatus == STATUS_ERROR)) {
+ ALOGE("%s: Access to static info %s!", __FUNCTION__,
+ mStatus == STATUS_ERROR ?
+ "when in error state" : "before init");
+ }
return mDeviceInfo;
}
status_t Camera3Device::capture(CameraMetadata &request) {
ATRACE_CALL();
- (void)request;
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ sp<CaptureRequest> newRequest = setUpRequestLocked(request);
+ if (newRequest == NULL) {
+ ALOGE("%s: Can't create capture request", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ return mRequestThread->queueRequest(newRequest);
}
status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
ATRACE_CALL();
- (void)request;
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request);
+ if (newRepeatingRequest == NULL) {
+ ALOGE("%s: Can't create repeating request", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ RequestList newRepeatingRequests;
+ newRepeatingRequests.push_back(newRepeatingRequest);
+
+ return mRequestThread->setRepeatingRequests(newRepeatingRequests);
+}
+
+
+sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
+ const CameraMetadata &request) {
+ status_t res;
+
+ if (mStatus == STATUS_IDLE) {
+ res = configureStreamsLocked();
+ if (res != OK) {
+ ALOGE("%s: Can't set up streams: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return NULL;
+ }
+ }
+
+ sp<CaptureRequest> newRequest = createCaptureRequest(request);
+ return newRequest;
}
status_t Camera3Device::clearStreamingRequest() {
ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ return mRequestThread->clearRepeatingRequests();
}
status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
@@ -204,11 +371,70 @@ status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time
status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
uint32_t width, uint32_t height, int format, size_t size, int *id) {
ATRACE_CALL();
- (void)consumer; (void)width; (void)height; (void)format;
- (void)size; (void)id;
+ Mutex::Autolock l(mLock);
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ status_t res;
+ bool wasActive = false;
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ // OK
+ break;
+ case STATUS_ACTIVE:
+ ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
+ mRequestThread->setPaused(true);
+ res = waitUntilDrainedLocked();
+ if (res != OK) {
+ ALOGE("%s: Can't pause captures to reconfigure streams!",
+ __FUNCTION__);
+ mStatus = STATUS_ERROR;
+ return res;
+ }
+ wasActive = true;
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
+ assert(mStatus == STATUS_IDLE);
+
+ sp<Camera3OutputStream> newStream;
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ newStream = new Camera3OutputStream(mNextStreamId, consumer,
+ width, height, size, format);
+ } else {
+ newStream = new Camera3OutputStream(mNextStreamId, consumer,
+ width, height, format);
+ }
+
+ res = mOutputStreams.add(mNextStreamId, newStream);
+ if (res < 0) {
+ ALOGE("%s: Can't add new stream to set: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ *id = mNextStreamId++;
+
+ // Continue captures if active at start
+ if (wasActive) {
+ ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
+ res = configureStreamsLocked();
+ if (res != OK) {
+ ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)",
+ __FUNCTION__, mNextStreamId, strerror(-res), res);
+ return res;
+ }
+ mRequestThread->setPaused(false);
+ }
+
+ return OK;
}
status_t Camera3Device::createReprocessStreamFromStream(int outputId, int *id) {
@@ -223,27 +449,104 @@ status_t Camera3Device::createReprocessStreamFromStream(int outputId, int *id) {
status_t Camera3Device::getStreamInfo(int id,
uint32_t *width, uint32_t *height, uint32_t *format) {
ATRACE_CALL();
- (void)id; (void)width; (void)height; (void)format;
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized!", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ ssize_t idx = mOutputStreams.indexOfKey(id);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d is unknown", __FUNCTION__, id);
+ return idx;
+ }
+
+ if (width) *width = mOutputStreams[idx]->getWidth();
+ if (height) *height = mOutputStreams[idx]->getHeight();
+ if (format) *format = mOutputStreams[idx]->getFormat();
+
+ return OK;
}
status_t Camera3Device::setStreamTransform(int id,
int transform) {
ATRACE_CALL();
- (void)id; (void)transform;
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device not initialized", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ ssize_t idx = mOutputStreams.indexOfKey(id);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d does not exist",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+
+ return mOutputStreams.editValueAt(idx)->setTransform(transform);
}
status_t Camera3Device::deleteStream(int id) {
ATRACE_CALL();
- (void)id;
+ Mutex::Autolock l(mLock);
+ status_t res;
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ // CameraDevice semantics require device to already be idle before
+ // deleteStream is called, unlike for createStream.
+ if (mStatus != STATUS_IDLE) {
+ ALOGE("%s: Device not idle", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Stream> deletedStream;
+ if (mInputStream != NULL && id == mInputStream->getId()) {
+ deletedStream = mInputStream;
+ mInputStream.clear();
+ } else {
+ ssize_t idx = mOutputStreams.indexOfKey(id);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d does not exist",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ deletedStream = mOutputStreams.editValueAt(idx);
+ mOutputStreams.removeItem(id);
+ }
+
+ // Free up the stream endpoint so that it can be used by some other stream
+ res = deletedStream->disconnect();
+ if (res != OK) {
+ ALOGE("%s: Can't disconnect deleted stream", __FUNCTION__);
+ // fall through since we want to still list the stream as deleted.
+ }
+ mDeletedStreams.add(deletedStream);
+
+ return res;
}
status_t Camera3Device::deleteReprocessStream(int id) {
@@ -259,6 +562,23 @@ status_t Camera3Device::createDefaultRequest(int templateId,
CameraMetadata *request) {
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock l(mLock);
+
+ switch (mStatus) {
+ case STATUS_ERROR:
+ ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_UNINITIALIZED:
+ ALOGE("%s: Device is not initialized!", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATUS_IDLE:
+ case STATUS_ACTIVE:
+ // OK
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
const camera_metadata_t *rawRequest;
rawRequest = mHal3Device->ops->construct_default_request_settings(
@@ -271,9 +591,63 @@ status_t Camera3Device::createDefaultRequest(int templateId,
status_t Camera3Device::waitUntilDrained() {
ATRACE_CALL();
+ Mutex::Autolock l(mLock);
- ALOGE("%s: Unimplemented", __FUNCTION__);
- return INVALID_OPERATION;
+ return waitUntilDrainedLocked();
+}
+
+status_t Camera3Device::waitUntilDrainedLocked() {
+ ATRACE_CALL();
+ status_t res;
+
+ switch (mStatus) {
+ case STATUS_UNINITIALIZED:
+ case STATUS_IDLE:
+ ALOGV("%s: Already idle", __FUNCTION__);
+ return OK;
+ case STATUS_ERROR:
+ case STATUS_ACTIVE:
+ // Need to shut down
+ break;
+ default:
+ ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ return INVALID_OPERATION;
+ }
+
+ if (mRequestThread != NULL) {
+ res = mRequestThread->waitUntilPaused(kShutdownTimeout);
+ if (res != OK) {
+ ALOGE("%s: Can't stop request thread in %f seconds!",
+ __FUNCTION__, kShutdownTimeout/1e9);
+ mStatus = STATUS_ERROR;
+ return res;
+ }
+ }
+ if (mInputStream != NULL) {
+ res = mInputStream->waitUntilIdle(kShutdownTimeout);
+ if (res != OK) {
+ ALOGE("%s: Can't idle input stream %d in %f seconds!",
+ __FUNCTION__, mInputStream->getId(), kShutdownTimeout/1e9);
+ mStatus = STATUS_ERROR;
+ return res;
+ }
+ }
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ res = mOutputStreams.editValueAt(i)->waitUntilIdle(kShutdownTimeout);
+ if (res != OK) {
+ ALOGE("%s: Can't idle output stream %d in %f seconds!",
+ __FUNCTION__, mOutputStreams.keyAt(i),
+ kShutdownTimeout/1e9);
+ mStatus = STATUS_ERROR;
+ return res;
+ }
+ }
+
+ if (mStatus != STATUS_ERROR) {
+ mStatus = STATUS_IDLE;
+ }
+
+ return OK;
}
status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
@@ -335,17 +709,149 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId,
return INVALID_OPERATION;
}
-Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent) :
- Thread(false),
- mParent(parent) {
+/**
+ * Camera3Device private methods
+ */
+
+sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(
+ const CameraMetadata &request) {
+ ATRACE_CALL();
+ status_t res;
+
+ sp<CaptureRequest> newRequest = new CaptureRequest;
+ newRequest->mSettings = request;
+
+ camera_metadata_entry_t inputStreams =
+ newRequest->mSettings.find(ANDROID_REQUEST_INPUT_STREAMS);
+ if (inputStreams.count > 0) {
+ if (mInputStream == NULL ||
+ mInputStream->getId() != inputStreams.data.u8[0]) {
+ ALOGE("%s: Request references unknown input stream %d",
+ __FUNCTION__, inputStreams.data.u8[0]);
+ return NULL;
+ }
+ // Lazy completion of stream configuration (allocation/registration)
+ // on first use
+ if (mInputStream->isConfiguring()) {
+ res = mInputStream->finishConfiguration(mHal3Device);
+ if (res != OK) {
+ ALOGE("%s: Unable to finish configuring input stream %d:"
+ " %s (%d)",
+ __FUNCTION__, mInputStream->getId(),
+ strerror(-res), res);
+ return NULL;
+ }
+ }
+
+ newRequest->mInputStream = mInputStream;
+ newRequest->mSettings.erase(ANDROID_REQUEST_INPUT_STREAMS);
+ }
+
+ camera_metadata_entry_t streams =
+ newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS);
+ if (streams.count == 0) {
+ ALOGE("%s: Zero output streams specified!", __FUNCTION__);
+ return NULL;
+ }
+
+ for (size_t i = 0; i < streams.count; i++) {
+ int idx = mOutputStreams.indexOfKey(streams.data.u8[i]);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Request references unknown stream %d",
+ __FUNCTION__, streams.data.u8[i]);
+ return NULL;
+ }
+ sp<Camera3OutputStream> stream = mOutputStreams.editValueAt(idx);
+
+ // Lazy completion of stream configuration (allocation/registration)
+ // on first use
+ if (stream->isConfiguring()) {
+ res = stream->finishConfiguration(mHal3Device);
+ if (res != OK) {
+ ALOGE("%s: Unable to finish configuring stream %d: %s (%d)",
+ __FUNCTION__, stream->getId(), strerror(-res), res);
+ return NULL;
+ }
+ }
+
+ newRequest->mOutputStreams.push(stream);
+ }
+ newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS);
+
+ return newRequest;
}
-bool Camera3Device::RequestThread::threadLoop() {
- ALOGE("%s: Unimplemented", __FUNCTION__);
+status_t Camera3Device::configureStreamsLocked() {
+ ATRACE_CALL();
+ status_t res;
- return false;
+ if (mStatus != STATUS_IDLE) {
+ ALOGE("%s: Not idle", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // Start configuring the streams
+
+ camera3_stream_configuration config;
+
+ config.num_streams = (mInputStream != NULL) + mOutputStreams.size();
+
+ Vector<camera3_stream_t*> streams;
+ streams.setCapacity(config.num_streams);
+
+ if (mInputStream != NULL) {
+ camera3_stream_t *inputStream;
+ inputStream = mInputStream->startConfiguration();
+ if (inputStream == NULL) {
+ ALOGE("%s: Can't start input stream configuration",
+ __FUNCTION__);
+ // TODO: Make sure the error flow here is correct
+ return INVALID_OPERATION;
+ }
+ streams.add(inputStream);
+ }
+
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ camera3_stream_t *outputStream;
+ outputStream = mOutputStreams.editValueAt(i)->startConfiguration();
+ if (outputStream == NULL) {
+ ALOGE("%s: Can't start output stream configuration",
+ __FUNCTION__);
+ // TODO: Make sure the error flow here is correct
+ return INVALID_OPERATION;
+ }
+ streams.add(outputStream);
+ }
+
+ config.streams = streams.editArray();
+
+ // Do the HAL configuration; will potentially touch stream
+ // max_buffers, usage, priv fields.
+
+ res = mHal3Device->ops->configure_streams(mHal3Device, &config);
+
+ if (res != OK) {
+ ALOGE("%s: Unable to configure streams with HAL: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // Request thread needs to know to avoid using repeat-last-settings protocol
+ // across configure_streams() calls
+ mRequestThread->configurationComplete();
+
+ // Finish configuring the streams lazily on first reference
+
+ mStatus = STATUS_ACTIVE;
+
+ return OK;
}
+
+/**
+ * Camera HAL device callback methods
+ */
+
void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
(void)result;
@@ -359,6 +865,244 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
}
/**
+ * RequestThread inner class methods
+ */
+
+Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
+ camera3_device_t *hal3Device) :
+ Thread(false),
+ mParent(parent),
+ mHal3Device(hal3Device),
+ mReconfigured(false),
+ mDoPause(false),
+ mPaused(true),
+ mFrameNumber(0) {
+}
+
+void Camera3Device::RequestThread::configurationComplete() {
+ Mutex::Autolock l(mRequestLock);
+ mReconfigured = true;
+}
+
+status_t Camera3Device::RequestThread::queueRequest(
+ sp<CaptureRequest> request) {
+ Mutex::Autolock l(mRequestLock);
+ mRequestQueue.push_back(request);
+
+ return OK;
+}
+
+status_t Camera3Device::RequestThread::setRepeatingRequests(
+ const RequestList &requests) {
+ Mutex::Autolock l(mRequestLock);
+ mRepeatingRequests.clear();
+ mRepeatingRequests.insert(mRepeatingRequests.begin(),
+ requests.begin(), requests.end());
+ return OK;
+}
+
+status_t Camera3Device::RequestThread::clearRepeatingRequests() {
+ Mutex::Autolock l(mRequestLock);
+ mRepeatingRequests.clear();
+ return OK;
+}
+
+void Camera3Device::RequestThread::setPaused(bool paused) {
+ Mutex::Autolock l(mPauseLock);
+ mDoPause = paused;
+ mDoPauseSignal.signal();
+}
+
+status_t Camera3Device::RequestThread::waitUntilPaused(nsecs_t timeout) {
+ status_t res;
+ Mutex::Autolock l(mPauseLock);
+ while (!mPaused) {
+ res = mPausedSignal.waitRelative(mPauseLock, timeout);
+ if (res == TIMED_OUT) {
+ return res;
+ }
+ }
+ return OK;
+}
+
+bool Camera3Device::RequestThread::threadLoop() {
+
+ status_t res;
+
+ // Handle paused state.
+ if (waitIfPaused()) {
+ return true;
+ }
+
+ // Get work to do
+
+ sp<CaptureRequest> nextRequest = waitForNextRequest();
+ if (nextRequest == NULL) {
+ return true;
+ }
+
+ // Create request to HAL
+
+ camera3_capture_request_t request = camera3_capture_request_t();
+
+ if (mPrevRequest != nextRequest) {
+ request.settings = nextRequest->mSettings.getAndLock();
+ mPrevRequest = nextRequest;
+ } // else leave request.settings NULL to indicate 'reuse latest given'
+
+ camera3_stream_buffer_t inputBuffer;
+ Vector<camera3_stream_buffer_t> outputBuffers;
+
+ // Fill in buffers
+
+ if (nextRequest->mInputStream != NULL) {
+ request.input_buffer = &inputBuffer;
+ res = nextRequest->mInputStream->getBuffer(&inputBuffer);
+ if (res != OK) {
+ ALOGE("RequestThread: Can't get input buffer, skipping request:"
+ " %s (%d)", strerror(-res), res);
+ cleanUpFailedRequest(request, nextRequest, outputBuffers);
+ return true;
+ }
+ } else {
+ request.input_buffer = NULL;
+ }
+
+ outputBuffers.insertAt(camera3_stream_buffer_t(), 0,
+ nextRequest->mOutputStreams.size());
+ request.output_buffers = outputBuffers.array();
+ for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) {
+ res = nextRequest->mOutputStreams.editItemAt(i)->
+ getBuffer(&outputBuffers.editItemAt(i));
+ if (res != OK) {
+ ALOGE("RequestThread: Can't get output buffer, skipping request:"
+ "%s (%d)", strerror(-res), res);
+ cleanUpFailedRequest(request, nextRequest, outputBuffers);
+ return true;
+ }
+ request.num_output_buffers++;
+ }
+
+ request.frame_number = mFrameNumber++;
+
+ // Submit request and block until ready for next one
+
+ res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
+ if (res != OK) {
+ ALOGE("RequestThread: Unable to submit capture request %d to HAL"
+ " device: %s (%d)", request.frame_number, strerror(-res), res);
+ cleanUpFailedRequest(request, nextRequest, outputBuffers);
+ return false;
+ }
+
+ if (request.settings != NULL) {
+ nextRequest->mSettings.unlock(request.settings);
+ }
+ return true;
+}
+
+void Camera3Device::RequestThread::cleanUpFailedRequest(
+ camera3_capture_request_t &request,
+ sp<CaptureRequest> &nextRequest,
+ Vector<camera3_stream_buffer_t> &outputBuffers) {
+
+ if (request.settings != NULL) {
+ nextRequest->mSettings.unlock(request.settings);
+ }
+ if (request.input_buffer != NULL) {
+ request.input_buffer->status = CAMERA3_BUFFER_STATUS_ERROR;
+ nextRequest->mInputStream->returnBuffer(*(request.input_buffer), 0);
+ }
+ for (size_t i = 0; i < request.num_output_buffers; i++) {
+ outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
+ nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
+ outputBuffers[i], 0);
+ }
+ // TODO: Report error upstream
+}
+
+sp<Camera3Device::CaptureRequest>
+ Camera3Device::RequestThread::waitForNextRequest() {
+ status_t res;
+ sp<CaptureRequest> nextRequest;
+
+ // Optimized a bit for the simple steady-state case (single repeating
+ // request), to avoid putting that request in the queue temporarily.
+ Mutex::Autolock l(mRequestLock);
+
+ while (mRequestQueue.empty()) {
+ if (!mRepeatingRequests.empty()) {
+ // Always atomically enqueue all requests in a repeating request
+ // list. Guarantees a complete in-sequence set of captures to
+ // application.
+ const RequestList &requests = mRepeatingRequests;
+ RequestList::const_iterator firstRequest =
+ requests.begin();
+ nextRequest = *firstRequest;
+ mRequestQueue.insert(mRequestQueue.end(),
+ ++firstRequest,
+ requests.end());
+ // No need to wait any longer
+ break;
+ }
+
+ res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);
+
+ if (res == TIMED_OUT) {
+ // Signal that we're paused by starvation
+ Mutex::Autolock pl(mPauseLock);
+ if (mPaused == false) {
+ mPaused = true;
+ mPausedSignal.signal();
+ }
+ // Stop waiting for now and let thread management happen
+ return NULL;
+ }
+ }
+
+ if (nextRequest == NULL) {
+ // Don't have a repeating request already in hand, so queue
+ // must have an entry now.
+ RequestList::iterator firstRequest =
+ mRequestQueue.begin();
+ nextRequest = *firstRequest;
+ mRequestQueue.erase(firstRequest);
+ }
+
+ // Not paused
+ Mutex::Autolock pl(mPauseLock);
+ mPaused = false;
+
+ // Check if we've reconfigured since last time, and reset the preview
+ // request if so. Can't use 'NULL request == repeat' across configure calls.
+ if (mReconfigured) {
+ mPrevRequest.clear();
+ mReconfigured = false;
+ }
+
+ return nextRequest;
+}
+
+bool Camera3Device::RequestThread::waitIfPaused() {
+ status_t res;
+ Mutex::Autolock l(mPauseLock);
+ while (mDoPause) {
+ // Signal that we're paused by request
+ if (mPaused == false) {
+ mPaused = true;
+ mPausedSignal.signal();
+ }
+ res = mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout);
+ if (res == TIMED_OUT) {
+ return true;
+ }
+ }
+ // We don't set mPaused to false here, because waitForNextRequest needs
+ // to further manage the paused state in case of starvation.
+ return false;
+}
+
+/**
* Static callback forwarding methods from HAL to instance
*/
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index df7352c..86f4c6a 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA3DEVICE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA3DEVICE_H
+#ifndef ANDROID_SERVERS_CAMERA3DEVICE_H
+#define ANDROID_SERVERS_CAMERA3DEVICE_H
#include <utils/Condition.h>
#include <utils/Errors.h>
@@ -24,6 +24,8 @@
#include <utils/Thread.h>
#include "CameraDeviceBase.h"
+#include "camera3/Camera3Stream.h"
+#include "camera3/Camera3OutputStream.h"
#include "hardware/camera3.h"
@@ -55,63 +57,202 @@ class Camera3Device :
virtual ~Camera3Device();
/**
- * CameraDevice interface
+ * CameraDeviceBase interface
*/
+
virtual int getId() const;
+
+ // Transitions to idle state on success.
virtual status_t initialize(camera_module_t *module);
virtual status_t disconnect();
virtual status_t dump(int fd, const Vector<String16> &args);
virtual const CameraMetadata& info() const;
+
+ // Capture and setStreamingRequest will configure streams if currently in
+ // idle state
virtual status_t capture(CameraMetadata &request);
virtual status_t setStreamingRequest(const CameraMetadata &request);
virtual status_t clearStreamingRequest();
+
virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
+
+ // Actual stream creation/deletion is delayed until first request is submitted
+ // If adding streams while actively capturing, will pause device before adding
+ // stream, reconfiguring device, and unpausing.
virtual status_t createStream(sp<ANativeWindow> consumer,
uint32_t width, uint32_t height, int format, size_t size,
int *id);
virtual status_t createReprocessStreamFromStream(int outputId, int *id);
+
virtual status_t getStreamInfo(int id,
uint32_t *width, uint32_t *height, uint32_t *format);
virtual status_t setStreamTransform(int id, int transform);
+
virtual status_t deleteStream(int id);
virtual status_t deleteReprocessStream(int id);
+
virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
+
+ // Transitions to the idle state on success
virtual status_t waitUntilDrained();
+
virtual status_t setNotifyCallback(NotificationListener *listener);
virtual status_t waitForNextFrame(nsecs_t timeout);
virtual status_t getNextFrame(CameraMetadata *frame);
+
virtual status_t triggerAutofocus(uint32_t id);
virtual status_t triggerCancelAutofocus(uint32_t id);
virtual status_t triggerPrecaptureMetering(uint32_t id);
+
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
private:
- const int mId;
- camera3_device_t *mHal3Device;
+ static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec
+
+
+ Mutex mLock;
+
+ /**** Scope for mLock ****/
+
+ const int mId;
+ camera3_device_t *mHal3Device;
+
+ CameraMetadata mDeviceInfo;
+ vendor_tag_query_ops_t mVendorTagOps;
+
+ enum {
+ STATUS_ERROR,
+ STATUS_UNINITIALIZED,
+ STATUS_IDLE,
+ STATUS_ACTIVE
+ } mStatus;
+
+ // Mapping of stream IDs to stream instances
+ typedef KeyedVector<int, sp<camera3::Camera3OutputStream> > StreamSet;
+
+ StreamSet mOutputStreams;
+ sp<camera3::Camera3Stream> mInputStream;
+ int mNextStreamId;
+
+ // Need to hold on to stream references until configure completes.
+ Vector<sp<camera3::Camera3Stream> > mDeletedStreams;
+
+ /**** End scope for mLock ****/
+
+ class CaptureRequest : public LightRefBase<CaptureRequest> {
+ public:
+ CameraMetadata mSettings;
+ sp<camera3::Camera3Stream> mInputStream;
+ Vector<sp<camera3::Camera3Stream> > mOutputStreams;
+ };
+ typedef List<sp<CaptureRequest> > RequestList;
+
+ /**
+ * Lock-held version of waitUntilDrained. Will transition to IDLE on
+ * success.
+ */
+ status_t waitUntilDrainedLocked();
+
+ /**
+ * Do common work for setting up a streaming or single capture request.
+ * On success, will transition to ACTIVE if in IDLE.
+ */
+ sp<CaptureRequest> setUpRequestLocked(const CameraMetadata &request);
+
+ /**
+ * Build a CaptureRequest request from the CameraDeviceBase request
+ * settings.
+ */
+ sp<CaptureRequest> createCaptureRequest(const CameraMetadata &request);
- CameraMetadata mDeviceInfo;
- vendor_tag_query_ops_t mVendorTagOps;
+ /**
+ * Take the currently-defined set of streams and configure the HAL to use
+ * them. This is a long-running operation (may be several hundered ms).
+ */
+ status_t configureStreamsLocked();
/**
* Thread for managing capture request submission to HAL device.
*/
- class RequestThread: public Thread {
+ class RequestThread : public Thread {
public:
- RequestThread(wp<Camera3Device> parent);
+ RequestThread(wp<Camera3Device> parent,
+ camera3_device_t *hal3Device);
+
+ /**
+ * Call after stream (re)-configuration is completed.
+ */
+ void configurationComplete();
+
+ /**
+ * Set or clear the list of repeating requests. Does not block
+ * on either. Use waitUntilPaused to wait until request queue
+ * has emptied out.
+ */
+ status_t setRepeatingRequests(const RequestList& requests);
+ status_t clearRepeatingRequests();
+
+ status_t queueRequest(sp<CaptureRequest> request);
+
+ /**
+ * Pause/unpause the capture thread. Doesn't block, so use
+ * waitUntilPaused to wait until the thread is paused.
+ */
+ void setPaused(bool paused);
+
+ /**
+ * Wait until thread is paused, either due to setPaused(true)
+ * or due to lack of input requests. Returns TIMED_OUT in case
+ * the thread does not pause within the timeout.
+ */
+ status_t waitUntilPaused(nsecs_t timeout);
protected:
virtual bool threadLoop();
private:
+ static const nsecs_t kRequestTimeout = 50e6; // 50 ms
+
+ // Waits for a request, or returns NULL if times out.
+ sp<CaptureRequest> waitForNextRequest();
+
+ // Return buffers, etc, for a request that couldn't be fully
+ // constructed. The buffers will be returned in the ERROR state
+ // to mark them as not having valid data.
+ // All arguments will be modified.
+ void cleanUpFailedRequest(camera3_capture_request_t &request,
+ sp<CaptureRequest> &nextRequest,
+ Vector<camera3_stream_buffer_t> &outputBuffers);
+
+ // Pause handling
+ bool waitIfPaused();
+
+ wp<Camera3Device> mParent;
+ camera3_device_t *mHal3Device;
+
+ Mutex mRequestLock;
+ Condition mRequestSignal;
+ RequestList mRequestQueue;
+ RequestList mRepeatingRequests;
+
+ bool mReconfigured;
+
+ // Used by waitIfPaused, waitForNextRequest, and waitUntilPaused
+ Mutex mPauseLock;
+ bool mDoPause;
+ Condition mDoPauseSignal;
+ bool mPaused;
+ Condition mPausedSignal;
- wp<Camera3Device> mParent;
+ sp<CaptureRequest> mPrevRequest;
+ int32_t mFrameNumber;
};
- sp<RequestThread> requestThread;
+ sp<RequestThread> mRequestThread;
/**
* Callback functions from HAL device