summaryrefslogtreecommitdiff
path: root/src/android/camera_device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/camera_device.cpp')
-rw-r--r--src/android/camera_device.cpp831
1 files changed, 831 insertions, 0 deletions
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
new file mode 100644
index 00000000..e2c1f2a2
--- /dev/null
+++ b/src/android/camera_device.cpp
@@ -0,0 +1,831 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * camera_device.cpp - libcamera Android Camera Device
+ */
+
+#include "camera_device.h"
+
+#include <system/camera_metadata.h>
+
+#include "log.h"
+
+#include "thread_rpc.h"
+
+using namespace libcamera;
+
+LOG_DECLARE_CATEGORY(HAL);
+
+/*
+ * \struct Camera3RequestDescriptor
+ *
+ * A utility structure that groups information about a capture request to be
+ * later re-used at request complete time to notify the framework.
+ */
+
+CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(
+ unsigned int frameNumber, unsigned int numBuffers)
+ : frameNumber(frameNumber), numBuffers(numBuffers)
+{
+ buffers = new camera3_stream_buffer_t[numBuffers];
+}
+
+CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor()
+{
+ delete[] buffers;
+}
+
+/*
+ * \class CameraDevice
+ *
+ * The CameraDevice class wraps a libcamera::Camera instance, and implements
+ * the camera_device_t interface by handling RPC requests received from its
+ * associated CameraProxy.
+ *
+ * It translate parameters and operations from Camera HALv3 API to the libcamera
+ * ones to provide static information for a Camera, create request templates
+ * for it, process capture requests and then deliver capture results back
+ * to the framework using the designated callbacks.
+ */
+
+CameraDevice::CameraDevice(unsigned int id, std::shared_ptr<Camera> &camera)
+ : running_(false), camera_(camera), staticMetadata_(nullptr),
+ requestTemplate_(nullptr)
+{
+ camera_->requestCompleted.connect(this, &CameraDevice::requestComplete);
+}
+
+CameraDevice::~CameraDevice()
+{
+ if (staticMetadata_)
+ free_camera_metadata(staticMetadata_);
+ staticMetadata_ = nullptr;
+
+ if (requestTemplate_)
+ free_camera_metadata(requestTemplate_);
+ requestTemplate_ = nullptr;
+}
+
+/*
+ * Handle RPC request received from the associated proxy.
+ */
+void CameraDevice::message(Message *message)
+{
+ if (message->type() != ThreadRpcMessage::type())
+ return Object::message(message);
+
+ ThreadRpcMessage *rpcMessage = static_cast<ThreadRpcMessage *>(message);
+ ThreadRpc *rpc = rpcMessage->rpc;
+
+ switch (rpc->tag) {
+ case ThreadRpc::ProcessCaptureRequest:
+ processCaptureRequest(rpc->request);
+ break;
+ case ThreadRpc::Close:
+ close();
+ break;
+ default:
+ LOG(HAL, Error) << "Unknown RPC operation: " << rpc->tag;
+ }
+
+ rpc->notifyReception();
+}
+
+int CameraDevice::open()
+{
+ int ret = camera_->acquire();
+ if (ret) {
+ LOG(HAL, Error) << "Failed to acquire the camera";
+ return ret;
+ }
+
+ return 0;
+}
+
+void CameraDevice::close()
+{
+ camera_->stop();
+
+ camera_->freeBuffers();
+ camera_->release();
+
+ running_ = false;
+}
+
+void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)
+{
+ callbacks_ = callbacks;
+}
+
+/*
+ * Return static information for the camera.
+ */
+camera_metadata_t *CameraDevice::getStaticMetadata()
+{
+ int ret;
+
+ if (staticMetadata_)
+ return staticMetadata_;
+
+ /*
+ * The here reported metadata are enough to implement a basic capture
+ * example application, but a real camera implementation will require
+ * more.
+ */
+
+ /* \todo Use correct sizes */
+ #define STATIC_ENTRY_CAP 256
+ #define STATIC_DATA_CAP 6688
+ camera_metadata_t *staticMetadata =
+ allocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);
+
+ /* Sensor static metadata. */
+ int32_t pixelArraySize[] = {
+ 2592, 1944,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+ &pixelArraySize, 2);
+ METADATA_ASSERT(ret);
+
+ int32_t sensorSizes[] = {
+ 0, 0, 2560, 1920,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ &sensorSizes, 4);
+ METADATA_ASSERT(ret);
+
+ int32_t sensitivityRange[] = {
+ 32, 2400,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
+ &sensitivityRange, 2);
+ METADATA_ASSERT(ret);
+
+ uint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
+ &filterArr, 1);
+ METADATA_ASSERT(ret);
+
+ int64_t exposureTimeRange[] = {
+ 100000, 200000000,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
+ &exposureTimeRange, 2);
+ METADATA_ASSERT(ret);
+
+ int32_t orientation = 0;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SENSOR_ORIENTATION,
+ &orientation, 1);
+ METADATA_ASSERT(ret);
+
+ /* Flash static metadata. */
+ char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_FLASH_INFO_AVAILABLE,
+ &flashAvailable, 1);
+ METADATA_ASSERT(ret);
+
+ /* Lens static metadata. */
+ float fn = 2.53 / 100;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_LENS_INFO_AVAILABLE_APERTURES, &fn, 1);
+ METADATA_ASSERT(ret);
+
+ /* Control metadata. */
+ char controlMetadata = ANDROID_CONTROL_MODE_AUTO;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_CONTROL_AVAILABLE_MODES,
+ &controlMetadata, 1);
+ METADATA_ASSERT(ret);
+
+ char availableAntiBandingModes[] = {
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+ availableAntiBandingModes, 4);
+ METADATA_ASSERT(ret);
+
+ char aeAvailableModes[] = {
+ ANDROID_CONTROL_AE_MODE_ON,
+ ANDROID_CONTROL_AE_MODE_OFF,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_CONTROL_AE_AVAILABLE_MODES,
+ aeAvailableModes, 2);
+ METADATA_ASSERT(ret);
+
+ controlMetadata = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+ &controlMetadata, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ &awbLockAvailable, 1);
+
+ /* Scaler static metadata. */
+ std::vector<uint32_t> availableStreamFormats = {
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SCALER_AVAILABLE_FORMATS,
+ availableStreamFormats.data(),
+ availableStreamFormats.size());
+ METADATA_ASSERT(ret);
+
+ std::vector<uint32_t> availableStreamConfigurations = {
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ availableStreamConfigurations.data(),
+ availableStreamConfigurations.size());
+ METADATA_ASSERT(ret);
+
+ std::vector<int64_t> availableStallDurations = {
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+ availableStallDurations.data(),
+ availableStallDurations.size());
+ METADATA_ASSERT(ret);
+
+ std::vector<int64_t> minFrameDurations = {
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920, 33333333,
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920, 33333333,
+ };
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ minFrameDurations.data(), minFrameDurations.size());
+ METADATA_ASSERT(ret);
+
+ /* Info static metadata. */
+ uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+ ret = add_camera_metadata_entry(staticMetadata,
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+ &supportedHWLevel, 1);
+
+ return staticMetadata;
+}
+
+/*
+ * Produce a metadata pack to be used as template for a capture request.
+ */
+const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)
+{
+ int ret;
+
+ /*
+ * \todo Inspect type and pick the right metadata pack.
+ * As of now just use a single one for all templates.
+ */
+ uint8_t captureIntent;
+ switch (type) {
+ case CAMERA3_TEMPLATE_PREVIEW:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+ break;
+ case CAMERA3_TEMPLATE_STILL_CAPTURE:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+ break;
+ case CAMERA3_TEMPLATE_VIDEO_RECORD:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+ break;
+ case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+ break;
+ case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
+ break;
+ case CAMERA3_TEMPLATE_MANUAL:
+ captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;
+ break;
+ default:
+ LOG(HAL, Error) << "Invalid template request type: " << type;
+ return nullptr;
+ }
+
+ if (requestTemplate_)
+ return requestTemplate_;
+
+ /* \todo Use correct sizes */
+ #define REQUEST_TEMPLATE_ENTRIES 30
+ #define REQUEST_TEMPLATE_DATA 2048
+ requestTemplate_ = allocate_camera_metadata(REQUEST_TEMPLATE_ENTRIES,
+ REQUEST_TEMPLATE_DATA);
+ if (!requestTemplate_) {
+ LOG(HAL, Error) << "Failed to allocate template metadata";
+ return nullptr;
+ }
+
+ /* Set to 0 the number of 'processed and stalling' streams (ie JPEG). */
+ int32_t maxOutStream[] = { 0, 2, 0 };
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+ maxOutStream, 3);
+ METADATA_ASSERT(ret);
+
+ uint8_t maxPipelineDepth = 5;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+ &maxPipelineDepth, 1);
+ METADATA_ASSERT(ret);
+
+ int32_t inputStreams = 0;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+ &inputStreams, 1);
+ METADATA_ASSERT(ret);
+
+ int32_t partialResultCount = 1;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+ &partialResultCount, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t availableCapabilities[] = {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
+ };
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ availableCapabilities, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AE_MODE,
+ &aeMode, 1);
+ METADATA_ASSERT(ret);
+
+ int32_t aeExposureCompensation = 0;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ &aeExposureCompensation, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ &aePrecaptureTrigger, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AE_LOCK,
+ &aeLock, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AF_TRIGGER,
+ &afTrigger, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AWB_MODE,
+ &awbMode, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AWB_LOCK,
+ &awbLock, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ &awbLockAvailable, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_FLASH_MODE,
+ &flashMode, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ &faceDetectMode, 1);
+ METADATA_ASSERT(ret);
+
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ &captureIntent, 1);
+ METADATA_ASSERT(ret);
+
+ /*
+ * This is quite hard to list at the moment wihtout knowing what
+ * we could control.
+ *
+ * For now, just list in the available Request keys and in the available
+ * result keys the control and reporting of the AE algorithm.
+ */
+ std::vector<int32_t> availableRequestKeys = {
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ ANDROID_CONTROL_AE_LOCK,
+ ANDROID_CONTROL_AF_TRIGGER,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_LOCK,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_FLASH_MODE,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ };
+
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
+ availableRequestKeys.data(),
+ availableRequestKeys.size());
+ METADATA_ASSERT(ret);
+
+ std::vector<int32_t> availableResultKeys = {
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ ANDROID_CONTROL_AE_LOCK,
+ ANDROID_CONTROL_AF_TRIGGER,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_LOCK,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_FLASH_MODE,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ };
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
+ availableResultKeys.data(),
+ availableResultKeys.size());
+ METADATA_ASSERT(ret);
+
+ /*
+ * \todo The available characteristics are be the tags reported
+ * as part of the static metadata reported at hal_get_camera_info()
+ * time. As of now, report an empty list.
+ */
+ std::vector<int32_t> availableCharacteristicsKeys = {};
+ ret = add_camera_metadata_entry(requestTemplate_,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+ availableCharacteristicsKeys.data(),
+ availableCharacteristicsKeys.size());
+ METADATA_ASSERT(ret);
+
+ return requestTemplate_;
+}
+
+/*
+ * Inspect the stream_list to produce a list of StreamConfiguration to
+ * be use to configure the Camera.
+ */
+int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
+{
+ for (unsigned int i = 0; i < stream_list->num_streams; ++i) {
+ camera3_stream_t *stream = stream_list->streams[i];
+
+ LOG(HAL, Info) << "Stream #" << i
+ << ", direction: " << stream->stream_type
+ << ", width: " << stream->width
+ << ", height: " << stream->height
+ << ", format: " << std::hex << stream->format;
+ }
+
+ /* Hardcode viewfinder role, collecting sizes from the stream config. */
+ if (stream_list->num_streams != 1) {
+ LOG(HAL, Error) << "Only one stream supported";
+ return -EINVAL;
+ }
+
+ StreamRoles roles = { StreamRole::Viewfinder };
+ config_ = camera_->generateConfiguration(roles);
+ if (!config_ || config_->empty()) {
+ LOG(HAL, Error) << "Failed to generate camera configuration";
+ return -EINVAL;
+ }
+
+ /* Only one stream is supported. */
+ camera3_stream_t *camera3Stream = stream_list->streams[0];
+ StreamConfiguration *streamConfiguration = &config_->at(0);
+ streamConfiguration->size.width = camera3Stream->width;
+ streamConfiguration->size.height = camera3Stream->height;
+ streamConfiguration->memoryType = ExternalMemory;
+
+ /*
+ * \todo We'll need to translate from Android defined pixel format codes
+ * to the libcamera image format codes. For now, do not change the
+ * format returned from Camera::generateConfiguration().
+ */
+
+ switch (config_->validate()) {
+ case CameraConfiguration::Valid:
+ break;
+ case CameraConfiguration::Adjusted:
+ LOG(HAL, Info) << "Camera configuration adjusted";
+ config_.reset();
+ return -EINVAL;
+ case CameraConfiguration::Invalid:
+ LOG(HAL, Info) << "Camera configuration invalid";
+ config_.reset();
+ return -EINVAL;
+ }
+
+ camera3Stream->max_buffers = streamConfiguration->bufferCount;
+
+ /*
+ * Once the CameraConfiguration has been adjusted/validated
+ * it can be applied to the camera.
+ */
+ int ret = camera_->configure(config_.get());
+ if (ret) {
+ LOG(HAL, Error) << "Failed to configure camera '"
+ << camera_->name() << "'";
+ return ret;
+ }
+
+ return 0;
+}
+
+int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)
+{
+ StreamConfiguration *streamConfiguration = &config_->at(0);
+ Stream *stream = streamConfiguration->stream();
+
+ if (camera3Request->num_output_buffers != 1) {
+ LOG(HAL, Error) << "Invalid number of output buffers: "
+ << camera3Request->num_output_buffers;
+ return -EINVAL;
+ }
+
+ /* Start the camera if that's the first request we handle. */
+ if (!running_) {
+ int ret = camera_->allocateBuffers();
+ if (ret) {
+ LOG(HAL, Error) << "Failed to allocate buffers";
+ return ret;
+ }
+
+ ret = camera_->start();
+ if (ret) {
+ LOG(HAL, Error) << "Failed to start camera";
+ camera_->freeBuffers();
+ return ret;
+ }
+
+ running_ = true;
+ }
+
+ /*
+ * Queue a request for the Camera with the provided dmabuf file
+ * descriptors.
+ */
+ const camera3_stream_buffer_t *camera3Buffers =
+ camera3Request->output_buffers;
+
+ /*
+ * Save the request descriptors for use at completion time.
+ * The descriptor and the associated memory reserved here are freed
+ * at request complete time.
+ */
+ Camera3RequestDescriptor *descriptor =
+ new Camera3RequestDescriptor(camera3Request->frame_number,
+ camera3Request->num_output_buffers);
+ for (unsigned int i = 0; i < descriptor->numBuffers; ++i) {
+ /*
+ * Keep track of which stream the request belongs to and store
+ * the native buffer handles.
+ *
+ * \todo Currently we only support one capture buffer. Copy
+ * all of them to be ready once we'll support more.
+ */
+ descriptor->buffers[i].stream = camera3Buffers[i].stream;
+ descriptor->buffers[i].buffer = camera3Buffers[i].buffer;
+ }
+
+ /*
+ * Create a libcamera buffer using the dmabuf descriptors of the first
+ * and (currently) only supported request buffer.
+ */
+ const buffer_handle_t camera3Handle = *camera3Buffers[0].buffer;
+ std::array<int, 3> fds = {
+ camera3Handle->data[0],
+ camera3Handle->data[1],
+ camera3Handle->data[2],
+ };
+
+ std::unique_ptr<Buffer> buffer = stream->createBuffer(fds);
+ if (!buffer) {
+ LOG(HAL, Error) << "Failed to create buffer";
+ delete descriptor;
+ return -EINVAL;
+ }
+
+ Request *request =
+ camera_->createRequest(reinterpret_cast<uint64_t>(descriptor));
+ request->addBuffer(std::move(buffer));
+
+ int ret = camera_->queueRequest(request);
+ if (ret) {
+ LOG(HAL, Error) << "Failed to queue request";
+ goto error;
+ }
+
+ return 0;
+
+error:
+ delete request;
+ delete descriptor;
+
+ return ret;
+}
+
+void CameraDevice::requestComplete(Request *request,
+ const std::map<Stream *, Buffer *> &buffers)
+{
+ Buffer *libcameraBuffer = buffers.begin()->second;
+ camera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;
+ camera_metadata_t *resultMetadata = nullptr;
+
+ if (request->status() != Request::RequestComplete) {
+ LOG(HAL, Error) << "Request not succesfully completed: "
+ << request->status();
+ status = CAMERA3_BUFFER_STATUS_ERROR;
+ }
+
+ /* Prepare to call back the Android camera stack. */
+ Camera3RequestDescriptor *descriptor =
+ reinterpret_cast<Camera3RequestDescriptor *>(request->cookie());
+
+ camera3_capture_result_t captureResult = {};
+ captureResult.frame_number = descriptor->frameNumber;
+ captureResult.num_output_buffers = descriptor->numBuffers;
+ for (unsigned int i = 0; i < descriptor->numBuffers; ++i) {
+ /*
+ * \todo Currently we only support one capture buffer. Prepare
+ * all of them to be ready once we'll support more.
+ */
+ descriptor->buffers[i].acquire_fence = -1;
+ descriptor->buffers[i].release_fence = -1;
+ descriptor->buffers[i].status = status;
+ }
+ captureResult.output_buffers =
+ const_cast<const camera3_stream_buffer_t *>(descriptor->buffers);
+
+ if (status == CAMERA3_BUFFER_STATUS_ERROR) {
+ /* \todo Improve error handling. */
+ notifyError(descriptor->frameNumber,
+ descriptor->buffers[0].stream);
+ } else {
+ notifyShutter(descriptor->frameNumber,
+ libcameraBuffer->timestamp());
+
+ captureResult.partial_result = 1;
+ resultMetadata = getResultMetadata(descriptor->frameNumber,
+ libcameraBuffer->timestamp());
+ captureResult.result = resultMetadata;
+ }
+
+ callbacks_->process_capture_result(callbacks_, &captureResult);
+
+ delete descriptor;
+ if (resultMetadata)
+ free_camera_metadata(resultMetadata);
+
+ return;
+}
+
+void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp)
+{
+ camera3_notify_msg_t notify = {};
+
+ notify.type = CAMERA3_MSG_SHUTTER;
+ notify.message.shutter.frame_number = frameNumber;
+ notify.message.shutter.timestamp = timestamp;
+
+ callbacks_->notify(callbacks_, &notify);
+}
+
+void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream)
+{
+ camera3_notify_msg_t notify = {};
+
+ notify.type = CAMERA3_MSG_ERROR;
+ notify.message.error.error_stream = stream;
+ notify.message.error.frame_number = frameNumber;
+ notify.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
+
+ callbacks_->notify(callbacks_, &notify);
+}
+
+/*
+ * Produce a set of fixed result metadata.
+ */
+camera_metadata_t *CameraDevice::getResultMetadata(int frame_number,
+ int64_t timestamp)
+{
+ int ret;
+
+ /* \todo Use correct sizes */
+ #define RESULT_ENTRY_CAP 256
+ #define RESULT_DATA_CAP 6688
+ camera_metadata_t *resultMetadata =
+ allocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);
+
+ const uint8_t ae_state = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ ret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_STATE,
+ &ae_state, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+ ret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_LOCK,
+ &ae_lock, 1);
+ METADATA_ASSERT(ret);
+
+ uint8_t af_state = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ ret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AF_STATE,
+ &af_state, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t awb_state = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_CONTROL_AWB_STATE,
+ &awb_state, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t awb_lock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_CONTROL_AWB_LOCK,
+ &awb_lock, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t lens_state = ANDROID_LENS_STATE_STATIONARY;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_LENS_STATE,
+ &lens_state, 1);
+ METADATA_ASSERT(ret);
+
+ int32_t sensorSizes[] = {
+ 0, 0, 2560, 1920,
+ };
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_SCALER_CROP_REGION,
+ sensorSizes, 4);
+ METADATA_ASSERT(ret);
+
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_SENSOR_TIMESTAMP,
+ &timestamp, 1);
+ METADATA_ASSERT(ret);
+
+ /* 33.3 msec */
+ const int64_t rolling_shutter_skew = 33300000;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
+ &rolling_shutter_skew, 1);
+ METADATA_ASSERT(ret);
+
+ /* 16.6 msec */
+ const int64_t exposure_time = 16600000;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_SENSOR_EXPOSURE_TIME,
+ &exposure_time, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t lens_shading_map_mode =
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+ &lens_shading_map_mode, 1);
+ METADATA_ASSERT(ret);
+
+ const uint8_t scene_flicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+ ret = add_camera_metadata_entry(resultMetadata,
+ ANDROID_STATISTICS_SCENE_FLICKER,
+ &scene_flicker, 1);
+ METADATA_ASSERT(ret);
+
+ return resultMetadata;
+}