[{"id":2374,"web_url":"https://patchwork.libcamera.org/comment/2374/","msgid":"<20190810165151.GE4788@pendragon.ideasonboard.com>","date":"2019-08-10T16:51:51","subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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 Fri, Aug 09, 2019 at 12:04:05PM +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>  meson_options.txt                  |   5 +\n>  src/android/camera3_hal.cpp        | 111 ++++\n>  src/android/camera_device.cpp      | 817 +++++++++++++++++++++++++++++\n>  src/android/camera_device.h        |  63 +++\n>  src/android/camera_hal_manager.cpp | 142 +++++\n>  src/android/camera_hal_manager.h   |  47 ++\n>  src/android/camera_proxy.cpp       | 199 +++++++\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, 1546 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..18bf459a37e1\n> --- /dev/null\n> +++ b/src/android/camera_device.cpp\n> @@ -0,0 +1,817 @@\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 <memory>\n> +\n> +#include <hardware/camera3.h>\n> +#include <system/camera_metadata.h>\n> +\n> +#include <libcamera/camera.h>\n> +\n> +#include \"log.h\"\n> +#include \"message.h\"\n> +\n> +#include \"thread_rpc.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL);\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 informations on a Camera, create request templates\n\ns/informations on/information for/\n\n> + * for it and process capture requests by then delivering capture results back\n\ns/and process/, process/\ns/by then delevering/, and then deliver/\n\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 informations on the camera.\n\ns/informations on/information for/\n\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> +\n\nExtra blank line.\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. As of now, do not change the\n\ns/As of/For/\n\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 = new Camera3RequestDescriptor();\n> +\tdescriptor->frameNumber = camera3Request->frame_number;\n> +\tdescriptor->numBuffers = camera3Request->num_output_buffers;\n> +\tdescriptor->buffers = new camera3_stream_buffer_t[descriptor->numBuffers];\n> +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> +\t\t/*\n> +\t\t * Keep track of which stream the request belong and of the\n> +\t\t * 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\treturn -EINVAL;\n\nYou're leaking descriptor and descriptor->buffers.\n\nI would implement a constructor for Camera3RequestDescriptor that takes\nthe number of buffers and allocate the buffers member, and a destructor\nthat deletes the buffers member. Then you will only need to care about\ndeleting descriptor here.\n\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\treturn ret;\n\nYou're leaking request, descriptor and descriptor->buffers.\n\nI wonder if Camera::createRequest() shouldn't return an std::unique_ptr\n(this doesn't need to be addressed in this patch series).\n\n> +\t}\n> +\n> +\treturn 0;\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 * The buffers in the descriptor have been set up at queue\n> +\t\t * request time.\n\nI think you can drop this sentence.\n\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].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->buffers;\n> +\tdelete descriptor;\n\nThis will also be simplified with a destructor for the\nCamera3RequestDescriptor class.\n\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..402c3dca69da\n> --- /dev/null\n> +++ b/src/android/camera_device.h\n> @@ -0,0 +1,63 @@\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/libcamera.h>\n\nJust the required headers please :-)\n\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\nYou can make the second argument a reference to avoid an unnecessary\ncopy.\n\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\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..0b4d50368ff8\n> --- /dev/null\n> +++ b/src/android/camera_hal_manager.cpp\n> @@ -0,0 +1,142 @@\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 <hardware/hardware.h>\n> +#include <system/camera_metadata.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\n\ns/for/for the/\n\n> + * camera_module_t operations, to retrieve the number of cameras in the system\n\ns/system/system, to retrieve /\n\n> + * their static informations and to open and close camera devices.\n\ns/informations/information/\n\n> + */\n> +\n> +int CameraHalManager::init()\n> +{\n> +\t/*\n> +\t * Start the camera HAL manager thread and wait until its\n> +\t * initialisation to complete to be fully operational before\n\ns/to complete/completes/\n\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 wich wraps a camera device.\n\ns/wich wraps/to wrap/\n\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> +\tint cameras = numCameras();\n> +\tif (id >= cameras || id < 0) {\n\ns/cameras/numCameras()/\n\nand drop the local variable.\n\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..23c33c8f6c9c\n> --- /dev/null\n> +++ b/src/android/camera_proxy.cpp\n> @@ -0,0 +1,199 @@\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 <memory>\n> +\n> +#include <hardware/camera3.h>\n> +#include <system/camera_metadata.h>\n> +\n> +#include <libcamera/camera.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 runs in two different threads and certain operations,\n\ns/runs/run/\n\n> + * such as queueing a new capture request to the camera, require to interrupt\n> + * and restart the even dispatches associated with the thread where the\n\ns/even dispatches/event dispatcher/\n\nIt's not about interrupting the event dispatcher, but about being called\nin the same thread than the one that handles events.\n\n\"such as queueing a new capture request to the camera, shall be called\nin the thread that dispatches events.\"\n\n> + * CameraDevice is running. Other operations do not require any bridging and\n> + * resolve to direct function calls on the CameraDevice instance 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\nRepeating my question for the previous version, does this method need to\nbe synchronous ? We can keep it as-is for now, but I wonder if it\nwouldn't make sense to later move (part of) the validation code here and\nmake the call asynchronous.\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[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C1D460C03\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 10 Aug 2019 18:51:56 +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 8902767;\n\tSat, 10 Aug 2019 18:51:55 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565455915;\n\tbh=EDStao9J5pWgwdpFTNFn27HfLnGhjTpvLFGtjn5Mf4M=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=vw7MoYMK67deJ3DLXqzRKw5yZ5ATngzKRoM94zD0/yj+6jV8p0/LrpagBylHigRfg\n\t8sNsoQ+vkJaK/REts0bANmZlAnMOzm7sK9b8cmkECPYaj4RKVBUPqKEtd/O0WrP4Gp\n\tpNWykPRjHXpaOPlnu6f7bitWgoN+YIC73gs/rLfQ=","Date":"Sat, 10 Aug 2019 19:51:51 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190810165151.GE4788@pendragon.ideasonboard.com>","References":"<20190809100406.22559-1-jacopo@jmondi.org>\n\t<20190809100406.22559-7-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190809100406.22559-7-jacopo@jmondi.org>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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":"Sat, 10 Aug 2019 16:51:56 -0000"}},{"id":2377,"web_url":"https://patchwork.libcamera.org/comment/2377/","msgid":"<20190812070907.qztqdxk7ofvn5bjr@uno.localdomain>","date":"2019-08-12T07:09:07","subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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 Sat, Aug 10, 2019 at 07:51:51PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> Thank you for the patch.\n>\n> On Fri, Aug 09, 2019 at 12:04:05PM +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> >  meson_options.txt                  |   5 +\n> >  src/android/camera3_hal.cpp        | 111 ++++\n> >  src/android/camera_device.cpp      | 817 +++++++++++++++++++++++++++++\n> >  src/android/camera_device.h        |  63 +++\n> >  src/android/camera_hal_manager.cpp | 142 +++++\n> >  src/android/camera_hal_manager.h   |  47 ++\n> >  src/android/camera_proxy.cpp       | 199 +++++++\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, 1546 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..18bf459a37e1\n> > --- /dev/null\n> > +++ b/src/android/camera_device.cpp\n> > @@ -0,0 +1,817 @@\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 <memory>\n> > +\n> > +#include <hardware/camera3.h>\n> > +#include <system/camera_metadata.h>\n> > +\n> > +#include <libcamera/camera.h>\n> > +\n> > +#include \"log.h\"\n> > +#include \"message.h\"\n> > +\n> > +#include \"thread_rpc.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DECLARE_CATEGORY(HAL);\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 informations on a Camera, create request templates\n>\n> s/informations on/information for/\n>\n> > + * for it and process capture requests by then delivering capture results back\n>\n> s/and process/, process/\n> s/by then delevering/, and then deliver/\n>\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 informations on the camera.\n>\n> s/informations on/information for/\n>\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> > +\n>\n> Extra blank line.\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. As of now, do not change the\n>\n> s/As of/For/\n>\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 = new Camera3RequestDescriptor();\n> > +\tdescriptor->frameNumber = camera3Request->frame_number;\n> > +\tdescriptor->numBuffers = camera3Request->num_output_buffers;\n> > +\tdescriptor->buffers = new camera3_stream_buffer_t[descriptor->numBuffers];\n> > +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> > +\t\t/*\n> > +\t\t * Keep track of which stream the request belong and of the\n> > +\t\t * 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\treturn -EINVAL;\n>\n> You're leaking descriptor and descriptor->buffers.\n>\n\nAre you sure? I delete them at the time a request completes. See\nbelow, you have commented on it.\n\nBut now I get you meant I'm leaking them in the error path! I\nre-ordered this sequence for cosmetic reasons and forgot to handle\nthis! thanks\n\n> I would implement a constructor for Camera3RequestDescriptor that takes\n> the number of buffers and allocate the buffers member, and a destructor\n> that deletes the buffers member. Then you will only need to care about\n> deleting descriptor here.\n\nGood idea\n\n>\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\treturn ret;\n>\n> You're leaking request, descriptor and descriptor->buffers.\n>\n> I wonder if Camera::createRequest() shouldn't return an std::unique_ptr\n> (this doesn't need to be addressed in this patch series).\n>\n> > +\t}\n> > +\n> > +\treturn 0;\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 * The buffers in the descriptor have been set up at queue\n> > +\t\t * request time.\n>\n> I think you can drop this sentence.\n>\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].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->buffers;\n> > +\tdelete descriptor;\n>\n> This will also be simplified with a destructor for the\n> Camera3RequestDescriptor class.\n>\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..402c3dca69da\n> > --- /dev/null\n> > +++ b/src/android/camera_device.h\n> > @@ -0,0 +1,63 @@\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/libcamera.h>\n>\n> Just the required headers please :-)\n>\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>\n> You can make the second argument a reference to avoid an unnecessary\n> copy.\n\nIsn't there some copy elision magic that helps here? The temporary\nargument instance is created and destroyed immediately... I can indeed\nuse a reference though\n\n>\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\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..0b4d50368ff8\n> > --- /dev/null\n> > +++ b/src/android/camera_hal_manager.cpp\n> > @@ -0,0 +1,142 @@\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 <hardware/hardware.h>\n> > +#include <system/camera_metadata.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\n>\n> s/for/for the/\n>\n> > + * camera_module_t operations, to retrieve the number of cameras in the system\n>\n> s/system/system, to retrieve /\n>\n> > + * their static informations and to open and close camera devices.\n>\n> s/informations/information/\n>\n> > + */\n> > +\n> > +int CameraHalManager::init()\n> > +{\n> > +\t/*\n> > +\t * Start the camera HAL manager thread and wait until its\n> > +\t * initialisation to complete to be fully operational before\n>\n> s/to complete/completes/\n>\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 wich wraps a camera device.\n>\n> s/wich wraps/to wrap/\n>\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> > +\tint cameras = numCameras();\n> > +\tif (id >= cameras || id < 0) {\n>\n> s/cameras/numCameras()/\n>\n> and drop the local variable.\n>\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..23c33c8f6c9c\n> > --- /dev/null\n> > +++ b/src/android/camera_proxy.cpp\n> > @@ -0,0 +1,199 @@\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 <memory>\n> > +\n> > +#include <hardware/camera3.h>\n> > +#include <system/camera_metadata.h>\n> > +\n> > +#include <libcamera/camera.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 runs in two different threads and certain operations,\n>\n> s/runs/run/\n>\n> > + * such as queueing a new capture request to the camera, require to interrupt\n> > + * and restart the even dispatches associated with the thread where the\n>\n> s/even dispatches/event dispatcher/\n>\n> It's not about interrupting the event dispatcher, but about being called\n> in the same thread than the one that handles events.\n\nI was actually thinking about the -first- capture request, that\nby starting the video device, updates the list of file descriptors to\nmonitor and requires the even notifier to be interrupted and\nrestarted. In general, you're correct and I'll change this.\n\n>\n> \"such as queueing a new capture request to the camera, shall be called\n> in the thread that dispatches events.\"\n>\n> > + * CameraDevice is running. Other operations do not require any bridging and\n> > + * resolve to direct function calls on the CameraDevice instance 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> Repeating my question for the previous version, does this method need to\n> be synchronous ? We can keep it as-is for now, but I wonder if it\n> wouldn't make sense to later move (part of) the validation code here and\n> make the call asynchronous.\n\nAre you suggesting to drop the wait on the delivery condition in the\nrpc call? How else would you make it asynchronous?\n\nThanks\n   j\n\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 relay10.mail.gandi.net (relay10.mail.gandi.net\n\t[217.70.178.230])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1FF0A60C43\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 09:07:48 +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 relay10.mail.gandi.net (Postfix) with ESMTPSA id 3054D24000D;\n\tMon, 12 Aug 2019 07:07:44 +0000 (UTC)"],"Date":"Mon, 12 Aug 2019 09:09:07 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812070907.qztqdxk7ofvn5bjr@uno.localdomain>","References":"<20190809100406.22559-1-jacopo@jmondi.org>\n\t<20190809100406.22559-7-jacopo@jmondi.org>\n\t<20190810165151.GE4788@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"fhnzjwhwquwenoki\"","Content-Disposition":"inline","In-Reply-To":"<20190810165151.GE4788@pendragon.ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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 07:07:48 -0000"}},{"id":2383,"web_url":"https://patchwork.libcamera.org/comment/2383/","msgid":"<20190812092102.4fi4w5zxeryji5qm@uno.localdomain>","date":"2019-08-12T09:21:02","subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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, one additiona note\n\nOn Sat, Aug 10, 2019 at 07:51:51PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n\n[snip]\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> Repeating my question for the previous version, does this method need to\n> be synchronous ? We can keep it as-is for now, but I wonder if it\n> wouldn't make sense to later move (part of) the validation code here and\n> make the call asynchronous.\n>\n\nQuoting the camera3.h header description of the expected operation\nsequence:\n\n * 7. The framework constructs and sends the first capture request to the HAL,\n *    with settings based on one of the sets of default settings, and with at\n *    least one output stream, which has been registered earlier by the\n *    framework. This is sent to the HAL with\n *    camera3_device_t->ops->process_capture_request(). The HAL must block the\n *    return of this call until it is ready for the next request to be sent.\n\nThe last statement makes me wonder if making the method asynchronous\nwould not then require serializin the requests on our side, as if we\nreturn earlier, there might be a chance (no idea how large the\nwindonw could be) we receive a new capture request while the previous\none still has to be handled.\n\nConsider this, I'm not sure it's a good idea to make this call\nasynchronous.\n\nThanks\n   j","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n\t[217.70.183.201])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id ED67A60E38\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 11:19:35 +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 relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 57CA91BF20C;\n\tMon, 12 Aug 2019 09:19:35 +0000 (UTC)"],"X-Originating-IP":"87.5.130.64","Date":"Mon, 12 Aug 2019 11:21:02 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812092102.4fi4w5zxeryji5qm@uno.localdomain>","References":"<20190809100406.22559-1-jacopo@jmondi.org>\n\t<20190809100406.22559-7-jacopo@jmondi.org>\n\t<20190810165151.GE4788@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"6zhtpxesnl6ccwpy\"","Content-Disposition":"inline","In-Reply-To":"<20190810165151.GE4788@pendragon.ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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:19:36 -0000"}},{"id":2385,"web_url":"https://patchwork.libcamera.org/comment/2385/","msgid":"<20190812094713.GB5006@pendragon.ideasonboard.com>","date":"2019-08-12T09:47:13","subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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\nOn Mon, Aug 12, 2019 at 09:09:07AM +0200, Jacopo Mondi wrote:\n> On Sat, Aug 10, 2019 at 07:51:51PM +0300, Laurent Pinchart wrote:\n> > On Fri, Aug 09, 2019 at 12:04:05PM +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> > >  meson_options.txt                  |   5 +\n> > >  src/android/camera3_hal.cpp        | 111 ++++\n> > >  src/android/camera_device.cpp      | 817 +++++++++++++++++++++++++++++\n> > >  src/android/camera_device.h        |  63 +++\n> > >  src/android/camera_hal_manager.cpp | 142 +++++\n> > >  src/android/camera_hal_manager.h   |  47 ++\n> > >  src/android/camera_proxy.cpp       | 199 +++++++\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, 1546 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..18bf459a37e1\n> > > --- /dev/null\n> > > +++ b/src/android/camera_device.cpp\n> > > @@ -0,0 +1,817 @@\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 <memory>\n> > > +\n> > > +#include <hardware/camera3.h>\n> > > +#include <system/camera_metadata.h>\n> > > +\n> > > +#include <libcamera/camera.h>\n> > > +\n> > > +#include \"log.h\"\n> > > +#include \"message.h\"\n> > > +\n> > > +#include \"thread_rpc.h\"\n> > > +\n> > > +using namespace libcamera;\n> > > +\n> > > +LOG_DECLARE_CATEGORY(HAL);\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 informations on a Camera, create request templates\n> >\n> > s/informations on/information for/\n> >\n> > > + * for it and process capture requests by then delivering capture results back\n> >\n> > s/and process/, process/\n> > s/by then delevering/, and then deliver/\n> >\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 informations on the camera.\n> >\n> > s/informations on/information for/\n> >\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> > > +\n> >\n> > Extra blank line.\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. As of now, do not change the\n> >\n> > s/As of/For/\n> >\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 = new Camera3RequestDescriptor();\n> > > +\tdescriptor->frameNumber = camera3Request->frame_number;\n> > > +\tdescriptor->numBuffers = camera3Request->num_output_buffers;\n> > > +\tdescriptor->buffers = new camera3_stream_buffer_t[descriptor->numBuffers];\n> > > +\tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n> > > +\t\t/*\n> > > +\t\t * Keep track of which stream the request belong and of the\n> > > +\t\t * 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\treturn -EINVAL;\n> >\n> > You're leaking descriptor and descriptor->buffers.\n> \n> Are you sure? I delete them at the time a request completes. See\n> below, you have commented on it.\n> \n> But now I get you meant I'm leaking them in the error path! I\n> re-ordered this sequence for cosmetic reasons and forgot to handle\n> this! thanks\n\nYes that's what I meant :-)\n\n> > I would implement a constructor for Camera3RequestDescriptor that takes\n> > the number of buffers and allocate the buffers member, and a destructor\n> > that deletes the buffers member. Then you will only need to care about\n> > deleting descriptor here.\n> \n> Good idea\n> \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\treturn ret;\n> >\n> > You're leaking request, descriptor and descriptor->buffers.\n> >\n> > I wonder if Camera::createRequest() shouldn't return an std::unique_ptr\n> > (this doesn't need to be addressed in this patch series).\n> >\n> > > +\t}\n> > > +\n> > > +\treturn 0;\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 * The buffers in the descriptor have been set up at queue\n> > > +\t\t * request time.\n> >\n> > I think you can drop this sentence.\n> >\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].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->buffers;\n> > > +\tdelete descriptor;\n> >\n> > This will also be simplified with a destructor for the\n> > Camera3RequestDescriptor class.\n> >\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..402c3dca69da\n> > > --- /dev/null\n> > > +++ b/src/android/camera_device.h\n> > > @@ -0,0 +1,63 @@\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/libcamera.h>\n> >\n> > Just the required headers please :-)\n> >\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> >\n> > You can make the second argument a reference to avoid an unnecessary\n> > copy.\n> \n> Isn't there some copy elision magic that helps here? The temporary\n> argument instance is created and destroyed immediately... I can indeed\n> use a reference though\n\nAs far as I can tell, copy elision only applies to return values.\n\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\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..0b4d50368ff8\n> > > --- /dev/null\n> > > +++ b/src/android/camera_hal_manager.cpp\n> > > @@ -0,0 +1,142 @@\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 <hardware/hardware.h>\n> > > +#include <system/camera_metadata.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\n> >\n> > s/for/for the/\n> >\n> > > + * camera_module_t operations, to retrieve the number of cameras in the system\n> >\n> > s/system/system, to retrieve /\n> >\n> > > + * their static informations and to open and close camera devices.\n> >\n> > s/informations/information/\n> >\n> > > + */\n> > > +\n> > > +int CameraHalManager::init()\n> > > +{\n> > > +\t/*\n> > > +\t * Start the camera HAL manager thread and wait until its\n> > > +\t * initialisation to complete to be fully operational before\n> >\n> > s/to complete/completes/\n> >\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 wich wraps a camera device.\n> >\n> > s/wich wraps/to wrap/\n> >\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> > > +\tint cameras = numCameras();\n> > > +\tif (id >= cameras || id < 0) {\n> >\n> > s/cameras/numCameras()/\n> >\n> > and drop the local variable.\n> >\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..23c33c8f6c9c\n> > > --- /dev/null\n> > > +++ b/src/android/camera_proxy.cpp\n> > > @@ -0,0 +1,199 @@\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 <memory>\n> > > +\n> > > +#include <hardware/camera3.h>\n> > > +#include <system/camera_metadata.h>\n> > > +\n> > > +#include <libcamera/camera.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 runs in two different threads and certain operations,\n> >\n> > s/runs/run/\n> >\n> > > + * such as queueing a new capture request to the camera, require to interrupt\n> > > + * and restart the even dispatches associated with the thread where the\n> >\n> > s/even dispatches/event dispatcher/\n> >\n> > It's not about interrupting the event dispatcher, but about being called\n> > in the same thread than the one that handles events.\n> \n> I was actually thinking about the -first- capture request, that\n> by starting the video device, updates the list of file descriptors to\n> monitor and requires the even notifier to be interrupted and\n> restarted. In general, you're correct and I'll change this.\n> \n> > \"such as queueing a new capture request to the camera, shall be called\n> > in the thread that dispatches events.\"\n> >\n> > > + * CameraDevice is running. Other operations do not require any bridging and\n> > > + * resolve to direct function calls on the CameraDevice instance 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> > Repeating my question for the previous version, does this method need to\n> > be synchronous ? We can keep it as-is for now, but I wonder if it\n> > wouldn't make sense to later move (part of) the validation code here and\n> > make the call asynchronous.\n> \n> Are you suggesting to drop the wait on the delivery condition in the\n> rpc call? How else would you make it asynchronous?\n\nYes, that's my question. Does it have to wait, or can\nprocessCaptureRequest return before the message is delivered on the\nother side ?\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 7CCD060E38\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 11:47:16 +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 BA925327;\n\tMon, 12 Aug 2019 11:47:15 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565603236;\n\tbh=vDGG8O/CLP6gbEbUG8Nlg5dsKW4PUuH9YEsy11ICXMY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=IiCMymf4JBhLCxgpuEtKbuYvn0PYrSmXgEV1xDrg9qASViWJhIEu1HTNKZHPr3w76\n\twlr28+eydrRGbIpgFy706dvLltg6rNdo2pvwg3nAZ2q20b8pPYDPdkOJXAjeikU2X5\n\tdO99pdhU00WsdJ5e54pJscgOMiaOQpEzN4X/wt2I=","Date":"Mon, 12 Aug 2019 12:47:13 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812094713.GB5006@pendragon.ideasonboard.com>","References":"<20190809100406.22559-1-jacopo@jmondi.org>\n\t<20190809100406.22559-7-jacopo@jmondi.org>\n\t<20190810165151.GE4788@pendragon.ideasonboard.com>\n\t<20190812070907.qztqdxk7ofvn5bjr@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190812070907.qztqdxk7ofvn5bjr@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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:47:16 -0000"}},{"id":2386,"web_url":"https://patchwork.libcamera.org/comment/2386/","msgid":"<20190812094936.GC5006@pendragon.ideasonboard.com>","date":"2019-08-12T09:49:36","subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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\nOn Mon, Aug 12, 2019 at 11:21:02AM +0200, Jacopo Mondi wrote:\n> Hi Laurent, one additiona note\n> \n> On Sat, Aug 10, 2019 at 07:51:51PM +0300, Laurent Pinchart wrote:\n> > Hi Jacopo,\n> \n> [snip]\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> > Repeating my question for the previous version, does this method need to\n> > be synchronous ? We can keep it as-is for now, but I wonder if it\n> > wouldn't make sense to later move (part of) the validation code here and\n> > make the call asynchronous.\n> \n> Quoting the camera3.h header description of the expected operation\n> sequence:\n> \n>  * 7. The framework constructs and sends the first capture request to the HAL,\n>  *    with settings based on one of the sets of default settings, and with at\n>  *    least one output stream, which has been registered earlier by the\n>  *    framework. This is sent to the HAL with\n>  *    camera3_device_t->ops->process_capture_request(). The HAL must block the\n>  *    return of this call until it is ready for the next request to be sent.\n> \n> The last statement makes me wonder if making the method asynchronous\n> would not then require serializin the requests on our side, as if we\n> return earlier, there might be a chance (no idea how large the\n> windonw could be) we receive a new capture request while the previous\n> one still has to be handled.\n> \n> Consider this, I'm not sure it's a good idea to make this call\n> asynchronous.\n\nAs the calls are queued and processed in order in our HAL implementation\nI think we could still make it asynchronous, but it may not be worth it\nindeed. Let's just keep it in mind for now.","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2AEE360E38\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 12 Aug 2019 11:49:39 +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 A309A327;\n\tMon, 12 Aug 2019 11:49:38 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565603378;\n\tbh=SBZLdAEHh6qP2iVEvl0kwjXAomQuzY/KzAR6s3rfaag=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=FFGpNypt/Xb1vHwLPceETLRSRpomsHv/f8b9jydxBkJ/ev5cW/1ugZQ1BqQTm225d\n\tR34ZKSjAhIt6DfBH9Q08TxtS/aMDFTxW6H3JIYNOGPkHO0s0AwN369yuNRyefJJkCx\n\t/pb89Ey/AIXQPCEvR+C2wQLt/Ik8+tRcj0kx0xUY=","Date":"Mon, 12 Aug 2019 12:49:36 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190812094936.GC5006@pendragon.ideasonboard.com>","References":"<20190809100406.22559-1-jacopo@jmondi.org>\n\t<20190809100406.22559-7-jacopo@jmondi.org>\n\t<20190810165151.GE4788@pendragon.ideasonboard.com>\n\t<20190812092102.4fi4w5zxeryji5qm@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190812092102.4fi4w5zxeryji5qm@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 6/6] 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:49:39 -0000"}}]