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
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