summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice/Camera2Device.cpp
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2012-08-29 17:37:16 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-09-06 10:38:22 -0700
commit69230df9905534cda15becd44c0109874c4be5f0 (patch)
tree579a2bd3dbea0c49b02a185324ec4724e2ba15ca /services/camera/libcameraservice/Camera2Device.cpp
parent56cd317a35a18ba5c40b344f0a5bf436546246a1 (diff)
downloadframeworks_av-69230df9905534cda15becd44c0109874c4be5f0.zip
frameworks_av-69230df9905534cda15becd44c0109874c4be5f0.tar.gz
frameworks_av-69230df9905534cda15becd44c0109874c4be5f0.tar.bz2
Camera2: Basic ZSL and precapture trigger support.
- Add capture sequencer to control still image capture process - Use precapture trigger for standard capture in sequencer - Add infrastructure for reprocessing streams - Add ZSL processor to maintain ZSL queue - Add ZSL capture sequence to sequencer This patch sets up ZSL mode and precapture triggers. For now, to enable zsl mode, set the system property camera.zsl_mode to 1. Bug: 6243944 Change-Id: Icf8cb1a83a7c11a152a11007c8f3c54f8ea1c70c
Diffstat (limited to 'services/camera/libcameraservice/Camera2Device.cpp')
-rw-r--r--services/camera/libcameraservice/Camera2Device.cpp284
1 files changed, 283 insertions, 1 deletions
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index daeeebb..a171c46 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -206,6 +206,42 @@ status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
return OK;
}
+status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) {
+ status_t res;
+ ALOGV("%s: E", __FUNCTION__);
+
+ bool found = false;
+ StreamList::iterator streamI;
+ for (streamI = mStreams.begin();
+ streamI != mStreams.end(); streamI++) {
+ if ((*streamI)->getId() == outputId) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Output stream %d doesn't exist; can't create "
+ "reprocess stream from it!", __FUNCTION__, mId, outputId);
+ return BAD_VALUE;
+ }
+
+ sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mDevice);
+
+ res = stream->connectToDevice((*streamI));
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create reprocessing stream from "\
+ "stream %d: %s (%d)", __FUNCTION__, mId, outputId,
+ strerror(-res), res);
+ return res;
+ }
+
+ *id = stream->getId();
+
+ mReprocessStreams.push_back(stream);
+ return OK;
+}
+
+
status_t Camera2Device::getStreamInfo(int id,
uint32_t *width, uint32_t *height, uint32_t *format) {
ALOGV("%s: E", __FUNCTION__);
@@ -277,6 +313,33 @@ status_t Camera2Device::deleteStream(int id) {
return OK;
}
+status_t Camera2Device::deleteReprocessStream(int id) {
+ ALOGV("%s: E", __FUNCTION__);
+ bool found = false;
+ for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
+ streamI != mReprocessStreams.end(); streamI++) {
+ if ((*streamI)->getId() == id) {
+ status_t res = (*streamI)->release();
+ if (res != OK) {
+ ALOGE("%s: Unable to release reprocess stream %d from "
+ "HAL device: %s (%d)", __FUNCTION__, id,
+ strerror(-res), res);
+ return res;
+ }
+ mReprocessStreams.erase(streamI);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Unable to find stream %d to delete",
+ __FUNCTION__, mId, id);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+
status_t Camera2Device::createDefaultRequest(int templateId,
CameraMetadata *request) {
status_t err;
@@ -405,6 +468,32 @@ status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) {
return res;
}
+status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
+ buffer_handle_t *buffer, wp<BufferReleasedListener> listener) {
+ ALOGV("%s: E", __FUNCTION__);
+ bool found = false;
+ status_t res = OK;
+ for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
+ streamI != mReprocessStreams.end(); streamI++) {
+ if ((*streamI)->getId() == reprocessStreamId) {
+ res = (*streamI)->pushIntoStream(buffer, listener);
+ if (res != OK) {
+ ALOGE("%s: Unable to push buffer to reprocess stream %d: %s (%d)",
+ __FUNCTION__, reprocessStreamId, strerror(-res), res);
+ return res;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Unable to find reprocess stream %d",
+ __FUNCTION__, mId, reprocessStreamId);
+ res = BAD_VALUE;
+ }
+ return res;
+}
+
/**
* Camera2Device::NotificationListener
*/
@@ -903,7 +992,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
}
buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
- ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)(buffers[bufferIdx]));
+ ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)buffers[bufferIdx]);
}
ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers);
@@ -1094,5 +1183,198 @@ int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
return native_window_set_crop(a, &crop);
}
+/**
+ * Camera2Device::ReprocessStreamAdapter
+ */
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char*)(ptr) - offsetof(type, member))
+#endif
+
+Camera2Device::ReprocessStreamAdapter::ReprocessStreamAdapter(camera2_device_t *d):
+ mState(RELEASED),
+ mDevice(d),
+ mId(-1),
+ mWidth(0), mHeight(0), mFormat(0),
+ mActiveBuffers(0),
+ mFrameCount(0)
+{
+ camera2_stream_in_ops::acquire_buffer = acquire_buffer;
+ camera2_stream_in_ops::release_buffer = release_buffer;
+}
+
+Camera2Device::ReprocessStreamAdapter::~ReprocessStreamAdapter() {
+ if (mState != RELEASED) {
+ release();
+ }
+}
+
+status_t Camera2Device::ReprocessStreamAdapter::connectToDevice(
+ const sp<StreamAdapter> &outputStream) {
+ status_t res;
+ ALOGV("%s: E", __FUNCTION__);
+
+ if (mState != RELEASED) return INVALID_OPERATION;
+ if (outputStream == NULL) {
+ ALOGE("%s: Null base stream passed to reprocess stream adapter",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mBaseStream = outputStream;
+ mWidth = outputStream->getWidth();
+ mHeight = outputStream->getHeight();
+ mFormat = outputStream->getFormat();
+
+ ALOGV("%s: New reprocess stream parameters %d x %d, format 0x%x",
+ __FUNCTION__, mWidth, mHeight, mFormat);
+
+ // Allocate device-side stream interface
+
+ uint32_t id;
+ res = mDevice->ops->allocate_reprocess_stream_from_stream(mDevice,
+ outputStream->getId(), getStreamOps(),
+ &id);
+ if (res != OK) {
+ ALOGE("%s: Device reprocess stream allocation failed: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ ALOGV("%s: Allocated reprocess stream id %d based on stream %d",
+ __FUNCTION__, id, outputStream->getId());
+
+ mId = id;
+
+ mState = ACTIVE;
+
+ return OK;
+}
+
+status_t Camera2Device::ReprocessStreamAdapter::release() {
+ status_t res;
+ ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
+ if (mState >= ACTIVE) {
+ res = mDevice->ops->release_reprocess_stream(mDevice, mId);
+ if (res != OK) {
+ ALOGE("%s: Unable to release stream %d",
+ __FUNCTION__, mId);
+ return res;
+ }
+ }
+
+ List<QueueEntry>::iterator s;
+ for (s = mQueue.begin(); s != mQueue.end(); s++) {
+ sp<BufferReleasedListener> listener = s->releaseListener.promote();
+ if (listener != 0) listener->onBufferReleased(s->handle);
+ }
+ for (s = mInFlightQueue.begin(); s != mInFlightQueue.end(); s++) {
+ sp<BufferReleasedListener> listener = s->releaseListener.promote();
+ if (listener != 0) listener->onBufferReleased(s->handle);
+ }
+ mQueue.clear();
+ mInFlightQueue.clear();
+
+ mState = RELEASED;
+ return OK;
+}
+
+status_t Camera2Device::ReprocessStreamAdapter::pushIntoStream(
+ buffer_handle_t *handle, const wp<BufferReleasedListener> &releaseListener) {
+ // TODO: Some error checking here would be nice
+ ALOGV("%s: Pushing buffer %p to stream", __FUNCTION__, (void*)(*handle));
+
+ QueueEntry entry;
+ entry.handle = handle;
+ entry.releaseListener = releaseListener;
+ mQueue.push_back(entry);
+ return OK;
+}
+
+status_t Camera2Device::ReprocessStreamAdapter::dump(int fd,
+ const Vector<String16>& args) {
+ String8 result =
+ String8::format(" Reprocess stream %d: %d x %d, fmt 0x%x\n",
+ mId, mWidth, mHeight, mFormat);
+ result.appendFormat(" acquired buffers: %d\n",
+ mActiveBuffers);
+ result.appendFormat(" frame count: %d\n",
+ mFrameCount);
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+const camera2_stream_in_ops *Camera2Device::ReprocessStreamAdapter::getStreamOps() {
+ return static_cast<camera2_stream_in_ops *>(this);
+}
+
+int Camera2Device::ReprocessStreamAdapter::acquire_buffer(
+ const camera2_stream_in_ops_t *w,
+ buffer_handle_t** buffer) {
+ int res;
+ ReprocessStreamAdapter* stream =
+ const_cast<ReprocessStreamAdapter*>(
+ static_cast<const ReprocessStreamAdapter*>(w));
+ if (stream->mState != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
+ return INVALID_OPERATION;
+ }
+
+ if (stream->mQueue.empty()) {
+ *buffer = NULL;
+ return OK;
+ }
+
+ QueueEntry &entry = *(stream->mQueue.begin());
+
+ *buffer = entry.handle;
+
+ stream->mInFlightQueue.push_back(entry);
+ stream->mQueue.erase(stream->mQueue.begin());
+
+ stream->mActiveBuffers++;
+
+ ALOGV("Stream %d acquire: Buffer %p acquired", stream->mId,
+ (void*)(**buffer));
+ return OK;
+}
+
+int Camera2Device::ReprocessStreamAdapter::release_buffer(
+ const camera2_stream_in_ops_t* w,
+ buffer_handle_t* buffer) {
+ ReprocessStreamAdapter *stream =
+ const_cast<ReprocessStreamAdapter*>(
+ static_cast<const ReprocessStreamAdapter*>(w) );
+ stream->mFrameCount++;
+ ALOGV("Reprocess stream %d release: Frame %d (%p)",
+ stream->mId, stream->mFrameCount, (void*)*buffer);
+ int state = stream->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ stream->mActiveBuffers--;
+
+ List<QueueEntry>::iterator s;
+ for (s = stream->mInFlightQueue.begin(); s != stream->mInFlightQueue.end(); s++) {
+ if ( s->handle == buffer ) break;
+ }
+ if (s == stream->mInFlightQueue.end()) {
+ ALOGE("%s: Can't find buffer %p in in-flight list!", __FUNCTION__,
+ buffer);
+ return INVALID_OPERATION;
+ }
+
+ sp<BufferReleasedListener> listener = s->releaseListener.promote();
+ if (listener != 0) {
+ listener->onBufferReleased(s->handle);
+ } else {
+ ALOGE("%s: Can't free buffer - missing listener", __FUNCTION__);
+ }
+ stream->mInFlightQueue.erase(s);
+
+ return OK;
+}
}; // namespace android