[{"id":2384,"web_url":"https://patchwork.libcamera.org/comment/2384/","msgid":"<20190812094238.GA5006@pendragon.ideasonboard.com>","date":"2019-08-12T09:42:38","subject":"Re: [libcamera-devel] [PATCH v4 1/1] android: hal: Add Camera3 HAL","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Mon, Aug 12, 2019 at 10:41:46AM +0200, Jacopo Mondi wrote:\n> Add libcamera Android Camera HALv3 implementation.\n> \n> The initial camera HAL implementation supports the LIMITED hardware\n> level and uses statically defined metadata and camera characteristics.\n> \n> Add a build option named 'android' and adjust the build system to\n> selectively compile the Android camera HAL and link it against the\n> required Android libraries.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nGreat work !!\n\n> ---\n>  meson_options.txt                  |   5 +\n>  src/android/camera3_hal.cpp        | 111 ++++\n>  src/android/camera_device.cpp      | 831 +++++++++++++++++++++++++++++\n>  src/android/camera_device.h        |  71 +++\n>  src/android/camera_hal_manager.cpp | 138 +++++\n>  src/android/camera_hal_manager.h   |  47 ++\n>  src/android/camera_proxy.cpp       | 194 +++++++\n>  src/android/camera_proxy.h         |  45 ++\n>  src/android/meson.build            |   8 +\n>  src/android/thread_rpc.cpp         |  42 ++\n>  src/android/thread_rpc.h           |  54 ++\n>  src/libcamera/meson.build          |   9 +\n>  src/meson.build                    |   5 +-\n>  13 files changed, 1559 insertions(+), 1 deletion(-)\n>  create mode 100644 src/android/camera3_hal.cpp\n>  create mode 100644 src/android/camera_device.cpp\n>  create mode 100644 src/android/camera_device.h\n>  create mode 100644 src/android/camera_hal_manager.cpp\n>  create mode 100644 src/android/camera_hal_manager.h\n>  create mode 100644 src/android/camera_proxy.cpp\n>  create mode 100644 src/android/camera_proxy.h\n>  create mode 100644 src/android/thread_rpc.cpp\n>  create mode 100644 src/android/thread_rpc.h\n> \n> diff --git a/meson_options.txt b/meson_options.txt\n> index 97efc85b4412..2d78b8d91f9c 100644\n> --- a/meson_options.txt\n> +++ b/meson_options.txt\n> @@ -1,3 +1,8 @@\n> +option('android',\n> +        type : 'boolean',\n> +        value : false,\n> +        description : 'Compile libcamera with Android Camera3 HAL interface')\n> +\n>  option('documentation',\n>          type : 'boolean',\n>          description : 'Generate the project documentation')\n> diff --git a/src/android/camera3_hal.cpp b/src/android/camera3_hal.cpp\n> new file mode 100644\n> index 000000000000..8d2629ca356c\n> --- /dev/null\n> +++ b/src/android/camera3_hal.cpp\n> @@ -0,0 +1,111 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera3_hal.cpp - Android Camera HALv3 module\n> + */\n> +\n> +#include <hardware/camera_common.h>\n> +\n> +#include \"camera_hal_manager.h\"\n> +#include \"camera_proxy.h\"\n> +#include \"log.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DEFINE_CATEGORY(HAL)\n> +\n> +static CameraHalManager cameraManager;\n> +\n> +/*------------------------------------------------------------------------------\n> + * Android Camera HAL callbacks\n> + */\n> +\n> +static int hal_get_number_of_cameras(void)\n> +{\n> +\treturn cameraManager.numCameras();\n> +}\n> +\n> +static int hal_get_camera_info(int id, struct camera_info *info)\n> +{\n> +\treturn cameraManager.getCameraInfo(id, info);\n> +}\n> +\n> +static int hal_set_callbacks(const camera_module_callbacks_t *callbacks)\n> +{\n> +\treturn 0;\n> +}\n> +\n> +static int hal_open_legacy(const struct hw_module_t *module, const char *id,\n> +\t\t\t   uint32_t halVersion, struct hw_device_t **device)\n> +{\n> +\treturn -ENOSYS;\n> +}\n> +\n> +static int hal_set_torch_mode(const char *camera_id, bool enabled)\n> +{\n> +\treturn -ENOSYS;\n> +}\n> +\n> +/*\n> + * First entry point of the camera HAL module.\n> + *\n> + * Initialize the HAL but does not open any camera device yet (see hal_dev_open)\n> + */\n> +static int hal_init()\n> +{\n> +\tLOG(HAL, Info) << \"Initialising Android camera HAL\";\n> +\n> +\tcameraManager.init();\n> +\n> +\treturn 0;\n> +}\n> +\n> +/*------------------------------------------------------------------------------\n> + * Android Camera Device\n> + */\n> +\n> +static int hal_dev_open(const hw_module_t *module, const char *name,\n> +\t\t\thw_device_t **device)\n> +{\n> +\tLOG(HAL, Debug) << \"Open camera \" << name;\n> +\n> +\tint id = atoi(name);\n> +\tCameraProxy *proxy = cameraManager.open(id, module);\n> +\tif (!proxy) {\n> +\t\tLOG(HAL, Error)\n> +\t\t\t<< \"Failed to open camera module '\" << id << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\t*device = &proxy->camera3Device()->common;\n> +\n> +\treturn 0;\n> +}\n> +\n> +static struct hw_module_methods_t hal_module_methods = {\n> +\t.open = hal_dev_open,\n> +};\n> +\n> +camera_module_t HAL_MODULE_INFO_SYM = {\n> +\t.common = {\n> +\t\t.tag = HARDWARE_MODULE_TAG,\n> +\t\t.module_api_version = CAMERA_MODULE_API_VERSION_2_4,\n> +\t\t.hal_api_version = HARDWARE_HAL_API_VERSION,\n> +\t\t.id = CAMERA_HARDWARE_MODULE_ID,\n> +\t\t.name = \"libcamera camera HALv3 module\",\n> +\t\t.author = \"libcamera\",\n> +\t\t.methods = &hal_module_methods,\n> +\t\t.dso = nullptr,\n> +\t\t.reserved = {},\n> +\t},\n> +\n> +\t.get_number_of_cameras = hal_get_number_of_cameras,\n> +\t.get_camera_info = hal_get_camera_info,\n> +\t.set_callbacks = hal_set_callbacks,\n> +\t.get_vendor_tag_ops = nullptr,\n> +\t.open_legacy = hal_open_legacy,\n> +\t.set_torch_mode = hal_set_torch_mode,\n> +\t.init = hal_init,\n> +\t.reserved = {},\n> +};\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> new file mode 100644\n> index 000000000000..e2c1f2a246c8\n> --- /dev/null\n> +++ b/src/android/camera_device.cpp\n> @@ -0,0 +1,831 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_device.cpp - libcamera Android Camera Device\n> + */\n> +\n> +#include \"camera_device.h\"\n> +\n> +#include <system/camera_metadata.h>\n> +\n> +#include \"log.h\"\n> +\n> +#include \"thread_rpc.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\n> +\n> +/*\n> + * \\struct Camera3RequestDescriptor\n> + *\n> + * A utility structure that groups information about a capture request to be\n> + * later re-used at request complete time to notify the framework.\n> + */\n> +\n> +CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(\n> +\t\tunsigned int frameNumber, unsigned int numBuffers)\n> +\t: frameNumber(frameNumber), numBuffers(numBuffers)\n> +{\n> +\tbuffers = new camera3_stream_buffer_t[numBuffers];\n> +}\n> +\n> +CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor()\n> +{\n> +\tdelete[] buffers;\n> +}\n> +\n> +/*\n> + * \\class CameraDevice\n> + *\n> + * The CameraDevice class wraps a libcamera::Camera instance, and implements\n> + * the camera_device_t interface by handling RPC requests received from its\n> + * associated CameraProxy.\n> + *\n> + * It translate parameters and operations from Camera HALv3 API to the libcamera\n> + * ones to provide static information for a Camera, create request templates\n> + * for it, process capture requests and then deliver capture results back\n> + * to the framework using the designated callbacks.\n> + */\n> +\n> +CameraDevice::CameraDevice(unsigned int id, std::shared_ptr<Camera> &camera)\n> +\t: running_(false), camera_(camera), staticMetadata_(nullptr),\n> +\t  requestTemplate_(nullptr)\n> +{\n> +\tcamera_->requestCompleted.connect(this, &CameraDevice::requestComplete);\n> +}\n> +\n> +CameraDevice::~CameraDevice()\n> +{\n> +\tif (staticMetadata_)\n> +\t\tfree_camera_metadata(staticMetadata_);\n> +\tstaticMetadata_ = nullptr;\n> +\n> +\tif (requestTemplate_)\n> +\t\tfree_camera_metadata(requestTemplate_);\n> +\trequestTemplate_ = nullptr;\n> +}\n> +\n> +/*\n> + * Handle RPC request received from the associated proxy.\n> + */\n> +void CameraDevice::message(Message *message)\n> +{\n> +\tif (message->type() != ThreadRpcMessage::type())\n> +\t\treturn Object::message(message);\n> +\n> +\tThreadRpcMessage *rpcMessage = static_cast<ThreadRpcMessage *>(message);\n> +\tThreadRpc *rpc = rpcMessage->rpc;\n> +\n> +\tswitch (rpc->tag) {\n> +\tcase ThreadRpc::ProcessCaptureRequest:\n> +\t\tprocessCaptureRequest(rpc->request);\n> +\t\tbreak;\n> +\tcase ThreadRpc::Close:\n> +\t\tclose();\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tLOG(HAL, Error) << \"Unknown RPC operation: \" << rpc->tag;\n> +\t}\n> +\n> +\trpc->notifyReception();\n> +}\n> +\n> +int CameraDevice::open()\n> +{\n> +\tint ret = camera_->acquire();\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to acquire the camera\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +void CameraDevice::close()\n> +{\n> +\tcamera_->stop();\n> +\n> +\tcamera_->freeBuffers();\n> +\tcamera_->release();\n> +\n> +\trunning_ = false;\n> +}\n> +\n> +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> +{\n> +\tcallbacks_ = callbacks;\n> +}\n> +\n> +/*\n> + * Return static information for the camera.\n> + */\n> +camera_metadata_t *CameraDevice::getStaticMetadata()\n> +{\n> +\tint ret;\n> +\n> +\tif (staticMetadata_)\n> +\t\treturn staticMetadata_;\n> +\n> +\t/*\n> +\t * The here reported metadata are enough to implement a basic capture\n> +\t * example application, but a real camera implementation will require\n> +\t * more.\n> +\t */\n> +\n> +\t/* \\todo Use correct sizes */\n> +\t#define STATIC_ENTRY_CAP 256\n> +\t#define STATIC_DATA_CAP 6688\n> +\tcamera_metadata_t *staticMetadata =\n> +\t\tallocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);\n> +\n> +\t/* Sensor static metadata. */\n> +\tint32_t pixelArraySize[] = {\n> +\t\t2592, 1944,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> +\t\t\t\t&pixelArraySize, 2);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t sensorSizes[] = {\n> +\t\t0, 0, 2560, 1920,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> +\t\t\t\t&sensorSizes, 4);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t sensitivityRange[] = {\n> +\t\t32, 2400,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> +\t\t\t\t&sensitivityRange, 2);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> +\t\t\t\t&filterArr, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint64_t exposureTimeRange[] = {\n> +\t\t100000, 200000000,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> +\t\t\t\t&exposureTimeRange, 2);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t orientation = 0;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_SENSOR_ORIENTATION,\n> +\t\t\t\t&orientation, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* Flash static metadata. */\n> +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_FLASH_INFO_AVAILABLE,\n> +\t\t\t&flashAvailable, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* Lens static metadata. */\n> +\tfloat fn = 2.53 / 100;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES, &fn, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* Control metadata. */\n> +\tchar controlMetadata = ANDROID_CONTROL_MODE_AUTO;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> +\t\t\t&controlMetadata, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tchar availableAntiBandingModes[] = {\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> +\t\t\tavailableAntiBandingModes, 4);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tchar aeAvailableModes[] = {\n> +\t\tANDROID_CONTROL_AE_MODE_ON,\n> +\t\tANDROID_CONTROL_AE_MODE_OFF,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> +\t\t\taeAvailableModes, 2);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tcontrolMetadata = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> +\t\t\t&controlMetadata, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\t\t&awbLockAvailable, 1);\n> +\n> +\t/* Scaler static metadata. */\n> +\tstd::vector<uint32_t> availableStreamFormats = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_SCALER_AVAILABLE_FORMATS,\n> +\t\t\tavailableStreamFormats.data(),\n> +\t\t\tavailableStreamFormats.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tstd::vector<uint32_t> availableStreamConfigurations = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920,\n> +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920,\n> +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920,\n> +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> +\t\t\tavailableStreamConfigurations.data(),\n> +\t\t\tavailableStreamConfigurations.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tstd::vector<int64_t> availableStallDurations = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> +\t\t\tavailableStallDurations.data(),\n> +\t\t\tavailableStallDurations.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tstd::vector<int64_t> minFrameDurations = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920, 33333333,\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920, 33333333,\n> +\t};\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> +\t\t\tminFrameDurations.data(), minFrameDurations.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* Info static metadata. */\n> +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> +\tret = add_camera_metadata_entry(staticMetadata,\n> +\t\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> +\t\t\t&supportedHWLevel, 1);\n> +\n> +\treturn staticMetadata;\n> +}\n> +\n> +/*\n> + * Produce a metadata pack to be used as template for a capture request.\n> + */\n> +const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> +{\n> +\tint ret;\n> +\n> +\t/*\n> +\t * \\todo Inspect type and pick the right metadata pack.\n> +\t * As of now just use a single one for all templates.\n> +\t */\n> +\tuint8_t captureIntent;\n> +\tswitch (type) {\n> +\tcase CAMERA3_TEMPLATE_PREVIEW:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> +\t\tbreak;\n> +\tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> +\t\tbreak;\n> +\tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> +\t\tbreak;\n> +\tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> +\t\tbreak;\n> +\tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;\n> +\t\tbreak;\n> +\tcase CAMERA3_TEMPLATE_MANUAL:\n> +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tLOG(HAL, Error) << \"Invalid template request type: \" << type;\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\tif (requestTemplate_)\n> +\t\treturn requestTemplate_;\n> +\n> +\t/* \\todo Use correct sizes */\n> +\t#define REQUEST_TEMPLATE_ENTRIES\t  30\n> +\t#define REQUEST_TEMPLATE_DATA\t\t2048\n> +\trequestTemplate_ = allocate_camera_metadata(REQUEST_TEMPLATE_ENTRIES,\n> +\t\t\t\t\t\t    REQUEST_TEMPLATE_DATA);\n> +\tif (!requestTemplate_) {\n> +\t\tLOG(HAL, Error) << \"Failed to allocate template metadata\";\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\t/* Set to 0 the number of 'processed and stalling' streams (ie JPEG). */\n> +\tint32_t maxOutStream[] = { 0, 2, 0 };\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> +\t\t\tmaxOutStream, 3);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t maxPipelineDepth = 5;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> +\t\t\t&maxPipelineDepth, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t inputStreams = 0;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> +\t\t\t&inputStreams, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t partialResultCount = 1;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> +\t\t\t&partialResultCount, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t availableCapabilities[] = {\n> +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> +\t};\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> +\t\t\tavailableCapabilities, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AE_MODE,\n> +\t\t\t&aeMode, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t aeExposureCompensation = 0;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\t\t&aeExposureCompensation, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\t\t&aePrecaptureTrigger, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\t\t&aeLock, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\t\t&afTrigger, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\t\t&awbMode, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\t\t&awbLock, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\t\t&awbLockAvailable, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_FLASH_MODE,\n> +\t\t\t&flashMode, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t\t\t&faceDetectMode, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\t\t&captureIntent, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/*\n> +\t * This is quite hard to list at the moment wihtout knowing what\n> +\t * we could control.\n> +\t *\n> +\t * For now, just list in the available Request keys and in the available\n> +\t * result keys the control and reporting of the AE algorithm.\n> +\t */\n> +\tstd::vector<int32_t> availableRequestKeys = {\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t};\n> +\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> +\t\t\tavailableRequestKeys.data(),\n> +\t\t\tavailableRequestKeys.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tstd::vector<int32_t> availableResultKeys = {\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t};\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> +\t\t\tavailableResultKeys.data(),\n> +\t\t\tavailableResultKeys.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/*\n> +\t * \\todo The available characteristics are be the tags reported\n> +\t * as part of the static metadata reported at hal_get_camera_info()\n> +\t * time. As of now, report an empty list.\n> +\t */\n> +\tstd::vector<int32_t> availableCharacteristicsKeys = {};\n> +\tret = add_camera_metadata_entry(requestTemplate_,\n> +\t\t\tANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> +\t\t\tavailableCharacteristicsKeys.data(),\n> +\t\t\tavailableCharacteristicsKeys.size());\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\treturn requestTemplate_;\n> +}\n> +\n> +/*\n> + * Inspect the stream_list to produce a list of StreamConfiguration to\n> + * be use to configure the Camera.\n> + */\n> +int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> +{\n> +\tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> +\t\tcamera3_stream_t *stream = stream_list->streams[i];\n> +\n> +\t\tLOG(HAL, Info) << \"Stream #\" << i\n> +\t\t\t       << \", direction: \" << stream->stream_type\n> +\t\t\t       << \", width: \" << stream->width\n> +\t\t\t       << \", height: \" << stream->height\n> +\t\t\t       << \", format: \" << std::hex << stream->format;\n> +\t}\n> +\n> +\t/* Hardcode viewfinder role, collecting sizes from the stream config. */\n> +\tif (stream_list->num_streams != 1) {\n> +\t\tLOG(HAL, Error) << \"Only one stream supported\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tStreamRoles roles = { StreamRole::Viewfinder };\n> +\tconfig_ = camera_->generateConfiguration(roles);\n> +\tif (!config_ || config_->empty()) {\n> +\t\tLOG(HAL, Error) << \"Failed to generate camera configuration\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\t/* Only one stream is supported. */\n> +\tcamera3_stream_t *camera3Stream = stream_list->streams[0];\n> +\tStreamConfiguration *streamConfiguration = &config_->at(0);\n> +\tstreamConfiguration->size.width = camera3Stream->width;\n> +\tstreamConfiguration->size.height = camera3Stream->height;\n> +\tstreamConfiguration->memoryType = ExternalMemory;\n> +\n> +\t/*\n> +\t * \\todo We'll need to translate from Android defined pixel format codes\n> +\t * to the libcamera image format codes. For now, do not change the\n> +\t * format returned from Camera::generateConfiguration().\n> +\t */\n> +\n> +\tswitch (config_->validate()) {\n> +\tcase CameraConfiguration::Valid:\n> +\t\tbreak;\n> +\tcase CameraConfiguration::Adjusted:\n> +\t\tLOG(HAL, Info) << \"Camera configuration adjusted\";\n> +\t\tconfig_.reset();\n> +\t\treturn -EINVAL;\n> +\tcase CameraConfiguration::Invalid:\n> +\t\tLOG(HAL, Info) << \"Camera configuration invalid\";\n> +\t\tconfig_.reset();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tcamera3Stream->max_buffers = streamConfiguration->bufferCount;\n> +\n> +\t/*\n> +\t * Once the CameraConfiguration has been adjusted/validated\n> +\t * it can be applied to the camera.\n> +\t */\n> +\tint ret = camera_->configure(config_.get());\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to configure camera '\"\n> +\t\t\t\t<< camera_->name() << \"'\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)\n> +{\n> +\tStreamConfiguration *streamConfiguration = &config_->at(0);\n> +\tStream *stream = streamConfiguration->stream();\n> +\n> +\tif (camera3Request->num_output_buffers != 1) {\n> +\t\tLOG(HAL, Error) << \"Invalid number of output buffers: \"\n> +\t\t\t\t<< camera3Request->num_output_buffers;\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\t/* Start the camera if that's the first request we handle. */\n> +\tif (!running_) {\n> +\t\tint ret = camera_->allocateBuffers();\n> +\t\tif (ret) {\n> +\t\t\tLOG(HAL, Error) << \"Failed to allocate buffers\";\n> +\t\t\treturn ret;\n> +\t\t}\n> +\n> +\t\tret = camera_->start();\n> +\t\tif (ret) {\n> +\t\t\tLOG(HAL, Error) << \"Failed to start camera\";\n> +\t\t\tcamera_->freeBuffers();\n> +\t\t\treturn ret;\n> +\t\t}\n> +\n> +\t\trunning_ = true;\n> +\t}\n> +\n> +\t/*\n> +\t * Queue a request for the Camera with the provided dmabuf file\n> +\t * descriptors.\n> +\t */\n> +\tconst camera3_stream_buffer_t *camera3Buffers =\n> +\t\t\t\t\tcamera3Request->output_buffers;\n> +\n> +\t/*\n> +\t * Save the request descriptors for use at completion time.\n> +\t * The descriptor and the associated memory reserved here are freed\n> +\t * at request complete time.\n> +\t */\n> +\tCamera3RequestDescriptor *descriptor =\n> +\t\tnew Camera3RequestDescriptor(camera3Request->frame_number,\n> +\t\t\t\t\t     camera3Request->num_output_buffers);\n> +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> +\t\t/*\n> +\t\t * Keep track of which stream the request belongs to and store\n> +\t\t * the native buffer handles.\n> +\t\t *\n> +\t\t * \\todo Currently we only support one capture buffer. Copy\n> +\t\t * all of them to be ready once we'll support more.\n> +\t\t */\n> +\t\tdescriptor->buffers[i].stream = camera3Buffers[i].stream;\n> +\t\tdescriptor->buffers[i].buffer = camera3Buffers[i].buffer;\n> +\t}\n> +\n> +\t/*\n> +\t * Create a libcamera buffer using the dmabuf descriptors of the first\n> +\t * and (currently) only supported request buffer.\n> +\t */\n> +\tconst buffer_handle_t camera3Handle = *camera3Buffers[0].buffer;\n> +\tstd::array<int, 3> fds = {\n> +\t\tcamera3Handle->data[0],\n> +\t\tcamera3Handle->data[1],\n> +\t\tcamera3Handle->data[2],\n> +\t};\n> +\n> +\tstd::unique_ptr<Buffer> buffer = stream->createBuffer(fds);\n> +\tif (!buffer) {\n> +\t\tLOG(HAL, Error) << \"Failed to create buffer\";\n> +\t\tdelete descriptor;\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tRequest *request =\n> +\t\tcamera_->createRequest(reinterpret_cast<uint64_t>(descriptor));\n> +\trequest->addBuffer(std::move(buffer));\n> +\n> +\tint ret = camera_->queueRequest(request);\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to queue request\";\n> +\t\tgoto error;\n> +\t}\n> +\n> +\treturn 0;\n> +\n> +error:\n> +\tdelete request;\n> +\tdelete descriptor;\n> +\n> +\treturn ret;\n> +}\n> +\n> +void CameraDevice::requestComplete(Request *request,\n> +\t\t\t\t   const std::map<Stream *, Buffer *> &buffers)\n> +{\n> +\tBuffer *libcameraBuffer = buffers.begin()->second;\n> +\tcamera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;\n> +\tcamera_metadata_t *resultMetadata = nullptr;\n> +\n> +\tif (request->status() != Request::RequestComplete) {\n> +\t\tLOG(HAL, Error) << \"Request not succesfully completed: \"\n> +\t\t\t\t<< request->status();\n> +\t\tstatus = CAMERA3_BUFFER_STATUS_ERROR;\n> +\t}\n> +\n> +\t/* Prepare to call back the Android camera stack. */\n> +\tCamera3RequestDescriptor *descriptor =\n> +\t\treinterpret_cast<Camera3RequestDescriptor *>(request->cookie());\n> +\n> +\tcamera3_capture_result_t captureResult = {};\n> +\tcaptureResult.frame_number = descriptor->frameNumber;\n> +\tcaptureResult.num_output_buffers = descriptor->numBuffers;\n> +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> +\t\t/*\n> +\t\t * \\todo Currently we only support one capture buffer. Prepare\n> +\t\t * all of them to be ready once we'll support more.\n> +\t\t */\n> +\t\tdescriptor->buffers[i].acquire_fence = -1;\n> +\t\tdescriptor->buffers[i].release_fence = -1;\n> +\t\tdescriptor->buffers[i].status = status;\n> +\t}\n> +\tcaptureResult.output_buffers =\n> +\t\tconst_cast<const camera3_stream_buffer_t *>(descriptor->buffers);\n> +\n> +\tif (status == CAMERA3_BUFFER_STATUS_ERROR) {\n> +\t\t/* \\todo Improve error handling. */\n> +\t\tnotifyError(descriptor->frameNumber,\n> +\t\t\t    descriptor->buffers[0].stream);\n> +\t} else {\n> +\t\tnotifyShutter(descriptor->frameNumber,\n> +\t\t\t      libcameraBuffer->timestamp());\n> +\n> +\t\tcaptureResult.partial_result = 1;\n> +\t\tresultMetadata = getResultMetadata(descriptor->frameNumber,\n> +\t\t\t\t\t\t   libcameraBuffer->timestamp());\n> +\t\tcaptureResult.result = resultMetadata;\n> +\t}\n> +\n> +\tcallbacks_->process_capture_result(callbacks_, &captureResult);\n> +\n> +\tdelete descriptor;\n> +\tif (resultMetadata)\n> +\t\tfree_camera_metadata(resultMetadata);\n> +\n> +\treturn;\n> +}\n> +\n> +void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp)\n> +{\n> +\tcamera3_notify_msg_t notify = {};\n> +\n> +\tnotify.type = CAMERA3_MSG_SHUTTER;\n> +\tnotify.message.shutter.frame_number = frameNumber;\n> +\tnotify.message.shutter.timestamp = timestamp;\n> +\n> +\tcallbacks_->notify(callbacks_, &notify);\n> +}\n> +\n> +void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream)\n> +{\n> +\tcamera3_notify_msg_t notify = {};\n> +\n> +\tnotify.type = CAMERA3_MSG_ERROR;\n> +\tnotify.message.error.error_stream = stream;\n> +\tnotify.message.error.frame_number = frameNumber;\n> +\tnotify.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;\n> +\n> +\tcallbacks_->notify(callbacks_, &notify);\n> +}\n> +\n> +/*\n> + * Produce a set of fixed result metadata.\n> + */\n> +camera_metadata_t *CameraDevice::getResultMetadata(int frame_number,\n> +\t\t\t\t\t\t   int64_t timestamp)\n> +{\n> +\tint ret;\n> +\n> +\t/* \\todo Use correct sizes */\n> +\t#define RESULT_ENTRY_CAP 256\n> +\t#define RESULT_DATA_CAP 6688\n> +\tcamera_metadata_t *resultMetadata =\n> +\t\tallocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);\n> +\n> +\tconst uint8_t ae_state = ANDROID_CONTROL_AE_STATE_CONVERGED;\n> +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_STATE,\n> +\t\t\t\t\t&ae_state, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;\n> +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_LOCK,\n> +\t\t\t\t\t&ae_lock, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tuint8_t af_state = ANDROID_CONTROL_AF_STATE_INACTIVE;\n> +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AF_STATE,\n> +\t\t\t\t\t&af_state, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t awb_state = ANDROID_CONTROL_AWB_STATE_CONVERGED;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_CONTROL_AWB_STATE,\n> +\t\t\t\t\t&awb_state, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t awb_lock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\t\t\t\t&awb_lock, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t lens_state = ANDROID_LENS_STATE_STATIONARY;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_LENS_STATE,\n> +\t\t\t\t\t&lens_state, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tint32_t sensorSizes[] = {\n> +\t\t0, 0, 2560, 1920,\n> +\t};\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_SCALER_CROP_REGION,\n> +\t\t\t\t\tsensorSizes, 4);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_SENSOR_TIMESTAMP,\n> +\t\t\t\t\t&timestamp, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* 33.3 msec */\n> +\tconst int64_t rolling_shutter_skew = 33300000;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> +\t\t\t\t\t&rolling_shutter_skew, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\t/* 16.6 msec */\n> +\tconst int64_t exposure_time = 16600000;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> +\t\t\t\t\t&exposure_time, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t lens_shading_map_mode =\n> +\t\t\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> +\t\t\t\t\t&lens_shading_map_mode, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\tconst uint8_t scene_flicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;\n> +\tret = add_camera_metadata_entry(resultMetadata,\n> +\t\t\t\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> +\t\t\t\t\t&scene_flicker, 1);\n> +\tMETADATA_ASSERT(ret);\n> +\n> +\treturn resultMetadata;\n> +}\n> diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> new file mode 100644\n> index 000000000000..ac5b95c95104\n> --- /dev/null\n> +++ b/src/android/camera_device.h\n> @@ -0,0 +1,71 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_device.h - libcamera Android Camera Device\n> + */\n> +#ifndef __ANDROID_CAMERA_DEVICE_H__\n> +#define __ANDROID_CAMERA_DEVICE_H__\n> +\n> +#include <memory>\n> +\n> +#include <hardware/camera3.h>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/camera.h>\n> +#include <libcamera/object.h>\n> +#include <libcamera/request.h>\n> +#include <libcamera/stream.h>\n> +\n> +#include \"message.h\"\n> +\n> +#define METADATA_ASSERT(_r)\t\t\\\n> +\tdo {\t\t\t\t\\\n> +\t\tif (!(_r)) break;\t\\\n> +\t\tLOG(HAL, Error) << \"Error: \" << __func__ << \":\" << __LINE__; \\\n> +\t\treturn nullptr;\t\t\\\n> +\t} while(0);\n> +\n> +class CameraDevice : public libcamera::Object\n> +{\n> +public:\n> +\tCameraDevice(unsigned int id, std::shared_ptr<libcamera::Camera> &camera);\n> +\t~CameraDevice();\n> +\n> +\tvoid message(libcamera::Message *message);\n> +\n> +\tint open();\n> +\tvoid close();\n> +\tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n> +\tcamera_metadata_t *getStaticMetadata();\n> +\tconst camera_metadata_t *constructDefaultRequestSettings(int type);\n> +\tint configureStreams(camera3_stream_configuration_t *stream_list);\n> +\tint processCaptureRequest(camera3_capture_request_t *request);\n> +\tvoid requestComplete(libcamera::Request *request,\n> +\t\t\t     const std::map<libcamera::Stream *, libcamera::Buffer *> &buffers);\n> +\n> +private:\n> +\tstruct Camera3RequestDescriptor {\n> +\t\tCamera3RequestDescriptor(unsigned int frameNumber,\n> +\t\t\t\t\t unsigned int numBuffers);\n> +\t\t~Camera3RequestDescriptor();\n> +\n> +\t\tuint32_t frameNumber;\n> +\t\tuint32_t numBuffers;\n> +\t\tcamera3_stream_buffer_t *buffers;\n> +\t};\n> +\n> +\tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n> +\tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream);\n> +\tcamera_metadata_t *getResultMetadata(int frame_number, int64_t timestamp);\n> +\n> +\tbool running_;\n> +\tstd::shared_ptr<libcamera::Camera> camera_;\n> +\tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> +\n> +\tcamera_metadata_t *staticMetadata_;\n> +\tcamera_metadata_t *requestTemplate_;\n> +\tconst camera3_callback_ops_t *callbacks_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_DEVICE_H__ */\n> diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp\n> new file mode 100644\n> index 000000000000..08c759dfd8a1\n> --- /dev/null\n> +++ b/src/android/camera_hal_manager.cpp\n> @@ -0,0 +1,138 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_hal_manager.cpp - libcamera Android Camera Manager\n> + */\n> +\n> +#include \"camera_hal_manager.h\"\n> +\n> +#include <libcamera/camera.h>\n> +\n> +#include \"log.h\"\n> +\n> +#include \"camera_device.h\"\n> +#include \"camera_proxy.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\n> +\n> +/*\n> + * \\class CameraHalManager\n> + *\n> + * The HAL camera manager is initializated at camera_module_t 'hal_init()' time\n> + * and spawns its own thread where libcamera related events are dispatched to.\n> + * It wraps the libcamera CameraManager operations and provides helpers for the\n> + * camera_module_t operations, to retrieve the number of cameras in the system,\n> + * their static information and to open and close camera devices.\n> + */\n> +\n> +int CameraHalManager::init()\n> +{\n> +\t/*\n> +\t * Start the camera HAL manager thread and wait until its\n> +\t * initialisation completes to be fully operational before\n> +\t * receiving calls from the camera stack.\n> +\t */\n> +\tstart();\n> +\n> +\tMutexLocker locker(mutex_);\n> +\tcv_.wait(locker);\n> +\n> +\treturn 0;\n> +}\n> +\n> +void CameraHalManager::run()\n> +{\n> +\t/*\n> +\t * All the libcamera components must be initialised here, in\n> +\t * order to bind them to the camera HAL manager thread that\n> +\t * executes the event dispatcher.\n> +\t */\n> +\tcameraManager_ = libcamera::CameraManager::instance();\n> +\n> +\tint ret = cameraManager_->start();\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to start camera manager: \"\n> +\t\t\t\t<< strerror(-ret);\n> +\t\treturn;\n> +\t}\n> +\n> +\t/*\n> +\t * For each Camera registered in the system, a CameraProxy\n> +\t * gets created here to wraps a camera device.\n> +\t *\n> +\t * \\todo Support camera hotplug.\n> +\t */\n> +\tunsigned int index = 0;\n> +\tfor (auto &camera : cameraManager_->cameras()) {\n> +\t\tCameraProxy *proxy = new CameraProxy(index, camera);\n> +\t\tproxies_.emplace_back(proxy);\n> +\n> +\t\t++index;\n> +\t}\n> +\n> +\t/*\n> +\t * libcamera has been initialized. Unlock the init() caller\n> +\t * as we're now ready to handle calls from the framework.\n> +\t */\n> +\tcv_.notify_one();\n> +\n> +\t/* Now start processing events and messages. */\n> +\texec();\n> +}\n> +\n> +CameraProxy *CameraHalManager::open(unsigned int id,\n> +\t\t\t\t    const hw_module_t *hardwareModule)\n> +{\n> +\tif (id < 0 || id >= numCameras()) {\n> +\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\tCameraProxy *proxy = proxies_[id].get();\n> +\tif (proxy->open(hardwareModule))\n> +\t\treturn nullptr;\n> +\n> +\tLOG(HAL, Info) << \"Open camera '\" << id << \"'\";\n> +\n> +\treturn proxy;\n> +}\n> +\n> +int CameraHalManager::close(CameraProxy *proxy)\n> +{\n> +\tproxy->close();\n> +\tLOG(HAL, Info) << \"Close camera '\" << proxy->id() << \"'\";\n> +\n> +\treturn 0;\n> +}\n> +\n> +unsigned int CameraHalManager::numCameras() const\n> +{\n> +\treturn cameraManager_->cameras().size();\n> +}\n> +\n> +int CameraHalManager::getCameraInfo(int id, struct camera_info *info)\n> +{\n> +\tif (!info)\n> +\t\treturn -EINVAL;\n> +\n> +\tif (id >= numCameras() || id < 0) {\n> +\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tCameraProxy *proxy = proxies_[id].get();\n> +\n> +\t/* \\todo Get these info dynamically inspecting the camera module. */\n> +\tinfo->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;\n> +\tinfo->orientation = 0;\n> +\tinfo->device_version = 0;\n> +\tinfo->resource_cost = 0;\n> +\tinfo->static_camera_characteristics = proxy->getStaticMetadata();\n> +\tinfo->conflicting_devices = nullptr;\n> +\tinfo->conflicting_devices_length = 0;\n> +\n> +\treturn 0;\n> +}\n> diff --git a/src/android/camera_hal_manager.h b/src/android/camera_hal_manager.h\n> new file mode 100644\n> index 000000000000..8004aaf660f5\n> --- /dev/null\n> +++ b/src/android/camera_hal_manager.h\n> @@ -0,0 +1,47 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_hal_manager.h - libcamera Android Camera Manager\n> + */\n> +#ifndef __ANDROID_CAMERA_MANAGER_H__\n> +#define __ANDROID_CAMERA_MANAGER_H__\n> +\n> +#include <condition_variable>\n> +#include <mutex>\n> +#include <vector>\n> +\n> +#include <hardware/hardware.h>\n> +#include <system/camera_metadata.h>\n> +\n> +#include <libcamera/camera_manager.h>\n> +\n> +#include \"thread.h\"\n> +\n> +class CameraDevice;\n> +class CameraProxy;\n> +\n> +class CameraHalManager : public libcamera::Thread\n> +{\n> +public:\n> +\tint init();\n> +\n> +\tCameraProxy *open(unsigned int id, const hw_module_t *module);\n> +\tint close(CameraProxy *proxy);\n> +\n> +\tunsigned int numCameras() const;\n> +\tint getCameraInfo(int id, struct camera_info *info);\n> +\n> +private:\n> +\tvoid run() override;\n> +\tcamera_metadata_t *getStaticMetadata(unsigned int id);\n> +\n> +\tlibcamera::CameraManager *cameraManager_;\n> +\n> +\tstd::mutex mutex_;\n> +\tstd::condition_variable cv_;\n> +\n> +\tstd::vector<std::unique_ptr<CameraProxy>> proxies_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_MANAGER_H__ */\n> diff --git a/src/android/camera_proxy.cpp b/src/android/camera_proxy.cpp\n> new file mode 100644\n> index 000000000000..f0cacac8025b\n> --- /dev/null\n> +++ b/src/android/camera_proxy.cpp\n> @@ -0,0 +1,194 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_proxy.cpp - Proxy to camera devices\n> + */\n> +\n> +#include \"camera_proxy.h\"\n> +\n> +#include <system/camera_metadata.h>\n> +\n> +#include \"log.h\"\n> +#include \"message.h\"\n> +#include \"utils.h\"\n> +\n> +#include \"camera_device.h\"\n> +#include \"thread_rpc.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\n> +\n> +/*\n> + * \\class CameraProxy\n> + *\n> + * The CameraProxy wraps a CameraDevice and implements the camera3_device_t\n> + * API, bridging calls received from the camera framework to the CameraDevice.\n> + *\n> + * Bridging operation calls between the framework and the CameraDevice is\n> + * required as the two run in two different threads and certain operations,\n> + * such as queueing a new capture request to the camera, shall be called in\n> + * the thread that dispatches events. Other operations do not require any\n> + * bridging and resolve to direct function calls on the CameraDevice instance\n> + * instead.\n> + */\n> +\n> +static int hal_dev_initialize(const struct camera3_device *dev,\n> +\t\t\t      const camera3_callback_ops_t *callback_ops)\n> +{\n> +\tif (!dev)\n> +\t\treturn -EINVAL;\n> +\n> +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> +\tproxy->initialize(callback_ops);\n> +\n> +\treturn 0;\n> +}\n> +\n> +static int hal_dev_configure_streams(const struct camera3_device *dev,\n> +\t\t\t\t     camera3_stream_configuration_t *stream_list)\n> +{\n> +\tif (!dev)\n> +\t\treturn -EINVAL;\n> +\n> +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> +\treturn proxy->configureStreams(stream_list);\n> +}\n> +\n> +static const camera_metadata_t *\n> +hal_dev_construct_default_request_settings(const struct camera3_device *dev,\n> +\t\t\t\t\t   int type)\n> +{\n> +\tif (!dev)\n> +\t\treturn nullptr;\n> +\n> +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> +\treturn proxy->constructDefaultRequestSettings(type);\n> +}\n> +\n> +static int hal_dev_process_capture_request(const struct camera3_device *dev,\n> +\t\t\t\t\t   camera3_capture_request_t *request)\n> +{\n> +\tif (!dev)\n> +\t\treturn -EINVAL;\n> +\n> +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> +\treturn proxy->processCaptureRequest(request);\n> +}\n> +\n> +static void hal_dev_dump(const struct camera3_device *dev, int fd)\n> +{\n> +}\n> +\n> +static int hal_dev_flush(const struct camera3_device *dev)\n> +{\n> +\treturn 0;\n> +}\n> +\n> +static int hal_dev_close(hw_device_t *hw_device)\n> +{\n> +\tif (!hw_device)\n> +\t\treturn -EINVAL;\n> +\n> +\tcamera3_device_t *dev = reinterpret_cast<camera3_device_t *>(hw_device);\n> +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> +\n> +\tproxy->close();\n> +\n> +\treturn 0;\n> +}\n> +\n> +static camera3_device_ops hal_dev_ops = {\n> +\t.initialize = hal_dev_initialize,\n> +\t.configure_streams = hal_dev_configure_streams,\n> +\t.register_stream_buffers = nullptr,\n> +\t.construct_default_request_settings = hal_dev_construct_default_request_settings,\n> +\t.process_capture_request = hal_dev_process_capture_request,\n> +\t.get_metadata_vendor_tag_ops = nullptr,\n> +\t.dump = hal_dev_dump,\n> +\t.flush = hal_dev_flush,\n> +\t.reserved = { nullptr },\n> +};\n> +\n> +CameraProxy::CameraProxy(unsigned int id, std::shared_ptr<Camera> camera)\n> +\t: id_(id)\n> +{\n> +\tcameraDevice_ = new CameraDevice(id, camera);\n> +}\n> +\n> +CameraProxy::~CameraProxy()\n> +{\n> +\tdelete cameraDevice_;\n> +}\n> +\n> +int CameraProxy::open(const hw_module_t *hardwareModule)\n> +{\n> +\tint ret = cameraDevice_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\t/* Initialize the hw_device_t in the instance camera3_module_t. */\n> +\tcamera3Device_.common.tag = HARDWARE_DEVICE_TAG;\n> +\tcamera3Device_.common.version = CAMERA_DEVICE_API_VERSION_3_3;\n> +\tcamera3Device_.common.module = (hw_module_t *)hardwareModule;\n> +\tcamera3Device_.common.close = hal_dev_close;\n> +\n> +\t/*\n> +\t * The camera device operations. These actually implement\n> +\t * the Android Camera HALv3 interface.\n> +\t */\n> +\tcamera3Device_.ops = &hal_dev_ops;\n> +\tcamera3Device_.priv = this;\n> +\n> +\treturn 0;\n> +}\n> +\n> +void CameraProxy::close()\n> +{\n> +\tThreadRpc rpcRequest;\n> +\trpcRequest.tag = ThreadRpc::Close;\n> +\n> +\tthreadRpcCall(rpcRequest);\n> +}\n> +\n> +void CameraProxy::initialize(const camera3_callback_ops_t *callbacks)\n> +{\n> +\tcameraDevice_->setCallbacks(callbacks);\n> +}\n> +\n> +const camera_metadata_t *CameraProxy::getStaticMetadata()\n> +{\n> +\treturn cameraDevice_->getStaticMetadata();\n> +}\n> +\n> +const camera_metadata_t *CameraProxy::constructDefaultRequestSettings(int type)\n> +{\n> +\treturn cameraDevice_->constructDefaultRequestSettings(type);\n> +}\n> +\n> +int CameraProxy::configureStreams(camera3_stream_configuration_t *stream_list)\n> +{\n> +\treturn cameraDevice_->configureStreams(stream_list);\n> +}\n> +\n> +int CameraProxy::processCaptureRequest(camera3_capture_request_t *request)\n> +{\n> +\tThreadRpc rpcRequest;\n> +\trpcRequest.tag = ThreadRpc::ProcessCaptureRequest;\n> +\trpcRequest.request = request;\n> +\n> +\tthreadRpcCall(rpcRequest);\n> +\n> +\treturn 0;\n> +}\n> +\n> +void CameraProxy::threadRpcCall(ThreadRpc &rpcRequest)\n> +{\n> +\tstd::unique_ptr<ThreadRpcMessage> message =\n> +\t\t\t\tutils::make_unique<ThreadRpcMessage>();\n> +\tmessage->rpc = &rpcRequest;\n> +\n> +\tcameraDevice_->postMessage(std::move(message));\n> +\trpcRequest.waitDelivery();\n> +}\n> diff --git a/src/android/camera_proxy.h b/src/android/camera_proxy.h\n> new file mode 100644\n> index 000000000000..da63bfa79fc9\n> --- /dev/null\n> +++ b/src/android/camera_proxy.h\n> @@ -0,0 +1,45 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * camera_proxy.h - Proxy to camera devices\n> + */\n> +#ifndef __ANDROID_CAMERA_PROXY_H__\n> +#define __ANDROID_CAMERA_PROXY_H__\n> +\n> +#include <memory>\n> +\n> +#include <hardware/camera3.h>\n> +\n> +#include <libcamera/camera.h>\n> +\n> +class CameraDevice;\n> +class ThreadRpc;\n> +\n> +class CameraProxy\n> +{\n> +public:\n> +\tCameraProxy(unsigned int id, std::shared_ptr<libcamera::Camera> camera);\n> +\t~CameraProxy();\n> +\n> +\tint open(const hw_module_t *hardwareModule);\n> +\tvoid close();\n> +\n> +\tvoid initialize(const camera3_callback_ops_t *callbacks);\n> +\tconst camera_metadata_t *getStaticMetadata();\n> +\tconst camera_metadata_t *constructDefaultRequestSettings(int type);\n> +\tint configureStreams(camera3_stream_configuration_t *stream_list);\n> +\tint processCaptureRequest(camera3_capture_request_t *request);\n> +\n> +\tunsigned int id() const { return id_; }\n> +\tcamera3_device_t *camera3Device() { return &camera3Device_; }\n> +\n> +private:\n> +\tvoid threadRpcCall(ThreadRpc &rpcRequest);\n> +\n> +\tunsigned int id_;\n> +\tCameraDevice *cameraDevice_;\n> +\tcamera3_device_t camera3Device_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_PROXY_H__ */\n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 1f242953db37..26537794bc29 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -1,3 +1,11 @@\n> +android_hal_sources = files([\n> +    'camera3_hal.cpp',\n> +    'camera_hal_manager.cpp',\n> +    'camera_device.cpp',\n> +    'camera_proxy.cpp',\n> +    'thread_rpc.cpp'\n> +])\n> +\n>  android_camera_metadata_sources = files([\n>      'metadata/camera_metadata.c',\n>  ])\n> diff --git a/src/android/thread_rpc.cpp b/src/android/thread_rpc.cpp\n> new file mode 100644\n> index 000000000000..295a05d7c676\n> --- /dev/null\n> +++ b/src/android/thread_rpc.cpp\n> @@ -0,0 +1,42 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * thread_rpc.cpp - Inter-thread procedure call\n> + */\n> +\n> +#include \"thread_rpc.h\"\n> +\n> +#include \"message.h\"\n> +\n> +using namespace libcamera;\n> +\n> +libcamera::Message::Type ThreadRpcMessage::rpcType_ = Message::Type::None;\n> +\n> +ThreadRpcMessage::ThreadRpcMessage()\n> +\t: Message(type())\n> +{\n> +}\n> +\n> +void ThreadRpc::notifyReception()\n> +{\n> +\t{\n> +\t\tlibcamera::MutexLocker locker(mutex_);\n> +\t\tdelivered_ = true;\n> +\t}\n> +\tcv_.notify_one();\n> +}\n> +\n> +void ThreadRpc::waitDelivery()\n> +{\n> +\tlibcamera::MutexLocker locker(mutex_);\n> +\tcv_.wait(locker, [&] { return delivered_; });\n> +}\n> +\n> +Message::Type ThreadRpcMessage::type()\n> +{\n> +\tif (ThreadRpcMessage::rpcType_ == Message::Type::None)\n> +\t\trpcType_ = Message::registerMessageType();\n> +\n> +\treturn rpcType_;\n> +}\n> diff --git a/src/android/thread_rpc.h b/src/android/thread_rpc.h\n> new file mode 100644\n> index 000000000000..6d8992839d0b\n> --- /dev/null\n> +++ b/src/android/thread_rpc.h\n> @@ -0,0 +1,54 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * thread_rpc.h - Inter-thread procedure call\n> + */\n> +#ifndef __ANDROID_THREAD_RPC_H__\n> +#define __ANDROID_THREAD_RPC_H__\n> +\n> +#include <condition_variable>\n> +#include <mutex>\n> +\n> +#include <hardware/camera3.h>\n> +\n> +#include \"message.h\"\n> +#include \"thread.h\"\n> +\n> +class ThreadRpc\n> +{\n> +public:\n> +\tenum RpcTag {\n> +\t\tProcessCaptureRequest,\n> +\t\tClose,\n> +\t};\n> +\n> +\tThreadRpc()\n> +\t\t: delivered_(false) {}\n> +\n> +\tvoid notifyReception();\n> +\tvoid waitDelivery();\n> +\n> +\tRpcTag tag;\n> +\n> +\tcamera3_capture_request_t *request;\n> +\n> +private:\n> +\tbool delivered_;\n> +\tstd::mutex mutex_;\n> +\tstd::condition_variable cv_;\n> +};\n> +\n> +class ThreadRpcMessage : public libcamera::Message\n> +{\n> +public:\n> +\tThreadRpcMessage();\n> +\tThreadRpc *rpc;\n> +\n> +\tstatic Message::Type type();\n> +\n> +private:\n> +\tstatic libcamera::Message::Type rpcType_;\n> +};\n> +\n> +#endif /* __ANDROID_THREAD_RPC_H__ */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index a09b23d60022..7d5d3c04fba0 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -103,9 +103,18 @@ libcamera_deps = [\n>      dependency('threads'),\n>  ]\n>  \n> +libcamera_link_with = []\n> +\n> +if get_option('android')\n> +    libcamera_sources += android_hal_sources\n> +    includes += android_includes\n> +    libcamera_link_with += android_camera_metadata\n> +endif\n> +\n>  libcamera = shared_library('camera',\n>                             libcamera_sources,\n>                             install : true,\n> +                           link_with : libcamera_link_with,\n>                             include_directories : includes,\n>                             dependencies : libcamera_deps)\n>  \n> diff --git a/src/meson.build b/src/meson.build\n> index 7148baee3eda..67ad20aab86b 100644\n> --- a/src/meson.build\n> +++ b/src/meson.build\n> @@ -1,4 +1,7 @@\n> -subdir('android')\n> +if get_option('android')\n> +    subdir('android')\n> +endif\n> +\n>  subdir('libcamera')\n>  subdir('ipa')\n>  subdir('cam')","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 95A9F60E38\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 11:42:42 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id CC286327;\n\tMon, 12 Aug 2019 11:42:41 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565602962;\n\tbh=VZovVvihLU1wjWjpMz5LTX/9AyxNXfVOT8GengpM+MQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=pDO0svEEMg8I7rnBn9HuZXVHzbx6SAMJPz2Vlx8J9Pbu1XHW/zguqmfF0aMAFaZdx\n\tp6yoBOORRuVIei0fTYLQqKHN20JINKQjqfrwzVfek4KflqehC3gCKBlWx0uxHnqceK\n\tx3WQ1ME7W03hgbTbKvzmrOw14knfBbMEObrtMV/I=","Date":"Mon, 12 Aug 2019 12:42:38 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812094238.GA5006@pendragon.ideasonboard.com>","References":"<20190812084146.23802-1-jacopo@jmondi.org>\n\t<20190812084146.23802-2-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190812084146.23802-2-jacopo@jmondi.org>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v4 1/1] android: hal: Add Camera3 HAL","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 12 Aug 2019 09:42:42 -0000"}},{"id":2387,"web_url":"https://patchwork.libcamera.org/comment/2387/","msgid":"<20190812095522.h5q5ni6ebfzcrudw@uno.localdomain>","date":"2019-08-12T09:55:22","subject":"Re: [libcamera-devel] [PATCH v4 1/1] android: hal: Add Camera3 HAL","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi LAurent,\n\nOn Mon, Aug 12, 2019 at 12:42:38PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> Thank you for the patch.\n>\n> On Mon, Aug 12, 2019 at 10:41:46AM +0200, Jacopo Mondi wrote:\n> > Add libcamera Android Camera HALv3 implementation.\n> >\n> > The initial camera HAL implementation supports the LIMITED hardware\n> > level and uses statically defined metadata and camera characteristics.\n> >\n> > Add a build option named 'android' and adjust the build system to\n> > selectively compile the Android camera HAL and link it against the\n> > required Android libraries.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>\n> Great work !!\n>\n\nThanks you for your incredible review effort, was quite some code to\nprocess!\n\nI'll now push this last patch to master and make the HAL\nimplementation \"official\" \\o/\n\nThanks\n  j\n\n> > ---\n> >  meson_options.txt                  |   5 +\n> >  src/android/camera3_hal.cpp        | 111 ++++\n> >  src/android/camera_device.cpp      | 831 +++++++++++++++++++++++++++++\n> >  src/android/camera_device.h        |  71 +++\n> >  src/android/camera_hal_manager.cpp | 138 +++++\n> >  src/android/camera_hal_manager.h   |  47 ++\n> >  src/android/camera_proxy.cpp       | 194 +++++++\n> >  src/android/camera_proxy.h         |  45 ++\n> >  src/android/meson.build            |   8 +\n> >  src/android/thread_rpc.cpp         |  42 ++\n> >  src/android/thread_rpc.h           |  54 ++\n> >  src/libcamera/meson.build          |   9 +\n> >  src/meson.build                    |   5 +-\n> >  13 files changed, 1559 insertions(+), 1 deletion(-)\n> >  create mode 100644 src/android/camera3_hal.cpp\n> >  create mode 100644 src/android/camera_device.cpp\n> >  create mode 100644 src/android/camera_device.h\n> >  create mode 100644 src/android/camera_hal_manager.cpp\n> >  create mode 100644 src/android/camera_hal_manager.h\n> >  create mode 100644 src/android/camera_proxy.cpp\n> >  create mode 100644 src/android/camera_proxy.h\n> >  create mode 100644 src/android/thread_rpc.cpp\n> >  create mode 100644 src/android/thread_rpc.h\n> >\n> > diff --git a/meson_options.txt b/meson_options.txt\n> > index 97efc85b4412..2d78b8d91f9c 100644\n> > --- a/meson_options.txt\n> > +++ b/meson_options.txt\n> > @@ -1,3 +1,8 @@\n> > +option('android',\n> > +        type : 'boolean',\n> > +        value : false,\n> > +        description : 'Compile libcamera with Android Camera3 HAL interface')\n> > +\n> >  option('documentation',\n> >          type : 'boolean',\n> >          description : 'Generate the project documentation')\n> > diff --git a/src/android/camera3_hal.cpp b/src/android/camera3_hal.cpp\n> > new file mode 100644\n> > index 000000000000..8d2629ca356c\n> > --- /dev/null\n> > +++ b/src/android/camera3_hal.cpp\n> > @@ -0,0 +1,111 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera3_hal.cpp - Android Camera HALv3 module\n> > + */\n> > +\n> > +#include <hardware/camera_common.h>\n> > +\n> > +#include \"camera_hal_manager.h\"\n> > +#include \"camera_proxy.h\"\n> > +#include \"log.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DEFINE_CATEGORY(HAL)\n> > +\n> > +static CameraHalManager cameraManager;\n> > +\n> > +/*------------------------------------------------------------------------------\n> > + * Android Camera HAL callbacks\n> > + */\n> > +\n> > +static int hal_get_number_of_cameras(void)\n> > +{\n> > +\treturn cameraManager.numCameras();\n> > +}\n> > +\n> > +static int hal_get_camera_info(int id, struct camera_info *info)\n> > +{\n> > +\treturn cameraManager.getCameraInfo(id, info);\n> > +}\n> > +\n> > +static int hal_set_callbacks(const camera_module_callbacks_t *callbacks)\n> > +{\n> > +\treturn 0;\n> > +}\n> > +\n> > +static int hal_open_legacy(const struct hw_module_t *module, const char *id,\n> > +\t\t\t   uint32_t halVersion, struct hw_device_t **device)\n> > +{\n> > +\treturn -ENOSYS;\n> > +}\n> > +\n> > +static int hal_set_torch_mode(const char *camera_id, bool enabled)\n> > +{\n> > +\treturn -ENOSYS;\n> > +}\n> > +\n> > +/*\n> > + * First entry point of the camera HAL module.\n> > + *\n> > + * Initialize the HAL but does not open any camera device yet (see hal_dev_open)\n> > + */\n> > +static int hal_init()\n> > +{\n> > +\tLOG(HAL, Info) << \"Initialising Android camera HAL\";\n> > +\n> > +\tcameraManager.init();\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +/*------------------------------------------------------------------------------\n> > + * Android Camera Device\n> > + */\n> > +\n> > +static int hal_dev_open(const hw_module_t *module, const char *name,\n> > +\t\t\thw_device_t **device)\n> > +{\n> > +\tLOG(HAL, Debug) << \"Open camera \" << name;\n> > +\n> > +\tint id = atoi(name);\n> > +\tCameraProxy *proxy = cameraManager.open(id, module);\n> > +\tif (!proxy) {\n> > +\t\tLOG(HAL, Error)\n> > +\t\t\t<< \"Failed to open camera module '\" << id << \"'\";\n> > +\t\treturn -ENODEV;\n> > +\t}\n> > +\n> > +\t*device = &proxy->camera3Device()->common;\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +static struct hw_module_methods_t hal_module_methods = {\n> > +\t.open = hal_dev_open,\n> > +};\n> > +\n> > +camera_module_t HAL_MODULE_INFO_SYM = {\n> > +\t.common = {\n> > +\t\t.tag = HARDWARE_MODULE_TAG,\n> > +\t\t.module_api_version = CAMERA_MODULE_API_VERSION_2_4,\n> > +\t\t.hal_api_version = HARDWARE_HAL_API_VERSION,\n> > +\t\t.id = CAMERA_HARDWARE_MODULE_ID,\n> > +\t\t.name = \"libcamera camera HALv3 module\",\n> > +\t\t.author = \"libcamera\",\n> > +\t\t.methods = &hal_module_methods,\n> > +\t\t.dso = nullptr,\n> > +\t\t.reserved = {},\n> > +\t},\n> > +\n> > +\t.get_number_of_cameras = hal_get_number_of_cameras,\n> > +\t.get_camera_info = hal_get_camera_info,\n> > +\t.set_callbacks = hal_set_callbacks,\n> > +\t.get_vendor_tag_ops = nullptr,\n> > +\t.open_legacy = hal_open_legacy,\n> > +\t.set_torch_mode = hal_set_torch_mode,\n> > +\t.init = hal_init,\n> > +\t.reserved = {},\n> > +};\n> > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > new file mode 100644\n> > index 000000000000..e2c1f2a246c8\n> > --- /dev/null\n> > +++ b/src/android/camera_device.cpp\n> > @@ -0,0 +1,831 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_device.cpp - libcamera Android Camera Device\n> > + */\n> > +\n> > +#include \"camera_device.h\"\n> > +\n> > +#include <system/camera_metadata.h>\n> > +\n> > +#include \"log.h\"\n> > +\n> > +#include \"thread_rpc.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DECLARE_CATEGORY(HAL);\n> > +\n> > +/*\n> > + * \\struct Camera3RequestDescriptor\n> > + *\n> > + * A utility structure that groups information about a capture request to be\n> > + * later re-used at request complete time to notify the framework.\n> > + */\n> > +\n> > +CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(\n> > +\t\tunsigned int frameNumber, unsigned int numBuffers)\n> > +\t: frameNumber(frameNumber), numBuffers(numBuffers)\n> > +{\n> > +\tbuffers = new camera3_stream_buffer_t[numBuffers];\n> > +}\n> > +\n> > +CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor()\n> > +{\n> > +\tdelete[] buffers;\n> > +}\n> > +\n> > +/*\n> > + * \\class CameraDevice\n> > + *\n> > + * The CameraDevice class wraps a libcamera::Camera instance, and implements\n> > + * the camera_device_t interface by handling RPC requests received from its\n> > + * associated CameraProxy.\n> > + *\n> > + * It translate parameters and operations from Camera HALv3 API to the libcamera\n> > + * ones to provide static information for a Camera, create request templates\n> > + * for it, process capture requests and then deliver capture results back\n> > + * to the framework using the designated callbacks.\n> > + */\n> > +\n> > +CameraDevice::CameraDevice(unsigned int id, std::shared_ptr<Camera> &camera)\n> > +\t: running_(false), camera_(camera), staticMetadata_(nullptr),\n> > +\t  requestTemplate_(nullptr)\n> > +{\n> > +\tcamera_->requestCompleted.connect(this, &CameraDevice::requestComplete);\n> > +}\n> > +\n> > +CameraDevice::~CameraDevice()\n> > +{\n> > +\tif (staticMetadata_)\n> > +\t\tfree_camera_metadata(staticMetadata_);\n> > +\tstaticMetadata_ = nullptr;\n> > +\n> > +\tif (requestTemplate_)\n> > +\t\tfree_camera_metadata(requestTemplate_);\n> > +\trequestTemplate_ = nullptr;\n> > +}\n> > +\n> > +/*\n> > + * Handle RPC request received from the associated proxy.\n> > + */\n> > +void CameraDevice::message(Message *message)\n> > +{\n> > +\tif (message->type() != ThreadRpcMessage::type())\n> > +\t\treturn Object::message(message);\n> > +\n> > +\tThreadRpcMessage *rpcMessage = static_cast<ThreadRpcMessage *>(message);\n> > +\tThreadRpc *rpc = rpcMessage->rpc;\n> > +\n> > +\tswitch (rpc->tag) {\n> > +\tcase ThreadRpc::ProcessCaptureRequest:\n> > +\t\tprocessCaptureRequest(rpc->request);\n> > +\t\tbreak;\n> > +\tcase ThreadRpc::Close:\n> > +\t\tclose();\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\tLOG(HAL, Error) << \"Unknown RPC operation: \" << rpc->tag;\n> > +\t}\n> > +\n> > +\trpc->notifyReception();\n> > +}\n> > +\n> > +int CameraDevice::open()\n> > +{\n> > +\tint ret = camera_->acquire();\n> > +\tif (ret) {\n> > +\t\tLOG(HAL, Error) << \"Failed to acquire the camera\";\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void CameraDevice::close()\n> > +{\n> > +\tcamera_->stop();\n> > +\n> > +\tcamera_->freeBuffers();\n> > +\tcamera_->release();\n> > +\n> > +\trunning_ = false;\n> > +}\n> > +\n> > +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> > +{\n> > +\tcallbacks_ = callbacks;\n> > +}\n> > +\n> > +/*\n> > + * Return static information for the camera.\n> > + */\n> > +camera_metadata_t *CameraDevice::getStaticMetadata()\n> > +{\n> > +\tint ret;\n> > +\n> > +\tif (staticMetadata_)\n> > +\t\treturn staticMetadata_;\n> > +\n> > +\t/*\n> > +\t * The here reported metadata are enough to implement a basic capture\n> > +\t * example application, but a real camera implementation will require\n> > +\t * more.\n> > +\t */\n> > +\n> > +\t/* \\todo Use correct sizes */\n> > +\t#define STATIC_ENTRY_CAP 256\n> > +\t#define STATIC_DATA_CAP 6688\n> > +\tcamera_metadata_t *staticMetadata =\n> > +\t\tallocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);\n> > +\n> > +\t/* Sensor static metadata. */\n> > +\tint32_t pixelArraySize[] = {\n> > +\t\t2592, 1944,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > +\t\t\t\t&pixelArraySize, 2);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t sensorSizes[] = {\n> > +\t\t0, 0, 2560, 1920,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > +\t\t\t\t&sensorSizes, 4);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t sensitivityRange[] = {\n> > +\t\t32, 2400,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > +\t\t\t\t&sensitivityRange, 2);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > +\t\t\t\t&filterArr, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint64_t exposureTimeRange[] = {\n> > +\t\t100000, 200000000,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > +\t\t\t\t&exposureTimeRange, 2);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t orientation = 0;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_SENSOR_ORIENTATION,\n> > +\t\t\t\t&orientation, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* Flash static metadata. */\n> > +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_FLASH_INFO_AVAILABLE,\n> > +\t\t\t&flashAvailable, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* Lens static metadata. */\n> > +\tfloat fn = 2.53 / 100;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES, &fn, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* Control metadata. */\n> > +\tchar controlMetadata = ANDROID_CONTROL_MODE_AUTO;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> > +\t\t\t&controlMetadata, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tchar availableAntiBandingModes[] = {\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > +\t\t\tavailableAntiBandingModes, 4);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tchar aeAvailableModes[] = {\n> > +\t\tANDROID_CONTROL_AE_MODE_ON,\n> > +\t\tANDROID_CONTROL_AE_MODE_OFF,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > +\t\t\taeAvailableModes, 2);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tcontrolMetadata = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > +\t\t\t&controlMetadata, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\t\t&awbLockAvailable, 1);\n> > +\n> > +\t/* Scaler static metadata. */\n> > +\tstd::vector<uint32_t> availableStreamFormats = {\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_SCALER_AVAILABLE_FORMATS,\n> > +\t\t\tavailableStreamFormats.data(),\n> > +\t\t\tavailableStreamFormats.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tstd::vector<uint32_t> availableStreamConfigurations = {\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920,\n> > +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920,\n> > +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920,\n> > +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > +\t\t\tavailableStreamConfigurations.data(),\n> > +\t\t\tavailableStreamConfigurations.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tstd::vector<int64_t> availableStallDurations = {\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > +\t\t\tavailableStallDurations.data(),\n> > +\t\t\tavailableStallDurations.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tstd::vector<int64_t> minFrameDurations = {\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920, 33333333,\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920, 33333333,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > +\t\t\tminFrameDurations.data(), minFrameDurations.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* Info static metadata. */\n> > +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> > +\tret = add_camera_metadata_entry(staticMetadata,\n> > +\t\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > +\t\t\t&supportedHWLevel, 1);\n> > +\n> > +\treturn staticMetadata;\n> > +}\n> > +\n> > +/*\n> > + * Produce a metadata pack to be used as template for a capture request.\n> > + */\n> > +const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> > +{\n> > +\tint ret;\n> > +\n> > +\t/*\n> > +\t * \\todo Inspect type and pick the right metadata pack.\n> > +\t * As of now just use a single one for all templates.\n> > +\t */\n> > +\tuint8_t captureIntent;\n> > +\tswitch (type) {\n> > +\tcase CAMERA3_TEMPLATE_PREVIEW:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > +\t\tbreak;\n> > +\tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> > +\t\tbreak;\n> > +\tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> > +\t\tbreak;\n> > +\tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> > +\t\tbreak;\n> > +\tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;\n> > +\t\tbreak;\n> > +\tcase CAMERA3_TEMPLATE_MANUAL:\n> > +\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\tLOG(HAL, Error) << \"Invalid template request type: \" << type;\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\tif (requestTemplate_)\n> > +\t\treturn requestTemplate_;\n> > +\n> > +\t/* \\todo Use correct sizes */\n> > +\t#define REQUEST_TEMPLATE_ENTRIES\t  30\n> > +\t#define REQUEST_TEMPLATE_DATA\t\t2048\n> > +\trequestTemplate_ = allocate_camera_metadata(REQUEST_TEMPLATE_ENTRIES,\n> > +\t\t\t\t\t\t    REQUEST_TEMPLATE_DATA);\n> > +\tif (!requestTemplate_) {\n> > +\t\tLOG(HAL, Error) << \"Failed to allocate template metadata\";\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\t/* Set to 0 the number of 'processed and stalling' streams (ie JPEG). */\n> > +\tint32_t maxOutStream[] = { 0, 2, 0 };\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > +\t\t\tmaxOutStream, 3);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t maxPipelineDepth = 5;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > +\t\t\t&maxPipelineDepth, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t inputStreams = 0;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > +\t\t\t&inputStreams, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t partialResultCount = 1;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > +\t\t\t&partialResultCount, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t availableCapabilities[] = {\n> > +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > +\t\t\tavailableCapabilities, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AE_MODE,\n> > +\t\t\t&aeMode, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t aeExposureCompensation = 0;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\t\t&aeExposureCompensation, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\t\t&aePrecaptureTrigger, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AE_LOCK,\n> > +\t\t\t&aeLock, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AF_TRIGGER,\n> > +\t\t\t&afTrigger, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AWB_MODE,\n> > +\t\t\t&awbMode, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\t\t&awbLock, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\t\t&awbLockAvailable, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_FLASH_MODE,\n> > +\t\t\t&flashMode, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > +\t\t\t&faceDetectMode, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\t\t&captureIntent, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/*\n> > +\t * This is quite hard to list at the moment wihtout knowing what\n> > +\t * we could control.\n> > +\t *\n> > +\t * For now, just list in the available Request keys and in the available\n> > +\t * result keys the control and reporting of the AE algorithm.\n> > +\t */\n> > +\tstd::vector<int32_t> availableRequestKeys = {\n> > +\t\tANDROID_CONTROL_AE_MODE,\n> > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\tANDROID_CONTROL_AE_LOCK,\n> > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > +\t\tANDROID_CONTROL_AWB_MODE,\n> > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\tANDROID_FLASH_MODE,\n> > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > +\t};\n> > +\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> > +\t\t\tavailableRequestKeys.data(),\n> > +\t\t\tavailableRequestKeys.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tstd::vector<int32_t> availableResultKeys = {\n> > +\t\tANDROID_CONTROL_AE_MODE,\n> > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\tANDROID_CONTROL_AE_LOCK,\n> > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > +\t\tANDROID_CONTROL_AWB_MODE,\n> > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\tANDROID_FLASH_MODE,\n> > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> > +\t\t\tavailableResultKeys.data(),\n> > +\t\t\tavailableResultKeys.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/*\n> > +\t * \\todo The available characteristics are be the tags reported\n> > +\t * as part of the static metadata reported at hal_get_camera_info()\n> > +\t * time. As of now, report an empty list.\n> > +\t */\n> > +\tstd::vector<int32_t> availableCharacteristicsKeys = {};\n> > +\tret = add_camera_metadata_entry(requestTemplate_,\n> > +\t\t\tANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> > +\t\t\tavailableCharacteristicsKeys.data(),\n> > +\t\t\tavailableCharacteristicsKeys.size());\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\treturn requestTemplate_;\n> > +}\n> > +\n> > +/*\n> > + * Inspect the stream_list to produce a list of StreamConfiguration to\n> > + * be use to configure the Camera.\n> > + */\n> > +int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > +{\n> > +\tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> > +\t\tcamera3_stream_t *stream = stream_list->streams[i];\n> > +\n> > +\t\tLOG(HAL, Info) << \"Stream #\" << i\n> > +\t\t\t       << \", direction: \" << stream->stream_type\n> > +\t\t\t       << \", width: \" << stream->width\n> > +\t\t\t       << \", height: \" << stream->height\n> > +\t\t\t       << \", format: \" << std::hex << stream->format;\n> > +\t}\n> > +\n> > +\t/* Hardcode viewfinder role, collecting sizes from the stream config. */\n> > +\tif (stream_list->num_streams != 1) {\n> > +\t\tLOG(HAL, Error) << \"Only one stream supported\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tStreamRoles roles = { StreamRole::Viewfinder };\n> > +\tconfig_ = camera_->generateConfiguration(roles);\n> > +\tif (!config_ || config_->empty()) {\n> > +\t\tLOG(HAL, Error) << \"Failed to generate camera configuration\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\t/* Only one stream is supported. */\n> > +\tcamera3_stream_t *camera3Stream = stream_list->streams[0];\n> > +\tStreamConfiguration *streamConfiguration = &config_->at(0);\n> > +\tstreamConfiguration->size.width = camera3Stream->width;\n> > +\tstreamConfiguration->size.height = camera3Stream->height;\n> > +\tstreamConfiguration->memoryType = ExternalMemory;\n> > +\n> > +\t/*\n> > +\t * \\todo We'll need to translate from Android defined pixel format codes\n> > +\t * to the libcamera image format codes. For now, do not change the\n> > +\t * format returned from Camera::generateConfiguration().\n> > +\t */\n> > +\n> > +\tswitch (config_->validate()) {\n> > +\tcase CameraConfiguration::Valid:\n> > +\t\tbreak;\n> > +\tcase CameraConfiguration::Adjusted:\n> > +\t\tLOG(HAL, Info) << \"Camera configuration adjusted\";\n> > +\t\tconfig_.reset();\n> > +\t\treturn -EINVAL;\n> > +\tcase CameraConfiguration::Invalid:\n> > +\t\tLOG(HAL, Info) << \"Camera configuration invalid\";\n> > +\t\tconfig_.reset();\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tcamera3Stream->max_buffers = streamConfiguration->bufferCount;\n> > +\n> > +\t/*\n> > +\t * Once the CameraConfiguration has been adjusted/validated\n> > +\t * it can be applied to the camera.\n> > +\t */\n> > +\tint ret = camera_->configure(config_.get());\n> > +\tif (ret) {\n> > +\t\tLOG(HAL, Error) << \"Failed to configure camera '\"\n> > +\t\t\t\t<< camera_->name() << \"'\";\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)\n> > +{\n> > +\tStreamConfiguration *streamConfiguration = &config_->at(0);\n> > +\tStream *stream = streamConfiguration->stream();\n> > +\n> > +\tif (camera3Request->num_output_buffers != 1) {\n> > +\t\tLOG(HAL, Error) << \"Invalid number of output buffers: \"\n> > +\t\t\t\t<< camera3Request->num_output_buffers;\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\t/* Start the camera if that's the first request we handle. */\n> > +\tif (!running_) {\n> > +\t\tint ret = camera_->allocateBuffers();\n> > +\t\tif (ret) {\n> > +\t\t\tLOG(HAL, Error) << \"Failed to allocate buffers\";\n> > +\t\t\treturn ret;\n> > +\t\t}\n> > +\n> > +\t\tret = camera_->start();\n> > +\t\tif (ret) {\n> > +\t\t\tLOG(HAL, Error) << \"Failed to start camera\";\n> > +\t\t\tcamera_->freeBuffers();\n> > +\t\t\treturn ret;\n> > +\t\t}\n> > +\n> > +\t\trunning_ = true;\n> > +\t}\n> > +\n> > +\t/*\n> > +\t * Queue a request for the Camera with the provided dmabuf file\n> > +\t * descriptors.\n> > +\t */\n> > +\tconst camera3_stream_buffer_t *camera3Buffers =\n> > +\t\t\t\t\tcamera3Request->output_buffers;\n> > +\n> > +\t/*\n> > +\t * Save the request descriptors for use at completion time.\n> > +\t * The descriptor and the associated memory reserved here are freed\n> > +\t * at request complete time.\n> > +\t */\n> > +\tCamera3RequestDescriptor *descriptor =\n> > +\t\tnew Camera3RequestDescriptor(camera3Request->frame_number,\n> > +\t\t\t\t\t     camera3Request->num_output_buffers);\n> > +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> > +\t\t/*\n> > +\t\t * Keep track of which stream the request belongs to and store\n> > +\t\t * the native buffer handles.\n> > +\t\t *\n> > +\t\t * \\todo Currently we only support one capture buffer. Copy\n> > +\t\t * all of them to be ready once we'll support more.\n> > +\t\t */\n> > +\t\tdescriptor->buffers[i].stream = camera3Buffers[i].stream;\n> > +\t\tdescriptor->buffers[i].buffer = camera3Buffers[i].buffer;\n> > +\t}\n> > +\n> > +\t/*\n> > +\t * Create a libcamera buffer using the dmabuf descriptors of the first\n> > +\t * and (currently) only supported request buffer.\n> > +\t */\n> > +\tconst buffer_handle_t camera3Handle = *camera3Buffers[0].buffer;\n> > +\tstd::array<int, 3> fds = {\n> > +\t\tcamera3Handle->data[0],\n> > +\t\tcamera3Handle->data[1],\n> > +\t\tcamera3Handle->data[2],\n> > +\t};\n> > +\n> > +\tstd::unique_ptr<Buffer> buffer = stream->createBuffer(fds);\n> > +\tif (!buffer) {\n> > +\t\tLOG(HAL, Error) << \"Failed to create buffer\";\n> > +\t\tdelete descriptor;\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tRequest *request =\n> > +\t\tcamera_->createRequest(reinterpret_cast<uint64_t>(descriptor));\n> > +\trequest->addBuffer(std::move(buffer));\n> > +\n> > +\tint ret = camera_->queueRequest(request);\n> > +\tif (ret) {\n> > +\t\tLOG(HAL, Error) << \"Failed to queue request\";\n> > +\t\tgoto error;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +\n> > +error:\n> > +\tdelete request;\n> > +\tdelete descriptor;\n> > +\n> > +\treturn ret;\n> > +}\n> > +\n> > +void CameraDevice::requestComplete(Request *request,\n> > +\t\t\t\t   const std::map<Stream *, Buffer *> &buffers)\n> > +{\n> > +\tBuffer *libcameraBuffer = buffers.begin()->second;\n> > +\tcamera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK;\n> > +\tcamera_metadata_t *resultMetadata = nullptr;\n> > +\n> > +\tif (request->status() != Request::RequestComplete) {\n> > +\t\tLOG(HAL, Error) << \"Request not succesfully completed: \"\n> > +\t\t\t\t<< request->status();\n> > +\t\tstatus = CAMERA3_BUFFER_STATUS_ERROR;\n> > +\t}\n> > +\n> > +\t/* Prepare to call back the Android camera stack. */\n> > +\tCamera3RequestDescriptor *descriptor =\n> > +\t\treinterpret_cast<Camera3RequestDescriptor *>(request->cookie());\n> > +\n> > +\tcamera3_capture_result_t captureResult = {};\n> > +\tcaptureResult.frame_number = descriptor->frameNumber;\n> > +\tcaptureResult.num_output_buffers = descriptor->numBuffers;\n> > +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> > +\t\t/*\n> > +\t\t * \\todo Currently we only support one capture buffer. Prepare\n> > +\t\t * all of them to be ready once we'll support more.\n> > +\t\t */\n> > +\t\tdescriptor->buffers[i].acquire_fence = -1;\n> > +\t\tdescriptor->buffers[i].release_fence = -1;\n> > +\t\tdescriptor->buffers[i].status = status;\n> > +\t}\n> > +\tcaptureResult.output_buffers =\n> > +\t\tconst_cast<const camera3_stream_buffer_t *>(descriptor->buffers);\n> > +\n> > +\tif (status == CAMERA3_BUFFER_STATUS_ERROR) {\n> > +\t\t/* \\todo Improve error handling. */\n> > +\t\tnotifyError(descriptor->frameNumber,\n> > +\t\t\t    descriptor->buffers[0].stream);\n> > +\t} else {\n> > +\t\tnotifyShutter(descriptor->frameNumber,\n> > +\t\t\t      libcameraBuffer->timestamp());\n> > +\n> > +\t\tcaptureResult.partial_result = 1;\n> > +\t\tresultMetadata = getResultMetadata(descriptor->frameNumber,\n> > +\t\t\t\t\t\t   libcameraBuffer->timestamp());\n> > +\t\tcaptureResult.result = resultMetadata;\n> > +\t}\n> > +\n> > +\tcallbacks_->process_capture_result(callbacks_, &captureResult);\n> > +\n> > +\tdelete descriptor;\n> > +\tif (resultMetadata)\n> > +\t\tfree_camera_metadata(resultMetadata);\n> > +\n> > +\treturn;\n> > +}\n> > +\n> > +void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp)\n> > +{\n> > +\tcamera3_notify_msg_t notify = {};\n> > +\n> > +\tnotify.type = CAMERA3_MSG_SHUTTER;\n> > +\tnotify.message.shutter.frame_number = frameNumber;\n> > +\tnotify.message.shutter.timestamp = timestamp;\n> > +\n> > +\tcallbacks_->notify(callbacks_, &notify);\n> > +}\n> > +\n> > +void CameraDevice::notifyError(uint32_t frameNumber, camera3_stream_t *stream)\n> > +{\n> > +\tcamera3_notify_msg_t notify = {};\n> > +\n> > +\tnotify.type = CAMERA3_MSG_ERROR;\n> > +\tnotify.message.error.error_stream = stream;\n> > +\tnotify.message.error.frame_number = frameNumber;\n> > +\tnotify.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;\n> > +\n> > +\tcallbacks_->notify(callbacks_, &notify);\n> > +}\n> > +\n> > +/*\n> > + * Produce a set of fixed result metadata.\n> > + */\n> > +camera_metadata_t *CameraDevice::getResultMetadata(int frame_number,\n> > +\t\t\t\t\t\t   int64_t timestamp)\n> > +{\n> > +\tint ret;\n> > +\n> > +\t/* \\todo Use correct sizes */\n> > +\t#define RESULT_ENTRY_CAP 256\n> > +\t#define RESULT_DATA_CAP 6688\n> > +\tcamera_metadata_t *resultMetadata =\n> > +\t\tallocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);\n> > +\n> > +\tconst uint8_t ae_state = ANDROID_CONTROL_AE_STATE_CONVERGED;\n> > +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_STATE,\n> > +\t\t\t\t\t&ae_state, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AE_LOCK,\n> > +\t\t\t\t\t&ae_lock, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tuint8_t af_state = ANDROID_CONTROL_AF_STATE_INACTIVE;\n> > +\tret = add_camera_metadata_entry(resultMetadata, ANDROID_CONTROL_AF_STATE,\n> > +\t\t\t\t\t&af_state, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t awb_state = ANDROID_CONTROL_AWB_STATE_CONVERGED;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_CONTROL_AWB_STATE,\n> > +\t\t\t\t\t&awb_state, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t awb_lock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\t\t\t\t&awb_lock, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t lens_state = ANDROID_LENS_STATE_STATIONARY;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_LENS_STATE,\n> > +\t\t\t\t\t&lens_state, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tint32_t sensorSizes[] = {\n> > +\t\t0, 0, 2560, 1920,\n> > +\t};\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_SCALER_CROP_REGION,\n> > +\t\t\t\t\tsensorSizes, 4);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_SENSOR_TIMESTAMP,\n> > +\t\t\t\t\t&timestamp, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* 33.3 msec */\n> > +\tconst int64_t rolling_shutter_skew = 33300000;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> > +\t\t\t\t\t&rolling_shutter_skew, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\t/* 16.6 msec */\n> > +\tconst int64_t exposure_time = 16600000;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> > +\t\t\t\t\t&exposure_time, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t lens_shading_map_mode =\n> > +\t\t\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> > +\t\t\t\t\t&lens_shading_map_mode, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\tconst uint8_t scene_flicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;\n> > +\tret = add_camera_metadata_entry(resultMetadata,\n> > +\t\t\t\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> > +\t\t\t\t\t&scene_flicker, 1);\n> > +\tMETADATA_ASSERT(ret);\n> > +\n> > +\treturn resultMetadata;\n> > +}\n> > diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> > new file mode 100644\n> > index 000000000000..ac5b95c95104\n> > --- /dev/null\n> > +++ b/src/android/camera_device.h\n> > @@ -0,0 +1,71 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_device.h - libcamera Android Camera Device\n> > + */\n> > +#ifndef __ANDROID_CAMERA_DEVICE_H__\n> > +#define __ANDROID_CAMERA_DEVICE_H__\n> > +\n> > +#include <memory>\n> > +\n> > +#include <hardware/camera3.h>\n> > +\n> > +#include <libcamera/buffer.h>\n> > +#include <libcamera/camera.h>\n> > +#include <libcamera/object.h>\n> > +#include <libcamera/request.h>\n> > +#include <libcamera/stream.h>\n> > +\n> > +#include \"message.h\"\n> > +\n> > +#define METADATA_ASSERT(_r)\t\t\\\n> > +\tdo {\t\t\t\t\\\n> > +\t\tif (!(_r)) break;\t\\\n> > +\t\tLOG(HAL, Error) << \"Error: \" << __func__ << \":\" << __LINE__; \\\n> > +\t\treturn nullptr;\t\t\\\n> > +\t} while(0);\n> > +\n> > +class CameraDevice : public libcamera::Object\n> > +{\n> > +public:\n> > +\tCameraDevice(unsigned int id, std::shared_ptr<libcamera::Camera> &camera);\n> > +\t~CameraDevice();\n> > +\n> > +\tvoid message(libcamera::Message *message);\n> > +\n> > +\tint open();\n> > +\tvoid close();\n> > +\tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n> > +\tcamera_metadata_t *getStaticMetadata();\n> > +\tconst camera_metadata_t *constructDefaultRequestSettings(int type);\n> > +\tint configureStreams(camera3_stream_configuration_t *stream_list);\n> > +\tint processCaptureRequest(camera3_capture_request_t *request);\n> > +\tvoid requestComplete(libcamera::Request *request,\n> > +\t\t\t     const std::map<libcamera::Stream *, libcamera::Buffer *> &buffers);\n> > +\n> > +private:\n> > +\tstruct Camera3RequestDescriptor {\n> > +\t\tCamera3RequestDescriptor(unsigned int frameNumber,\n> > +\t\t\t\t\t unsigned int numBuffers);\n> > +\t\t~Camera3RequestDescriptor();\n> > +\n> > +\t\tuint32_t frameNumber;\n> > +\t\tuint32_t numBuffers;\n> > +\t\tcamera3_stream_buffer_t *buffers;\n> > +\t};\n> > +\n> > +\tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n> > +\tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream);\n> > +\tcamera_metadata_t *getResultMetadata(int frame_number, int64_t timestamp);\n> > +\n> > +\tbool running_;\n> > +\tstd::shared_ptr<libcamera::Camera> camera_;\n> > +\tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> > +\n> > +\tcamera_metadata_t *staticMetadata_;\n> > +\tcamera_metadata_t *requestTemplate_;\n> > +\tconst camera3_callback_ops_t *callbacks_;\n> > +};\n> > +\n> > +#endif /* __ANDROID_CAMERA_DEVICE_H__ */\n> > diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp\n> > new file mode 100644\n> > index 000000000000..08c759dfd8a1\n> > --- /dev/null\n> > +++ b/src/android/camera_hal_manager.cpp\n> > @@ -0,0 +1,138 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_hal_manager.cpp - libcamera Android Camera Manager\n> > + */\n> > +\n> > +#include \"camera_hal_manager.h\"\n> > +\n> > +#include <libcamera/camera.h>\n> > +\n> > +#include \"log.h\"\n> > +\n> > +#include \"camera_device.h\"\n> > +#include \"camera_proxy.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DECLARE_CATEGORY(HAL);\n> > +\n> > +/*\n> > + * \\class CameraHalManager\n> > + *\n> > + * The HAL camera manager is initializated at camera_module_t 'hal_init()' time\n> > + * and spawns its own thread where libcamera related events are dispatched to.\n> > + * It wraps the libcamera CameraManager operations and provides helpers for the\n> > + * camera_module_t operations, to retrieve the number of cameras in the system,\n> > + * their static information and to open and close camera devices.\n> > + */\n> > +\n> > +int CameraHalManager::init()\n> > +{\n> > +\t/*\n> > +\t * Start the camera HAL manager thread and wait until its\n> > +\t * initialisation completes to be fully operational before\n> > +\t * receiving calls from the camera stack.\n> > +\t */\n> > +\tstart();\n> > +\n> > +\tMutexLocker locker(mutex_);\n> > +\tcv_.wait(locker);\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void CameraHalManager::run()\n> > +{\n> > +\t/*\n> > +\t * All the libcamera components must be initialised here, in\n> > +\t * order to bind them to the camera HAL manager thread that\n> > +\t * executes the event dispatcher.\n> > +\t */\n> > +\tcameraManager_ = libcamera::CameraManager::instance();\n> > +\n> > +\tint ret = cameraManager_->start();\n> > +\tif (ret) {\n> > +\t\tLOG(HAL, Error) << \"Failed to start camera manager: \"\n> > +\t\t\t\t<< strerror(-ret);\n> > +\t\treturn;\n> > +\t}\n> > +\n> > +\t/*\n> > +\t * For each Camera registered in the system, a CameraProxy\n> > +\t * gets created here to wraps a camera device.\n> > +\t *\n> > +\t * \\todo Support camera hotplug.\n> > +\t */\n> > +\tunsigned int index = 0;\n> > +\tfor (auto &camera : cameraManager_->cameras()) {\n> > +\t\tCameraProxy *proxy = new CameraProxy(index, camera);\n> > +\t\tproxies_.emplace_back(proxy);\n> > +\n> > +\t\t++index;\n> > +\t}\n> > +\n> > +\t/*\n> > +\t * libcamera has been initialized. Unlock the init() caller\n> > +\t * as we're now ready to handle calls from the framework.\n> > +\t */\n> > +\tcv_.notify_one();\n> > +\n> > +\t/* Now start processing events and messages. */\n> > +\texec();\n> > +}\n> > +\n> > +CameraProxy *CameraHalManager::open(unsigned int id,\n> > +\t\t\t\t    const hw_module_t *hardwareModule)\n> > +{\n> > +\tif (id < 0 || id >= numCameras()) {\n> > +\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\tCameraProxy *proxy = proxies_[id].get();\n> > +\tif (proxy->open(hardwareModule))\n> > +\t\treturn nullptr;\n> > +\n> > +\tLOG(HAL, Info) << \"Open camera '\" << id << \"'\";\n> > +\n> > +\treturn proxy;\n> > +}\n> > +\n> > +int CameraHalManager::close(CameraProxy *proxy)\n> > +{\n> > +\tproxy->close();\n> > +\tLOG(HAL, Info) << \"Close camera '\" << proxy->id() << \"'\";\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +unsigned int CameraHalManager::numCameras() const\n> > +{\n> > +\treturn cameraManager_->cameras().size();\n> > +}\n> > +\n> > +int CameraHalManager::getCameraInfo(int id, struct camera_info *info)\n> > +{\n> > +\tif (!info)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tif (id >= numCameras() || id < 0) {\n> > +\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tCameraProxy *proxy = proxies_[id].get();\n> > +\n> > +\t/* \\todo Get these info dynamically inspecting the camera module. */\n> > +\tinfo->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;\n> > +\tinfo->orientation = 0;\n> > +\tinfo->device_version = 0;\n> > +\tinfo->resource_cost = 0;\n> > +\tinfo->static_camera_characteristics = proxy->getStaticMetadata();\n> > +\tinfo->conflicting_devices = nullptr;\n> > +\tinfo->conflicting_devices_length = 0;\n> > +\n> > +\treturn 0;\n> > +}\n> > diff --git a/src/android/camera_hal_manager.h b/src/android/camera_hal_manager.h\n> > new file mode 100644\n> > index 000000000000..8004aaf660f5\n> > --- /dev/null\n> > +++ b/src/android/camera_hal_manager.h\n> > @@ -0,0 +1,47 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_hal_manager.h - libcamera Android Camera Manager\n> > + */\n> > +#ifndef __ANDROID_CAMERA_MANAGER_H__\n> > +#define __ANDROID_CAMERA_MANAGER_H__\n> > +\n> > +#include <condition_variable>\n> > +#include <mutex>\n> > +#include <vector>\n> > +\n> > +#include <hardware/hardware.h>\n> > +#include <system/camera_metadata.h>\n> > +\n> > +#include <libcamera/camera_manager.h>\n> > +\n> > +#include \"thread.h\"\n> > +\n> > +class CameraDevice;\n> > +class CameraProxy;\n> > +\n> > +class CameraHalManager : public libcamera::Thread\n> > +{\n> > +public:\n> > +\tint init();\n> > +\n> > +\tCameraProxy *open(unsigned int id, const hw_module_t *module);\n> > +\tint close(CameraProxy *proxy);\n> > +\n> > +\tunsigned int numCameras() const;\n> > +\tint getCameraInfo(int id, struct camera_info *info);\n> > +\n> > +private:\n> > +\tvoid run() override;\n> > +\tcamera_metadata_t *getStaticMetadata(unsigned int id);\n> > +\n> > +\tlibcamera::CameraManager *cameraManager_;\n> > +\n> > +\tstd::mutex mutex_;\n> > +\tstd::condition_variable cv_;\n> > +\n> > +\tstd::vector<std::unique_ptr<CameraProxy>> proxies_;\n> > +};\n> > +\n> > +#endif /* __ANDROID_CAMERA_MANAGER_H__ */\n> > diff --git a/src/android/camera_proxy.cpp b/src/android/camera_proxy.cpp\n> > new file mode 100644\n> > index 000000000000..f0cacac8025b\n> > --- /dev/null\n> > +++ b/src/android/camera_proxy.cpp\n> > @@ -0,0 +1,194 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_proxy.cpp - Proxy to camera devices\n> > + */\n> > +\n> > +#include \"camera_proxy.h\"\n> > +\n> > +#include <system/camera_metadata.h>\n> > +\n> > +#include \"log.h\"\n> > +#include \"message.h\"\n> > +#include \"utils.h\"\n> > +\n> > +#include \"camera_device.h\"\n> > +#include \"thread_rpc.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DECLARE_CATEGORY(HAL);\n> > +\n> > +/*\n> > + * \\class CameraProxy\n> > + *\n> > + * The CameraProxy wraps a CameraDevice and implements the camera3_device_t\n> > + * API, bridging calls received from the camera framework to the CameraDevice.\n> > + *\n> > + * Bridging operation calls between the framework and the CameraDevice is\n> > + * required as the two run in two different threads and certain operations,\n> > + * such as queueing a new capture request to the camera, shall be called in\n> > + * the thread that dispatches events. Other operations do not require any\n> > + * bridging and resolve to direct function calls on the CameraDevice instance\n> > + * instead.\n> > + */\n> > +\n> > +static int hal_dev_initialize(const struct camera3_device *dev,\n> > +\t\t\t      const camera3_callback_ops_t *callback_ops)\n> > +{\n> > +\tif (!dev)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> > +\tproxy->initialize(callback_ops);\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +static int hal_dev_configure_streams(const struct camera3_device *dev,\n> > +\t\t\t\t     camera3_stream_configuration_t *stream_list)\n> > +{\n> > +\tif (!dev)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> > +\treturn proxy->configureStreams(stream_list);\n> > +}\n> > +\n> > +static const camera_metadata_t *\n> > +hal_dev_construct_default_request_settings(const struct camera3_device *dev,\n> > +\t\t\t\t\t   int type)\n> > +{\n> > +\tif (!dev)\n> > +\t\treturn nullptr;\n> > +\n> > +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> > +\treturn proxy->constructDefaultRequestSettings(type);\n> > +}\n> > +\n> > +static int hal_dev_process_capture_request(const struct camera3_device *dev,\n> > +\t\t\t\t\t   camera3_capture_request_t *request)\n> > +{\n> > +\tif (!dev)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> > +\treturn proxy->processCaptureRequest(request);\n> > +}\n> > +\n> > +static void hal_dev_dump(const struct camera3_device *dev, int fd)\n> > +{\n> > +}\n> > +\n> > +static int hal_dev_flush(const struct camera3_device *dev)\n> > +{\n> > +\treturn 0;\n> > +}\n> > +\n> > +static int hal_dev_close(hw_device_t *hw_device)\n> > +{\n> > +\tif (!hw_device)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tcamera3_device_t *dev = reinterpret_cast<camera3_device_t *>(hw_device);\n> > +\tCameraProxy *proxy = reinterpret_cast<CameraProxy *>(dev->priv);\n> > +\n> > +\tproxy->close();\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +static camera3_device_ops hal_dev_ops = {\n> > +\t.initialize = hal_dev_initialize,\n> > +\t.configure_streams = hal_dev_configure_streams,\n> > +\t.register_stream_buffers = nullptr,\n> > +\t.construct_default_request_settings = hal_dev_construct_default_request_settings,\n> > +\t.process_capture_request = hal_dev_process_capture_request,\n> > +\t.get_metadata_vendor_tag_ops = nullptr,\n> > +\t.dump = hal_dev_dump,\n> > +\t.flush = hal_dev_flush,\n> > +\t.reserved = { nullptr },\n> > +};\n> > +\n> > +CameraProxy::CameraProxy(unsigned int id, std::shared_ptr<Camera> camera)\n> > +\t: id_(id)\n> > +{\n> > +\tcameraDevice_ = new CameraDevice(id, camera);\n> > +}\n> > +\n> > +CameraProxy::~CameraProxy()\n> > +{\n> > +\tdelete cameraDevice_;\n> > +}\n> > +\n> > +int CameraProxy::open(const hw_module_t *hardwareModule)\n> > +{\n> > +\tint ret = cameraDevice_->open();\n> > +\tif (ret)\n> > +\t\treturn ret;\n> > +\n> > +\t/* Initialize the hw_device_t in the instance camera3_module_t. */\n> > +\tcamera3Device_.common.tag = HARDWARE_DEVICE_TAG;\n> > +\tcamera3Device_.common.version = CAMERA_DEVICE_API_VERSION_3_3;\n> > +\tcamera3Device_.common.module = (hw_module_t *)hardwareModule;\n> > +\tcamera3Device_.common.close = hal_dev_close;\n> > +\n> > +\t/*\n> > +\t * The camera device operations. These actually implement\n> > +\t * the Android Camera HALv3 interface.\n> > +\t */\n> > +\tcamera3Device_.ops = &hal_dev_ops;\n> > +\tcamera3Device_.priv = this;\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void CameraProxy::close()\n> > +{\n> > +\tThreadRpc rpcRequest;\n> > +\trpcRequest.tag = ThreadRpc::Close;\n> > +\n> > +\tthreadRpcCall(rpcRequest);\n> > +}\n> > +\n> > +void CameraProxy::initialize(const camera3_callback_ops_t *callbacks)\n> > +{\n> > +\tcameraDevice_->setCallbacks(callbacks);\n> > +}\n> > +\n> > +const camera_metadata_t *CameraProxy::getStaticMetadata()\n> > +{\n> > +\treturn cameraDevice_->getStaticMetadata();\n> > +}\n> > +\n> > +const camera_metadata_t *CameraProxy::constructDefaultRequestSettings(int type)\n> > +{\n> > +\treturn cameraDevice_->constructDefaultRequestSettings(type);\n> > +}\n> > +\n> > +int CameraProxy::configureStreams(camera3_stream_configuration_t *stream_list)\n> > +{\n> > +\treturn cameraDevice_->configureStreams(stream_list);\n> > +}\n> > +\n> > +int CameraProxy::processCaptureRequest(camera3_capture_request_t *request)\n> > +{\n> > +\tThreadRpc rpcRequest;\n> > +\trpcRequest.tag = ThreadRpc::ProcessCaptureRequest;\n> > +\trpcRequest.request = request;\n> > +\n> > +\tthreadRpcCall(rpcRequest);\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void CameraProxy::threadRpcCall(ThreadRpc &rpcRequest)\n> > +{\n> > +\tstd::unique_ptr<ThreadRpcMessage> message =\n> > +\t\t\t\tutils::make_unique<ThreadRpcMessage>();\n> > +\tmessage->rpc = &rpcRequest;\n> > +\n> > +\tcameraDevice_->postMessage(std::move(message));\n> > +\trpcRequest.waitDelivery();\n> > +}\n> > diff --git a/src/android/camera_proxy.h b/src/android/camera_proxy.h\n> > new file mode 100644\n> > index 000000000000..da63bfa79fc9\n> > --- /dev/null\n> > +++ b/src/android/camera_proxy.h\n> > @@ -0,0 +1,45 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * camera_proxy.h - Proxy to camera devices\n> > + */\n> > +#ifndef __ANDROID_CAMERA_PROXY_H__\n> > +#define __ANDROID_CAMERA_PROXY_H__\n> > +\n> > +#include <memory>\n> > +\n> > +#include <hardware/camera3.h>\n> > +\n> > +#include <libcamera/camera.h>\n> > +\n> > +class CameraDevice;\n> > +class ThreadRpc;\n> > +\n> > +class CameraProxy\n> > +{\n> > +public:\n> > +\tCameraProxy(unsigned int id, std::shared_ptr<libcamera::Camera> camera);\n> > +\t~CameraProxy();\n> > +\n> > +\tint open(const hw_module_t *hardwareModule);\n> > +\tvoid close();\n> > +\n> > +\tvoid initialize(const camera3_callback_ops_t *callbacks);\n> > +\tconst camera_metadata_t *getStaticMetadata();\n> > +\tconst camera_metadata_t *constructDefaultRequestSettings(int type);\n> > +\tint configureStreams(camera3_stream_configuration_t *stream_list);\n> > +\tint processCaptureRequest(camera3_capture_request_t *request);\n> > +\n> > +\tunsigned int id() const { return id_; }\n> > +\tcamera3_device_t *camera3Device() { return &camera3Device_; }\n> > +\n> > +private:\n> > +\tvoid threadRpcCall(ThreadRpc &rpcRequest);\n> > +\n> > +\tunsigned int id_;\n> > +\tCameraDevice *cameraDevice_;\n> > +\tcamera3_device_t camera3Device_;\n> > +};\n> > +\n> > +#endif /* __ANDROID_CAMERA_PROXY_H__ */\n> > diff --git a/src/android/meson.build b/src/android/meson.build\n> > index 1f242953db37..26537794bc29 100644\n> > --- a/src/android/meson.build\n> > +++ b/src/android/meson.build\n> > @@ -1,3 +1,11 @@\n> > +android_hal_sources = files([\n> > +    'camera3_hal.cpp',\n> > +    'camera_hal_manager.cpp',\n> > +    'camera_device.cpp',\n> > +    'camera_proxy.cpp',\n> > +    'thread_rpc.cpp'\n> > +])\n> > +\n> >  android_camera_metadata_sources = files([\n> >      'metadata/camera_metadata.c',\n> >  ])\n> > diff --git a/src/android/thread_rpc.cpp b/src/android/thread_rpc.cpp\n> > new file mode 100644\n> > index 000000000000..295a05d7c676\n> > --- /dev/null\n> > +++ b/src/android/thread_rpc.cpp\n> > @@ -0,0 +1,42 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * thread_rpc.cpp - Inter-thread procedure call\n> > + */\n> > +\n> > +#include \"thread_rpc.h\"\n> > +\n> > +#include \"message.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +libcamera::Message::Type ThreadRpcMessage::rpcType_ = Message::Type::None;\n> > +\n> > +ThreadRpcMessage::ThreadRpcMessage()\n> > +\t: Message(type())\n> > +{\n> > +}\n> > +\n> > +void ThreadRpc::notifyReception()\n> > +{\n> > +\t{\n> > +\t\tlibcamera::MutexLocker locker(mutex_);\n> > +\t\tdelivered_ = true;\n> > +\t}\n> > +\tcv_.notify_one();\n> > +}\n> > +\n> > +void ThreadRpc::waitDelivery()\n> > +{\n> > +\tlibcamera::MutexLocker locker(mutex_);\n> > +\tcv_.wait(locker, [&] { return delivered_; });\n> > +}\n> > +\n> > +Message::Type ThreadRpcMessage::type()\n> > +{\n> > +\tif (ThreadRpcMessage::rpcType_ == Message::Type::None)\n> > +\t\trpcType_ = Message::registerMessageType();\n> > +\n> > +\treturn rpcType_;\n> > +}\n> > diff --git a/src/android/thread_rpc.h b/src/android/thread_rpc.h\n> > new file mode 100644\n> > index 000000000000..6d8992839d0b\n> > --- /dev/null\n> > +++ b/src/android/thread_rpc.h\n> > @@ -0,0 +1,54 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * thread_rpc.h - Inter-thread procedure call\n> > + */\n> > +#ifndef __ANDROID_THREAD_RPC_H__\n> > +#define __ANDROID_THREAD_RPC_H__\n> > +\n> > +#include <condition_variable>\n> > +#include <mutex>\n> > +\n> > +#include <hardware/camera3.h>\n> > +\n> > +#include \"message.h\"\n> > +#include \"thread.h\"\n> > +\n> > +class ThreadRpc\n> > +{\n> > +public:\n> > +\tenum RpcTag {\n> > +\t\tProcessCaptureRequest,\n> > +\t\tClose,\n> > +\t};\n> > +\n> > +\tThreadRpc()\n> > +\t\t: delivered_(false) {}\n> > +\n> > +\tvoid notifyReception();\n> > +\tvoid waitDelivery();\n> > +\n> > +\tRpcTag tag;\n> > +\n> > +\tcamera3_capture_request_t *request;\n> > +\n> > +private:\n> > +\tbool delivered_;\n> > +\tstd::mutex mutex_;\n> > +\tstd::condition_variable cv_;\n> > +};\n> > +\n> > +class ThreadRpcMessage : public libcamera::Message\n> > +{\n> > +public:\n> > +\tThreadRpcMessage();\n> > +\tThreadRpc *rpc;\n> > +\n> > +\tstatic Message::Type type();\n> > +\n> > +private:\n> > +\tstatic libcamera::Message::Type rpcType_;\n> > +};\n> > +\n> > +#endif /* __ANDROID_THREAD_RPC_H__ */\n> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > index a09b23d60022..7d5d3c04fba0 100644\n> > --- a/src/libcamera/meson.build\n> > +++ b/src/libcamera/meson.build\n> > @@ -103,9 +103,18 @@ libcamera_deps = [\n> >      dependency('threads'),\n> >  ]\n> >\n> > +libcamera_link_with = []\n> > +\n> > +if get_option('android')\n> > +    libcamera_sources += android_hal_sources\n> > +    includes += android_includes\n> > +    libcamera_link_with += android_camera_metadata\n> > +endif\n> > +\n> >  libcamera = shared_library('camera',\n> >                             libcamera_sources,\n> >                             install : true,\n> > +                           link_with : libcamera_link_with,\n> >                             include_directories : includes,\n> >                             dependencies : libcamera_deps)\n> >\n> > diff --git a/src/meson.build b/src/meson.build\n> > index 7148baee3eda..67ad20aab86b 100644\n> > --- a/src/meson.build\n> > +++ b/src/meson.build\n> > @@ -1,4 +1,7 @@\n> > -subdir('android')\n> > +if get_option('android')\n> > +    subdir('android')\n> > +endif\n> > +\n> >  subdir('libcamera')\n> >  subdir('ipa')\n> >  subdir('cam')\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net\n\t[217.70.183.197])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3DD1860E38\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 11:53:58 +0200 (CEST)","from uno.localdomain\n\t(host64-130-dynamic.5-87-r.retail.telecomitalia.it [87.5.130.64])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 6B4641C0004;\n\tMon, 12 Aug 2019 09:53:55 +0000 (UTC)"],"X-Originating-IP":"87.5.130.64","Date":"Mon, 12 Aug 2019 11:55:22 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812095522.h5q5ni6ebfzcrudw@uno.localdomain>","References":"<20190812084146.23802-1-jacopo@jmondi.org>\n\t<20190812084146.23802-2-jacopo@jmondi.org>\n\t<20190812094238.GA5006@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"ugo4reszdzokvokn\"","Content-Disposition":"inline","In-Reply-To":"<20190812094238.GA5006@pendragon.ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v4 1/1] android: hal: Add Camera3 HAL","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 12 Aug 2019 09:53:58 -0000"}}]