Camera service: Minimally functional preview for camera 2 devices.

- Camera app starts up
- Basic preview operation with defaults
- Shutdown sequence is very minimal

Bug: 6243944

Change-Id: I67673b7c1fc08956d218d99f9171e74a7a82bf07
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 4b0cfc4..bd62fa1 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -26,11 +26,12 @@
         mId(id),
         mDevice(NULL)
 {
-
+    ALOGV("%s: E", __FUNCTION__);
 }
 
 Camera2Device::~Camera2Device()
 {
+    ALOGV("%s: E", __FUNCTION__);
     if (mDevice) {
         status_t res;
         res = mDevice->common.close(&mDevice->common);
@@ -45,6 +46,8 @@
 
 status_t Camera2Device::initialize(camera_module_t *module)
 {
+    ALOGV("%s: E", __FUNCTION__);
+
     status_t res;
     char name[10];
     snprintf(name, sizeof(name), "%d", mId);
@@ -79,26 +82,90 @@
 
     mDeviceInfo = info.static_camera_characteristics;
 
-    res = mDevice->ops->set_request_queue_src_ops(mDevice,
-            mRequestQueue.getToConsumerInterface());
-    if (res != OK) return res;
-
-    res = mDevice->ops->set_frame_queue_dst_ops(mDevice,
-            mFrameQueue.getToProducerInterface());
-    if (res != OK) return res;
+    res = mRequestQueue.setConsumerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
+    res = mFrameQueue.setProducerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
 
     res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
-    if (res != OK ) return res;
+    if (res != OK ) {
+        ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
 
     return OK;
 }
 
+camera_metadata_t *Camera2Device::info() {
+    ALOGV("%s: E", __FUNCTION__);
+
+    return mDeviceInfo;
+}
+
 status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
 {
+    ALOGV("%s: E", __FUNCTION__);
+
     mRequestQueue.setStreamSlot(request);
     return OK;
 }
 
+status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format, int *id) {
+    status_t res;
+    ALOGV("%s: E", __FUNCTION__);
+
+    sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+
+    res = stream->connectToDevice(consumer, width, height, format);
+    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::deleteStream(int id) {
+    ALOGV("%s: E", __FUNCTION__);
+
+    bool found = false;
+    for (StreamList::iterator streamI = mStreams.begin();
+         streamI != mStreams.end(); streamI++) {
+        if ((*streamI)->getId() == id) {
+            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::createDefaultRequest(int templateId,
+        camera_metadata_t **request) {
+    ALOGV("%s: E", __FUNCTION__);
+    return mDevice->ops->construct_default_request(mDevice, templateId, request);
+}
+
 /**
  * Camera2Device::MetadataQueue
  */
@@ -125,39 +192,32 @@
     freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
 }
 
-// Interface to camera2 HAL as consumer (input requests/reprocessing)
-const camera2_request_queue_src_ops_t*
-Camera2Device::MetadataQueue::getToConsumerInterface() {
-    return static_cast<camera2_request_queue_src_ops_t*>(this);
-}
-
-void Camera2Device::MetadataQueue::setFromConsumerInterface(camera2_device_t *d) {
-    Mutex::Autolock l(mMutex);
+// Connect to camera2 HAL as consumer (input requests/reprocessing)
+status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
+    status_t res;
+    res = d->ops->set_request_queue_src_ops(d,
+            this);
+    if (res != OK) return res;
     mDevice = d;
+    return OK;
 }
 
-const camera2_frame_queue_dst_ops_t*
-Camera2Device::MetadataQueue::getToProducerInterface() {
-    return static_cast<camera2_frame_queue_dst_ops_t*>(this);
+status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
+    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) {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
 
     mCount++;
     mEntries.push_back(buf);
-    notEmpty.signal();
 
-    if (mSignalConsumer && mDevice != NULL) {
-        mSignalConsumer = false;
-
-        mMutex.unlock();
-        ALOGV("%s: Signaling consumer", __FUNCTION__);
-        mDevice->ops->notify_request_queue_not_empty(mDevice);
-        mMutex.lock();
-    }
-    return OK;
+    return signalConsumerLocked();
 }
 
 int Camera2Device::MetadataQueue::getBufferCount() {
@@ -171,6 +231,8 @@
 status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
         bool incrementCount)
 {
+    ALOGV("%s: E", __FUNCTION__);
+    status_t res;
     Mutex::Autolock l(mMutex);
 
     if (mCount == 0) {
@@ -201,9 +263,16 @@
     mEntries.erase(mEntries.begin());
 
     if (incrementCount) {
-        add_camera_metadata_entry(b,
+        camera_metadata_entry_t frameCount;
+        res = find_camera_metadata_entry(b,
                 ANDROID_REQUEST_FRAME_COUNT,
-                (void**)&mFrameCount, 1);
+                &frameCount);
+        if (res != OK) {
+            ALOGE("%s: Unable to add frame count: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+        } else {
+            *frameCount.data.i32 = mFrameCount;
+        }
         mFrameCount++;
     }
 
@@ -226,6 +295,7 @@
 
 status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
 {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
     if (buf == NULL) {
         freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
@@ -244,20 +314,34 @@
         mStreamSlot.push_front(buf);
         mStreamSlotCount = 1;
     }
-    return OK;
+    return signalConsumerLocked();
 }
 
 status_t Camera2Device::MetadataQueue::setStreamSlot(
         const List<camera_metadata_t*> &bufs)
 {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
     if (mStreamSlotCount > 0) {
         freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
     }
     mStreamSlot = bufs;
     mStreamSlotCount = mStreamSlot.size();
+    return signalConsumerLocked();
+}
 
-    return OK;
+status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
+    status_t res = OK;
+    notEmpty.signal();
+    if (mSignalConsumer && mDevice != NULL) {
+        mSignalConsumer = false;
+
+        mMutex.unlock();
+        ALOGV("%s: Signaling consumer", __FUNCTION__);
+        res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+        mMutex.lock();
+    }
+    return res;
 }
 
 status_t Camera2Device::MetadataQueue::freeBuffers(
@@ -337,5 +421,268 @@
     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(DISCONNECTED),
+        mDevice(d),
+        mId(-1),
+        mWidth(0), mHeight(0), mFormatRequested(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() {
+    disconnect();
+}
+
+status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format) {
+    status_t res;
+
+    if (mState != DISCONNECTED) return INVALID_OPERATION;
+    if (consumer == NULL) {
+        ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    mConsumerInterface = consumer;
+    mWidth = width;
+    mHeight = height;
+    mFormatRequested = format;
+
+    // Allocate device-side stream interface
+
+    uint32_t id;
+    uint32_t formatActual;
+    uint32_t usage;
+    uint32_t maxBuffers = 2;
+    res = mDevice->ops->allocate_stream(mDevice,
+            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;
+    }
+
+    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_buffers_geometry(mConsumerInterface.get(),
+            mWidth, mHeight, mFormat);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure 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: Producer wants %d buffers, consumer wants %d", __FUNCTION__,
+            mMaxProducerBuffers, mMaxConsumerBuffers);
+
+    int totalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
+
+    res = native_window_set_buffer_count(mConsumerInterface.get(),
+            totalBuffers);
+    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[totalBuffers];
+    ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[totalBuffers];
+    int bufferIdx = 0;
+    for (; bufferIdx < totalBuffers; bufferIdx++) {
+        res = mConsumerInterface->dequeueBuffer(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;
+        }
+
+        res = mConsumerInterface->lockBuffer(mConsumerInterface.get(),
+                anwBuffers[bufferIdx]);
+        if (res != OK) {
+            ALOGE("%s: Unable to lock buffer %d for initial registration for"
+                    "stream %d", __FUNCTION__, bufferIdx, mId);
+            bufferIdx++;
+            goto cleanUpBuffers;
+        }
+
+        buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
+    }
+
+    res = mDevice->ops->register_stream_buffers(mDevice,
+            mId,
+            totalBuffers,
+            buffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to register buffers with HAL device for stream %d",
+                __FUNCTION__, mId);
+    } else {
+        mState = ACTIVE;
+    }
+
+cleanUpBuffers:
+    for (int i = 0; i < bufferIdx; i++) {
+        res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
+                anwBuffers[i]);
+        if (res != OK) {
+            ALOGE("%s: Unable to cancel buffer %d after registration",
+                    __FUNCTION__, i);
+        }
+    }
+    delete anwBuffers;
+    delete buffers;
+
+    return res;
+}
+
+status_t Camera2Device::StreamAdapter::disconnect() {
+    status_t res;
+    if (mState >= ALLOCATED) {
+        res = mDevice->ops->release_stream(mDevice, 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);
+        if (res != OK) {
+            ALOGE("%s: Unable to disconnect stream %d from native window",
+                    __FUNCTION__, mId);
+            return res;
+        }
+    }
+    mId = -1;
+    mState = DISCONNECTED;
+    return OK;
+}
+
+int Camera2Device::StreamAdapter::getId() {
+    return mId;
+}
+
+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) {
+    int res;
+    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);
+    ANativeWindowBuffer* anb;
+    res = a->dequeueBuffer(a, &anb);
+    if (res != OK) return res;
+    res = a->lockBuffer(a, anb);
+    if (res != OK) return res;
+
+    *buffer = &(anb->handle);
+    ALOGV("%s: Buffer %p", __FUNCTION__, *buffer);
+    return res;
+}
+
+int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
+        int64_t timestamp,
+        buffer_handle_t* buffer) {
+    ALOGV("%s: Buffer %p captured at %lld ns", __FUNCTION__, buffer, timestamp);
+    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);
+    status_t err;
+    err = native_window_set_buffers_timestamp(a, timestamp);
+    if (err != OK) return err;
+    return a->queueBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
+        buffer_handle_t* buffer) {
+    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);
+    return a->cancelBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
+        int left, int top, int right, int bottom) {
+    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);
+}
+
 
 }; // namespace android