Show a patch.

GET /api/1.1/patches/1761/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1761,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/1761/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/1761/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20190809100406.22559-7-jacopo@jmondi.org>",
    "date": "2019-08-09T10:04:05",
    "name": "[libcamera-devel,v3,6/6] android: hal: Add Camera3 HAL",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "5cbc6a44f11c369513762316739262747ff762c4",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/1761/mbox/",
    "series": [
        {
            "id": 450,
            "url": "https://patchwork.libcamera.org/api/1.1/series/450/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=450",
            "date": "2019-08-09T10:03:59",
            "name": "android: Add initial Camera HAL implementation",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/450/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/1761/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/1761/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<jacopo@jmondi.org>",
        "Received": [
            "from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net\n\t[217.70.183.198])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E8BFA6162C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  9 Aug 2019 12:03:14 +0200 (CEST)",
            "from uno.homenet.telecomitalia.it\n\t(host150-24-dynamic.51-79-r.retail.telecomitalia.it [79.51.24.150])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay6-d.mail.gandi.net (Postfix) with ESMTPSA id 71EBAC000D;\n\tFri,  9 Aug 2019 10:03:12 +0000 (UTC)"
        ],
        "X-Originating-IP": "79.51.24.150",
        "From": "Jacopo Mondi <jacopo@jmondi.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri,  9 Aug 2019 12:04:05 +0200",
        "Message-Id": "<20190809100406.22559-7-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.22.0",
        "In-Reply-To": "<20190809100406.22559-1-jacopo@jmondi.org>",
        "References": "<20190809100406.22559-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[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": "Fri, 09 Aug 2019 10:03:15 -0000"
    },
    "content": "Add libcamera Android Camera HALv3 implementation.\n\nThe initial camera HAL implementation supports the LIMITED hardware\nlevel and uses statically defined metadata and camera characteristics.\n\nAdd a build option named 'android' and adjust the build system to\nselectively compile the Android camera HAL and link it against the\nrequired Android libraries.\n\nSigned-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",
    "diff": "diff --git a/meson_options.txt b/meson_options.txt\nindex 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')\ndiff --git a/src/android/camera3_hal.cpp b/src/android/camera3_hal.cpp\nnew file mode 100644\nindex 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+};\ndiff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\nnew file mode 100644\nindex 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+ * for it and process capture requests by then delivering capture results back\n+ * to the framework using the designated callbacks.\n+ */\n+\n+CameraDevice::CameraDevice(unsigned int id, std::shared_ptr<Camera> camera)\n+\t: running_(false), camera_(camera), staticMetadata_(nullptr),\n+\t  requestTemplate_(nullptr)\n+{\n+\tcamera_->requestCompleted.connect(this, &CameraDevice::requestComplete);\n+}\n+\n+CameraDevice::~CameraDevice()\n+{\n+\tif (staticMetadata_)\n+\t\tfree_camera_metadata(staticMetadata_);\n+\tstaticMetadata_ = nullptr;\n+\n+\tif (requestTemplate_)\n+\t\tfree_camera_metadata(requestTemplate_);\n+\trequestTemplate_ = nullptr;\n+}\n+\n+/*\n+ * Handle RPC request received from the associated proxy.\n+ */\n+void CameraDevice::message(Message *message)\n+{\n+\tif (message->type() != ThreadRpcMessage::type())\n+\t\treturn Object::message(message);\n+\n+\tThreadRpcMessage *rpcMessage = static_cast<ThreadRpcMessage *>(message);\n+\tThreadRpc *rpc = rpcMessage->rpc;\n+\n+\tswitch (rpc->tag) {\n+\tcase ThreadRpc::ProcessCaptureRequest:\n+\t\tprocessCaptureRequest(rpc->request);\n+\t\tbreak;\n+\tcase ThreadRpc::Close:\n+\t\tclose();\n+\t\tbreak;\n+\tdefault:\n+\t\tLOG(HAL, Error) << \"Unknown RPC operation: \" << rpc->tag;\n+\t}\n+\n+\trpc->notifyReception();\n+}\n+\n+int CameraDevice::open()\n+{\n+\tint ret = camera_->acquire();\n+\tif (ret) {\n+\t\tLOG(HAL, Error) << \"Failed to acquire the camera\";\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void CameraDevice::close()\n+{\n+\tcamera_->stop();\n+\n+\tcamera_->freeBuffers();\n+\tcamera_->release();\n+\n+\trunning_ = false;\n+}\n+\n+void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n+{\n+\tcallbacks_ = callbacks;\n+}\n+\n+/*\n+ * Return static informations on the camera.\n+ */\n+camera_metadata_t *CameraDevice::getStaticMetadata()\n+{\n+\tint ret;\n+\n+\tif (staticMetadata_)\n+\t\treturn staticMetadata_;\n+\n+\t/*\n+\t * The here reported metadata are enough to implement a basic capture\n+\t * example application, but a real camera implementation will require\n+\t * more.\n+\t */\n+\n+\t/* \\todo Use correct sizes */\n+\t#define STATIC_ENTRY_CAP 256\n+\t#define STATIC_DATA_CAP 6688\n+\tcamera_metadata_t *staticMetadata =\n+\t\tallocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);\n+\n+\t/* Sensor static metadata. */\n+\tint32_t pixelArraySize[] = {\n+\t\t2592, 1944,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n+\t\t\t\t&pixelArraySize, 2);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t sensorSizes[] = {\n+\t\t0, 0, 2560, 1920,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n+\t\t\t\t&sensorSizes, 4);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t sensitivityRange[] = {\n+\t\t32, 2400,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n+\t\t\t\t&sensitivityRange, 2);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n+\t\t\t\t&filterArr, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint64_t exposureTimeRange[] = {\n+\t\t100000, 200000000,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n+\t\t\t\t&exposureTimeRange, 2);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t orientation = 0;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_SENSOR_ORIENTATION,\n+\t\t\t\t&orientation, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\t/* Flash static metadata. */\n+\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_FLASH_INFO_AVAILABLE,\n+\t\t\t&flashAvailable, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\t/* Lens static metadata. */\n+\tfloat fn = 2.53 / 100;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES, &fn, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\t/* Control metadata. */\n+\tchar controlMetadata = ANDROID_CONTROL_MODE_AUTO;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_CONTROL_AVAILABLE_MODES,\n+\t\t\t&controlMetadata, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tchar availableAntiBandingModes[] = {\n+\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n+\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n+\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n+\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n+\t\t\tavailableAntiBandingModes, 4);\n+\tMETADATA_ASSERT(ret);\n+\n+\tchar aeAvailableModes[] = {\n+\t\tANDROID_CONTROL_AE_MODE_ON,\n+\t\tANDROID_CONTROL_AE_MODE_OFF,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n+\t\t\taeAvailableModes, 2);\n+\tMETADATA_ASSERT(ret);\n+\n+\tcontrolMetadata = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n+\t\t\t&controlMetadata, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\t\t&awbLockAvailable, 1);\n+\n+\t/* Scaler static metadata. */\n+\tstd::vector<uint32_t> availableStreamFormats = {\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_SCALER_AVAILABLE_FORMATS,\n+\t\t\tavailableStreamFormats.data(),\n+\t\t\tavailableStreamFormats.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\tstd::vector<uint32_t> availableStreamConfigurations = {\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920,\n+\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920,\n+\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920,\n+\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n+\t\t\tavailableStreamConfigurations.data(),\n+\t\t\tavailableStreamConfigurations.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\tstd::vector<int64_t> availableStallDurations = {\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n+\t\t\tavailableStallDurations.data(),\n+\t\t\tavailableStallDurations.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\tstd::vector<int64_t> minFrameDurations = {\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920, 33333333,\n+\t\tANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920, 33333333,\n+\t};\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n+\t\t\tminFrameDurations.data(), minFrameDurations.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\t/* Info static metadata. */\n+\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n+\tret = add_camera_metadata_entry(staticMetadata,\n+\t\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n+\t\t\t&supportedHWLevel, 1);\n+\n+\treturn staticMetadata;\n+}\n+\n+/*\n+ * Produce a metadata pack to be used as template for a capture request.\n+ */\n+const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n+{\n+\tint ret;\n+\n+\t/*\n+\t * \\todo Inspect type and pick the right metadata pack.\n+\t * As of now just use a single one for all templates.\n+\t */\n+\tuint8_t captureIntent;\n+\tswitch (type) {\n+\tcase CAMERA3_TEMPLATE_PREVIEW:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n+\t\tbreak;\n+\tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n+\t\tbreak;\n+\tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n+\t\tbreak;\n+\tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n+\t\tbreak;\n+\tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;\n+\t\tbreak;\n+\tcase CAMERA3_TEMPLATE_MANUAL:\n+\t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL;\n+\t\tbreak;\n+\tdefault:\n+\t\tLOG(HAL, Error) << \"Invalid template request type: \" << type;\n+\t\treturn nullptr;\n+\t}\n+\n+\tif (requestTemplate_)\n+\t\treturn requestTemplate_;\n+\n+\t/* \\todo Use correct sizes */\n+\t#define REQUEST_TEMPLATE_ENTRIES\t  30\n+\t#define REQUEST_TEMPLATE_DATA\t\t2048\n+\trequestTemplate_ = allocate_camera_metadata(REQUEST_TEMPLATE_ENTRIES,\n+\t\t\t\t\t\t    REQUEST_TEMPLATE_DATA);\n+\tif (!requestTemplate_) {\n+\t\tLOG(HAL, Error) << \"Failed to allocate template metadata\";\n+\t\treturn nullptr;\n+\t}\n+\n+\t/* Set to 0 the number of 'processed and stalling' streams (ie JPEG). */\n+\tint32_t maxOutStream[] = { 0, 2, 0 };\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n+\t\t\tmaxOutStream, 3);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t maxPipelineDepth = 5;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n+\t\t\t&maxPipelineDepth, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t inputStreams = 0;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n+\t\t\t&inputStreams, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t partialResultCount = 1;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n+\t\t\t&partialResultCount, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t availableCapabilities[] = {\n+\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n+\t};\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n+\t\t\tavailableCapabilities, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AE_MODE,\n+\t\t\t&aeMode, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tint32_t aeExposureCompensation = 0;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n+\t\t\t&aeExposureCompensation, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n+\t\t\t&aePrecaptureTrigger, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AE_LOCK,\n+\t\t\t&aeLock, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AF_TRIGGER,\n+\t\t\t&afTrigger, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AWB_MODE,\n+\t\t\t&awbMode, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AWB_LOCK,\n+\t\t\t&awbLock, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\t\t&awbLockAvailable, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_FLASH_MODE,\n+\t\t\t&flashMode, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n+\t\t\t&faceDetectMode, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_CONTROL_CAPTURE_INTENT,\n+\t\t\t&captureIntent, 1);\n+\tMETADATA_ASSERT(ret);\n+\n+\t/*\n+\t * This is quite hard to list at the moment wihtout knowing what\n+\t * we could control.\n+\t *\n+\t * For now, just list in the available Request keys and in the available\n+\t * result keys the control and reporting of the AE algorithm.\n+\t */\n+\tstd::vector<int32_t> availableRequestKeys = {\n+\t\tANDROID_CONTROL_AE_MODE,\n+\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n+\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n+\t\tANDROID_CONTROL_AE_LOCK,\n+\t\tANDROID_CONTROL_AF_TRIGGER,\n+\t\tANDROID_CONTROL_AWB_MODE,\n+\t\tANDROID_CONTROL_AWB_LOCK,\n+\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\tANDROID_CONTROL_CAPTURE_INTENT,\n+\t\tANDROID_FLASH_MODE,\n+\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n+\t};\n+\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n+\t\t\tavailableRequestKeys.data(),\n+\t\t\tavailableRequestKeys.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\tstd::vector<int32_t> availableResultKeys = {\n+\t\tANDROID_CONTROL_AE_MODE,\n+\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n+\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n+\t\tANDROID_CONTROL_AE_LOCK,\n+\t\tANDROID_CONTROL_AF_TRIGGER,\n+\t\tANDROID_CONTROL_AWB_MODE,\n+\t\tANDROID_CONTROL_AWB_LOCK,\n+\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\tANDROID_CONTROL_CAPTURE_INTENT,\n+\t\tANDROID_FLASH_MODE,\n+\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n+\t};\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n+\t\t\tavailableResultKeys.data(),\n+\t\t\tavailableResultKeys.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\t/*\n+\t * \\todo The available characteristics are be the tags reported\n+\t * as part of the static metadata reported at hal_get_camera_info()\n+\t * time. As of now, report an empty list.\n+\t */\n+\tstd::vector<int32_t> availableCharacteristicsKeys = {};\n+\tret = add_camera_metadata_entry(requestTemplate_,\n+\t\t\tANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n+\t\t\tavailableCharacteristicsKeys.data(),\n+\t\t\tavailableCharacteristicsKeys.size());\n+\tMETADATA_ASSERT(ret);\n+\n+\treturn requestTemplate_;\n+}\n+\n+/*\n+ * Inspect the stream_list to produce a list of StreamConfiguration to\n+ * be use to configure the Camera.\n+ */\n+int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n+{\n+\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+\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+\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+\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+\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+\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+}\ndiff --git a/src/android/camera_device.h b/src/android/camera_device.h\nnew file mode 100644\nindex 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+#include \"message.h\"\n+\n+#define METADATA_ASSERT(_r)\t\t\\\n+\tdo {\t\t\t\t\\\n+\t\tif (!(_r)) break;\t\\\n+\t\tLOG(HAL, Error) << \"Error: \" << __func__ << \":\" << __LINE__; \\\n+\t\treturn nullptr;\t\t\\\n+\t} while(0);\n+\n+class CameraDevice : public libcamera::Object\n+{\n+public:\n+\tCameraDevice(unsigned int id, std::shared_ptr<libcamera::Camera> camera);\n+\t~CameraDevice();\n+\n+\tvoid message(libcamera::Message *message);\n+\n+\tint open();\n+\tvoid close();\n+\tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n+\tcamera_metadata_t *getStaticMetadata();\n+\tconst camera_metadata_t *constructDefaultRequestSettings(int type);\n+\tint configureStreams(camera3_stream_configuration_t *stream_list);\n+\tint processCaptureRequest(camera3_capture_request_t *request);\n+\tvoid requestComplete(libcamera::Request *request,\n+\t\t\t     const std::map<libcamera::Stream *, libcamera::Buffer *> &buffers);\n+\n+private:\n+\tstruct Camera3RequestDescriptor {\n+\t\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__ */\ndiff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp\nnew file mode 100644\nindex 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+ * camera_module_t operations, to retrieve the number of cameras in the system\n+ * their static informations and to open and close camera devices.\n+ */\n+\n+int CameraHalManager::init()\n+{\n+\t/*\n+\t * Start the camera HAL manager thread and wait until its\n+\t * initialisation to complete to be fully operational before\n+\t * receiving calls from the camera stack.\n+\t */\n+\tstart();\n+\n+\tMutexLocker locker(mutex_);\n+\tcv_.wait(locker);\n+\n+\treturn 0;\n+}\n+\n+void CameraHalManager::run()\n+{\n+\t/*\n+\t * All the libcamera components must be initialised here, in\n+\t * order to bind them to the camera HAL manager thread that\n+\t * executes the event dispatcher.\n+\t */\n+\tcameraManager_ = libcamera::CameraManager::instance();\n+\n+\tint ret = cameraManager_->start();\n+\tif (ret) {\n+\t\tLOG(HAL, Error) << \"Failed to start camera manager: \"\n+\t\t\t\t<< strerror(-ret);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * For each Camera registered in the system, a CameraProxy\n+\t * gets created here wich wraps a camera device.\n+\t *\n+\t * \\todo Support camera hotplug.\n+\t */\n+\tunsigned int index = 0;\n+\tfor (auto &camera : cameraManager_->cameras()) {\n+\t\tCameraProxy *proxy = new CameraProxy(index, camera);\n+\t\tproxies_.emplace_back(proxy);\n+\n+\t\t++index;\n+\t}\n+\n+\t/*\n+\t * libcamera has been initialized. Unlock the init() caller\n+\t * as we're now ready to handle calls from the framework.\n+\t */\n+\tcv_.notify_one();\n+\n+\t/* Now start processing events and messages. */\n+\texec();\n+}\n+\n+CameraProxy *CameraHalManager::open(unsigned int id,\n+\t\t\t\t    const hw_module_t *hardwareModule)\n+{\n+\tif (id < 0 || id >= numCameras()) {\n+\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n+\t\treturn nullptr;\n+\t}\n+\n+\tCameraProxy *proxy = proxies_[id].get();\n+\tif (proxy->open(hardwareModule))\n+\t\treturn nullptr;\n+\n+\tLOG(HAL, Info) << \"Open camera '\" << id << \"'\";\n+\n+\treturn proxy;\n+}\n+\n+int CameraHalManager::close(CameraProxy *proxy)\n+{\n+\tproxy->close();\n+\tLOG(HAL, Info) << \"Close camera '\" << proxy->id() << \"'\";\n+\n+\treturn 0;\n+}\n+\n+unsigned int CameraHalManager::numCameras() const\n+{\n+\treturn cameraManager_->cameras().size();\n+}\n+\n+int CameraHalManager::getCameraInfo(int id, struct camera_info *info)\n+{\n+\tif (!info)\n+\t\treturn -EINVAL;\n+\n+\tint cameras = numCameras();\n+\tif (id >= cameras || id < 0) {\n+\t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tCameraProxy *proxy = proxies_[id].get();\n+\n+\t/* \\todo Get these info dynamically inspecting the camera module. */\n+\tinfo->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;\n+\tinfo->orientation = 0;\n+\tinfo->device_version = 0;\n+\tinfo->resource_cost = 0;\n+\tinfo->static_camera_characteristics = proxy->getStaticMetadata();\n+\tinfo->conflicting_devices = nullptr;\n+\tinfo->conflicting_devices_length = 0;\n+\n+\treturn 0;\n+}\ndiff --git a/src/android/camera_hal_manager.h b/src/android/camera_hal_manager.h\nnew file mode 100644\nindex 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__ */\ndiff --git a/src/android/camera_proxy.cpp b/src/android/camera_proxy.cpp\nnew file mode 100644\nindex 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+ * 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+ * 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+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+}\ndiff --git a/src/android/camera_proxy.h b/src/android/camera_proxy.h\nnew file mode 100644\nindex 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__ */\ndiff --git a/src/android/meson.build b/src/android/meson.build\nindex 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 ])\ndiff --git a/src/android/thread_rpc.cpp b/src/android/thread_rpc.cpp\nnew file mode 100644\nindex 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+}\ndiff --git a/src/android/thread_rpc.h b/src/android/thread_rpc.h\nnew file mode 100644\nindex 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__ */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 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 \ndiff --git a/src/meson.build b/src/meson.build\nindex 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",
    "prefixes": [
        "libcamera-devel",
        "v3",
        "6/6"
    ]
}