diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2013-07-25 17:12:35 -0700 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2013-07-30 10:58:44 -0700 |
commit | 7b82efe7a376c882f8f938e1c41b8311a8cdda4a (patch) | |
tree | d7ed69f0a495bc1a873a285ba11e72a9867c5565 /services/camera/libcameraservice/device2 | |
parent | d054c32443a493513ab63529b0c8b1aca290278c (diff) | |
download | frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.zip frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.tar.gz frameworks_av-7b82efe7a376c882f8f938e1c41b8311a8cdda4a.tar.bz2 |
Camera: Rename new API to camera2, rearrange camera service
- Support API rename from photography to camera2
- Reorganize camera service files
- API support files to api1/, api2/, api_pro/
- HAL device support files into device{1,2,3}/
- Common files into common/
- Camera service remains at top-level
Change-Id: Ie474c12536f543832fba0a2dc936ac4fd39fe6a9
Diffstat (limited to 'services/camera/libcameraservice/device2')
-rw-r--r-- | services/camera/libcameraservice/device2/Camera2Device.cpp | 1515 | ||||
-rw-r--r-- | services/camera/libcameraservice/device2/Camera2Device.h | 345 |
2 files changed, 1860 insertions, 0 deletions
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp new file mode 100644 index 0000000..710d0e9 --- /dev/null +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -0,0 +1,1515 @@ +/* + * 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. + */ + +#define LOG_TAG "Camera2-Device" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 +//#define LOG_NNDEBUG 0 // Per-frame verbose logging + +#ifdef LOG_NNDEBUG +#define ALOGVV(...) ALOGV(__VA_ARGS__) +#else +#define ALOGVV(...) ((void)0) +#endif + +#include <utils/Log.h> +#include <utils/Trace.h> +#include <utils/Timers.h> +#include "Camera2Device.h" + +namespace android { + +Camera2Device::Camera2Device(int id): + mId(id), + mHal2Device(NULL) +{ + ATRACE_CALL(); + ALOGV("%s: Created device for camera %d", __FUNCTION__, id); +} + +Camera2Device::~Camera2Device() +{ + ATRACE_CALL(); + ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId); + disconnect(); +} + +int Camera2Device::getId() const { + return mId; +} + +status_t Camera2Device::initialize(camera_module_t *module) +{ + ATRACE_CALL(); + ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId); + if (mHal2Device != NULL) { + ALOGE("%s: Already initialized!", __FUNCTION__); + return INVALID_OPERATION; + } + + status_t res; + char name[10]; + snprintf(name, sizeof(name), "%d", mId); + + camera2_device_t *device; + + res = module->common.methods->open(&module->common, name, + reinterpret_cast<hw_device_t**>(&device)); + + if (res != OK) { + ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__, + mId, strerror(-res), res); + return res; + } + + if (device->common.version != CAMERA_DEVICE_API_VERSION_2_0) { + ALOGE("%s: Could not open camera %d: " + "Camera device is not version %x, reports %x instead", + __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0, + device->common.version); + device->common.close(&device->common); + return BAD_VALUE; + } + + camera_info info; + res = module->get_camera_info(mId, &info); + if (res != OK ) return res; + + if (info.device_version != device->common.version) { + ALOGE("%s: HAL reporting mismatched camera_info version (%x)" + " and device version (%x).", __FUNCTION__, + device->common.version, info.device_version); + device->common.close(&device->common); + return BAD_VALUE; + } + + res = mRequestQueue.setConsumerDevice(device); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + device->common.close(&device->common); + return res; + } + res = mFrameQueue.setProducerDevice(device); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + device->common.close(&device->common); + return res; + } + + res = device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps); + if (res != OK ) { + ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + device->common.close(&device->common); + return res; + } + res = set_camera_metadata_vendor_tag_ops(mVendorTagOps); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + device->common.close(&device->common); + return res; + } + res = device->ops->set_notify_callback(device, notificationCallback, + NULL); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to initialize notification callback!", + __FUNCTION__, mId); + device->common.close(&device->common); + return res; + } + + mDeviceInfo = info.static_camera_characteristics; + mHal2Device = device; + + return OK; +} + +status_t Camera2Device::disconnect() { + ATRACE_CALL(); + status_t res = OK; + if (mHal2Device) { + ALOGV("%s: Closing device for camera %d", __FUNCTION__, mId); + + int inProgressCount = mHal2Device->ops->get_in_progress_count(mHal2Device); + if (inProgressCount > 0) { + ALOGW("%s: Closing camera device %d with %d requests in flight!", + __FUNCTION__, mId, inProgressCount); + } + mReprocessStreams.clear(); + mStreams.clear(); + res = mHal2Device->common.close(&mHal2Device->common); + if (res != OK) { + ALOGE("%s: Could not close camera %d: %s (%d)", + __FUNCTION__, + mId, strerror(-res), res); + } + mHal2Device = NULL; + ALOGV("%s: Shutdown complete", __FUNCTION__); + } + return res; +} + +status_t Camera2Device::dump(int fd, const Vector<String16>& args) { + ATRACE_CALL(); + String8 result; + int detailLevel = 0; + int n = args.size(); + String16 detailOption("-d"); + for (int i = 0; i + 1 < n; i++) { + if (args[i] == detailOption) { + String8 levelStr(args[i+1]); + detailLevel = atoi(levelStr.string()); + } + } + + result.appendFormat(" Camera2Device[%d] dump (detail level %d):\n", + mId, detailLevel); + + if (detailLevel > 0) { + result = " Request queue contents:\n"; + write(fd, result.string(), result.size()); + mRequestQueue.dump(fd, args); + + result = " Frame queue contents:\n"; + write(fd, result.string(), result.size()); + mFrameQueue.dump(fd, args); + } + + result = " Active streams:\n"; + write(fd, result.string(), result.size()); + for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) { + (*s)->dump(fd, args); + } + + result = " HAL device dump:\n"; + write(fd, result.string(), result.size()); + + status_t res; + res = mHal2Device->ops->dump(mHal2Device, fd); + + return res; +} + +const CameraMetadata& Camera2Device::info() const { + ALOGVV("%s: E", __FUNCTION__); + + return mDeviceInfo; +} + +status_t Camera2Device::capture(CameraMetadata &request) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + + mRequestQueue.enqueue(request.release()); + return OK; +} + + +status_t Camera2Device::setStreamingRequest(const CameraMetadata &request) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + CameraMetadata streamRequest(request); + return mRequestQueue.setStreamSlot(streamRequest.release()); +} + +status_t Camera2Device::clearStreamingRequest() { + ATRACE_CALL(); + return mRequestQueue.setStreamSlot(NULL); +} + +status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) { + ATRACE_CALL(); + return mRequestQueue.waitForDequeue(requestId, timeout); +} + +status_t Camera2Device::createStream(sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, int format, size_t size, int *id) { + ATRACE_CALL(); + status_t res; + ALOGV("%s: E", __FUNCTION__); + + sp<StreamAdapter> stream = new StreamAdapter(mHal2Device); + + res = stream->connectToDevice(consumer, width, height, format, size); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):" + "%s (%d)", + __FUNCTION__, mId, width, height, format, strerror(-res), res); + return res; + } + + *id = stream->getId(); + + mStreams.push_back(stream); + return OK; +} + +status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) { + ATRACE_CALL(); + 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(mHal2Device); + + 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) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + bool found = false; + StreamList::iterator streamI; + for (streamI = mStreams.begin(); + streamI != mStreams.end(); streamI++) { + if ((*streamI)->getId() == id) { + found = true; + break; + } + } + if (!found) { + ALOGE("%s: Camera %d: Stream %d does not exist", + __FUNCTION__, mId, id); + return BAD_VALUE; + } + + if (width) *width = (*streamI)->getWidth(); + if (height) *height = (*streamI)->getHeight(); + if (format) *format = (*streamI)->getFormat(); + + return OK; +} + +status_t Camera2Device::setStreamTransform(int id, + int transform) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + bool found = false; + StreamList::iterator streamI; + for (streamI = mStreams.begin(); + streamI != mStreams.end(); streamI++) { + if ((*streamI)->getId() == id) { + found = true; + break; + } + } + if (!found) { + ALOGE("%s: Camera %d: Stream %d does not exist", + __FUNCTION__, mId, id); + return BAD_VALUE; + } + + return (*streamI)->setTransform(transform); +} + +status_t Camera2Device::deleteStream(int id) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + bool found = false; + for (StreamList::iterator streamI = mStreams.begin(); + streamI != mStreams.end(); streamI++) { + if ((*streamI)->getId() == id) { + status_t res = (*streamI)->release(); + if (res != OK) { + ALOGE("%s: Unable to release stream %d from HAL device: " + "%s (%d)", __FUNCTION__, id, strerror(-res), res); + return res; + } + mStreams.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::deleteReprocessStream(int id) { + ATRACE_CALL(); + 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) { + ATRACE_CALL(); + status_t err; + ALOGV("%s: E", __FUNCTION__); + camera_metadata_t *rawRequest; + err = mHal2Device->ops->construct_default_request( + mHal2Device, templateId, &rawRequest); + request->acquire(rawRequest); + return err; +} + +status_t Camera2Device::waitUntilDrained() { + ATRACE_CALL(); + static const uint32_t kSleepTime = 50000; // 50 ms + static const uint32_t kMaxSleepTime = 10000000; // 10 s + ALOGV("%s: Camera %d: Starting wait", __FUNCTION__, mId); + if (mRequestQueue.getBufferCount() == + CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION; + + // TODO: Set up notifications from HAL, instead of sleeping here + uint32_t totalTime = 0; + while (mHal2Device->ops->get_in_progress_count(mHal2Device) > 0) { + usleep(kSleepTime); + totalTime += kSleepTime; + if (totalTime > kMaxSleepTime) { + ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__, + totalTime, mHal2Device->ops->get_in_progress_count(mHal2Device)); + return TIMED_OUT; + } + } + ALOGV("%s: Camera %d: HAL is idle", __FUNCTION__, mId); + return OK; +} + +status_t Camera2Device::setNotifyCallback(NotificationListener *listener) { + ATRACE_CALL(); + status_t res; + res = mHal2Device->ops->set_notify_callback(mHal2Device, notificationCallback, + reinterpret_cast<void*>(listener) ); + if (res != OK) { + ALOGE("%s: Unable to set notification callback!", __FUNCTION__); + } + return res; +} + +bool Camera2Device::willNotify3A() { + return true; +} + +void Camera2Device::notificationCallback(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3, + void *user) { + ATRACE_CALL(); + NotificationListener *listener = reinterpret_cast<NotificationListener*>(user); + ALOGV("%s: Notification %d, arguments %d, %d, %d", __FUNCTION__, msg_type, + ext1, ext2, ext3); + if (listener != NULL) { + switch (msg_type) { + case CAMERA2_MSG_ERROR: + listener->notifyError(ext1, ext2, ext3); + break; + case CAMERA2_MSG_SHUTTER: { + nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 ); + listener->notifyShutter(ext1, timestamp); + break; + } + case CAMERA2_MSG_AUTOFOCUS: + listener->notifyAutoFocus(ext1, ext2); + break; + case CAMERA2_MSG_AUTOEXPOSURE: + listener->notifyAutoExposure(ext1, ext2); + break; + case CAMERA2_MSG_AUTOWB: + listener->notifyAutoWhitebalance(ext1, ext2); + break; + default: + ALOGE("%s: Unknown notification %d (arguments %d, %d, %d)!", + __FUNCTION__, msg_type, ext1, ext2, ext3); + } + } +} + +status_t Camera2Device::waitForNextFrame(nsecs_t timeout) { + return mFrameQueue.waitForBuffer(timeout); +} + +status_t Camera2Device::getNextFrame(CameraMetadata *frame) { + ATRACE_CALL(); + status_t res; + camera_metadata_t *rawFrame; + res = mFrameQueue.dequeue(&rawFrame); + if (rawFrame == NULL) { + return NOT_ENOUGH_DATA; + } else if (res == OK) { + frame->acquire(rawFrame); + } + return res; +} + +status_t Camera2Device::triggerAutofocus(uint32_t id) { + ATRACE_CALL(); + status_t res; + ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id); + res = mHal2Device->ops->trigger_action(mHal2Device, + CAMERA2_TRIGGER_AUTOFOCUS, id, 0); + if (res != OK) { + ALOGE("%s: Error triggering autofocus (id %d)", + __FUNCTION__, id); + } + return res; +} + +status_t Camera2Device::triggerCancelAutofocus(uint32_t id) { + ATRACE_CALL(); + status_t res; + ALOGV("%s: Canceling autofocus, id %d", __FUNCTION__, id); + res = mHal2Device->ops->trigger_action(mHal2Device, + CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, id, 0); + if (res != OK) { + ALOGE("%s: Error canceling autofocus (id %d)", + __FUNCTION__, id); + } + return res; +} + +status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) { + ATRACE_CALL(); + status_t res; + ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id); + res = mHal2Device->ops->trigger_action(mHal2Device, + CAMERA2_TRIGGER_PRECAPTURE_METERING, id, 0); + if (res != OK) { + ALOGE("%s: Error triggering precapture metering (id %d)", + __FUNCTION__, id); + } + return res; +} + +status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId, + buffer_handle_t *buffer, wp<BufferReleasedListener> listener) { + ATRACE_CALL(); + 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::MetadataQueue + */ + +Camera2Device::MetadataQueue::MetadataQueue(): + mHal2Device(NULL), + mFrameCount(0), + mLatestRequestId(0), + mCount(0), + mStreamSlotCount(0), + mSignalConsumer(true) +{ + ATRACE_CALL(); + camera2_request_queue_src_ops::dequeue_request = consumer_dequeue; + camera2_request_queue_src_ops::request_count = consumer_buffer_count; + camera2_request_queue_src_ops::free_request = consumer_free; + + camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue; + camera2_frame_queue_dst_ops::cancel_frame = producer_cancel; + camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue; +} + +Camera2Device::MetadataQueue::~MetadataQueue() { + ATRACE_CALL(); + Mutex::Autolock l(mMutex); + freeBuffers(mEntries.begin(), mEntries.end()); + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); +} + +// Connect to camera2 HAL as consumer (input requests/reprocessing) +status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) { + ATRACE_CALL(); + status_t res; + res = d->ops->set_request_queue_src_ops(d, + this); + if (res != OK) return res; + mHal2Device = d; + return OK; +} + +status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) { + ATRACE_CALL(); + status_t res; + res = d->ops->set_frame_queue_dst_ops(d, + this); + return res; +} + +// Real interfaces +status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) { + ATRACE_CALL(); + ALOGVV("%s: E", __FUNCTION__); + Mutex::Autolock l(mMutex); + + mCount++; + mEntries.push_back(buf); + + return signalConsumerLocked(); +} + +int Camera2Device::MetadataQueue::getBufferCount() { + ATRACE_CALL(); + Mutex::Autolock l(mMutex); + if (mStreamSlotCount > 0) { + return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS; + } + return mCount; +} + +status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf, + bool incrementCount) +{ + ATRACE_CALL(); + ALOGVV("%s: E", __FUNCTION__); + status_t res; + Mutex::Autolock l(mMutex); + + if (mCount == 0) { + if (mStreamSlotCount == 0) { + ALOGVV("%s: Empty", __FUNCTION__); + *buf = NULL; + mSignalConsumer = true; + return OK; + } + ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__, + mStreamSlotCount); + + for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin(); + slotEntry != mStreamSlot.end(); + slotEntry++ ) { + size_t entries = get_camera_metadata_entry_count(*slotEntry); + size_t dataBytes = get_camera_metadata_data_count(*slotEntry); + + camera_metadata_t *copy = + allocate_camera_metadata(entries, dataBytes); + append_camera_metadata(copy, *slotEntry); + mEntries.push_back(copy); + } + mCount = mStreamSlotCount; + } + ALOGVV("MetadataQueue: deque (%d buffers)", mCount); + camera_metadata_t *b = *(mEntries.begin()); + mEntries.erase(mEntries.begin()); + + if (incrementCount) { + ATRACE_INT("cam2_request", mFrameCount); + camera_metadata_entry_t frameCount; + res = find_camera_metadata_entry(b, + ANDROID_REQUEST_FRAME_COUNT, + &frameCount); + if (res != OK) { + ALOGE("%s: Unable to add frame count: %s (%d)", + __FUNCTION__, strerror(-res), res); + } else { + *frameCount.data.i32 = mFrameCount; + } + mFrameCount++; + } + + // Check for request ID, and if present, signal waiters. + camera_metadata_entry_t requestId; + res = find_camera_metadata_entry(b, + ANDROID_REQUEST_ID, + &requestId); + if (res == OK) { + mLatestRequestId = requestId.data.i32[0]; + mNewRequestId.signal(); + } + + *buf = b; + mCount--; + + return OK; +} + +status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout) +{ + Mutex::Autolock l(mMutex); + status_t res; + while (mCount == 0) { + res = notEmpty.waitRelative(mMutex,timeout); + if (res != OK) return res; + } + return OK; +} + +status_t Camera2Device::MetadataQueue::waitForDequeue(int32_t id, + nsecs_t timeout) { + Mutex::Autolock l(mMutex); + status_t res; + while (mLatestRequestId != id) { + nsecs_t startTime = systemTime(); + + res = mNewRequestId.waitRelative(mMutex, timeout); + if (res != OK) return res; + + timeout -= (systemTime() - startTime); + } + + return OK; +} + +status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf) +{ + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + Mutex::Autolock l(mMutex); + if (buf == NULL) { + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); + mStreamSlotCount = 0; + return OK; + } + camera_metadata_t *buf2 = clone_camera_metadata(buf); + if (!buf2) { + ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__); + return NO_MEMORY; + } + + if (mStreamSlotCount > 1) { + List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin(); + freeBuffers(++mStreamSlot.begin(), mStreamSlot.end()); + mStreamSlotCount = 1; + } + if (mStreamSlotCount == 1) { + free_camera_metadata( *(mStreamSlot.begin()) ); + *(mStreamSlot.begin()) = buf2; + } else { + mStreamSlot.push_front(buf2); + mStreamSlotCount = 1; + } + return signalConsumerLocked(); +} + +status_t Camera2Device::MetadataQueue::setStreamSlot( + const List<camera_metadata_t*> &bufs) +{ + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + Mutex::Autolock l(mMutex); + + if (mStreamSlotCount > 0) { + freeBuffers(mStreamSlot.begin(), mStreamSlot.end()); + } + mStreamSlotCount = 0; + for (List<camera_metadata_t*>::const_iterator r = bufs.begin(); + r != bufs.end(); r++) { + camera_metadata_t *r2 = clone_camera_metadata(*r); + if (!r2) { + ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__); + return NO_MEMORY; + } + mStreamSlot.push_back(r2); + mStreamSlotCount++; + } + return signalConsumerLocked(); +} + +status_t Camera2Device::MetadataQueue::dump(int fd, + const Vector<String16>& /*args*/) { + ATRACE_CALL(); + String8 result; + status_t notLocked; + notLocked = mMutex.tryLock(); + if (notLocked) { + result.append(" (Unable to lock queue mutex)\n"); + } + result.appendFormat(" Current frame number: %d\n", mFrameCount); + if (mStreamSlotCount == 0) { + result.append(" Stream slot: Empty\n"); + write(fd, result.string(), result.size()); + } else { + result.appendFormat(" Stream slot: %d entries\n", + mStreamSlot.size()); + int i = 0; + for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin(); + r != mStreamSlot.end(); r++) { + result = String8::format(" Stream slot buffer %d:\n", i); + write(fd, result.string(), result.size()); + dump_indented_camera_metadata(*r, fd, 2, 10); + i++; + } + } + if (mEntries.size() == 0) { + result = " Main queue is empty\n"; + write(fd, result.string(), result.size()); + } else { + result = String8::format(" Main queue has %d entries:\n", + mEntries.size()); + int i = 0; + for (List<camera_metadata_t*>::iterator r = mEntries.begin(); + r != mEntries.end(); r++) { + result = String8::format(" Queue entry %d:\n", i); + write(fd, result.string(), result.size()); + dump_indented_camera_metadata(*r, fd, 2, 10); + i++; + } + } + + if (notLocked == 0) { + mMutex.unlock(); + } + + return OK; +} + +status_t Camera2Device::MetadataQueue::signalConsumerLocked() { + ATRACE_CALL(); + status_t res = OK; + notEmpty.signal(); + if (mSignalConsumer && mHal2Device != NULL) { + mSignalConsumer = false; + + mMutex.unlock(); + ALOGV("%s: Signaling consumer", __FUNCTION__); + res = mHal2Device->ops->notify_request_queue_not_empty(mHal2Device); + mMutex.lock(); + } + return res; +} + +status_t Camera2Device::MetadataQueue::freeBuffers( + List<camera_metadata_t*>::iterator start, + List<camera_metadata_t*>::iterator end) +{ + ATRACE_CALL(); + while (start != end) { + free_camera_metadata(*start); + start = mStreamSlot.erase(start); + } + return OK; +} + +Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance( + const camera2_request_queue_src_ops_t *q) +{ + const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q); + return const_cast<MetadataQueue*>(cmq); +} + +Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance( + const camera2_frame_queue_dst_ops_t *q) +{ + const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q); + return const_cast<MetadataQueue*>(cmq); +} + +int Camera2Device::MetadataQueue::consumer_buffer_count( + const camera2_request_queue_src_ops_t *q) +{ + MetadataQueue *queue = getInstance(q); + return queue->getBufferCount(); +} + +int Camera2Device::MetadataQueue::consumer_dequeue( + const camera2_request_queue_src_ops_t *q, + camera_metadata_t **buffer) +{ + MetadataQueue *queue = getInstance(q); + return queue->dequeue(buffer, true); +} + +int Camera2Device::MetadataQueue::consumer_free( + const camera2_request_queue_src_ops_t *q, + camera_metadata_t *old_buffer) +{ + ATRACE_CALL(); + MetadataQueue *queue = getInstance(q); + (void)queue; + free_camera_metadata(old_buffer); + return OK; +} + +int Camera2Device::MetadataQueue::producer_dequeue( + const camera2_frame_queue_dst_ops_t * /*q*/, + size_t entries, size_t bytes, + camera_metadata_t **buffer) +{ + ATRACE_CALL(); + camera_metadata_t *new_buffer = + allocate_camera_metadata(entries, bytes); + if (new_buffer == NULL) return NO_MEMORY; + *buffer = new_buffer; + return OK; +} + +int Camera2Device::MetadataQueue::producer_cancel( + const camera2_frame_queue_dst_ops_t * /*q*/, + camera_metadata_t *old_buffer) +{ + ATRACE_CALL(); + free_camera_metadata(old_buffer); + return OK; +} + +int Camera2Device::MetadataQueue::producer_enqueue( + const camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *filled_buffer) +{ + MetadataQueue *queue = getInstance(q); + return queue->enqueue(filled_buffer); +} + +/** + * Camera2Device::StreamAdapter + */ + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char*)(ptr) - offsetof(type, member)) +#endif + +Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d): + mState(RELEASED), + mHal2Device(d), + mId(-1), + mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0), + mMaxProducerBuffers(0), mMaxConsumerBuffers(0), + mTotalBuffers(0), + mFormatRequested(0), + mActiveBuffers(0), + mFrameCount(0), + mLastTimestamp(0) +{ + camera2_stream_ops::dequeue_buffer = dequeue_buffer; + camera2_stream_ops::enqueue_buffer = enqueue_buffer; + camera2_stream_ops::cancel_buffer = cancel_buffer; + camera2_stream_ops::set_crop = set_crop; +} + +Camera2Device::StreamAdapter::~StreamAdapter() { + ATRACE_CALL(); + if (mState != RELEASED) { + release(); + } +} + +status_t Camera2Device::StreamAdapter::connectToDevice( + sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, int format, size_t size) { + ATRACE_CALL(); + status_t res; + ALOGV("%s: E", __FUNCTION__); + + if (mState != RELEASED) return INVALID_OPERATION; + if (consumer == NULL) { + ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__); + return BAD_VALUE; + } + + ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %d", + __FUNCTION__, width, height, format, size); + + mConsumerInterface = consumer; + mWidth = width; + mHeight = height; + mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0; + mFormatRequested = format; + + // Allocate device-side stream interface + + uint32_t id; + uint32_t formatActual; + uint32_t usage; + uint32_t maxBuffers = 2; + res = mHal2Device->ops->allocate_stream(mHal2Device, + mWidth, mHeight, mFormatRequested, getStreamOps(), + &id, &formatActual, &usage, &maxBuffers); + if (res != OK) { + ALOGE("%s: Device stream allocation failed: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + + ALOGV("%s: Allocated stream id %d, actual format 0x%x, " + "usage 0x%x, producer wants %d buffers", __FUNCTION__, + id, formatActual, usage, maxBuffers); + + mId = id; + mFormat = formatActual; + mUsage = usage; + mMaxProducerBuffers = maxBuffers; + + mState = ALLOCATED; + + // Configure consumer-side ANativeWindow interface + res = native_window_api_connect(mConsumerInterface.get(), + NATIVE_WINDOW_API_CAMERA); + if (res != OK) { + ALOGE("%s: Unable to connect to native window for stream %d", + __FUNCTION__, mId); + + return res; + } + + mState = CONNECTED; + + res = native_window_set_usage(mConsumerInterface.get(), mUsage); + if (res != OK) { + ALOGE("%s: Unable to configure usage %08x for stream %d", + __FUNCTION__, mUsage, mId); + return res; + } + + res = native_window_set_scaling_mode(mConsumerInterface.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (res != OK) { + ALOGE("%s: Unable to configure stream scaling: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + + res = setTransform(0); + if (res != OK) { + return res; + } + + if (mFormat == HAL_PIXEL_FORMAT_BLOB) { + res = native_window_set_buffers_geometry(mConsumerInterface.get(), + mSize, 1, mFormat); + if (res != OK) { + ALOGE("%s: Unable to configure compressed stream buffer geometry" + " %d x %d, size %d for stream %d", + __FUNCTION__, mWidth, mHeight, mSize, mId); + return res; + } + } else { + res = native_window_set_buffers_geometry(mConsumerInterface.get(), + mWidth, mHeight, mFormat); + if (res != OK) { + ALOGE("%s: Unable to configure stream buffer geometry" + " %d x %d, format 0x%x for stream %d", + __FUNCTION__, mWidth, mHeight, mFormat, mId); + return res; + } + } + + int maxConsumerBuffers; + res = mConsumerInterface->query(mConsumerInterface.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); + if (res != OK) { + ALOGE("%s: Unable to query consumer undequeued" + " buffer count for stream %d", __FUNCTION__, mId); + return res; + } + mMaxConsumerBuffers = maxConsumerBuffers; + + ALOGV("%s: Consumer wants %d buffers", __FUNCTION__, + mMaxConsumerBuffers); + + mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers; + mActiveBuffers = 0; + mFrameCount = 0; + mLastTimestamp = 0; + + res = native_window_set_buffer_count(mConsumerInterface.get(), + mTotalBuffers); + if (res != OK) { + ALOGE("%s: Unable to set buffer count for stream %d", + __FUNCTION__, mId); + return res; + } + + // Register allocated buffers with HAL device + buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers]; + ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers]; + uint32_t bufferIdx = 0; + for (; bufferIdx < mTotalBuffers; bufferIdx++) { + res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(), + &anwBuffers[bufferIdx]); + if (res != OK) { + ALOGE("%s: Unable to dequeue buffer %d for initial registration for " + "stream %d", __FUNCTION__, bufferIdx, mId); + goto cleanUpBuffers; + } + + buffers[bufferIdx] = anwBuffers[bufferIdx]->handle; + ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)buffers[bufferIdx]); + } + + ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers); + res = mHal2Device->ops->register_stream_buffers(mHal2Device, + mId, + mTotalBuffers, + buffers); + if (res != OK) { + ALOGE("%s: Unable to register buffers with HAL device for stream %d", + __FUNCTION__, mId); + } else { + mState = ACTIVE; + } + +cleanUpBuffers: + ALOGV("%s: Cleaning up %d buffers", __FUNCTION__, bufferIdx); + for (uint32_t i = 0; i < bufferIdx; i++) { + res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(), + anwBuffers[i], -1); + if (res != OK) { + ALOGE("%s: Unable to cancel buffer %d after registration", + __FUNCTION__, i); + } + } + delete[] anwBuffers; + delete[] buffers; + + return res; +} + +status_t Camera2Device::StreamAdapter::release() { + ATRACE_CALL(); + status_t res; + ALOGV("%s: Releasing stream %d (%d x %d, format %d)", __FUNCTION__, mId, + mWidth, mHeight, mFormat); + if (mState >= ALLOCATED) { + res = mHal2Device->ops->release_stream(mHal2Device, mId); + if (res != OK) { + ALOGE("%s: Unable to release stream %d", + __FUNCTION__, mId); + return res; + } + } + if (mState >= CONNECTED) { + res = native_window_api_disconnect(mConsumerInterface.get(), + NATIVE_WINDOW_API_CAMERA); + + /* this is not an error. if client calling process dies, + the window will also die and all calls to it will return + DEAD_OBJECT, thus it's already "disconnected" */ + if (res == DEAD_OBJECT) { + ALOGW("%s: While disconnecting stream %d from native window, the" + " native window died from under us", __FUNCTION__, mId); + } + else if (res != OK) { + ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)", + __FUNCTION__, mId, res, strerror(-res)); + return res; + } + } + mId = -1; + mState = RELEASED; + return OK; +} + +status_t Camera2Device::StreamAdapter::setTransform(int transform) { + ATRACE_CALL(); + status_t res; + if (mState < CONNECTED) { + ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__); + return INVALID_OPERATION; + } + res = native_window_set_buffers_transform(mConsumerInterface.get(), + transform); + if (res != OK) { + ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", + __FUNCTION__, transform, strerror(-res), res); + } + return res; +} + +status_t Camera2Device::StreamAdapter::dump(int fd, + const Vector<String16>& /*args*/) { + ATRACE_CALL(); + String8 result = String8::format(" Stream %d: %d x %d, format 0x%x\n", + mId, mWidth, mHeight, mFormat); + result.appendFormat(" size %d, usage 0x%x, requested format 0x%x\n", + mSize, mUsage, mFormatRequested); + result.appendFormat(" total buffers: %d, dequeued buffers: %d\n", + mTotalBuffers, mActiveBuffers); + result.appendFormat(" frame count: %d, last timestamp %lld\n", + mFrameCount, mLastTimestamp); + write(fd, result.string(), result.size()); + return OK; +} + +const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() { + return static_cast<camera2_stream_ops *>(this); +} + +ANativeWindow* Camera2Device::StreamAdapter::toANW( + const camera2_stream_ops_t *w) { + return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get(); +} + +int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w, + buffer_handle_t** buffer) { + ATRACE_CALL(); + int res; + StreamAdapter* stream = + const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w)); + if (stream->mState != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState); + return INVALID_OPERATION; + } + + ANativeWindow *a = toANW(w); + ANativeWindowBuffer* anb; + res = native_window_dequeue_buffer_and_wait(a, &anb); + if (res != OK) { + ALOGE("Stream %d dequeue: Error from native_window: %s (%d)", stream->mId, + strerror(-res), res); + return res; + } + + *buffer = &(anb->handle); + stream->mActiveBuffers++; + + ALOGVV("Stream %d dequeue: Buffer %p dequeued", stream->mId, (void*)(**buffer)); + return res; +} + +int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w, + int64_t timestamp, + buffer_handle_t* buffer) { + ATRACE_CALL(); + StreamAdapter *stream = + const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w)); + stream->mFrameCount++; + ALOGVV("Stream %d enqueue: Frame %d (%p) captured at %lld ns", + stream->mId, stream->mFrameCount, (void*)(*buffer), timestamp); + int state = stream->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + ANativeWindow *a = toANW(w); + status_t err; + + err = native_window_set_buffers_timestamp(a, timestamp); + if (err != OK) { + ALOGE("%s: Error setting timestamp on native window: %s (%d)", + __FUNCTION__, strerror(-err), err); + return err; + } + err = a->queueBuffer(a, + container_of(buffer, ANativeWindowBuffer, handle), -1); + if (err != OK) { + ALOGE("%s: Error queueing buffer to native window: %s (%d)", + __FUNCTION__, strerror(-err), err); + return err; + } + + stream->mActiveBuffers--; + stream->mLastTimestamp = timestamp; + return OK; +} + +int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w, + buffer_handle_t* buffer) { + ATRACE_CALL(); + StreamAdapter *stream = + const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w)); + ALOGVV("Stream %d cancel: Buffer %p", + stream->mId, (void*)(*buffer)); + if (stream->mState != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState); + return INVALID_OPERATION; + } + + ANativeWindow *a = toANW(w); + int err = a->cancelBuffer(a, + container_of(buffer, ANativeWindowBuffer, handle), -1); + if (err != OK) { + ALOGE("%s: Error canceling buffer to native window: %s (%d)", + __FUNCTION__, strerror(-err), err); + return err; + } + + stream->mActiveBuffers--; + return OK; +} + +int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w, + int left, int top, int right, int bottom) { + ATRACE_CALL(); + int state = static_cast<const StreamAdapter*>(w)->mState; + if (state != ACTIVE) { + ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state); + return INVALID_OPERATION; + } + ANativeWindow *a = toANW(w); + android_native_rect_t crop = { left, top, right, bottom }; + 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), + mHal2Device(d), + mId(-1), + mWidth(0), mHeight(0), mFormat(0), + mActiveBuffers(0), + mFrameCount(0) +{ + ATRACE_CALL(); + camera2_stream_in_ops::acquire_buffer = acquire_buffer; + camera2_stream_in_ops::release_buffer = release_buffer; +} + +Camera2Device::ReprocessStreamAdapter::~ReprocessStreamAdapter() { + ATRACE_CALL(); + if (mState != RELEASED) { + release(); + } +} + +status_t Camera2Device::ReprocessStreamAdapter::connectToDevice( + const sp<StreamAdapter> &outputStream) { + ATRACE_CALL(); + 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 = mHal2Device->ops->allocate_reprocess_stream_from_stream(mHal2Device, + 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() { + ATRACE_CALL(); + status_t res; + ALOGV("%s: Releasing stream %d", __FUNCTION__, mId); + if (mState >= ACTIVE) { + res = mHal2Device->ops->release_reprocess_stream(mHal2Device, 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) { + ATRACE_CALL(); + // 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*/) { + ATRACE_CALL(); + 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) { + ATRACE_CALL(); + + 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) { + ATRACE_CALL(); + 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 diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h new file mode 100644 index 0000000..8945ec2 --- /dev/null +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -0,0 +1,345 @@ +/* + * 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. + */ + +#ifndef ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H +#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H + +#include <utils/Condition.h> +#include <utils/Errors.h> +#include <utils/List.h> +#include <utils/Mutex.h> + +#include "common/CameraDeviceBase.h" + +namespace android { + +/** + * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0 + */ +class Camera2Device: public CameraDeviceBase { + public: + Camera2Device(int id); + + virtual ~Camera2Device(); + + /** + * CameraDevice interface + */ + virtual int getId() const; + 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; + 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); + 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); + virtual status_t waitUntilDrained(); + virtual status_t setNotifyCallback(NotificationListener *listener); + virtual bool willNotify3A(); + 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; + camera2_device_t *mHal2Device; + + CameraMetadata mDeviceInfo; + vendor_tag_query_ops_t *mVendorTagOps; + + /** + * Queue class for both sending requests to a camera2 device, and for + * receiving frames from a camera2 device. + */ + class MetadataQueue: public camera2_request_queue_src_ops_t, + public camera2_frame_queue_dst_ops_t { + public: + MetadataQueue(); + ~MetadataQueue(); + + // Interface to camera2 HAL device, either for requests (device is + // consumer) or for frames (device is producer) + const camera2_request_queue_src_ops_t* getToConsumerInterface(); + void setFromConsumerInterface(camera2_device_t *d); + + // Connect queue consumer endpoint to a camera2 device + status_t setConsumerDevice(camera2_device_t *d); + // Connect queue producer endpoint to a camera2 device + status_t setProducerDevice(camera2_device_t *d); + + const camera2_frame_queue_dst_ops_t* getToProducerInterface(); + + // Real interfaces. On enqueue, queue takes ownership of buffer pointer + // On dequeue, user takes ownership of buffer pointer. + status_t enqueue(camera_metadata_t *buf); + status_t dequeue(camera_metadata_t **buf, bool incrementCount = false); + int getBufferCount(); + status_t waitForBuffer(nsecs_t timeout); + // Wait until a buffer with the given ID is dequeued. Will return + // immediately if the latest buffer dequeued has that ID. + status_t waitForDequeue(int32_t id, nsecs_t timeout); + + // Set repeating buffer(s); if the queue is empty on a dequeue call, the + // queue copies the contents of the stream slot into the queue, and then + // dequeues the first new entry. The metadata buffers passed in are + // copied. + status_t setStreamSlot(camera_metadata_t *buf); + status_t setStreamSlot(const List<camera_metadata_t*> &bufs); + + status_t dump(int fd, const Vector<String16>& args); + + private: + status_t signalConsumerLocked(); + status_t freeBuffers(List<camera_metadata_t*>::iterator start, + List<camera_metadata_t*>::iterator end); + + camera2_device_t *mHal2Device; + + Mutex mMutex; + Condition notEmpty; + + int mFrameCount; + int32_t mLatestRequestId; + Condition mNewRequestId; + + int mCount; + List<camera_metadata_t*> mEntries; + int mStreamSlotCount; + List<camera_metadata_t*> mStreamSlot; + + bool mSignalConsumer; + + static MetadataQueue* getInstance( + const camera2_frame_queue_dst_ops_t *q); + static MetadataQueue* getInstance( + const camera2_request_queue_src_ops_t *q); + + static int consumer_buffer_count( + const camera2_request_queue_src_ops_t *q); + + static int consumer_dequeue(const camera2_request_queue_src_ops_t *q, + camera_metadata_t **buffer); + + static int consumer_free(const camera2_request_queue_src_ops_t *q, + camera_metadata_t *old_buffer); + + static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q, + size_t entries, size_t bytes, + camera_metadata_t **buffer); + + static int producer_cancel(const camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *old_buffer); + + static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q, + camera_metadata_t *filled_buffer); + + }; // class MetadataQueue + + MetadataQueue mRequestQueue; + MetadataQueue mFrameQueue; + + /** + * Adapter from an ANativeWindow interface to camera2 device stream ops. + * Also takes care of allocating/deallocating stream in device interface + */ + class StreamAdapter: public camera2_stream_ops, public virtual RefBase { + public: + StreamAdapter(camera2_device_t *d); + + ~StreamAdapter(); + + /** + * Create a HAL device stream of the requested size and format. + * + * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device + * selects an appropriate format; it can be queried with getFormat. + * + * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must + * be equal to the size in bytes of the buffers to allocate for the + * stream. For other formats, the size parameter is ignored. + */ + status_t connectToDevice(sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, int format, size_t size); + + status_t release(); + + status_t setTransform(int transform); + + // Get stream parameters. + // Only valid after a successful connectToDevice call. + int getId() const { return mId; } + uint32_t getWidth() const { return mWidth; } + uint32_t getHeight() const { return mHeight; } + uint32_t getFormat() const { return mFormat; } + + // Dump stream information + status_t dump(int fd, const Vector<String16>& args); + + private: + enum { + ERROR = -1, + RELEASED = 0, + ALLOCATED, + CONNECTED, + ACTIVE + } mState; + + sp<ANativeWindow> mConsumerInterface; + camera2_device_t *mHal2Device; + + uint32_t mId; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mFormat; + size_t mSize; + uint32_t mUsage; + uint32_t mMaxProducerBuffers; + uint32_t mMaxConsumerBuffers; + uint32_t mTotalBuffers; + int mFormatRequested; + + /** Debugging information */ + uint32_t mActiveBuffers; + uint32_t mFrameCount; + int64_t mLastTimestamp; + + const camera2_stream_ops *getStreamOps(); + + static ANativeWindow* toANW(const camera2_stream_ops_t *w); + + static int dequeue_buffer(const camera2_stream_ops_t *w, + buffer_handle_t** buffer); + + static int enqueue_buffer(const camera2_stream_ops_t* w, + int64_t timestamp, + buffer_handle_t* buffer); + + static int cancel_buffer(const camera2_stream_ops_t* w, + buffer_handle_t* buffer); + + static int set_crop(const camera2_stream_ops_t* w, + int left, int top, int right, int bottom); + }; // class StreamAdapter + + typedef List<sp<StreamAdapter> > StreamList; + StreamList mStreams; + + /** + * Adapter from an ANativeWindow interface to camera2 device stream ops. + * Also takes care of allocating/deallocating stream in device interface + */ + class ReprocessStreamAdapter: public camera2_stream_in_ops, public virtual RefBase { + public: + ReprocessStreamAdapter(camera2_device_t *d); + + ~ReprocessStreamAdapter(); + + /** + * Create a HAL device reprocess stream based on an existing output stream. + */ + status_t connectToDevice(const sp<StreamAdapter> &outputStream); + + status_t release(); + + /** + * Push buffer into stream for reprocessing. Takes ownership until it notifies + * that the buffer has been released + */ + status_t pushIntoStream(buffer_handle_t *handle, + const wp<BufferReleasedListener> &releaseListener); + + /** + * Get stream parameters. + * Only valid after a successful connectToDevice call. + */ + int getId() const { return mId; } + uint32_t getWidth() const { return mWidth; } + uint32_t getHeight() const { return mHeight; } + uint32_t getFormat() const { return mFormat; } + + // Dump stream information + status_t dump(int fd, const Vector<String16>& args); + + private: + enum { + ERROR = -1, + RELEASED = 0, + ACTIVE + } mState; + + sp<ANativeWindow> mConsumerInterface; + wp<StreamAdapter> mBaseStream; + + struct QueueEntry { + buffer_handle_t *handle; + wp<BufferReleasedListener> releaseListener; + }; + + List<QueueEntry> mQueue; + + List<QueueEntry> mInFlightQueue; + + camera2_device_t *mHal2Device; + + uint32_t mId; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mFormat; + + /** Debugging information */ + uint32_t mActiveBuffers; + uint32_t mFrameCount; + int64_t mLastTimestamp; + + const camera2_stream_in_ops *getStreamOps(); + + static int acquire_buffer(const camera2_stream_in_ops_t *w, + buffer_handle_t** buffer); + + static int release_buffer(const camera2_stream_in_ops_t* w, + buffer_handle_t* buffer); + + }; // class ReprocessStreamAdapter + + typedef List<sp<ReprocessStreamAdapter> > ReprocessStreamList; + ReprocessStreamList mReprocessStreams; + + // Receives HAL notifications and routes them to the NotificationListener + static void notificationCallback(int32_t msg_type, + int32_t ext1, + int32_t ext2, + int32_t ext3, + void *user); + +}; // class Camera2Device + +}; // namespace android + +#endif |