Move V4L2 camera HAL work to libhardware
BUG: 31117512
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
new file mode 100644
index 0000000..bf888be
--- /dev/null
+++ b/modules/camera/3_4/Android.mk
@@ -0,0 +1,104 @@
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Prevent the HAL from building on devices not specifically
+# requesting to use it.
+ifeq ($(USE_CAMERA_V4L2_HAL), true)
+
+v4l2_shared_libs := \
+ libbase \
+ libcamera_client \
+ libcamera_metadata \
+ libcutils \
+ libhardware \
+ liblog \
+ libnativehelper \
+ libsync \
+ libutils \
+
+v4l2_static_libs :=
+
+v4l2_cflags := -fno-short-enums -Wall -Wextra -fvisibility=hidden
+
+v4l2_c_includes := $(call include-path-for, camera)
+
+v4l2_src_files := \
+ camera.cpp \
+ format_metadata_factory.cpp \
+ metadata/enum_converter.cpp \
+ metadata/metadata.cpp \
+ stream.cpp \
+ stream_format.cpp \
+ v4l2_camera.cpp \
+ v4l2_camera_hal.cpp \
+ v4l2_gralloc.cpp \
+ v4l2_metadata_factory.cpp \
+ v4l2_wrapper.cpp \
+
+v4l2_test_files := \
+ format_metadata_factory_test.cpp \
+ metadata/control_test.cpp \
+ metadata/enum_converter_test.cpp \
+ metadata/ignored_control_delegate_test.cpp \
+ metadata/map_converter_test.cpp \
+ metadata/menu_control_options_test.cpp \
+ metadata/metadata_test.cpp \
+ metadata/no_effect_control_delegate_test.cpp \
+ metadata/partial_metadata_factory_test.cpp \
+ metadata/property_test.cpp \
+ metadata/ranged_converter_test.cpp \
+ metadata/slider_control_options_test.cpp \
+ metadata/state_test.cpp \
+ metadata/tagged_control_delegate_test.cpp \
+ metadata/tagged_control_options_test.cpp \
+ metadata/v4l2_control_delegate_test.cpp \
+
+# V4L2 Camera HAL.
+# ==============================================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := camera.v4l2
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_CFLAGS += $(v4l2_cflags)
+LOCAL_SHARED_LIBRARIES := $(v4l2_shared_libs)
+LOCAL_STATIC_LIBRARIES := \
+ libgtest_prod \
+ $(v4l2_static_libs) \
+
+LOCAL_C_INCLUDES += $(v4l2_c_includes)
+LOCAL_SRC_FILES := $(v4l2_src_files)
+include $(BUILD_SHARED_LIBRARY)
+
+# Unit tests for V4L2 Camera HAL.
+# ==============================================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := camera.v4l2_test
+LOCAL_CFLAGS += $(v4l2_cflags)
+LOCAL_SHARED_LIBRARIES := $(v4l2_shared_libs)
+LOCAL_STATIC_LIBRARIES := \
+ libBionicGtestMain \
+ libgmock \
+ $(v4l2_static_libs) \
+
+LOCAL_C_INCLUDES += $(v4l2_c_includes)
+LOCAL_SRC_FILES := \
+ $(v4l2_src_files) \
+ $(v4l2_test_files) \
+
+include $(BUILD_NATIVE_TEST)
+
+endif # USE_CAMERA_V4L2_HAL
diff --git a/modules/camera/3_4/camera.cpp b/modules/camera/3_4/camera.cpp
new file mode 100644
index 0000000..a1f7e86
--- /dev/null
+++ b/modules/camera/3_4/camera.cpp
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/Camera.cpp
+
+#include <cstdlib>
+#include <memory>
+#include <vector>
+#include <stdio.h>
+#include <hardware/camera3.h>
+#include <sync/sync.h>
+#include <system/camera_metadata.h>
+#include <system/graphics.h>
+#include <utils/Mutex.h>
+
+#include "metadata/metadata_common.h"
+#include "stream.h"
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Camera"
+#include <cutils/log.h>
+
+#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+#include <utils/Trace.h>
+
+#include "camera.h"
+
+#define CAMERA_SYNC_TIMEOUT 5000 // in msecs
+
+namespace default_camera_hal {
+
+extern "C" {
+// Shim passed to the framework to close an opened device.
+static int close_device(hw_device_t* dev)
+{
+ camera3_device_t* cam_dev = reinterpret_cast<camera3_device_t*>(dev);
+ Camera* cam = static_cast<Camera*>(cam_dev->priv);
+ return cam->close();
+}
+} // extern "C"
+
+Camera::Camera(int id)
+ : mId(id),
+ mSettingsSet(false),
+ mBusy(false),
+ mCallbackOps(NULL),
+ mStreams(NULL),
+ mNumStreams(0)
+{
+ memset(&mTemplates, 0, sizeof(mTemplates));
+ memset(&mDevice, 0, sizeof(mDevice));
+ mDevice.common.tag = HARDWARE_DEVICE_TAG;
+ mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_4;
+ mDevice.common.close = close_device;
+ mDevice.ops = const_cast<camera3_device_ops_t*>(&sOps);
+ mDevice.priv = this;
+}
+
+Camera::~Camera()
+{
+}
+
+int Camera::openDevice(const hw_module_t *module, hw_device_t **device)
+{
+ ALOGI("%s:%d: Opening camera device", __func__, mId);
+ ATRACE_CALL();
+ android::Mutex::Autolock al(mDeviceLock);
+
+ if (mBusy) {
+ ALOGE("%s:%d: Error! Camera device already opened", __func__, mId);
+ return -EBUSY;
+ }
+
+ int connectResult = connect();
+ if (connectResult != 0) {
+ return connectResult;
+ }
+ mBusy = true;
+ mDevice.common.module = const_cast<hw_module_t*>(module);
+ *device = &mDevice.common;
+ return 0;
+}
+
+int Camera::getInfo(struct camera_info *info)
+{
+ android::Mutex::Autolock al(mStaticInfoLock);
+
+ info->device_version = mDevice.common.version;
+ initDeviceInfo(info);
+ if (mStaticInfo == NULL) {
+ std::unique_ptr<android::CameraMetadata> static_info =
+ std::make_unique<android::CameraMetadata>();
+ if (initStaticInfo(static_info.get())) {
+ return -ENODEV;
+ }
+ mStaticInfo = std::move(static_info);
+ }
+ // The "locking" here only causes non-const methods to fail,
+ // which is not a problem since the CameraMetadata being locked
+ // is already const. Destructing automatically "unlocks".
+ info->static_camera_characteristics = mStaticInfo->getAndLock();
+
+ // Get facing & orientation from the static info.
+ uint8_t facing = 0;
+ int res = v4l2_camera_hal::SingleTagValue(
+ *mStaticInfo, ANDROID_LENS_FACING, &facing);
+ if (res) {
+ ALOGE("%s:%d: Failed to get facing from static metadata.",
+ __func__, mId);
+ return res;
+ }
+ switch (facing) {
+ case (ANDROID_LENS_FACING_FRONT):
+ info->facing = CAMERA_FACING_FRONT;
+ break;
+ case (ANDROID_LENS_FACING_BACK):
+ info->facing = CAMERA_FACING_BACK;
+ break;
+ case (ANDROID_LENS_FACING_EXTERNAL):
+ info->facing = CAMERA_FACING_EXTERNAL;
+ break;
+ default:
+ ALOGE("%s:%d: Invalid facing from metadata: %d.",
+ __func__, mId, facing);
+ return -ENODEV;
+ }
+ int32_t orientation = 0;
+ res = v4l2_camera_hal::SingleTagValue(
+ *mStaticInfo, ANDROID_SENSOR_ORIENTATION, &orientation);
+ if (res) {
+ ALOGE("%s:%d: Failed to get orientation from static metadata.",
+ __func__, mId);
+ return res;
+ }
+ info->orientation = static_cast<int>(orientation);
+
+ return 0;
+}
+
+int Camera::close()
+{
+ ALOGI("%s:%d: Closing camera device", __func__, mId);
+ ATRACE_CALL();
+ android::Mutex::Autolock al(mDeviceLock);
+
+ if (!mBusy) {
+ ALOGE("%s:%d: Error! Camera device not open", __func__, mId);
+ return -EINVAL;
+ }
+
+ disconnect();
+ mBusy = false;
+ return 0;
+}
+
+int Camera::initialize(const camera3_callback_ops_t *callback_ops)
+{
+ int res;
+
+ ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops);
+ mCallbackOps = callback_ops;
+ // per-device specific initialization
+ res = initDevice();
+ if (res != 0) {
+ ALOGE("%s:%d: Failed to initialize device!", __func__, mId);
+ return res;
+ }
+ return 0;
+}
+
+int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
+{
+ camera3_stream_t *astream;
+ Stream **newStreams = NULL;
+ int res = 0;
+
+ // Must provide new settings after configureStreams.
+ mSettingsSet = false;
+
+ ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config);
+ ATRACE_CALL();
+ android::Mutex::Autolock al(mDeviceLock);
+
+ if (stream_config == NULL) {
+ ALOGE("%s:%d: NULL stream configuration array", __func__, mId);
+ return -EINVAL;
+ }
+ if (stream_config->num_streams == 0) {
+ ALOGE("%s:%d: Empty stream configuration array", __func__, mId);
+ return -EINVAL;
+ }
+
+ // Create new stream array
+ newStreams = new Stream*[stream_config->num_streams];
+ ALOGV("%s:%d: Number of Streams: %d", __func__, mId,
+ stream_config->num_streams);
+
+ // Mark all current streams unused for now
+ for (int i = 0; i < mNumStreams; i++)
+ mStreams[i]->mReuse = false;
+ // Fill new stream array with reused streams and new streams
+ for (unsigned int i = 0; i < stream_config->num_streams; i++) {
+ astream = stream_config->streams[i];
+ if (astream->max_buffers > 0) {
+ ALOGV("%s:%d: Reusing stream %d", __func__, mId, i);
+ newStreams[i] = reuseStream(astream);
+ } else {
+ ALOGV("%s:%d: Creating new stream %d", __func__, mId, i);
+ newStreams[i] = new Stream(mId, astream);
+ }
+
+ if (newStreams[i] == NULL) {
+ ALOGE("%s:%d: Error processing stream %d", __func__, mId, i);
+ goto err_out;
+ }
+ astream->priv = newStreams[i];
+ }
+
+ // Verify the set of streams in aggregate
+ if (!isValidStreamSet(newStreams, stream_config->num_streams,
+ stream_config->operation_mode)) {
+ ALOGE("%s:%d: Invalid stream set", __func__, mId);
+ goto err_out;
+ }
+
+ // Set up all streams (calculate usage/max_buffers for each,
+ // do any device-specific initialization)
+ res = setupStreams(newStreams, stream_config->num_streams);
+ if (res) {
+ ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
+ goto err_out;
+ }
+
+ // Destroy all old streams and replace stream array with new one
+ destroyStreams(mStreams, mNumStreams);
+ mStreams = newStreams;
+ mNumStreams = stream_config->num_streams;
+
+ return 0;
+
+err_out:
+ // Clean up temporary streams, preserve existing mStreams/mNumStreams
+ destroyStreams(newStreams, stream_config->num_streams);
+ // Set error if it wasn't specified.
+ if (!res) {
+ res = -EINVAL;
+ }
+ return res;
+}
+
+void Camera::destroyStreams(Stream **streams, int count)
+{
+ if (streams == NULL)
+ return;
+ for (int i = 0; i < count; i++) {
+ // Only destroy streams that weren't reused
+ if (streams[i] != NULL && !streams[i]->mReuse)
+ delete streams[i];
+ }
+ delete [] streams;
+}
+
+Stream *Camera::reuseStream(camera3_stream_t *astream)
+{
+ Stream *priv = reinterpret_cast<Stream*>(astream->priv);
+ // Verify the re-used stream's parameters match
+ if (!priv->isValidReuseStream(mId, astream)) {
+ ALOGE("%s:%d: Mismatched parameter in reused stream", __func__, mId);
+ return NULL;
+ }
+ // Mark stream to be reused
+ priv->mReuse = true;
+ return priv;
+}
+
+bool Camera::isValidStreamSet(Stream **streams, int count, uint32_t mode)
+{
+ int inputs = 0;
+ int outputs = 0;
+
+ if (streams == NULL) {
+ ALOGE("%s:%d: NULL stream configuration streams", __func__, mId);
+ return false;
+ }
+ if (count == 0) {
+ ALOGE("%s:%d: Zero count stream configuration streams", __func__, mId);
+ return false;
+ }
+ // Validate there is at most one input stream and at least one output stream
+ for (int i = 0; i < count; i++) {
+ // A stream may be both input and output (bidirectional)
+ if (streams[i]->isInputType())
+ inputs++;
+ if (streams[i]->isOutputType())
+ outputs++;
+ }
+ ALOGV("%s:%d: Configuring %d output streams and %d input streams",
+ __func__, mId, outputs, inputs);
+ if (outputs < 1) {
+ ALOGE("%s:%d: Stream config must have >= 1 output", __func__, mId);
+ return false;
+ }
+ if (inputs > 1) {
+ ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId);
+ return false;
+ }
+
+ // check for correct number of Bayer/YUV/JPEG/Encoder streams
+ return isSupportedStreamSet(streams, count, mode);
+}
+
+int Camera::setupStreams(Stream **streams, int count)
+{
+ /*
+ * This is where the HAL has to decide internally how to handle all of the
+ * streams, and then produce usage and max_buffer values for each stream.
+ * Note, the stream array has been checked before this point for ALL invalid
+ * conditions, so it must find a successful configuration for this stream
+ * array. The only errors should be from individual streams requesting
+ * unsupported features (such as data_space or rotation).
+ */
+ for (int i = 0; i < count; i++) {
+ uint32_t usage = 0;
+ if (streams[i]->isOutputType())
+ usage |= GRALLOC_USAGE_HW_CAMERA_WRITE;
+ if (streams[i]->isInputType())
+ usage |= GRALLOC_USAGE_HW_CAMERA_READ;
+ streams[i]->setUsage(usage);
+
+ uint32_t max_buffers;
+ int res = setupStream(streams[i], &max_buffers);
+ if (res) {
+ return res;
+ }
+ streams[i]->setMaxBuffers(max_buffers);
+ }
+ return 0;
+}
+
+bool Camera::isValidTemplateType(int type)
+{
+ return type > 0 && type < CAMERA3_TEMPLATE_COUNT;
+}
+
+const camera_metadata_t* Camera::constructDefaultRequestSettings(int type)
+{
+ ALOGV("%s:%d: type=%d", __func__, mId, type);
+
+ if (!isValidTemplateType(type)) {
+ ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type);
+ return NULL;
+ }
+
+ if (!mTemplates[type]) {
+ // Initialize this template if it hasn't been initialized yet.
+ std::unique_ptr<android::CameraMetadata> new_template =
+ std::make_unique<android::CameraMetadata>();
+ int res = initTemplate(type, new_template.get());
+ if (res || !new_template) {
+ ALOGE("%s:%d: Failed to generate template of type: %d",
+ __func__, mId, type);
+ return NULL;
+ }
+ mTemplates[type] = std::move(new_template);
+ }
+
+ // The "locking" here only causes non-const methods to fail,
+ // which is not a problem since the CameraMetadata being locked
+ // is already const. Destructing automatically "unlocks".
+ return mTemplates[type]->getAndLock();
+}
+
+int Camera::processCaptureRequest(camera3_capture_request_t *request)
+{
+ int res;
+
+ ALOGV("%s:%d: request=%p", __func__, mId, request);
+ ATRACE_CALL();
+
+ if (request == NULL) {
+ ALOGE("%s:%d: NULL request recieved", __func__, mId);
+ return -EINVAL;
+ }
+
+ ALOGV("%s:%d: Request Frame:%d Settings:%p", __func__, mId,
+ request->frame_number, request->settings);
+
+ // NULL indicates use last settings
+ if (request->settings == NULL && !mSettingsSet) {
+ ALOGE("%s:%d: NULL settings without previous set Frame:%d Req:%p",
+ __func__, mId, request->frame_number, request);
+ return -EINVAL;
+ }
+
+ if (request->input_buffer != NULL) {
+ ALOGV("%s:%d: Reprocessing input buffer %p", __func__, mId,
+ request->input_buffer);
+
+ if (!isValidReprocessSettings(request->settings)) {
+ ALOGE("%s:%d: Invalid settings for reprocess request: %p",
+ __func__, mId, request->settings);
+ return -EINVAL;
+ }
+ } else {
+ ALOGV("%s:%d: Capturing new frame.", __func__, mId);
+
+ // Make a copy since CameraMetadata doesn't support weak ownership,
+ // but |request| is supposed to maintain ownership.
+ android::CameraMetadata request_settings;
+ request_settings = request->settings;
+ if (!isValidCaptureSettings(request_settings)) {
+ ALOGE("%s:%d: Invalid settings for capture request: %p",
+ __func__, mId, request->settings);
+ return -EINVAL;
+ }
+ // Settings are valid, go ahead and set them.
+ res = setSettings(request_settings);
+ if (res) {
+ ALOGE("%s:%d: Failed to set valid settings for capture request: %p",
+ __func__, mId, request->settings);
+ return res;
+ }
+ mSettingsSet = true;
+ }
+
+ // Setup and process output buffers.
+ if (request->num_output_buffers <= 0) {
+ ALOGE("%s:%d: Invalid number of output buffers: %d", __func__, mId,
+ request->num_output_buffers);
+ return -EINVAL;
+ }
+ camera3_capture_result result;
+ result.num_output_buffers = request->num_output_buffers;
+ std::vector<camera3_stream_buffer_t> output_buffers(
+ result.num_output_buffers);
+ for (unsigned int i = 0; i < request->num_output_buffers; i++) {
+ res = processCaptureBuffer(&request->output_buffers[i],
+ &output_buffers[i]);
+ if (res)
+ return -ENODEV;
+ }
+ result.output_buffers = &output_buffers[0];
+
+ // Get metadata for this frame. Since the framework guarantees only
+ // one call to process_capture_request at a time, this call is guaranteed
+ // to correspond with the most recently enqueued buffer.
+
+ android::CameraMetadata result_metadata;
+ uint64_t timestamp = 0;
+ // TODO(b/29334616): this may also want to use a callback, since
+ // the shutter may not happen immediately.
+ res = getResultSettings(&result_metadata, ×tamp);
+ if (res) {
+ return res;
+ }
+ result.result = result_metadata.release();
+
+ // Notify the framework with the shutter time.
+ result.frame_number = request->frame_number;
+ notifyShutter(result.frame_number, timestamp);
+
+ // TODO(b/29334616): asynchronously return results (the following should
+ // be done once all enqueued buffers for the request complete and callback).
+ result.partial_result = 1;
+ mCallbackOps->process_capture_result(mCallbackOps, &result);
+
+ return 0;
+}
+
+bool Camera::isValidReprocessSettings(const camera_metadata_t* /*settings*/)
+{
+ // TODO: reject settings that cannot be reprocessed
+ // input buffers unimplemented, use this to reject reprocessing requests
+ ALOGE("%s:%d: Input buffer reprocessing not implemented", __func__, mId);
+ return false;
+}
+
+int Camera::processCaptureBuffer(const camera3_stream_buffer_t *in,
+ camera3_stream_buffer_t *out)
+{
+ int res;
+ // TODO(b/29334616): This probably should be non-blocking (currently blocks
+ // here and on gralloc lock). Perhaps caller should put "in" in a queue
+ // initially, then have a thread that dequeues from there and calls this
+ // function.
+ if (in->acquire_fence != -1) {
+ res = sync_wait(in->acquire_fence, CAMERA_SYNC_TIMEOUT);
+ if (res == -ETIME) {
+ ALOGE("%s:%d: Timeout waiting on buffer acquire fence",
+ __func__, mId);
+ return res;
+ } else if (res) {
+ ALOGE("%s:%d: Error waiting on buffer acquire fence: %s(%d)",
+ __func__, mId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ out->stream = in->stream;
+ out->buffer = in->buffer;
+ out->status = CAMERA3_BUFFER_STATUS_OK;
+
+ // Enqueue buffer for software-painting
+ res = enqueueBuffer(out);
+ if (res) {
+ return res;
+ }
+
+ // TODO(b/29334616): This should be part of a callback made when the
+ // enqueued buffer finishes painting.
+ // TODO: use driver-backed release fences
+ out->acquire_fence = -1;
+ out->release_fence = -1;
+ return 0;
+}
+
+void Camera::notifyShutter(uint32_t frame_number, uint64_t timestamp)
+{
+ int res;
+ struct timespec ts;
+
+ // If timestamp is 0, get timestamp from right now instead
+ if (timestamp == 0) {
+ ALOGW("%s:%d: No timestamp provided, using CLOCK_BOOTTIME",
+ __func__, mId);
+ res = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (res == 0) {
+ timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+ } else {
+ ALOGE("%s:%d: No timestamp and failed to get CLOCK_BOOTTIME %s(%d)",
+ __func__, mId, strerror(errno), errno);
+ }
+ }
+ camera3_notify_msg_t m;
+ memset(&m, 0, sizeof(m));
+ m.type = CAMERA3_MSG_SHUTTER;
+ m.message.shutter.frame_number = frame_number;
+ m.message.shutter.timestamp = timestamp;
+ mCallbackOps->notify(mCallbackOps, &m);
+}
+
+void Camera::dump(int fd)
+{
+ ALOGV("%s:%d: Dumping to fd %d", __func__, mId, fd);
+ ATRACE_CALL();
+ android::Mutex::Autolock al(mDeviceLock);
+
+ dprintf(fd, "Camera ID: %d (Busy: %d)\n", mId, mBusy);
+
+ // TODO: dump all settings
+
+ dprintf(fd, "Number of streams: %d\n", mNumStreams);
+ for (int i = 0; i < mNumStreams; i++) {
+ dprintf(fd, "Stream %d/%d:\n", i, mNumStreams);
+ mStreams[i]->dump(fd);
+ }
+}
+
+const char* Camera::templateToString(int type)
+{
+ switch (type) {
+ case CAMERA3_TEMPLATE_PREVIEW:
+ return "CAMERA3_TEMPLATE_PREVIEW";
+ case CAMERA3_TEMPLATE_STILL_CAPTURE:
+ return "CAMERA3_TEMPLATE_STILL_CAPTURE";
+ case CAMERA3_TEMPLATE_VIDEO_RECORD:
+ return "CAMERA3_TEMPLATE_VIDEO_RECORD";
+ case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+ return "CAMERA3_TEMPLATE_VIDEO_SNAPSHOT";
+ case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+ return "CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG";
+ }
+ // TODO: support vendor templates
+ return "Invalid template type!";
+}
+
+extern "C" {
+// Get handle to camera from device priv data
+static Camera *camdev_to_camera(const camera3_device_t *dev)
+{
+ return reinterpret_cast<Camera*>(dev->priv);
+}
+
+static int initialize(const camera3_device_t *dev,
+ const camera3_callback_ops_t *callback_ops)
+{
+ return camdev_to_camera(dev)->initialize(callback_ops);
+}
+
+static int configure_streams(const camera3_device_t *dev,
+ camera3_stream_configuration_t *stream_list)
+{
+ return camdev_to_camera(dev)->configureStreams(stream_list);
+}
+
+static const camera_metadata_t *construct_default_request_settings(
+ const camera3_device_t *dev, int type)
+{
+ return camdev_to_camera(dev)->constructDefaultRequestSettings(type);
+}
+
+static int process_capture_request(const camera3_device_t *dev,
+ camera3_capture_request_t *request)
+{
+ return camdev_to_camera(dev)->processCaptureRequest(request);
+}
+
+static void dump(const camera3_device_t *dev, int fd)
+{
+ camdev_to_camera(dev)->dump(fd);
+}
+
+static int flush(const camera3_device_t*)
+{
+ // TODO(b/29937783)
+ ALOGE("%s: unimplemented.", __func__);
+ return -1;
+}
+
+} // extern "C"
+
+const camera3_device_ops_t Camera::sOps = {
+ .initialize = default_camera_hal::initialize,
+ .configure_streams = default_camera_hal::configure_streams,
+ .register_stream_buffers = nullptr,
+ .construct_default_request_settings
+ = default_camera_hal::construct_default_request_settings,
+ .process_capture_request = default_camera_hal::process_capture_request,
+ .get_metadata_vendor_tag_ops = nullptr,
+ .dump = default_camera_hal::dump,
+ .flush = default_camera_hal::flush,
+ .reserved = {0},
+};
+
+} // namespace default_camera_hal
diff --git a/modules/camera/3_4/camera.h b/modules/camera/3_4/camera.h
new file mode 100644
index 0000000..158c36d
--- /dev/null
+++ b/modules/camera/3_4/camera.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/Camera.h
+
+#ifndef DEFAULT_CAMERA_HAL_CAMERA_H_
+#define DEFAULT_CAMERA_HAL_CAMERA_H_
+
+#include <camera/CameraMetadata.h>
+#include <hardware/hardware.h>
+#include <hardware/camera3.h>
+#include <utils/Mutex.h>
+
+#include "metadata/metadata.h"
+#include "stream.h"
+
+namespace default_camera_hal {
+// Camera represents a physical camera on a device.
+// This is constructed when the HAL module is loaded, one per physical camera.
+// TODO(b/29185945): Support hotplugging.
+// It is opened by the framework, and must be closed before it can be opened
+// again.
+// This is an abstract class, containing all logic and data shared between all
+// camera devices (front, back, etc) and common to the ISP.
+class Camera {
+ public:
+ // id is used to distinguish cameras. 0 <= id < NUM_CAMERAS.
+ // module is a handle to the HAL module, used when the device is opened.
+ Camera(int id);
+ virtual ~Camera();
+
+ // Common Camera Device Operations (see <hardware/camera_common.h>)
+ int openDevice(const hw_module_t *module, hw_device_t **device);
+ int getInfo(struct camera_info *info);
+ int close();
+
+ // Camera v3 Device Operations (see <hardware/camera3.h>)
+ int initialize(const camera3_callback_ops_t *callback_ops);
+ int configureStreams(camera3_stream_configuration_t *stream_list);
+ const camera_metadata_t *constructDefaultRequestSettings(int type);
+ int processCaptureRequest(camera3_capture_request_t *request);
+ void dump(int fd);
+
+
+ protected:
+ // Connect to the device: open dev nodes, etc.
+ virtual int connect() = 0;
+ // Disconnect from the device: close dev nodes, etc.
+ virtual void disconnect() = 0;
+ // Initialize static camera characteristics for individual device
+ virtual int initStaticInfo(android::CameraMetadata* out) = 0;
+ // Initialize a template of the given type
+ virtual int initTemplate(int type, android::CameraMetadata* out) = 0;
+ // Initialize device info: resource cost and conflicting devices
+ // (/conflicting devices length)
+ virtual void initDeviceInfo(struct camera_info *info) = 0;
+ // Verify stream configuration is device-compatible
+ virtual bool isSupportedStreamSet(Stream** streams, int count,
+ uint32_t mode) = 0;
+ // Set up the device for a stream, and get the maximum number of
+ // buffers that stream can handle (max_buffers is an output parameter)
+ virtual int setupStream(Stream* stream, uint32_t* max_buffers) = 0;
+ // Verify settings are valid for a capture
+ virtual bool isValidCaptureSettings(
+ const android::CameraMetadata& settings) = 0;
+ // Set settings for a capture
+ virtual int setSettings(
+ const android::CameraMetadata& new_settings) = 0;
+ // Separate initialization method for individual devices when opened
+ virtual int initDevice() = 0;
+ // Enqueue a buffer to receive data from the camera
+ virtual int enqueueBuffer(
+ const camera3_stream_buffer_t *camera_buffer) = 0;
+ // Get the shutter time and updated settings for the most recent frame.
+ // The metadata parameter is both an input and output; frame-specific
+ // result fields should be appended to what is passed in.
+ virtual int getResultSettings(android::CameraMetadata* metadata,
+ uint64_t *timestamp) = 0;
+ // Prettyprint template names
+ const char* templateToString(int type);
+
+ private:
+ // Camera device handle returned to framework for use
+ camera3_device_t mDevice;
+ // Reuse a stream already created by this device
+ Stream *reuseStream(camera3_stream_t *astream);
+ // Destroy all streams in a stream array, and the array itself
+ void destroyStreams(Stream **array, int count);
+ // Verify a set of streams is valid in aggregate
+ bool isValidStreamSet(Stream **array, int count, uint32_t mode);
+ // Calculate usage and max_bufs of each stream
+ int setupStreams(Stream **array, int count);
+ // Verify settings are valid for reprocessing an input buffer
+ bool isValidReprocessSettings(const camera_metadata_t *settings);
+ // Process an output buffer
+ int processCaptureBuffer(const camera3_stream_buffer_t *in,
+ camera3_stream_buffer_t *out);
+ // Send a shutter notify message with start of exposure time
+ void notifyShutter(uint32_t frame_number, uint64_t timestamp);
+ // Is type a valid template type (and valid index into mTemplates)
+ bool isValidTemplateType(int type);
+
+ // Identifier used by framework to distinguish cameras
+ const int mId;
+ // CameraMetadata containing static characteristics
+ std::unique_ptr<const android::CameraMetadata> mStaticInfo;
+ // Flag indicating if settings have been set since
+ // the last configure_streams() call.
+ bool mSettingsSet;
+ // Busy flag indicates camera is in use
+ bool mBusy;
+ // Camera device operations handle shared by all devices
+ const static camera3_device_ops_t sOps;
+ // Methods used to call back into the framework
+ const camera3_callback_ops_t *mCallbackOps;
+ // Lock protecting the Camera object for modifications
+ android::Mutex mDeviceLock;
+ // Lock protecting only static camera characteristics, which may
+ // be accessed without the camera device open
+ android::Mutex mStaticInfoLock;
+ // Array of handles to streams currently in use by the device
+ Stream **mStreams;
+ // Number of streams in mStreams
+ int mNumStreams;
+ // Standard camera settings templates
+ std::unique_ptr<const android::CameraMetadata> mTemplates[CAMERA3_TEMPLATE_COUNT];
+};
+} // namespace default_camera_hal
+
+#endif // DEFAULT_CAMERA_HAL_CAMERA_H_
diff --git a/modules/camera/3_4/common.h b/modules/camera/3_4/common.h
new file mode 100644
index 0000000..e77c0b2
--- /dev/null
+++ b/modules/camera/3_4/common.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_COMMON_H_
+#define V4L2_CAMERA_HAL_COMMON_H_
+
+// #define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+#define LOG_TAG "V4L2CameraHAL"
+
+// Helpers of logging (showing function name and line number).
+#define HAL_LOGE(fmt, args...) do { \
+ ALOGE("%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+#define HAL_LOGE_IF(cond, fmt, args...) do { \
+ ALOGE_IF(cond, "%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+#define HAL_LOGW(fmt, args...) do { \
+ ALOGW("%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+#define HAL_LOGW_IF(cond, fmt, args...) do { \
+ ALOGW_IF(cond, "%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+#define HAL_LOGD(fmt, args...) do { \
+ ALOGD("%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+#define HAL_LOGV(fmt, args...) do { \
+ ALOGV("%s:%d: " fmt, __func__, __LINE__, ##args); \
+ } while(0)
+
+// Log enter/exit of methods.
+#define HAL_LOG_ENTER() HAL_LOGV("enter")
+#define HAL_LOG_EXIT() HAL_LOGV("exit")
+
+// Fix confliction in case it's defined elsewhere.
+#ifndef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&);
+#endif
+
+#endif // V4L2_CAMERA_HAL_COMMON_H_
diff --git a/modules/camera/3_4/format_metadata_factory.cpp b/modules/camera/3_4/format_metadata_factory.cpp
new file mode 100644
index 0000000..673477b
--- /dev/null
+++ b/modules/camera/3_4/format_metadata_factory.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format_metadata_factory.h"
+
+#include "metadata/array_vector.h"
+#include "metadata/partial_metadata_factory.h"
+#include "metadata/property.h"
+
+namespace v4l2_camera_hal {
+
+static int GetHalFormats(const std::shared_ptr<V4L2Wrapper>& device,
+ std::set<int32_t>* result_formats) {
+ if (!result_formats) {
+ HAL_LOGE("Null result formats pointer passed");
+ return -EINVAL;
+ }
+
+ std::set<uint32_t> v4l2_formats;
+ int res = device->GetFormats(&v4l2_formats);
+ if (res) {
+ HAL_LOGE("Failed to get device formats.");
+ return res;
+ }
+ for (auto v4l2_format : v4l2_formats) {
+ int32_t hal_format = StreamFormat::V4L2ToHalPixelFormat(v4l2_format);
+ if (hal_format < 0) {
+ // Unrecognized/unused format. Skip it.
+ continue;
+ }
+ result_formats->insert(hal_format);
+ }
+
+ // In addition to well-defined formats, there may be an
+ // "Implementation Defined" format chosen by the HAL (in this
+ // case what that means is managed by the StreamFormat class).
+
+ // Get the V4L2 format for IMPLEMENTATION_DEFINED.
+ int v4l2_format = StreamFormat::HalToV4L2PixelFormat(
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+ // If it's available, add IMPLEMENTATION_DEFINED to the result set.
+ if (v4l2_format && v4l2_formats.count(v4l2_format) > 0) {
+ result_formats->insert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+ }
+
+ return 0;
+}
+
+int AddFormatComponents(
+ std::shared_ptr<V4L2Wrapper> device,
+ std::insert_iterator<PartialMetadataSet> insertion_point) {
+ HAL_LOG_ENTER();
+
+ // Get all supported formats.
+ std::set<int32_t> hal_formats;
+ int res = GetHalFormats(device, &hal_formats);
+ if (res) {
+ return res;
+ }
+
+ // Requirements check: need to support YCbCr_420_888, JPEG,
+ // and "Implementation Defined".
+ if (hal_formats.find(HAL_PIXEL_FORMAT_YCbCr_420_888) == hal_formats.end()) {
+ HAL_LOGE("YCbCr_420_888 not supported by device.");
+ return -ENODEV;
+ } else if (hal_formats.find(HAL_PIXEL_FORMAT_BLOB) == hal_formats.end()) {
+ HAL_LOGE("JPEG not supported by device.");
+ return -ENODEV;
+ } else if (hal_formats.find(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) ==
+ hal_formats.end()) {
+ HAL_LOGE("HAL implementation defined format not supported by device.");
+ return -ENODEV;
+ }
+
+ // Find sizes and frame/stall durations for all formats.
+ // We also want to find the smallest max frame duration amongst all formats,
+ // And the largest min frame duration amongst YUV (i.e. largest max frame rate
+ // supported by all YUV sizes).
+ // Stream configs are {format, width, height, direction} (input or output).
+ ArrayVector<int32_t, 4> stream_configs;
+ // Frame durations are {format, width, height, duration} (duration in ns).
+ ArrayVector<int64_t, 4> min_frame_durations;
+ // Stall durations are {format, width, height, duration} (duration in ns).
+ ArrayVector<int64_t, 4> stall_durations;
+ int64_t min_max_frame_duration = std::numeric_limits<int64_t>::max();
+ int64_t max_min_frame_duration_yuv = std::numeric_limits<int64_t>::min();
+ for (auto hal_format : hal_formats) {
+ // Get the corresponding V4L2 format.
+ uint32_t v4l2_format = StreamFormat::HalToV4L2PixelFormat(hal_format);
+ if (v4l2_format == 0) {
+ // Unrecognized/unused format. Should never happen since hal_formats
+ // came from translating a bunch of V4L2 formats above.
+ HAL_LOGE("Couldn't find V4L2 format for HAL format %d", hal_format);
+ return -ENODEV;
+ }
+
+ // Get the available sizes for this format.
+ std::set<std::array<int32_t, 2>> frame_sizes;
+ res = device->GetFormatFrameSizes(v4l2_format, &frame_sizes);
+ if (res) {
+ HAL_LOGE("Failed to get all frame sizes for format %d", v4l2_format);
+ return res;
+ }
+
+ for (const auto& frame_size : frame_sizes) {
+ // Note the format and size combination in stream configs.
+ stream_configs.push_back(
+ {{hal_format,
+ frame_size[0],
+ frame_size[1],
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}});
+
+ // Find the duration range for this format and size.
+ std::array<int64_t, 2> duration_range;
+ res = device->GetFormatFrameDurationRange(
+ v4l2_format, frame_size, &duration_range);
+ if (res) {
+ HAL_LOGE(
+ "Failed to get frame duration range for format %d, "
+ "size %u x %u",
+ v4l2_format,
+ frame_size[0],
+ frame_size[1]);
+ return res;
+ }
+ int64_t size_min_frame_duration = duration_range[0];
+ int64_t size_max_frame_duration = duration_range[1];
+ min_frame_durations.push_back({{hal_format,
+ frame_size[0],
+ frame_size[1],
+ size_min_frame_duration}});
+
+ // Note the stall duration for this format and size.
+ // Usually 0 for non-jpeg, non-zero for JPEG.
+ // Randomly choosing absurd 1 sec for JPEG. Unsure what this breaks.
+ int64_t stall_duration = 0;
+ if (hal_format == HAL_PIXEL_FORMAT_BLOB) {
+ stall_duration = 1000000000;
+ }
+ stall_durations.push_back(
+ {{hal_format, frame_size[0], frame_size[1], stall_duration}});
+
+ // Update our search for general min & max frame durations.
+ // In theory max frame duration (min frame rate) should be consistent
+ // between all formats, but we check and only advertise the smallest
+ // available max duration just in case.
+ if (size_max_frame_duration < min_max_frame_duration) {
+ min_max_frame_duration = size_max_frame_duration;
+ }
+ // We only care about the largest min frame duration
+ // (smallest max frame rate) for YUV sizes.
+ if (hal_format == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+ size_min_frame_duration > max_min_frame_duration_yuv) {
+ max_min_frame_duration_yuv = size_min_frame_duration;
+ }
+ }
+ }
+
+ // Convert from frame durations measured in ns.
+ // Min fps supported by all formats.
+ int32_t min_fps = 1000000000 / min_max_frame_duration;
+ if (min_fps > 15) {
+ HAL_LOGE("Minimum FPS %d is larger than HAL max allowable value of 15",
+ min_fps);
+ return -ENODEV;
+ }
+ // Max fps supported by all YUV formats.
+ int32_t max_yuv_fps = 1000000000 / max_min_frame_duration_yuv;
+ // ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES should be at minimum
+ // {mi, ma}, {ma, ma} where mi and ma are min and max frame rates for
+ // YUV_420_888. Min should be at most 15.
+ std::vector<std::array<int32_t, 2>> fps_ranges;
+ fps_ranges.push_back({{min_fps, max_yuv_fps}});
+ fps_ranges.push_back({{max_yuv_fps, max_yuv_fps}});
+
+ // Construct the metadata components.
+ insertion_point = std::make_unique<Property<ArrayVector<int32_t, 4>>>(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ std::move(stream_configs));
+ insertion_point = std::make_unique<Property<ArrayVector<int64_t, 4>>>(
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ std::move(min_frame_durations));
+ insertion_point = std::make_unique<Property<ArrayVector<int64_t, 4>>>(
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, std::move(stall_durations));
+ insertion_point = std::make_unique<Property<int64_t>>(
+ ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, min_max_frame_duration);
+ // TODO(b/31019725): This should probably not be a NoEffect control.
+ insertion_point = NoEffectMenuControl<std::array<int32_t, 2>>(
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+ fps_ranges);
+
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/format_metadata_factory.h b/modules/camera/3_4/format_metadata_factory.h
new file mode 100644
index 0000000..4cf5952
--- /dev/null
+++ b/modules/camera/3_4/format_metadata_factory.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
+#define V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
+
+#include <iterator>
+#include <memory>
+#include <set>
+
+#include "common.h"
+#include "metadata/metadata_common.h"
+#include "v4l2_wrapper.h"
+
+namespace v4l2_camera_hal {
+
+// A factory method to construct all the format-related
+// partial metadata for a V4L2 device.
+int AddFormatComponents(
+ std::shared_ptr<V4L2Wrapper> device,
+ std::insert_iterator<PartialMetadataSet> insertion_point);
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
diff --git a/modules/camera/3_4/format_metadata_factory_test.cpp b/modules/camera/3_4/format_metadata_factory_test.cpp
new file mode 100644
index 0000000..f033e37
--- /dev/null
+++ b/modules/camera/3_4/format_metadata_factory_test.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "format_metadata_factory.h"
+#include "metadata/test_common.h"
+#include "v4l2_wrapper_mock.h"
+
+using testing::AtLeast;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class FormatMetadataFactoryTest : public Test {
+ protected:
+ virtual void SetUp() { mock_device_.reset(new V4L2WrapperMock()); }
+
+ virtual void ExpectMetadataTagCount(const android::CameraMetadata& metadata,
+ uint32_t tag,
+ size_t count) {
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ EXPECT_EQ(entry.count, count);
+ }
+
+ std::shared_ptr<V4L2WrapperMock> mock_device_;
+};
+
+TEST_F(FormatMetadataFactoryTest, GetFormatMetadata) {
+ std::set<uint32_t> formats{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420};
+ std::map<uint32_t, std::set<std::array<int32_t, 2>>> sizes{
+ {V4L2_PIX_FMT_JPEG, {{{10, 20}}, {{30, 60}}, {{120, 240}}}},
+ {V4L2_PIX_FMT_YUV420, {{{1, 2}}, {{3, 6}}, {{12, 24}}}}};
+ // These need to be on the correct order of magnitude,
+ // as there is a check for min fps > 15.
+ std::map<uint32_t, std::map<std::array<int32_t, 2>, std::array<int64_t, 2>>>
+ durations{{V4L2_PIX_FMT_JPEG,
+ {{{{10, 20}}, {{100000000, 200000000}}},
+ {{{30, 60}}, {{1000000000, 2000000000}}},
+ {{{120, 240}}, {{700000000, 1200000000}}}}},
+ {V4L2_PIX_FMT_YUV420,
+ {{{{1, 2}}, {{10000000000, 20000000000}}},
+ {{{3, 6}}, {{11000000000, 21000000000}}},
+ {{{12, 24}}, {{10500000000, 19000000000}}}}}};
+
+ EXPECT_CALL(*mock_device_, GetFormats(_))
+ .WillOnce(DoAll(SetArgPointee<0>(formats), Return(0)));
+
+ for (auto format : formats) {
+ std::set<std::array<int32_t, 2>> format_sizes = sizes[format];
+ EXPECT_CALL(*mock_device_, GetFormatFrameSizes(format, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(format_sizes), Return(0)));
+ for (auto size : format_sizes) {
+ EXPECT_CALL(*mock_device_, GetFormatFrameDurationRange(format, size, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<2>(durations[format][size]), Return(0)));
+ }
+ }
+
+ PartialMetadataSet components;
+ ASSERT_EQ(AddFormatComponents(mock_device_,
+ std::inserter(components, components.end())),
+ 0);
+
+ for (auto& component : components) {
+ android::CameraMetadata metadata;
+ component->PopulateStaticFields(&metadata);
+ ASSERT_EQ(metadata.entryCount(), 1);
+ int32_t tag = component->StaticTags()[0];
+ switch (tag) {
+ case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS: // Fall through.
+ case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS: // Fall through.
+ case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS: // Fall through.
+ // 3 sizes per format, 4 elements per config.
+ // # formats + 1 for IMPLEMENTATION_DEFINED.
+ ExpectMetadataTagCount(metadata, tag, (formats.size() + 1) * 3 * 4);
+ break;
+ case ANDROID_SENSOR_INFO_MAX_FRAME_DURATION:
+ // The lowest max duration from above.
+ ExpectMetadataEq(metadata, tag, 200000000);
+ break;
+ case ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES:
+ // 2 ranges ({min, max} and {max, max}), each with a min and max.
+ ExpectMetadataTagCount(metadata, tag, 4);
+ break;
+ default:
+ FAIL() << "Unexpected component created.";
+ break;
+ }
+ }
+}
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/array_vector.h b/modules/camera/3_4/metadata/array_vector.h
new file mode 100644
index 0000000..0481ed4
--- /dev/null
+++ b/modules/camera/3_4/metadata/array_vector.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_ARRAY_VECTOR_H_
+#define V4L2_CAMERA_HAL_ARRAY_VECTOR_H_
+
+#include <array>
+#include <vector>
+
+namespace v4l2_camera_hal {
+// ArrayVector behaves like a std::vector of fixed length C arrays,
+// with push_back accepting std::arrays to standardize length.
+// Specific methods to get number of arrays/number of elements
+// are provided and an ambiguous "size" is not, to avoid accidental
+// incorrect use.
+template <class T, size_t N>
+class ArrayVector {
+ public:
+ const T* data() const { return mItems.data(); }
+ // The number of arrays.
+ size_t num_arrays() const { return mItems.size() / N; }
+ // The number of elements amongst all arrays.
+ size_t total_num_elements() const { return mItems.size(); }
+
+ // Access the ith array.
+ const T* operator[](int i) const { return mItems.data() + (i * N); }
+ T* operator[](int i) { return mItems.data() + (i * N); }
+
+ void push_back(const std::array<T, N>& values) {
+ mItems.insert(mItems.end(), values.begin(), values.end());
+ }
+
+ private:
+ std::vector<T> mItems;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_ARRAY_VECTOR_H_
diff --git a/modules/camera/3_4/metadata/control.h b/modules/camera/3_4/metadata/control.h
new file mode 100644
index 0000000..6442f90
--- /dev/null
+++ b/modules/camera/3_4/metadata/control.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_H_
+
+#include <vector>
+
+#include <system/camera_metadata.h>
+
+#include "../common.h"
+#include "metadata_common.h"
+#include "partial_metadata_interface.h"
+#include "tagged_control_delegate.h"
+#include "tagged_control_options.h"
+
+namespace v4l2_camera_hal {
+
+// A Control is a PartialMetadata with values that can be gotten/set.
+template <typename T>
+class Control : public PartialMetadataInterface {
+ public:
+ // Options are optional (i.e. nullable), delegate is not.
+ Control(std::unique_ptr<TaggedControlDelegate<T>> delegate,
+ std::unique_ptr<TaggedControlOptions<T>> options = nullptr);
+
+ virtual std::vector<int32_t> StaticTags() const override;
+ virtual std::vector<int32_t> ControlTags() const override;
+ virtual std::vector<int32_t> DynamicTags() const override;
+
+ virtual int PopulateStaticFields(
+ android::CameraMetadata* metadata) const override;
+ virtual int PopulateDynamicFields(
+ android::CameraMetadata* metadata) const override;
+ virtual int PopulateTemplateRequest(
+ int template_type, android::CameraMetadata* metadata) const override;
+ virtual bool SupportsRequestValues(
+ const android::CameraMetadata& metadata) const override;
+ virtual int SetRequestValues(
+ const android::CameraMetadata& metadata) override;
+
+ private:
+ std::unique_ptr<TaggedControlDelegate<T>> delegate_;
+ std::unique_ptr<TaggedControlOptions<T>> options_;
+
+ DISALLOW_COPY_AND_ASSIGN(Control);
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename T>
+Control<T>::Control(std::unique_ptr<TaggedControlDelegate<T>> delegate,
+ std::unique_ptr<TaggedControlOptions<T>> options)
+ : delegate_(std::move(delegate)), options_(std::move(options)) {
+ HAL_LOG_ENTER();
+}
+
+template <typename T>
+std::vector<int32_t> Control<T>::StaticTags() const {
+ std::vector<int32_t> result;
+ if (options_) {
+ result.push_back(options_->tag());
+ }
+ return result;
+}
+
+template <typename T>
+std::vector<int32_t> Control<T>::ControlTags() const {
+ return {delegate_->tag()};
+}
+
+template <typename T>
+std::vector<int32_t> Control<T>::DynamicTags() const {
+ return {delegate_->tag()};
+}
+
+template <typename T>
+int Control<T>::PopulateStaticFields(android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+
+ if (!options_) {
+ HAL_LOGV("No options for control, nothing to populate.");
+ return 0;
+ }
+
+ return UpdateMetadata(
+ metadata, options_->tag(), options_->MetadataRepresentation());
+}
+
+template <typename T>
+int Control<T>::PopulateDynamicFields(android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+
+ // Populate the current setting.
+ T value;
+ int res = delegate_->GetValue(&value);
+ if (res) {
+ return res;
+ }
+ return UpdateMetadata(metadata, delegate_->tag(), value);
+}
+
+template <typename T>
+int Control<T>::PopulateTemplateRequest(
+ int template_type, android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+
+ // Populate with a default.
+ T value;
+ int res;
+ if (options_) {
+ res = options_->DefaultValueForTemplate(template_type, &value);
+ } else {
+ // If there's no options (and thus no default option),
+ // fall back to whatever the current value is.
+ res = delegate_->GetValue(&value);
+ }
+ if (res) {
+ return res;
+ }
+
+ return UpdateMetadata(metadata, delegate_->tag(), value);
+}
+
+template <typename T>
+bool Control<T>::SupportsRequestValues(
+ const android::CameraMetadata& metadata) const {
+ HAL_LOG_ENTER();
+ if (metadata.isEmpty()) {
+ // Implicitly supported.
+ return true;
+ }
+
+ // Get the requested setting for this control.
+ T requested;
+ int res = SingleTagValue(metadata, delegate_->tag(), &requested);
+ if (res == -ENOENT) {
+ // Nothing requested of this control, that's fine.
+ return true;
+ } else if (res) {
+ HAL_LOGE("Failure while searching for request value for tag %d",
+ delegate_->tag());
+ return false;
+ }
+
+ // Check that the requested setting is in the supported options.
+ if (!options_) {
+ HAL_LOGV("No options for control %d; request implicitly supported.",
+ delegate_->tag());
+ return true;
+ }
+ return options_->IsSupported(requested);
+}
+
+template <typename T>
+int Control<T>::SetRequestValues(const android::CameraMetadata& metadata) {
+ HAL_LOG_ENTER();
+ if (metadata.isEmpty()) {
+ // No changes necessary.
+ return 0;
+ }
+
+ // Get the requested value.
+ T requested;
+ int res = SingleTagValue(metadata, delegate_->tag(), &requested);
+ if (res == -ENOENT) {
+ // Nothing requested of this control, nothing to do.
+ return 0;
+ } else if (res) {
+ HAL_LOGE("Failure while searching for request value for tag %d",
+ delegate_->tag());
+ return res;
+ }
+
+ // Check that the value is supported.
+ if (options_ && !options_->IsSupported(requested)) {
+ HAL_LOGE("Unsupported value requested for control %d.", delegate_->tag());
+ return -EINVAL;
+ }
+
+ return delegate_->SetValue(requested);
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_H_
diff --git a/modules/camera/3_4/metadata/control_delegate_interface.h b/modules/camera/3_4/metadata/control_delegate_interface.h
new file mode 100644
index 0000000..8896e72
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_delegate_interface.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_H_
+
+#include "state_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A ControlDelegate extends StateDelegate with a setter method.
+template <typename T>
+class ControlDelegateInterface : public StateDelegateInterface<T> {
+ public:
+ virtual ~ControlDelegateInterface(){};
+
+ // ControlDelegates are allowed to be unreliable, so SetValue is best-effort;
+ // GetValue immediately after may not match (SetValue may, for example,
+ // automatically replace invalid values with valid ones,
+ // or have a delay before setting the requested value).
+ // Returns 0 on success, error code on failure.
+ virtual int SetValue(const T& value) = 0;
+ // Children must also override GetValue from StateDelegateInterface.
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/control_delegate_interface_mock.h b/modules/camera/3_4/metadata/control_delegate_interface_mock.h
new file mode 100644
index 0000000..7ed05ed
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_delegate_interface_mock.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for control delegate interfaces.
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_MOCK_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "control_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+template <typename T>
+class ControlDelegateInterfaceMock : public ControlDelegateInterface<T> {
+ public:
+ ControlDelegateInterfaceMock(){};
+ MOCK_METHOD1_T(GetValue, int(T*));
+ MOCK_METHOD1_T(SetValue, int(const T&));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/control_options_interface.h b/modules/camera/3_4/metadata/control_options_interface.h
new file mode 100644
index 0000000..438cefa
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_options_interface.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_H_
+
+#include <vector>
+
+namespace v4l2_camera_hal {
+
+// A ControlOptions defines acceptable values for a control.
+template <typename T>
+class ControlOptionsInterface {
+ public:
+ virtual ~ControlOptionsInterface(){};
+
+ // Get a metadata-acceptable representation of the options.
+ // For enums this will be a list of values, for ranges this
+ // will be min and max, etc.
+ virtual std::vector<T> MetadataRepresentation() = 0;
+ // Get whether or not a given value is acceptable.
+ virtual bool IsSupported(const T& option);
+ // Get a default option for a given template type, from the available options.
+ // Because a default must be available, any ControlOptions should have at
+ // least one supported value.
+ virtual int DefaultValueForTemplate(int template_type, T* default_value);
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/control_options_interface_mock.h b/modules/camera/3_4/metadata/control_options_interface_mock.h
new file mode 100644
index 0000000..ab8f6ee
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_options_interface_mock.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for control options interfaces.
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_MOCK_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "control_options_interface.h"
+
+namespace v4l2_camera_hal {
+
+template <typename T>
+class ControlOptionsInterfaceMock : public ControlOptionsInterface<T> {
+ public:
+ ControlOptionsInterfaceMock(){};
+ MOCK_METHOD0_T(MetadataRepresentation, std::vector<T>());
+ MOCK_METHOD1_T(IsSupported, bool(const T&));
+ MOCK_METHOD2_T(DefaultValueForTemplate, int(int, T*));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/control_test.cpp b/modules/camera/3_4/metadata/control_test.cpp
new file mode 100644
index 0000000..572f25f
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_test.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "control.h"
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "control_delegate_interface_mock.h"
+#include "control_options_interface_mock.h"
+#include "metadata_common.h"
+#include "test_common.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class ControlTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_delegate_.reset(new ControlDelegateInterfaceMock<uint8_t>());
+ mock_options_.reset(new ControlOptionsInterfaceMock<uint8_t>());
+ // Nullify control so an error will be thrown if a test doesn't call
+ // PrepareControl.
+ control_.reset();
+ }
+
+ virtual void PrepareControl(bool with_options = true) {
+ // Use this method after all the EXPECT_CALLs to pass ownership of the mocks
+ // to the device.
+ std::unique_ptr<TaggedControlDelegate<uint8_t>> delegate =
+ std::make_unique<TaggedControlDelegate<uint8_t>>(
+ delegate_tag_, std::move(mock_delegate_));
+ std::unique_ptr<TaggedControlOptions<uint8_t>> options =
+ std::make_unique<TaggedControlOptions<uint8_t>>(
+ options_tag_, std::move(mock_options_));
+ if (with_options) {
+ control_.reset(
+ new Control<uint8_t>(std::move(delegate), std::move(options)));
+ } else {
+ control_.reset(new Control<uint8_t>(std::move(delegate)));
+ }
+ }
+
+ virtual void ExpectTags(bool with_options = true) {
+ if (with_options) {
+ ASSERT_EQ(control_->StaticTags().size(), 1);
+ EXPECT_EQ(control_->StaticTags()[0], options_tag_);
+ } else {
+ EXPECT_TRUE(control_->StaticTags().empty());
+ }
+ // Controls use the same delgate, and thus tag, for getting and setting.
+ ASSERT_EQ(control_->ControlTags().size(), 1);
+ EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
+ ASSERT_EQ(control_->DynamicTags().size(), 1);
+ EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ }
+
+ virtual void ExpectOptions(const std::vector<uint8_t>& options) {
+ // Options should be available.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, options_tag_, options);
+ }
+
+ virtual void ExpectValue(uint8_t value) {
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+ }
+
+ std::unique_ptr<Control<uint8_t>> control_;
+ std::unique_ptr<ControlDelegateInterfaceMock<uint8_t>> mock_delegate_;
+ std::unique_ptr<ControlOptionsInterfaceMock<uint8_t>> mock_options_;
+
+ // Need tags that match the data type (uint8_t) being passed.
+ const int32_t delegate_tag_ = ANDROID_COLOR_CORRECTION_ABERRATION_MODE;
+ const int32_t options_tag_ =
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
+};
+
+TEST_F(ControlTest, Tags) {
+ PrepareControl();
+ ExpectTags();
+}
+
+TEST_F(ControlTest, TagsNoOptions) {
+ PrepareControl(false);
+ ExpectTags(false);
+}
+
+TEST_F(ControlTest, PopulateStatic) {
+ std::vector<uint8_t> expected{1, 10, 20};
+ EXPECT_CALL(*mock_options_, MetadataRepresentation())
+ .WillOnce(Return(expected));
+ PrepareControl();
+ ExpectOptions(expected);
+}
+
+TEST_F(ControlTest, PopulateStaticNoOptions) {
+ PrepareControl(false);
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
+ // Should not have added any entry.
+ EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(ControlTest, PopulateDynamic) {
+ uint8_t test_option = 99;
+ EXPECT_CALL(*mock_delegate_, GetValue(_))
+ .WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
+ PrepareControl();
+ ExpectValue(test_option);
+}
+
+TEST_F(ControlTest, PopulateDynamicNoOptions) {
+ // Lack of options shouldn't change anything for PopulateDynamic.
+ uint8_t test_option = 99;
+ EXPECT_CALL(*mock_delegate_, GetValue(_))
+ .WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
+ PrepareControl(false);
+ ExpectValue(test_option);
+}
+
+TEST_F(ControlTest, PopulateDynamicFail) {
+ int err = -99;
+ EXPECT_CALL(*mock_delegate_, GetValue(_)).WillOnce(Return(err));
+ PrepareControl();
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(control_->PopulateDynamicFields(&metadata), err);
+
+ // Should not have added an entry.
+ EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(ControlTest, PopulateTemplate) {
+ int template_type = 3;
+ uint8_t default_value = 123;
+ EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_type, _))
+ .WillOnce(DoAll(SetArgPointee<1>(default_value), Return(0)));
+ PrepareControl();
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), 0);
+ ExpectMetadataEq(metadata, delegate_tag_, default_value);
+}
+
+TEST_F(ControlTest, PopulateTemplateFail) {
+ int template_type = 3;
+ int err = 10;
+ EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_type, _))
+ .WillOnce(Return(err));
+ PrepareControl();
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), err);
+}
+
+TEST_F(ControlTest, PopulateTemplateOptionless) {
+ int template_type = 3;
+ uint8_t value = 12;
+ // Should use delegate instead of options if no options.
+ EXPECT_CALL(*mock_delegate_, GetValue(_))
+ .WillOnce(DoAll(SetArgPointee<0>(value), Return(0)));
+ PrepareControl(false);
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), 0);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+}
+
+TEST_F(ControlTest, PopulateTemplateOptionlessFail) {
+ int template_type = 3;
+ int err = 10;
+ // Should use delegate instead of options if no options.
+ EXPECT_CALL(*mock_delegate_, GetValue(_)).WillOnce(Return(err));
+ PrepareControl(false);
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), err);
+}
+
+TEST_F(ControlTest, SupportsRequest) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ EXPECT_CALL(*mock_options_, IsSupported(test_option)).WillOnce(Return(true));
+ PrepareControl();
+
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SupportsRequestNoOptions) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+ PrepareControl(false);
+
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SupportsRequestFail) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ EXPECT_CALL(*mock_options_, IsSupported(test_option)).WillOnce(Return(false));
+ PrepareControl();
+
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, SupportsRequestInvalidNumber) {
+ // Start with a request for multiple values.
+ android::CameraMetadata metadata;
+ std::vector<uint8_t> test_data = {1, 2, 3};
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
+ PrepareControl();
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, SupportsRequestInvalidNumberNoOptions) {
+ // Start with a request for multiple values.
+ android::CameraMetadata metadata;
+ std::vector<uint8_t> test_data = {1, 2, 3};
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
+ PrepareControl(false);
+ // Not having any explicit options does not exempt a control
+ // from requiring the right number of values.
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, SupportsRequestEmpty) {
+ android::CameraMetadata metadata;
+ PrepareControl();
+ EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SetRequest) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ Expectation validation_check =
+ EXPECT_CALL(*mock_options_, IsSupported(test_option))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_delegate_, SetValue(test_option))
+ .After(validation_check)
+ .WillOnce(Return(0));
+ PrepareControl();
+
+ // Make the request.
+ ASSERT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlTest, SetRequestNoOptions) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ // No options, no validation check.
+ EXPECT_CALL(*mock_delegate_, SetValue(test_option)).WillOnce(Return(0));
+ PrepareControl(false);
+
+ // Make the request.
+ ASSERT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlTest, SetRequestSettingFail) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ int err = 99;
+ Expectation validation_check =
+ EXPECT_CALL(*mock_options_, IsSupported(test_option))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_delegate_, SetValue(test_option))
+ .After(validation_check)
+ .WillOnce(Return(err));
+ PrepareControl();
+
+ EXPECT_EQ(control_->SetRequestValues(metadata), err);
+}
+
+TEST_F(ControlTest, SetRequestValidationFail) {
+ android::CameraMetadata metadata;
+ uint8_t test_option = 123;
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+ EXPECT_CALL(*mock_options_, IsSupported(test_option)).WillOnce(Return(false));
+ PrepareControl();
+
+ EXPECT_EQ(control_->SetRequestValues(metadata), -EINVAL);
+}
+
+TEST_F(ControlTest, SetRequestInvalidNumber) {
+ // Start with a request for multiple values.
+ android::CameraMetadata metadata;
+ std::vector<uint8_t> test_data = {1, 2, 3};
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
+
+ PrepareControl();
+ EXPECT_EQ(control_->SetRequestValues(metadata), -EINVAL);
+}
+
+TEST_F(ControlTest, SetRequestInvalidNumberNoOptions) {
+ // Start with a request for multiple values.
+ android::CameraMetadata metadata;
+ std::vector<uint8_t> test_data = {1, 2, 3};
+ ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
+
+ PrepareControl(false);
+ // Not having explicit options does not change that an incorrect
+ // number of values is invalid.
+ EXPECT_EQ(control_->SetRequestValues(metadata), -EINVAL);
+}
+
+TEST_F(ControlTest, SetRequestEmpty) {
+ // Should do nothing.
+ android::CameraMetadata metadata;
+ PrepareControl();
+ EXPECT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/converter_interface.h b/modules/camera/3_4/metadata/converter_interface.h
new file mode 100644
index 0000000..ca6a0f2
--- /dev/null
+++ b/modules/camera/3_4/metadata/converter_interface.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_H_
+#define V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_H_
+
+#include "../common.h"
+
+namespace v4l2_camera_hal {
+
+// A ConverterInterface converts metadata values to V4L2 values vice-versa.
+template <typename TMetadata, typename TV4L2>
+class ConverterInterface {
+ public:
+ virtual ~ConverterInterface(){};
+
+ // Convert.
+ virtual int MetadataToV4L2(TMetadata value, TV4L2* conversion) = 0;
+ virtual int V4L2ToMetadata(TV4L2 value, TMetadata* conversion) = 0;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/converter_interface_mock.h b/modules/camera/3_4/metadata/converter_interface_mock.h
new file mode 100644
index 0000000..3f7e6f7
--- /dev/null
+++ b/modules/camera/3_4/metadata/converter_interface_mock.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for converter interfaces.
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_MOCK_H_
+#define V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+template <typename TMetadata, typename TV4L2>
+class ConverterInterfaceMock : public ConverterInterface<TMetadata, TV4L2> {
+ public:
+ ConverterInterfaceMock(){};
+ MOCK_METHOD2_T(MetadataToV4L2, int(TMetadata, TV4L2*));
+ MOCK_METHOD2_T(V4L2ToMetadata, int(TV4L2, TMetadata*));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONVERTER_INTERFACE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/enum_converter.cpp b/modules/camera/3_4/metadata/enum_converter.cpp
new file mode 100644
index 0000000..f4c9819
--- /dev/null
+++ b/modules/camera/3_4/metadata/enum_converter.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "enum_converter.h"
+
+#include <errno.h>
+
+#include "../common.h"
+
+namespace v4l2_camera_hal {
+
+EnumConverter::EnumConverter(
+ const std::multimap<int32_t, uint8_t>& v4l2_to_metadata)
+ : v4l2_to_metadata_(v4l2_to_metadata) {
+ HAL_LOG_ENTER();
+}
+
+int EnumConverter::MetadataToV4L2(uint8_t value, int32_t* conversion) {
+ HAL_LOG_ENTER();
+
+ // Unfortunately no bi-directional map lookup in C++.
+ // Breaking on second, not first found so that a warning
+ // can be given if there are multiple values.
+ size_t count = 0;
+ for (auto kv : v4l2_to_metadata_) {
+ if (kv.second == value) {
+ ++count;
+ if (count == 1) {
+ // First match.
+ *conversion = kv.first;
+ } else {
+ // second match.
+ break;
+ }
+ }
+ }
+
+ if (count == 0) {
+ HAL_LOGV("Couldn't find V4L2 conversion of metadata value %d.", value);
+ return -EINVAL;
+ } else if (count > 1) {
+ HAL_LOGV(
+ "Multiple V4L2 conversions found for metadata value %d, using first.",
+ value);
+ }
+ return 0;
+}
+
+int EnumConverter::V4L2ToMetadata(int32_t value, uint8_t* conversion) {
+ HAL_LOG_ENTER();
+
+ auto element_range = v4l2_to_metadata_.equal_range(value);
+ if (element_range.first == element_range.second) {
+ HAL_LOGV("Couldn't find metadata conversion of V4L2 value %d.", value);
+ return -EINVAL;
+ }
+
+ auto element = element_range.first;
+ *conversion = element->second;
+
+ if (++element != element_range.second) {
+ HAL_LOGV(
+ "Multiple metadata conversions found for V4L2 value %d, using first.",
+ value);
+ }
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/enum_converter.h b/modules/camera/3_4/metadata/enum_converter.h
new file mode 100644
index 0000000..df5cabb
--- /dev/null
+++ b/modules/camera/3_4/metadata/enum_converter.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_ENUM_CONVERTER_H_
+#define V4L2_CAMERA_HAL_METADATA_ENUM_CONVERTER_H_
+
+#include <map>
+
+#include "../common.h"
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+// An EnumConverter converts between enum values.
+class EnumConverter : public ConverterInterface<uint8_t, int32_t> {
+ public:
+ EnumConverter(const std::multimap<int32_t, uint8_t>& v4l2_to_metadata);
+
+ virtual int MetadataToV4L2(uint8_t value, int32_t* conversion) override;
+ virtual int V4L2ToMetadata(int32_t value, uint8_t* conversion) override;
+
+ private:
+ const std::multimap<int32_t, uint8_t> v4l2_to_metadata_;
+
+ DISALLOW_COPY_AND_ASSIGN(EnumConverter);
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_ENUM_CONVERTER_H_
diff --git a/modules/camera/3_4/metadata/enum_converter_test.cpp b/modules/camera/3_4/metadata/enum_converter_test.cpp
new file mode 100644
index 0000000..9ba7ffc
--- /dev/null
+++ b/modules/camera/3_4/metadata/enum_converter_test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "enum_converter.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+class EnumConverterTest : public Test {
+ protected:
+ virtual void SetUp() {
+ converter_.reset(
+ new EnumConverter({{one_to_one_v4l2_, one_to_one_metadata_},
+ {one_to_many_v4l2_, many_to_one_metadata_1_},
+ {one_to_many_v4l2_, many_to_one_metadata_2_},
+ {many_to_one_v4l2_1_, one_to_many_metadata_},
+ {many_to_one_v4l2_2_, one_to_many_metadata_},
+ {unused_v4l2_, unused_metadata_}}));
+ }
+
+ std::unique_ptr<EnumConverter> converter_;
+
+ const int32_t one_to_one_v4l2_ = 12;
+ const int32_t one_to_many_v4l2_ = 34;
+ const int32_t many_to_one_v4l2_1_ = 56;
+ const int32_t many_to_one_v4l2_2_ = 78;
+ const int32_t unused_v4l2_ = 910;
+ const uint8_t one_to_one_metadata_ = 109;
+ const uint8_t one_to_many_metadata_ = 87;
+ const uint8_t many_to_one_metadata_1_ = 65;
+ const uint8_t many_to_one_metadata_2_ = 43;
+ const uint8_t unused_metadata_ = 21;
+};
+
+// Convert single.
+TEST_F(EnumConverterTest, OneToOneConversion) {
+ uint8_t metadata_val = 1;
+ ASSERT_EQ(converter_->V4L2ToMetadata(one_to_one_v4l2_, &metadata_val), 0);
+ EXPECT_EQ(metadata_val, one_to_one_metadata_);
+
+ int32_t v4l2_val = 1;
+ ASSERT_EQ(converter_->MetadataToV4L2(one_to_one_metadata_, &v4l2_val), 0);
+ EXPECT_EQ(v4l2_val, one_to_one_v4l2_);
+}
+
+TEST_F(EnumConverterTest, OneToManyConversion) {
+ // Should be one of the acceptable values.
+ uint8_t metadata_val = 1;
+ ASSERT_EQ(converter_->V4L2ToMetadata(one_to_many_v4l2_, &metadata_val), 0);
+ EXPECT_TRUE(metadata_val == many_to_one_metadata_1_ ||
+ metadata_val == many_to_one_metadata_2_);
+
+ int32_t v4l2_val = 1;
+ ASSERT_EQ(converter_->MetadataToV4L2(one_to_many_metadata_, &v4l2_val), 0);
+ EXPECT_TRUE(v4l2_val == many_to_one_v4l2_1_ ||
+ v4l2_val == many_to_one_v4l2_2_);
+}
+
+TEST_F(EnumConverterTest, ManyToOneConversion) {
+ uint8_t metadata_val = 1;
+ ASSERT_EQ(converter_->V4L2ToMetadata(many_to_one_v4l2_1_, &metadata_val), 0);
+ EXPECT_EQ(metadata_val, one_to_many_metadata_);
+ metadata_val = 1; // Reset.
+ ASSERT_EQ(converter_->V4L2ToMetadata(many_to_one_v4l2_2_, &metadata_val), 0);
+ EXPECT_EQ(metadata_val, one_to_many_metadata_);
+
+ int32_t v4l2_val = 1;
+ ASSERT_EQ(converter_->MetadataToV4L2(many_to_one_metadata_1_, &v4l2_val), 0);
+ EXPECT_EQ(v4l2_val, one_to_many_v4l2_);
+ v4l2_val = 1; // Reset.
+ ASSERT_EQ(converter_->MetadataToV4L2(many_to_one_metadata_2_, &v4l2_val), 0);
+ EXPECT_EQ(v4l2_val, one_to_many_v4l2_);
+}
+
+TEST_F(EnumConverterTest, InvalidConversion) {
+ uint8_t metadata_val = 1;
+ EXPECT_EQ(converter_->V4L2ToMetadata(1, &metadata_val), -EINVAL);
+
+ int32_t v4l2_val = 1;
+ EXPECT_EQ(converter_->MetadataToV4L2(1, &v4l2_val), -EINVAL);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/ignored_control_delegate.h b/modules/camera/3_4/metadata/ignored_control_delegate.h
new file mode 100644
index 0000000..f1d5da1
--- /dev/null
+++ b/modules/camera/3_4/metadata/ignored_control_delegate.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_IGNORED_CONTROL_DELEGATE_H_
+#define V4L2_CAMERA_HAL_METADATA_IGNORED_CONTROL_DELEGATE_H_
+
+#include "control_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+// An IgnoredControlDelegate, as the name implies,
+// has a fixed value and ignores all requests to set it.
+template <typename T>
+class IgnoredControlDelegate : public ControlDelegateInterface<T> {
+ public:
+ IgnoredControlDelegate(T value) : value_(value){};
+
+ int GetValue(T* value) override {
+ *value = value_;
+ return 0;
+ };
+ int SetValue(const T& value) override { return 0; };
+
+ private:
+ const T value_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_IGNORED_CONTROL_DELEGATE_H_
diff --git a/modules/camera/3_4/metadata/ignored_control_delegate_test.cpp b/modules/camera/3_4/metadata/ignored_control_delegate_test.cpp
new file mode 100644
index 0000000..80c30df
--- /dev/null
+++ b/modules/camera/3_4/metadata/ignored_control_delegate_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ignored_control_delegate.h"
+
+#include <gtest/gtest.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+TEST(IgnoredControlDelegateTest, DefaultGet) {
+ int32_t value = 12;
+ IgnoredControlDelegate<int32_t> control(value);
+ int32_t actual = 0;
+ ASSERT_EQ(control.GetValue(&actual), 0);
+ EXPECT_EQ(actual, value);
+}
+
+TEST(IgnoredControlDelegateTest, GetAndSet) {
+ int32_t value = 12;
+ IgnoredControlDelegate<int32_t> control(value);
+ int32_t new_value = 13;
+ ASSERT_EQ(control.SetValue(new_value), 0);
+ int32_t actual = 0;
+ ASSERT_EQ(control.GetValue(&actual), 0);
+ // Should still be the default.
+ EXPECT_EQ(actual, value);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/map_converter.h b/modules/camera/3_4/metadata/map_converter.h
new file mode 100644
index 0000000..b1734b5
--- /dev/null
+++ b/modules/camera/3_4/metadata/map_converter.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_
+#define V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_
+
+#include <errno.h>
+
+#include <map>
+#include <memory>
+
+#include "../common.h"
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A MapConverter fits values converted by a wrapped converter
+// to a map entry corresponding to the key with the nearest value.
+template <typename TMetadata, typename TV4L2, typename TMapKey>
+class MapConverter : public ConverterInterface<TMetadata, TV4L2> {
+ public:
+ MapConverter(
+ std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter,
+ std::map<TMapKey, TV4L2> conversion_map);
+
+ virtual int MetadataToV4L2(TMetadata value, TV4L2* conversion) override;
+ virtual int V4L2ToMetadata(TV4L2 value, TMetadata* conversion) override;
+
+ private:
+ std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter_;
+ std::map<TMapKey, TV4L2> conversion_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MapConverter);
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename TMetadata, typename TV4L2, typename TMapKey>
+MapConverter<TMetadata, TV4L2, TMapKey>::MapConverter(
+ std::shared_ptr<ConverterInterface<TMetadata, TMapKey>> wrapped_converter,
+ std::map<TMapKey, TV4L2> conversion_map)
+ : wrapped_converter_(std::move(wrapped_converter)),
+ conversion_map_(conversion_map) {
+ HAL_LOG_ENTER();
+}
+
+template <typename TMetadata, typename TV4L2, typename TMapKey>
+int MapConverter<TMetadata, TV4L2, TMapKey>::MetadataToV4L2(TMetadata value,
+ TV4L2* conversion) {
+ HAL_LOG_ENTER();
+
+ if (conversion_map_.empty()) {
+ HAL_LOGE("Empty conversion map.");
+ return -EINVAL;
+ }
+
+ TMapKey raw_conversion = 0;
+ int res = wrapped_converter_->MetadataToV4L2(value, &raw_conversion);
+ if (res) {
+ HAL_LOGE("Failed to perform underlying conversion.");
+ return res;
+ }
+
+ // Find nearest key.
+ auto kv = conversion_map_.lower_bound(raw_conversion);
+ // lower_bound finds the first >= element.
+ if (kv == conversion_map_.begin()) {
+ // Searching for less than the smallest key, so that will be the nearest.
+ *conversion = kv->second;
+ } else if (kv == conversion_map_.end()) {
+ // Searching for greater than the largest key, so that will be the nearest.
+ --kv;
+ *conversion = kv->second;
+ } else {
+ // Since kv points to the first >= element, either that or the previous
+ // element will be nearest.
+ *conversion = kv->second;
+ TMapKey diff = kv->first - raw_conversion;
+
+ // Now compare to the previous. This element will be < raw conversion,
+ // so reverse the order of the subtraction.
+ --kv;
+ if (raw_conversion - kv->first < diff) {
+ *conversion = kv->second;
+ }
+ }
+
+ return 0;
+}
+
+template <typename TMetadata, typename TV4L2, typename TMapKey>
+int MapConverter<TMetadata, TV4L2, TMapKey>::V4L2ToMetadata(
+ TV4L2 value, TMetadata* conversion) {
+ HAL_LOG_ENTER();
+
+ // Unfortunately no bi-directional map lookup in C++.
+ // Breaking on second, not first found so that a warning
+ // can be given if there are multiple values.
+ size_t count = 0;
+ int res;
+ for (auto kv : conversion_map_) {
+ if (kv.second == value) {
+ ++count;
+ if (count == 1) {
+ // First match.
+ res = wrapped_converter_->V4L2ToMetadata(kv.first, conversion);
+ } else {
+ // second match.
+ break;
+ }
+ }
+ }
+
+ if (count == 0) {
+ HAL_LOGE("Couldn't find map conversion of V4L2 value %d.", value);
+ return -EINVAL;
+ } else if (count > 1) {
+ HAL_LOGW("Multiple map conversions found for V4L2 value %d, using first.",
+ value);
+ }
+ return res;
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_MAP_CONVERTER_H_
diff --git a/modules/camera/3_4/metadata/map_converter_test.cpp b/modules/camera/3_4/metadata/map_converter_test.cpp
new file mode 100644
index 0000000..0361810
--- /dev/null
+++ b/modules/camera/3_4/metadata/map_converter_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "map_converter.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "converter_interface_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class MapConverterTest : public Test {
+ protected:
+ virtual void SetUp() {
+ converter_.reset(new ConverterInterfaceMock<int, int32_t>());
+ dut_.reset(new MapConverter<int, int32_t, int32_t>(converter_, map_));
+ }
+
+ virtual void ExpectConvertToV4L2(int32_t converted, int32_t expected) {
+ int initial = 99;
+ EXPECT_CALL(*converter_, MetadataToV4L2(initial, _))
+ .WillOnce(DoAll(SetArgPointee<1>(converted), Return(0)));
+
+ int32_t actual = expected + 1; // Initialize to non-expected value.
+ ASSERT_EQ(dut_->MetadataToV4L2(initial, &actual), 0);
+ EXPECT_EQ(actual, expected);
+ }
+
+ std::shared_ptr<ConverterInterfaceMock<int, int32_t>> converter_;
+ std::unique_ptr<MapConverter<int, int32_t, int32_t>> dut_;
+
+ const std::map<int32_t, int32_t> map_{{10, 1}, {40, 4}, {20, 2}, {30, 3}};
+};
+
+TEST_F(MapConverterTest, NormalConversionToV4L2) {
+ // A value that matches the map perfectly.
+ auto kv = map_.begin();
+ ExpectConvertToV4L2(kv->first, kv->second);
+}
+
+TEST_F(MapConverterTest, RoundingDownConversionToV4L2) {
+ // A value that's in range but not an exact key value.
+ auto kv = map_.begin();
+ ExpectConvertToV4L2(kv->first + 1, kv->second);
+}
+
+TEST_F(MapConverterTest, RoundingUpConversionToV4L2) {
+ // A value that's in range but not an exact key value.
+ auto kv = map_.begin();
+ ++kv;
+ ExpectConvertToV4L2(kv->first - 1, kv->second);
+}
+
+TEST_F(MapConverterTest, ClampUpConversionToV4L2) {
+ // A value that's below range.
+ auto kv = map_.begin();
+ ExpectConvertToV4L2(kv->first - 1, kv->second);
+}
+
+TEST_F(MapConverterTest, ClampDownConversionToV4L2) {
+ // A value that's above range (even after fitting to step).
+ auto kv = map_.rbegin();
+ ExpectConvertToV4L2(kv->first + 1, kv->second);
+}
+
+TEST_F(MapConverterTest, ConversionErrorToV4L2) {
+ int initial = 99;
+ int err = -99;
+ EXPECT_CALL(*converter_, MetadataToV4L2(initial, _)).WillOnce(Return(err));
+
+ int32_t unused;
+ EXPECT_EQ(dut_->MetadataToV4L2(initial, &unused), err);
+}
+
+TEST_F(MapConverterTest, NormalConversionToMetadata) {
+ auto kv = map_.begin();
+ int expected = 99;
+ EXPECT_CALL(*converter_, V4L2ToMetadata(kv->first, _))
+ .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
+
+ int actual = expected + 1; // Initialize to non-expected value.
+ ASSERT_EQ(dut_->V4L2ToMetadata(kv->second, &actual), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MapConverterTest, NotFoundConversionToMetadata) {
+ int unused;
+ ASSERT_EQ(dut_->V4L2ToMetadata(100, &unused), -EINVAL);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/menu_control_options.h b/modules/camera/3_4/metadata/menu_control_options.h
new file mode 100644
index 0000000..95ed3b6
--- /dev/null
+++ b/modules/camera/3_4/metadata/menu_control_options.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_MENU_CONTROL_OPTIONS_H_
+#define V4L2_CAMERA_HAL_METADATA_MENU_CONTROL_OPTIONS_H_
+
+#include <errno.h>
+
+#include "../common.h"
+#include "control_options_interface.h"
+
+namespace v4l2_camera_hal {
+
+// MenuControlOptions offer a fixed list of acceptable values.
+template <typename T>
+class MenuControlOptions : public ControlOptionsInterface<T> {
+ public:
+ // |options| must be non-empty.
+ MenuControlOptions(std::vector<T> options) : options_(options) {}
+
+ virtual std::vector<T> MetadataRepresentation() override { return options_; };
+ virtual bool IsSupported(const T& option) override {
+ return (std::find(options_.begin(), options_.end(), option) !=
+ options_.end());
+ };
+ virtual int DefaultValueForTemplate(int template_type,
+ T* default_value) override {
+ // TODO(b/31017806): More complex logic, depend on template_type.
+ // Default to the first option.
+ if (options_.empty()) {
+ HAL_LOGE("Can't get default value, options are empty.");
+ return -ENODEV;
+ }
+ *default_value = options_[0];
+ return 0;
+ }
+
+ private:
+ std::vector<T> options_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_MENU_CONTROL_OPTIONS_H_
diff --git a/modules/camera/3_4/metadata/menu_control_options_test.cpp b/modules/camera/3_4/metadata/menu_control_options_test.cpp
new file mode 100644
index 0000000..24582f6
--- /dev/null
+++ b/modules/camera/3_4/metadata/menu_control_options_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "menu_control_options.h"
+
+#include <memory>
+
+#include <gtest/gtest.h>
+#include <hardware/camera3.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+class MenuControlOptionsTest : public Test {
+ protected:
+ virtual void SetUp() { dut_.reset(new MenuControlOptions<int>(options_)); }
+
+ std::unique_ptr<MenuControlOptions<int>> dut_;
+ const std::vector<int> options_{1, 10, 19, 30};
+};
+
+TEST_F(MenuControlOptionsTest, MetadataRepresentation) {
+ // Technically order doesn't matter, but this is faster to write,
+ // and still passes.
+ EXPECT_EQ(dut_->MetadataRepresentation(), options_);
+}
+
+TEST_F(MenuControlOptionsTest, IsSupported) {
+ for (auto option : options_) {
+ EXPECT_TRUE(dut_->IsSupported(option));
+ }
+ // And at least one unsupported.
+ EXPECT_FALSE(dut_->IsSupported(99));
+}
+
+TEST_F(MenuControlOptionsTest, DefaultValue) {
+ // All default values should be supported.
+ // For some reason, the templates have values in the range [1, COUNT).
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
+ int value = -1;
+ EXPECT_EQ(dut_->DefaultValueForTemplate(i, &value), 0);
+ EXPECT_TRUE(dut_->IsSupported(value));
+ }
+}
+
+TEST_F(MenuControlOptionsTest, NoDefaultValue) {
+ // Invalid options don't have a valid default.
+ MenuControlOptions<int> bad_options({});
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
+ int value = -1;
+ EXPECT_EQ(bad_options.DefaultValueForTemplate(i, &value), -ENODEV);
+ }
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/metadata.cpp b/modules/camera/3_4/metadata/metadata.cpp
new file mode 100644
index 0000000..efc9959
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "metadata.h"
+
+#include <camera/CameraMetadata.h>
+#include <hardware/camera3.h>
+
+#include "../common.h"
+#include "metadata_common.h"
+
+namespace v4l2_camera_hal {
+
+Metadata::Metadata(PartialMetadataSet components)
+ : components_(std::move(components)) {
+ HAL_LOG_ENTER();
+}
+
+Metadata::~Metadata() {
+ HAL_LOG_ENTER();
+}
+
+int Metadata::FillStaticMetadata(android::CameraMetadata* metadata) {
+ HAL_LOG_ENTER();
+ if (!metadata) {
+ HAL_LOGE("Can't fill null metadata.");
+ return -EINVAL;
+ }
+
+ std::vector<int32_t> static_tags;
+ std::vector<int32_t> control_tags;
+ std::vector<int32_t> dynamic_tags;
+ int res = 0;
+
+ for (auto& component : components_) {
+ // Prevent components from potentially overriding others.
+ android::CameraMetadata additional_metadata;
+ // Populate the fields.
+ res = component->PopulateStaticFields(&additional_metadata);
+ if (res) {
+ HAL_LOGE("Failed to get all static properties.");
+ return res;
+ }
+ // Add it to the overall result.
+ if (!additional_metadata.isEmpty()) {
+ res = metadata->append(additional_metadata);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to append all static properties.");
+ return res;
+ }
+ }
+
+ // Note what tags the component adds.
+ std::vector<int32_t> tags = component->StaticTags();
+ std::move(tags.begin(),
+ tags.end(),
+ std::inserter(static_tags, static_tags.end()));
+ tags = component->ControlTags();
+ std::move(tags.begin(),
+ tags.end(),
+ std::inserter(control_tags, control_tags.end()));
+ tags = component->DynamicTags();
+ std::move(tags.begin(),
+ tags.end(),
+ std::inserter(dynamic_tags, dynamic_tags.end()));
+ }
+
+ // Populate the meta fields.
+ static_tags.push_back(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ res = UpdateMetadata(
+ metadata, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, control_tags);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to add request keys meta key.");
+ return -ENODEV;
+ }
+ static_tags.push_back(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+ res = UpdateMetadata(
+ metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, dynamic_tags);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to add result keys meta key.");
+ return -ENODEV;
+ }
+ static_tags.push_back(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ res = UpdateMetadata(
+ metadata, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, static_tags);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to add characteristics keys meta key.");
+ return -ENODEV;
+ }
+
+ // TODO(b/31018853): cache result.
+ return 0;
+}
+
+bool Metadata::IsValidRequest(const android::CameraMetadata& metadata) {
+ HAL_LOG_ENTER();
+
+ // Empty means "use previous settings", which are inherently valid.
+ if (metadata.isEmpty())
+ return true;
+
+ for (auto& component : components_) {
+ // Check that all components support the values requested of them.
+ bool valid_request = component->SupportsRequestValues(metadata);
+ if (!valid_request) {
+ // Exit early if possible.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int Metadata::GetRequestTemplate(int template_type,
+ android::CameraMetadata* template_metadata) {
+ HAL_LOG_ENTER();
+ if (!template_metadata) {
+ HAL_LOGE("Can't fill null template.");
+ return -EINVAL;
+ }
+
+ // Templates are numbered 1 through COUNT-1 for some reason.
+ if (template_type < 1 || template_type >= CAMERA3_TEMPLATE_COUNT) {
+ HAL_LOGE("Unrecognized template type %d.", template_type);
+ return -EINVAL;
+ }
+
+ for (auto& component : components_) {
+ // Prevent components from potentially overriding others.
+ android::CameraMetadata additional_metadata;
+ int res =
+ component->PopulateTemplateRequest(template_type, &additional_metadata);
+ if (res) {
+ HAL_LOGE("Failed to get all default request fields.");
+ return res;
+ }
+ // Add it to the overall result.
+ if (!additional_metadata.isEmpty()) {
+ res = template_metadata->append(additional_metadata);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to append all default request fields.");
+ return res;
+ }
+ }
+ }
+
+ // TODO(b/31018853): cache result.
+ return 0;
+}
+
+int Metadata::SetRequestSettings(const android::CameraMetadata& metadata) {
+ HAL_LOG_ENTER();
+
+ // Empty means "use previous settings".
+ if (metadata.isEmpty())
+ return 0;
+
+ for (auto& component : components_) {
+ int res = component->SetRequestValues(metadata);
+ if (res) {
+ HAL_LOGE("Failed to set all requested settings.");
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+int Metadata::FillResultMetadata(android::CameraMetadata* metadata) {
+ HAL_LOG_ENTER();
+ if (!metadata) {
+ HAL_LOGE("Can't fill null metadata.");
+ return -EINVAL;
+ }
+
+ for (auto& component : components_) {
+ // Prevent components from potentially overriding others.
+ android::CameraMetadata additional_metadata;
+ int res = component->PopulateDynamicFields(&additional_metadata);
+ if (res) {
+ HAL_LOGE("Failed to get all dynamic result fields.");
+ return res;
+ }
+ // Add it to the overall result.
+ if (!additional_metadata.isEmpty()) {
+ res = metadata->append(additional_metadata);
+ if (res != android::OK) {
+ HAL_LOGE("Failed to append all dynamic result fields.");
+ return res;
+ }
+ }
+ }
+
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/metadata.h b/modules/camera/3_4/metadata/metadata.h
new file mode 100644
index 0000000..e2232b5
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_H_
+#define V4L2_CAMERA_HAL_METADATA_H_
+
+#include <set>
+
+#include <camera/CameraMetadata.h>
+#include <hardware/camera3.h>
+
+#include "../common.h"
+#include "metadata_common.h"
+
+namespace v4l2_camera_hal {
+class Metadata {
+ public:
+ Metadata(PartialMetadataSet components);
+ virtual ~Metadata();
+
+ int FillStaticMetadata(android::CameraMetadata* metadata);
+ bool IsValidRequest(const android::CameraMetadata& metadata);
+ int GetRequestTemplate(int template_type,
+ android::CameraMetadata* template_metadata);
+ int SetRequestSettings(const android::CameraMetadata& metadata);
+ int FillResultMetadata(android::CameraMetadata* metadata);
+
+ private:
+ // The overall metadata is broken down into several distinct pieces.
+ // Note: it is undefined behavior if multiple components share tags.
+ PartialMetadataSet components_;
+
+ DISALLOW_COPY_AND_ASSIGN(Metadata);
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_METADATA_H_
diff --git a/modules/camera/3_4/metadata/metadata_common.h b/modules/camera/3_4/metadata/metadata_common.h
new file mode 100644
index 0000000..15f8084
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_common.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_METADATA_COMMON_H_
+#define V4L2_CAMERA_HAL_METADATA_METADATA_COMMON_H_
+
+#include <array>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include <camera/CameraMetadata.h>
+
+#include "array_vector.h"
+#include "partial_metadata_interface.h"
+
+namespace v4l2_camera_hal {
+
+typedef std::set<std::unique_ptr<PartialMetadataInterface>> PartialMetadataSet;
+
+// Templated helper functions effectively extending android::CameraMetadata.
+// Will cause a compile-time errors if CameraMetadata doesn't support
+// using the templated type. Templates are provided to extend this support
+// to std::arrays, std::vectors, and ArrayVectors of supported types as
+// appropriate.
+
+// UpdateMetadata(metadata, tag, data):
+//
+// Updates the entry for |tag| in |metadata| (functionally similar to
+// android::CameraMetadata::update).
+//
+// Args:
+// metadata: the android::CameraMetadata to update.
+// tag: the tag within |metadata| to update.
+// data: A reference to the data to update |tag| with.
+//
+// Returns:
+// 0: Success.
+// -ENODEV: The type of |data| does not match the expected type for |tag|,
+// or another error occured. Note: no errors are given for updating a
+// metadata entry with an incorrect amount of data (e.g. filling a tag
+// that expects to have only one value with multiple values), as this
+// information is not encoded in the type associated with the tag by
+// get_camera_metadata_tag_type (from <system/camera_metadata.h>).
+
+// Generic (pointer & size).
+template <typename T>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const T* data,
+ size_t count) {
+ int res = metadata->update(tag, data, count);
+ if (res) {
+ HAL_LOGE("Failed to update metadata tag %d", tag);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+// Generic (single item reference).
+template <typename T>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const T& val) {
+ return UpdateMetadata(metadata, tag, &val, 1);
+}
+
+// Specialization for vectors.
+template <typename T>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const std::vector<T>& val) {
+ return UpdateMetadata(metadata, tag, val.data(), val.size());
+}
+
+// Specialization for arrays.
+template <typename T, size_t N>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const std::array<T, N>& val) {
+ return UpdateMetadata(metadata, tag, val.data(), N);
+}
+
+// Specialization for ArrayVectors.
+template <typename T, size_t N>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const ArrayVector<T, N>& val) {
+ return UpdateMetadata(metadata, tag, val.data(), val.total_num_elements());
+}
+
+// Specialization for vectors of arrays.
+template <typename T, size_t N>
+static int UpdateMetadata(android::CameraMetadata* metadata,
+ int32_t tag,
+ const std::vector<std::array<T, N>>& val) {
+ // Convert to array vector so we know all the elements are contiguous.
+ ArrayVector<T, N> array_vector;
+ for (const auto& array : val) {
+ array_vector.push_back(array);
+ }
+ return UpdateMetadata(metadata, tag, array_vector);
+}
+
+// GetDataPointer(entry, val)
+//
+// A helper for other methods in this file.
+// Gets the data pointer of a given metadata entry into |*val|.
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const uint8_t** val) {
+ *val = entry.data.u8;
+}
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const int32_t** val) {
+ *val = entry.data.i32;
+}
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const float** val) {
+ *val = entry.data.f;
+}
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const int64_t** val) {
+ *val = entry.data.i64;
+}
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const double** val) {
+ *val = entry.data.d;
+}
+
+static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+ const camera_metadata_rational_t** val) {
+ *val = entry.data.r;
+}
+
+// SingleTagValue(metadata, tag, val)
+//
+// Get the value of the |tag| entry in |metadata|.
+// |tag| is expected to refer to an entry with a single item
+// of the templated type (a "single item" is exactly N values
+// if the templated type is an array of size N). An error will be
+// returned if it the wrong number of items are present.
+//
+// Returns:
+// -ENOENT: The tag couldn't be found or was empty.
+// -EINVAL: The tag contained more than one item.
+// -ENODEV: The tag claims to be non-empty, but the data pointer is null.
+// 0: Success. |*val| will contain the value for |tag|.
+
+// Singleton.
+template <typename T>
+static int SingleTagValue(const android::CameraMetadata& metadata,
+ int32_t tag,
+ T* val) {
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ if (entry.count == 0) {
+ HAL_LOGE("Metadata tag %d is empty.", tag);
+ return -ENOENT;
+ } else if (entry.count != 1) {
+ HAL_LOGE(
+ "Error: expected metadata tag %d to contain exactly 1 value "
+ "(had %d).",
+ tag,
+ entry.count);
+ return -EINVAL;
+ }
+ const T* data = nullptr;
+ GetDataPointer(entry, &data);
+ if (data == nullptr) {
+ HAL_LOGE("Metadata tag %d is empty.", tag);
+ return -ENODEV;
+ }
+ *val = *data;
+ return 0;
+}
+
+// Specialization for std::array.
+template <typename T, size_t N>
+static int SingleTagValue(const android::CameraMetadata& metadata,
+ int32_t tag,
+ std::array<T, N>* val) {
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ if (entry.count == 0) {
+ HAL_LOGE("Metadata tag %d is empty.", tag);
+ return -ENOENT;
+ } else if (entry.count != N) {
+ HAL_LOGE(
+ "Error: expected metadata tag %d to contain a single array of "
+ "exactly %d values (had %d).",
+ tag,
+ N,
+ entry.count);
+ return -EINVAL;
+ }
+ const T* data = nullptr;
+ GetDataPointer(entry, &data);
+ if (data == nullptr) {
+ HAL_LOGE("Metadata tag %d is empty.", tag);
+ return -ENODEV;
+ }
+ // Fill in the array.
+ for (size_t i = 0; i < N; ++i) {
+ (*val)[i] = data[i];
+ }
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_METADATA_COMMON_H_
diff --git a/modules/camera/3_4/metadata/metadata_test.cpp b/modules/camera/3_4/metadata/metadata_test.cpp
new file mode 100644
index 0000000..508884c
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_test.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "metadata.h"
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "metadata_common.h"
+#include "partial_metadata_interface_mock.h"
+
+using testing::AtMost;
+using testing::Return;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class MetadataTest : public Test {
+ protected:
+ virtual void SetUp() {
+ // Clear the DUT. AddComponents must be called before using it.
+ dut_.reset();
+
+ component1_.reset(new PartialMetadataInterfaceMock());
+ component2_.reset(new PartialMetadataInterfaceMock());
+ metadata_.reset(new android::CameraMetadata());
+ non_empty_metadata_.reset(new android::CameraMetadata());
+ uint8_t val = 1;
+ non_empty_metadata_->update(ANDROID_COLOR_CORRECTION_MODE, &val, 1);
+ }
+
+ // Once the component mocks have had expectations set,
+ // add them to the device under test.
+ virtual void AddComponents() {
+ // Don't mind moving; Gmock/Gtest fails on leaked mocks unless disabled by
+ // runtime flags.
+ PartialMetadataSet components;
+ components.insert(std::move(component1_));
+ components.insert(std::move(component2_));
+ dut_.reset(new Metadata(std::move(components)));
+ }
+
+ virtual void CompareTags(const std::set<int32_t>& expected,
+ const camera_metadata_entry_t& actual) {
+ ASSERT_EQ(expected.size(), actual.count);
+ for (size_t i = 0; i < actual.count; ++i) {
+ EXPECT_NE(expected.find(actual.data.i32[i]), expected.end());
+ }
+ }
+
+ // Device under test.
+ std::unique_ptr<Metadata> dut_;
+ // Mocks.
+ std::unique_ptr<PartialMetadataInterfaceMock> component1_;
+ std::unique_ptr<PartialMetadataInterfaceMock> component2_;
+ // Metadata.
+ std::unique_ptr<android::CameraMetadata> metadata_;
+ std::unique_ptr<android::CameraMetadata> non_empty_metadata_;
+ // An empty vector to use as necessary.
+ std::vector<int32_t> empty_tags_;
+};
+
+TEST_F(MetadataTest, FillStaticSuccess) {
+ // Should populate all the component static pieces.
+ EXPECT_CALL(*component1_, PopulateStaticFields(_)).WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateStaticFields(_)).WillOnce(Return(0));
+
+ // Should populate the meta keys, by polling each component's keys.
+ std::vector<int32_t> static_tags_1({1, 2});
+ std::vector<int32_t> static_tags_2({3, 4});
+ std::vector<int32_t> control_tags_1({5, 6});
+ std::vector<int32_t> control_tags_2({7, 8});
+ std::vector<int32_t> dynamic_tags_1({9, 10});
+ std::vector<int32_t> dynamic_tags_2({11, 12});
+ EXPECT_CALL(*component1_, StaticTags()).WillOnce(Return(static_tags_1));
+ EXPECT_CALL(*component1_, ControlTags()).WillOnce(Return(control_tags_1));
+ EXPECT_CALL(*component1_, DynamicTags()).WillOnce(Return(dynamic_tags_1));
+ EXPECT_CALL(*component2_, StaticTags()).WillOnce(Return(static_tags_2));
+ EXPECT_CALL(*component2_, ControlTags()).WillOnce(Return(control_tags_2));
+ EXPECT_CALL(*component2_, DynamicTags()).WillOnce(Return(dynamic_tags_2));
+
+ AddComponents();
+ // Should succeed. If it didn't, no reason to continue checking output.
+ ASSERT_EQ(dut_->FillStaticMetadata(metadata_.get()), 0);
+
+ // Meta keys should be filled correctly.
+ // Note: sets are used here, but it is undefined behavior if
+ // the class has multiple componenets reporting overlapping tags.
+
+ // Get the expected tags = combined tags of all components.
+ std::set<int32_t> static_tags(static_tags_1.begin(), static_tags_1.end());
+ static_tags.insert(static_tags_2.begin(), static_tags_2.end());
+ std::set<int32_t> control_tags(control_tags_1.begin(), control_tags_1.end());
+ control_tags.insert(control_tags_2.begin(), control_tags_2.end());
+ std::set<int32_t> dynamic_tags(dynamic_tags_1.begin(), dynamic_tags_1.end());
+ dynamic_tags.insert(dynamic_tags_2.begin(), dynamic_tags_2.end());
+
+ // Static tags includes not only all component static tags, but also
+ // the meta AVAILABLE_*_KEYS (* = [REQUEST, RESULT, CHARACTERISTICS]).
+ static_tags.emplace(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ static_tags.emplace(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
+ static_tags.emplace(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+
+ // Check against what was filled in in the metadata.
+ CompareTags(static_tags,
+ metadata_->find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS));
+ CompareTags(control_tags,
+ metadata_->find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS));
+ CompareTags(dynamic_tags,
+ metadata_->find(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS));
+}
+
+TEST_F(MetadataTest, FillStaticFail) {
+ int err = -99;
+ // Order undefined, and may or may not exit early; use AtMost.
+ EXPECT_CALL(*component1_, PopulateStaticFields(_))
+ .Times(AtMost(1))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateStaticFields(_)).WillOnce(Return(err));
+
+ // May or may not exit early, may still try to populate meta tags.
+ EXPECT_CALL(*component1_, StaticTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+ EXPECT_CALL(*component1_, ControlTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+ EXPECT_CALL(*component1_, DynamicTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+ EXPECT_CALL(*component2_, StaticTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+ EXPECT_CALL(*component2_, ControlTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+ EXPECT_CALL(*component2_, DynamicTags())
+ .Times(AtMost(1))
+ .WillOnce(Return(empty_tags_));
+
+ AddComponents();
+ // If any component errors, error should be returned
+ EXPECT_EQ(dut_->FillStaticMetadata(metadata_.get()), err);
+}
+
+TEST_F(MetadataTest, FillStaticNull) {
+ AddComponents();
+ EXPECT_EQ(dut_->FillStaticMetadata(nullptr), -EINVAL);
+}
+
+TEST_F(MetadataTest, IsValidSuccess) {
+ // Should check if all the component request values are valid.
+ EXPECT_CALL(*component1_, SupportsRequestValues(_)).WillOnce(Return(true));
+ EXPECT_CALL(*component2_, SupportsRequestValues(_)).WillOnce(Return(true));
+
+ AddComponents();
+ // Should succeed.
+ // Note: getAndLock is a lock against pointer invalidation, not concurrency,
+ // and unlocks on object destruction.
+ EXPECT_TRUE(dut_->IsValidRequest(*non_empty_metadata_));
+}
+
+TEST_F(MetadataTest, IsValidFail) {
+ // Should check if all the component request values are valid.
+ // Order undefined, and may or may not exit early; use AtMost.
+ EXPECT_CALL(*component1_, SupportsRequestValues(_))
+ .Times(AtMost(1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*component2_, SupportsRequestValues(_)).WillOnce(Return(false));
+
+ AddComponents();
+ // Should fail since one of the components failed.
+ // Note: getAndLock is a lock against pointer invalidation, not concurrency,
+ // and unlocks on object destruction.
+ EXPECT_FALSE(dut_->IsValidRequest(*non_empty_metadata_));
+}
+
+TEST_F(MetadataTest, IsValidEmpty) {
+ // Setting null settings is a special case indicating to use the
+ // previous (valid) settings. As such it is inherently valid.
+ // Should not try to check any components.
+ EXPECT_CALL(*component1_, SupportsRequestValues(_)).Times(0);
+ EXPECT_CALL(*component2_, SupportsRequestValues(_)).Times(0);
+
+ AddComponents();
+ EXPECT_TRUE(dut_->IsValidRequest(*metadata_));
+}
+
+TEST_F(MetadataTest, GetTemplateSuccess) {
+ int template_type = 3;
+
+ // Should check if all the components fill the template successfully.
+ EXPECT_CALL(*component1_, PopulateTemplateRequest(template_type, _))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateTemplateRequest(template_type, _))
+ .WillOnce(Return(0));
+
+ AddComponents();
+ // Should succeed.
+ EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), 0);
+}
+
+TEST_F(MetadataTest, GetTemplateFail) {
+ int err = -99;
+ int template_type = 3;
+
+ // Should check if all the components fill the template successfully.
+ // Order undefined, and may or may not exit early; use AtMost.
+ EXPECT_CALL(*component1_, PopulateTemplateRequest(template_type, _))
+ .Times(AtMost(1))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateTemplateRequest(template_type, _))
+ .WillOnce(Return(err));
+
+ AddComponents();
+ // Should fail since one of the components failed.
+ EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), err);
+}
+
+TEST_F(MetadataTest, GetTemplateNull) {
+ AddComponents();
+ EXPECT_EQ(dut_->GetRequestTemplate(1, nullptr), -EINVAL);
+}
+
+TEST_F(MetadataTest, GetTemplateInvalid) {
+ int template_type = 99; // Invalid template type.
+
+ AddComponents();
+ // Should fail fast since template type is invalid.
+ EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), -EINVAL);
+}
+
+TEST_F(MetadataTest, SetSettingsSuccess) {
+ // Should check if all the components set successfully.
+ EXPECT_CALL(*component1_, SetRequestValues(_)).WillOnce(Return(0));
+ EXPECT_CALL(*component2_, SetRequestValues(_)).WillOnce(Return(0));
+
+ AddComponents();
+ // Should succeed.
+ // Note: getAndLock is a lock against pointer invalidation, not concurrency,
+ // and unlocks on object destruction.
+ EXPECT_EQ(dut_->SetRequestSettings(*non_empty_metadata_), 0);
+}
+
+TEST_F(MetadataTest, SetSettingsFail) {
+ int err = -99;
+
+ // Should check if all the components set successfully.
+ // Order undefined, and may or may not exit early; use AtMost.
+ EXPECT_CALL(*component1_, SetRequestValues(_))
+ .Times(AtMost(1))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*component2_, SetRequestValues(_)).WillOnce(Return(err));
+
+ AddComponents();
+ // Should fail since one of the components failed.
+ // Note: getAndLock is a lock against pointer invalidation, not concurrency,
+ // and unlocks on object destruction.
+ EXPECT_EQ(dut_->SetRequestSettings(*non_empty_metadata_), err);
+}
+
+TEST_F(MetadataTest, SetSettingsEmpty) {
+ // Setting null settings is a special case indicating to use the
+ // previous settings. Should not try to set any components.
+ EXPECT_CALL(*component1_, SetRequestValues(_)).Times(0);
+ EXPECT_CALL(*component2_, SetRequestValues(_)).Times(0);
+
+ AddComponents();
+ // Should succeed.
+ EXPECT_EQ(dut_->SetRequestSettings(*metadata_), 0);
+}
+
+TEST_F(MetadataTest, FillResultSuccess) {
+ // Should check if all the components fill results successfully.
+ EXPECT_CALL(*component1_, PopulateDynamicFields(_)).WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateDynamicFields(_)).WillOnce(Return(0));
+
+ AddComponents();
+ // Should succeed.
+ EXPECT_EQ(dut_->FillResultMetadata(metadata_.get()), 0);
+}
+
+TEST_F(MetadataTest, FillResultFail) {
+ int err = -99;
+
+ // Should check if all the components fill results successfully.
+ // Order undefined, and may or may not exit early; use AtMost.
+ EXPECT_CALL(*component1_, PopulateDynamicFields(_))
+ .Times(AtMost(1))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*component2_, PopulateDynamicFields(_)).WillOnce(Return(err));
+
+ AddComponents();
+ // Should fail since one of the components failed.
+ EXPECT_EQ(dut_->FillResultMetadata(metadata_.get()), err);
+}
+
+TEST_F(MetadataTest, FillResultNull) {
+ AddComponents();
+ EXPECT_EQ(dut_->FillResultMetadata(nullptr), -EINVAL);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/no_effect_control_delegate.h b/modules/camera/3_4/metadata/no_effect_control_delegate.h
new file mode 100644
index 0000000..e1936f1
--- /dev/null
+++ b/modules/camera/3_4/metadata/no_effect_control_delegate.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_NO_EFFECT_CONTROL_DELEGATE_H_
+#define V4L2_CAMERA_HAL_METADATA_NO_EFFECT_CONTROL_DELEGATE_H_
+
+#include "control_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A NoEffectControlDelegate, as the name implies, has no effect.
+// The value can be gotten and set, but it does nothing.
+template <typename T>
+class NoEffectControlDelegate : public ControlDelegateInterface<T> {
+ public:
+ NoEffectControlDelegate(T default_value) : value_(default_value){};
+
+ int GetValue(T* value) override {
+ *value = value_;
+ return 0;
+ };
+ int SetValue(const T& value) override {
+ value_ = value;
+ return 0;
+ };
+
+ private:
+ T value_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_NO_EFFECT_CONTROL_DELEGATE_H_
diff --git a/modules/camera/3_4/metadata/no_effect_control_delegate_test.cpp b/modules/camera/3_4/metadata/no_effect_control_delegate_test.cpp
new file mode 100644
index 0000000..0a7a24c
--- /dev/null
+++ b/modules/camera/3_4/metadata/no_effect_control_delegate_test.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "no_effect_control_delegate.h"
+
+#include <gtest/gtest.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+TEST(NoEffectControlDelegateTest, DefaultGet) {
+ int32_t value = 12;
+ NoEffectControlDelegate<int32_t> control(value);
+ int32_t actual = 0;
+ ASSERT_EQ(control.GetValue(&actual), 0);
+ EXPECT_EQ(actual, value);
+}
+
+TEST(NoEffectControlDelegateTest, GetAndSet) {
+ int32_t value = 12;
+ NoEffectControlDelegate<int32_t> control(value);
+ int32_t new_value = 13;
+ ASSERT_EQ(control.SetValue(new_value), 0);
+ int32_t actual = 0;
+ ASSERT_EQ(control.GetValue(&actual), 0);
+ EXPECT_EQ(actual, new_value);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/partial_metadata_factory.h b/modules/camera/3_4/metadata/partial_metadata_factory.h
new file mode 100644
index 0000000..27ea6e8
--- /dev/null
+++ b/modules/camera/3_4/metadata/partial_metadata_factory.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
+
+#include "../common.h"
+#include "control.h"
+#include "menu_control_options.h"
+#include "no_effect_control_delegate.h"
+#include "ranged_converter.h"
+#include "slider_control_options.h"
+#include "state.h"
+#include "tagged_control_delegate.h"
+#include "tagged_control_options.h"
+#include "v4l2_control_delegate.h"
+
+namespace v4l2_camera_hal {
+
+enum class ControlType { kMenu, kSlider };
+
+// Static functions to create partial metadata. Nullptr is returned on failures.
+
+// FixedState: A state that doesn't change.
+template <typename T>
+static std::unique_ptr<State<T>> FixedState(int32_t tag, T value);
+
+// NoEffectOptionlessControl: A control that accepts any value,
+// and has no effect. A default value is given.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectOptionlessControl(
+ int32_t delegate_tag, T default_value);
+
+// NoEffectMenuControl: Some menu options, but they have no effect.
+// The default value will be the first element of |options|.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectMenuControl(
+ int32_t delegate_tag, int32_t options_tag, const std::vector<T>& options);
+
+// NoEffectSliderControl: A slider of options, but they have no effect.
+// The default value will be |min|.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
+ int32_t options_tag,
+ T min,
+ T max);
+
+// NoEffectControl: A control with no effect and only a single allowable
+// value. Chooses an appropriate ControlOptionsInterface depending on type.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ T value);
+
+// V4L2Control: A control corresponding to a V4L2 control.
+template <typename T>
+static std::unique_ptr<Control<T>> V4L2Control(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter);
+
+// V4L2ControlOrDefault: Like V4L2Control, but if the V4L2Control fails to
+// initialize for some reason, this method will fall back to NoEffectControl.
+template <typename T>
+static std::unique_ptr<Control<T>> V4L2ControlOrDefault(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+ const T& default_value);
+
+// -----------------------------------------------------------------------------
+
+template <typename T>
+std::unique_ptr<State<T>> FixedState(int32_t tag, T value) {
+ HAL_LOG_ENTER();
+
+ // Take advantage of ControlDelegate inheriting from StateDelegate;
+ // This will only expose GetValue, not SetValue, so the default will
+ // always be returned.
+ return std::make_unique<State<T>>(
+ tag, std::make_unique<NoEffectControlDelegate<T>>(value));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectOptionlessControl(int32_t delegate_tag,
+ T default_value) {
+ HAL_LOG_ENTER();
+
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag,
+ std::make_unique<NoEffectControlDelegate<T>>(default_value)),
+ nullptr);
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectMenuControl(int32_t delegate_tag,
+ int32_t options_tag,
+ const std::vector<T>& options) {
+ HAL_LOG_ENTER();
+
+ if (options.empty()) {
+ HAL_LOGE("At least one option must be provided.");
+ return nullptr;
+ }
+
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag,
+ std::make_unique<NoEffectControlDelegate<T>>(options[0])),
+ std::make_unique<TaggedControlOptions<T>>(
+ options_tag, std::make_unique<MenuControlOptions<T>>(options)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
+ int32_t options_tag,
+ T min,
+ T max) {
+ HAL_LOG_ENTER();
+
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag, std::make_unique<NoEffectControlDelegate<T>>(min)),
+ std::make_unique<TaggedControlOptions<T>>(
+ options_tag, std::make_unique<SliderControlOptions<T>>(min, max)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ T value) {
+ HAL_LOG_ENTER();
+
+ switch (type) {
+ case ControlType::kMenu:
+ return NoEffectMenuControl<T>(delegate_tag, options_tag, {value});
+ case ControlType::kSlider:
+ return NoEffectSliderControl(delegate_tag, options_tag, value, value);
+ }
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> V4L2Control(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter) {
+ HAL_LOG_ENTER();
+
+ // Query the device.
+ v4l2_query_ext_ctrl control_query;
+ int res = device->QueryControl(control_id, &control_query);
+ if (res) {
+ HAL_LOGE("Failed to query control %d.", control_id);
+ return nullptr;
+ }
+
+ int32_t control_min = static_cast<int32_t>(control_query.minimum);
+ int32_t control_max = static_cast<int32_t>(control_query.maximum);
+ int32_t control_step = static_cast<int32_t>(control_query.step);
+ if (control_min > control_max) {
+ HAL_LOGE("No acceptable values (min %d is greater than max %d).",
+ control_min,
+ control_max);
+ return nullptr;
+ }
+
+ // Variables needed by the various switch statements.
+ std::vector<T> options;
+ T metadata_val;
+ T metadata_min;
+ T metadata_max;
+ // Set up the result converter and result options based on type.
+ std::shared_ptr<ConverterInterface<T, int32_t>> result_converter(converter);
+ std::unique_ptr<ControlOptionsInterface<T>> result_options;
+ switch (control_query.type) {
+ case V4L2_CTRL_TYPE_BOOLEAN: // Fall-through.
+ case V4L2_CTRL_TYPE_MENU:
+ if (type != ControlType::kMenu) {
+ HAL_LOGE(
+ "V4L2 control %d is of type %d, which isn't compatible with "
+ "desired metadata control type %d",
+ control_id,
+ control_query.type,
+ type);
+ return nullptr;
+ }
+
+ // Convert each available option,
+ // ignoring ones without a known conversion.
+ for (int32_t i = control_min; i <= control_max; i += control_step) {
+ res = converter->V4L2ToMetadata(i, &metadata_val);
+ if (res == -EINVAL) {
+ HAL_LOGV("V4L2 value %d for control %d has no metadata equivalent.",
+ i,
+ control_id);
+ continue;
+ } else if (res) {
+ HAL_LOGE("Error converting value %d for control %d.", i, control_id);
+ return nullptr;
+ }
+ if (control_id == V4L2_CID_COLORFX) {
+ HAL_LOGE("Adding color effect %d (%d)", i, metadata_val);
+ }
+ options.push_back(metadata_val);
+ }
+ // Check to make sure there's at least one option.
+ if (options.empty()) {
+ HAL_LOGE("No valid options for control %d.", control_id);
+ return nullptr;
+ }
+ result_options.reset(new MenuControlOptions<T>(options));
+ // No converter changes necessary.
+ break;
+ case V4L2_CTRL_TYPE_INTEGER:
+ if (type != ControlType::kSlider) {
+ HAL_LOGE(
+ "V4L2 control %d is of type %d, which isn't compatible with "
+ "desired metadata control type %d",
+ control_id,
+ control_query.type,
+ type);
+ return nullptr;
+ }
+
+ // Upgrade to a range/step-clamping converter.
+ result_converter.reset(new RangedConverter<T, int32_t>(
+ converter, control_min, control_max, control_step));
+
+ // Convert the min and max.
+ res = result_converter->V4L2ToMetadata(control_min, &metadata_min);
+ if (res) {
+ HAL_LOGE(
+ "Failed to convert V4L2 min value %d for control %d to metadata.",
+ control_min,
+ control_id);
+ return nullptr;
+ }
+ res = result_converter->V4L2ToMetadata(control_max, &metadata_max);
+ if (res) {
+ HAL_LOGE(
+ "Failed to convert V4L2 max value %d for control %d to metadata.",
+ control_max,
+ control_id);
+ return nullptr;
+ }
+ result_options.reset(
+ new SliderControlOptions<T>(metadata_min, metadata_max));
+ break;
+ default:
+ HAL_LOGE("Control %d (%s) is of unsupported type %d",
+ control_id,
+ control_query.name,
+ control_query.type);
+ return nullptr;
+ }
+
+ // Construct the control.
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag,
+ std::make_unique<V4L2ControlDelegate<T>>(
+ device, control_id, result_converter)),
+ std::make_unique<TaggedControlOptions<T>>(options_tag,
+ std::move(result_options)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> V4L2ControlOrDefault(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+ const T& default_value) {
+ HAL_LOG_ENTER();
+
+ std::unique_ptr<Control<T>> result = V4L2Control(
+ type, delegate_tag, options_tag, device, control_id, converter);
+ if (!result) {
+ result = NoEffectControl(type, delegate_tag, options_tag, default_value);
+ }
+ return result;
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
diff --git a/modules/camera/3_4/metadata/partial_metadata_factory_test.cpp b/modules/camera/3_4/metadata/partial_metadata_factory_test.cpp
new file mode 100644
index 0000000..4c4a1b1
--- /dev/null
+++ b/modules/camera/3_4/metadata/partial_metadata_factory_test.cpp
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "../v4l2_wrapper_mock.h"
+#include "converter_interface_mock.h"
+#include "metadata_common.h"
+#include "partial_metadata_factory.h"
+#include "test_common.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class PartialMetadataFactoryTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_device_.reset(new V4L2WrapperMock());
+ mock_converter_.reset(new ConverterInterfaceMock<uint8_t, int32_t>());
+ // Nullify control so an error will be thrown
+ // if a test doesn't construct it.
+ control_.reset();
+ }
+
+ virtual void ExpectControlTags() {
+ ASSERT_EQ(control_->StaticTags().size(), 1);
+ EXPECT_EQ(control_->StaticTags()[0], options_tag_);
+ ASSERT_EQ(control_->ControlTags().size(), 1);
+ EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
+ ASSERT_EQ(control_->DynamicTags().size(), 1);
+ EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ }
+
+ virtual void ExpectControlOptions(const std::vector<uint8_t>& options) {
+ // Options should be available.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, options_tag_, options);
+ }
+
+ virtual void ExpectControlValue(uint8_t value) {
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+ }
+
+ std::unique_ptr<Control<uint8_t>> control_;
+ std::shared_ptr<ConverterInterfaceMock<uint8_t, int32_t>> mock_converter_;
+ std::shared_ptr<V4L2WrapperMock> mock_device_;
+
+ // Need tags that match the data type (uint8_t) being passed.
+ const int32_t delegate_tag_ = ANDROID_COLOR_CORRECTION_ABERRATION_MODE;
+ const int32_t options_tag_ =
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
+};
+
+TEST_F(PartialMetadataFactoryTest, FixedState) {
+ uint8_t value = 13;
+ std::unique_ptr<State<uint8_t>> state = FixedState(delegate_tag_, value);
+
+ ASSERT_EQ(state->StaticTags().size(), 0);
+ ASSERT_EQ(state->ControlTags().size(), 0);
+ ASSERT_EQ(state->DynamicTags().size(), 1);
+ EXPECT_EQ(state->DynamicTags()[0], delegate_tag_);
+
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+}
+
+TEST_F(PartialMetadataFactoryTest, NoEffectMenu) {
+ std::vector<uint8_t> test_options = {9, 8, 12};
+ control_ =
+ NoEffectMenuControl<uint8_t>(delegate_tag_, options_tag_, test_options);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Options should be available.
+ ExpectControlOptions(test_options);
+ // Default value should be test_options[0].
+ ExpectControlValue(test_options[0]);
+}
+
+TEST_F(PartialMetadataFactoryTest, NoEffectGenericMenu) {
+ uint8_t default_val = 9;
+ control_ = NoEffectControl<uint8_t>(
+ ControlType::kMenu, delegate_tag_, options_tag_, default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Options should be available.
+ ExpectControlOptions({default_val});
+ // |default_val| should be default option.
+ ExpectControlValue(default_val);
+}
+
+TEST_F(PartialMetadataFactoryTest, NoEffectSlider) {
+ std::vector<uint8_t> test_range = {9, 12};
+ control_ = NoEffectSliderControl<uint8_t>(
+ delegate_tag_, options_tag_, test_range[0], test_range[1]);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Single option should be available.
+ ExpectControlOptions(test_range);
+ // Default value should be the minimum (test_range[0]).
+ ExpectControlValue(test_range[0]);
+}
+
+TEST_F(PartialMetadataFactoryTest, NoEffectGenericSlider) {
+ uint8_t default_val = 9;
+ control_ = NoEffectControl<uint8_t>(
+ ControlType::kSlider, delegate_tag_, options_tag_, default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Range containing only |default_val| should be available.
+ ExpectControlOptions({default_val, default_val});
+ // |default_val| should be default option.
+ ExpectControlValue(default_val);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryQueryFail) {
+ int control_id = 55;
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryQueryBadType) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryQueryBadRange) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 10;
+ query_result.maximum = 1; // Less than minimum.
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryTypeRequestMenuMismatch) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+
+ // If you ask for a Menu, but the V4L2 control is a slider type, that's bad.
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryTypeRequestSliderMismatch) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+
+ // If you ask for a Slider and get a Menu, that's bad.
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryMenu) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Should convert values.
+ std::vector<uint8_t> expected_options;
+ for (auto kv : conversion_map) {
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(kv.first, _))
+ .WillOnce(DoAll(SetArgPointee<1>(kv.second), Return(0)));
+ expected_options.push_back(kv.second);
+ }
+ // Will fail to convert 7 with -EINVAL, shouldn't matter.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(7, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+ ExpectControlOptions(expected_options);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryMenuConversionFail) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Conversion fails with non-EINVAL error.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(_, _)).WillOnce(Return(-1));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryMenuNoConversions) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 1;
+ query_result.step = 1;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Conversion fails with -EINVAL error.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(1, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Since there were no convertable options, should fail.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryInteger) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1 & 7.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {7, 70}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Should convert values.
+ std::vector<uint8_t> expected_options;
+ for (auto kv : conversion_map) {
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(kv.first, _))
+ .WillOnce(DoAll(SetArgPointee<1>(kv.second), Return(0)));
+ expected_options.push_back(kv.second);
+ }
+
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+ ExpectControlOptions(expected_options);
+
+ // Should be fitting converted values to steps.
+ uint8_t set_val = 10;
+ android::CameraMetadata metadata;
+ EXPECT_EQ(UpdateMetadata(&metadata, delegate_tag_, set_val), 0);
+ EXPECT_CALL(*mock_converter_, MetadataToV4L2(set_val, _))
+ .WillOnce(DoAll(SetArgPointee<1>(4), Return(0)));
+ // When it calls into the device, the 4 returned above should be
+ // rounded down to the step value of 3.
+ EXPECT_CALL(*mock_device_, SetControl(control_id, 3, _)).WillOnce(Return(0));
+ EXPECT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FactoryIntegerFailedConversion) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Fail to convert a value. Even -EINVAL is bad in this case.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(1, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FallbackMenu) {
+ uint8_t default_val = 9;
+ int control_id = 55;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+
+ // Shouldn't fail, should fall back to menu control.
+ control_ = V4L2ControlOrDefault<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_,
+ default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Options should be available.
+ ExpectControlOptions({default_val});
+ // |default_val| should be default option.
+ ExpectControlValue(default_val);
+}
+
+TEST_F(PartialMetadataFactoryTest, V4L2FallbackSlider) {
+ uint8_t default_val = 9;
+ int control_id = 55;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+
+ // Shouldn't fail, should fall back to slider control.
+ control_ = V4L2ControlOrDefault<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_,
+ default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectControlTags();
+
+ // Range containing only |default_val| should be available.
+ ExpectControlOptions({default_val, default_val});
+ // |default_val| should be default option.
+ ExpectControlValue(default_val);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/partial_metadata_interface.h b/modules/camera/3_4/metadata/partial_metadata_interface.h
new file mode 100644
index 0000000..f6e9138
--- /dev/null
+++ b/modules/camera/3_4/metadata/partial_metadata_interface.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_PARTIAL_METADATA_INTERFACE_H_
+#define V4L2_CAMERA_HAL_METADATA_PARTIAL_METADATA_INTERFACE_H_
+
+#include <array>
+#include <vector>
+
+#include <camera/CameraMetadata.h>
+
+#include "../common.h"
+#include "array_vector.h"
+
+namespace v4l2_camera_hal {
+
+// A subset of metadata.
+class PartialMetadataInterface {
+ public:
+ virtual ~PartialMetadataInterface(){};
+
+ // The metadata tags this partial metadata is responsible for.
+ // See system/media/camera/docs/docs.html for descriptions of each tag.
+ virtual std::vector<int32_t> StaticTags() const = 0;
+ virtual std::vector<int32_t> ControlTags() const = 0;
+ virtual std::vector<int32_t> DynamicTags() const = 0;
+
+ // Add all the static properties this partial metadata
+ // is responsible for to |metadata|.
+ virtual int PopulateStaticFields(android::CameraMetadata* metadata) const = 0;
+ // Add all the dynamic states this partial metadata
+ // is responsible for to |metadata|.
+ virtual int PopulateDynamicFields(
+ android::CameraMetadata* metadata) const = 0;
+ // Add default request values for a given template type for all the controls
+ // this partial metadata owns.
+ virtual int PopulateTemplateRequest(
+ int template_type, android::CameraMetadata* metadata) const = 0;
+ // Check if the requested control values from |metadata| (for controls
+ // this partial metadata owns) are supported. Empty/null values for owned
+ // control tags indicate no change, and are thus inherently supported.
+ // If |metadata| is empty all controls are implicitly supported.
+ virtual bool SupportsRequestValues(
+ const android::CameraMetadata& metadata) const = 0;
+ // Set all the controls this partial metadata
+ // is responsible for from |metadata|. Empty/null values for owned control
+ // tags indicate no change. If |metadata| is empty no controls should
+ // be changed.
+ virtual int SetRequestValues(const android::CameraMetadata& metadata) = 0;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_PARTIAL_METADATA_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/partial_metadata_interface_mock.h b/modules/camera/3_4/metadata/partial_metadata_interface_mock.h
new file mode 100644
index 0000000..9e822a1
--- /dev/null
+++ b/modules/camera/3_4/metadata/partial_metadata_interface_mock.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for partial metadata interfaces.
+
+#ifndef V4L2_CAMERA_HAL_PARTIAL_METADATA_INTERFACE_MOCK_H_
+#define V4L2_CAMERA_HAL_PARTIAL_METADATA_INTERFACE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "partial_metadata_interface.h"
+
+namespace v4l2_camera_hal {
+
+class PartialMetadataInterfaceMock : public PartialMetadataInterface {
+ public:
+ PartialMetadataInterfaceMock() : PartialMetadataInterface(){};
+ MOCK_CONST_METHOD0(StaticTags, std::vector<int32_t>());
+ MOCK_CONST_METHOD0(ControlTags, std::vector<int32_t>());
+ MOCK_CONST_METHOD0(DynamicTags, std::vector<int32_t>());
+ MOCK_CONST_METHOD1(PopulateStaticFields, int(android::CameraMetadata*));
+ MOCK_CONST_METHOD1(PopulateDynamicFields, int(android::CameraMetadata*));
+ MOCK_CONST_METHOD2(PopulateTemplateRequest,
+ int(int, android::CameraMetadata*));
+ MOCK_CONST_METHOD1(SupportsRequestValues,
+ bool(const android::CameraMetadata&));
+ MOCK_METHOD1(SetRequestValues, int(const android::CameraMetadata&));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_PARTIAL_METADATA_INTERFACE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/property.h b/modules/camera/3_4/metadata/property.h
new file mode 100644
index 0000000..03da434
--- /dev/null
+++ b/modules/camera/3_4/metadata/property.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_PROPERTY_H_
+#define V4L2_CAMERA_HAL_METADATA_PROPERTY_H_
+
+#include "../common.h"
+#include "metadata_common.h"
+#include "partial_metadata_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A Property is a PartialMetadata that only has a single static tag.
+template <typename T>
+class Property : public PartialMetadataInterface {
+ public:
+ Property(int32_t tag, T value) : tag_(tag), value_(std::move(value)){};
+
+ virtual std::vector<int32_t> StaticTags() const override { return {tag_}; };
+
+ virtual std::vector<int32_t> ControlTags() const override { return {}; };
+
+ virtual std::vector<int32_t> DynamicTags() const override { return {}; };
+
+ virtual int PopulateStaticFields(
+ android::CameraMetadata* metadata) const override {
+ HAL_LOG_ENTER();
+ return UpdateMetadata(metadata, tag_, value_);
+ };
+
+ virtual int PopulateDynamicFields(
+ android::CameraMetadata* metadata) const override {
+ HAL_LOG_ENTER();
+ return 0;
+ };
+
+ virtual int PopulateTemplateRequest(
+ int template_type, android::CameraMetadata* metadata) const override {
+ HAL_LOG_ENTER();
+ return 0;
+ };
+
+ virtual bool SupportsRequestValues(
+ const android::CameraMetadata& metadata) const override {
+ HAL_LOG_ENTER();
+ return true;
+ };
+
+ virtual int SetRequestValues(
+ const android::CameraMetadata& metadata) override {
+ HAL_LOG_ENTER();
+ return 0;
+ };
+
+ private:
+ int32_t tag_;
+ T value_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_PROPERTY_H_
diff --git a/modules/camera/3_4/metadata/property_test.cpp b/modules/camera/3_4/metadata/property_test.cpp
new file mode 100644
index 0000000..8e947ea
--- /dev/null
+++ b/modules/camera/3_4/metadata/property_test.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "property.h"
+
+#include <array>
+#include <vector>
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hardware/camera3.h>
+
+#include "array_vector.h"
+#include "metadata_common.h"
+#include "test_common.h"
+
+using testing::AtMost;
+using testing::Return;
+using testing::ReturnRef;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class PropertyTest : public Test {
+ protected:
+ // Need tags that match the data types being passed.
+ static constexpr int32_t byte_tag_ = ANDROID_CONTROL_SCENE_MODE_OVERRIDES;
+ static constexpr int32_t float_tag_ = ANDROID_COLOR_CORRECTION_GAINS;
+ static constexpr int32_t int_tag_ = ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION;
+ static constexpr int32_t int_tag2_ = ANDROID_JPEG_ORIENTATION;
+};
+
+TEST_F(PropertyTest, Tags) {
+ Property<int32_t> property(int_tag_, 1);
+
+ // Should have only the single tag it was constructed with.
+ EXPECT_EQ(property.ControlTags().size(), 0);
+ EXPECT_EQ(property.DynamicTags().size(), 0);
+ ASSERT_EQ(property.StaticTags().size(), 1);
+ // The macro doesn't like the int_tag_ variable being passed in directly.
+ int32_t expected_tag = int_tag_;
+ EXPECT_EQ(property.StaticTags()[0], expected_tag);
+}
+
+TEST_F(PropertyTest, PopulateStaticSingleNumber) {
+ // Set up a fixed property.
+ int32_t data = 1234;
+ Property<int32_t> property(int_tag_, data);
+
+ // Populate static fields.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(property.PopulateStaticFields(&metadata), 0);
+
+ // Check the results.
+ // Should only have added 1 entry.
+ EXPECT_EQ(metadata.entryCount(), 1);
+ // Should have added the right entry.
+ ExpectMetadataEq(metadata, int_tag_, data);
+}
+
+// TODO(b/30839858): These tests are really testing the metadata_common.h
+// UpdateMetadata methods, and shouldn't be conducted here.
+TEST_F(PropertyTest, PopulateStaticVector) {
+ // Set up a fixed property.
+ std::vector<float> data({0.1, 2.3, 4.5, 6.7});
+ Property<std::vector<float>> property(float_tag_, data);
+
+ // Populate static fields.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(property.PopulateStaticFields(&metadata), 0);
+
+ // Check the results.
+ // Should only have added 1 entry.
+ EXPECT_EQ(metadata.entryCount(), 1);
+ // Should have added the right entry.
+ ExpectMetadataEq(metadata, float_tag_, data);
+}
+
+TEST_F(PropertyTest, PopulateStaticArray) {
+ // Set up a fixed property.
+ std::array<float, 4> data({{0.1, 2.3, 4.5, 6.7}});
+ Property<std::array<float, 4>> property(float_tag_, data);
+
+ // Populate static fields.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(property.PopulateStaticFields(&metadata), 0);
+
+ // Check the results.
+ // Should only have added 1 entry.
+ EXPECT_EQ(metadata.entryCount(), 1);
+ // Should have added the right entry.
+ ExpectMetadataEq(metadata, float_tag_, data);
+}
+
+TEST_F(PropertyTest, PopulateStaticArrayVector) {
+ // Set up a fixed property.
+ ArrayVector<uint8_t, 3> data;
+ data.push_back({{1, 2, 3}});
+ data.push_back({{4, 5, 6}});
+ Property<ArrayVector<uint8_t, 3>> property(byte_tag_, data);
+
+ // Populate static fields.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(property.PopulateStaticFields(&metadata), 0);
+
+ // Check the results.
+ // Should only have added 1 entry.
+ EXPECT_EQ(metadata.entryCount(), 1);
+ // Should have added the right entry.
+ ExpectMetadataEq(metadata, byte_tag_, data);
+}
+
+TEST_F(PropertyTest, PopulateDynamic) {
+ Property<int32_t> property(int_tag_, 1);
+
+ android::CameraMetadata metadata;
+ EXPECT_EQ(property.PopulateDynamicFields(&metadata), 0);
+
+ // Shouldn't have added anything.
+ EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(PropertyTest, PopulateTemplate) {
+ Property<int32_t> property(int_tag_, 1);
+
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
+ android::CameraMetadata metadata;
+ EXPECT_EQ(property.PopulateTemplateRequest(i, &metadata), 0);
+ // Shouldn't have added anything.
+ EXPECT_TRUE(metadata.isEmpty());
+ }
+}
+
+TEST_F(PropertyTest, SupportsRequest) {
+ Property<int32_t> property(int_tag_, 1);
+ android::CameraMetadata metadata;
+ EXPECT_EQ(property.SupportsRequestValues(metadata), true);
+}
+
+TEST_F(PropertyTest, SetRequest) {
+ Property<int32_t> property(int_tag_, 1);
+ android::CameraMetadata metadata;
+ EXPECT_EQ(property.SetRequestValues(metadata), 0);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/ranged_converter.h b/modules/camera/3_4/metadata/ranged_converter.h
new file mode 100644
index 0000000..115ac2a
--- /dev/null
+++ b/modules/camera/3_4/metadata/ranged_converter.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_RANGED_CONVERTER_H_
+#define V4L2_CAMERA_HAL_METADATA_RANGED_CONVERTER_H_
+
+#include <memory>
+
+#include "../common.h"
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+// An RangedConverter fits values converted by a wrapped converter
+// to a stepped range (when going from metadata -> v4l2. The other
+// direction remains unchanged).
+template <typename TMetadata, typename TV4L2>
+class RangedConverter : public ConverterInterface<TMetadata, TV4L2> {
+ public:
+ RangedConverter(
+ std::shared_ptr<ConverterInterface<TMetadata, TV4L2>> wrapped_converter,
+ TV4L2 min,
+ TV4L2 max,
+ TV4L2 step);
+
+ virtual int MetadataToV4L2(TMetadata value, TV4L2* conversion) override;
+ virtual int V4L2ToMetadata(TV4L2 value, TMetadata* conversion) override;
+
+ private:
+ std::shared_ptr<ConverterInterface<TMetadata, TV4L2>> wrapped_converter_;
+ const TV4L2 min_;
+ const TV4L2 max_;
+ const TV4L2 step_;
+
+ DISALLOW_COPY_AND_ASSIGN(RangedConverter);
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename TMetadata, typename TV4L2>
+RangedConverter<TMetadata, TV4L2>::RangedConverter(
+ std::shared_ptr<ConverterInterface<TMetadata, TV4L2>> wrapped_converter,
+ TV4L2 min,
+ TV4L2 max,
+ TV4L2 step)
+ : wrapped_converter_(std::move(wrapped_converter)),
+ min_(min),
+ max_(max),
+ step_(step) {
+ HAL_LOG_ENTER();
+}
+
+template <typename TMetadata, typename TV4L2>
+int RangedConverter<TMetadata, TV4L2>::MetadataToV4L2(TMetadata value,
+ TV4L2* conversion) {
+ HAL_LOG_ENTER();
+
+ TV4L2 raw_conversion = 0;
+ int res = wrapped_converter_->MetadataToV4L2(value, &raw_conversion);
+ if (res) {
+ HAL_LOGE("Failed to perform underlying conversion.");
+ return res;
+ }
+
+ // Round down to step (steps start at min_).
+ raw_conversion -= (raw_conversion - min_) % step_;
+
+ // Clamp to range.
+ if (raw_conversion < min_) {
+ raw_conversion = min_;
+ } else if (raw_conversion > max_) {
+ raw_conversion = max_;
+ }
+
+ *conversion = raw_conversion;
+ return 0;
+}
+
+template <typename TMetadata, typename TV4L2>
+int RangedConverter<TMetadata, TV4L2>::V4L2ToMetadata(TV4L2 value,
+ TMetadata* conversion) {
+ HAL_LOG_ENTER();
+
+ return wrapped_converter_->V4L2ToMetadata(value, conversion);
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_RANGED_CONVERTER_H_
diff --git a/modules/camera/3_4/metadata/ranged_converter_test.cpp b/modules/camera/3_4/metadata/ranged_converter_test.cpp
new file mode 100644
index 0000000..2b5ccc6
--- /dev/null
+++ b/modules/camera/3_4/metadata/ranged_converter_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ranged_converter.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "converter_interface_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class RangedConverterTest : public Test {
+ protected:
+ virtual void SetUp() {
+ converter_.reset(new ConverterInterfaceMock<int, int32_t>());
+ dut_.reset(
+ new RangedConverter<int, int32_t>(converter_, min_, max_, step_));
+ }
+
+ virtual void ExpectConvert(int32_t converted, int32_t expected) {
+ int initial = 99;
+ EXPECT_CALL(*converter_, MetadataToV4L2(initial, _))
+ .WillOnce(DoAll(SetArgPointee<1>(converted), Return(0)));
+
+ int32_t actual = expected + 1; // Initialize to non-expected value.
+ ASSERT_EQ(dut_->MetadataToV4L2(initial, &actual), 0);
+ EXPECT_EQ(actual, expected);
+ }
+
+ std::shared_ptr<ConverterInterfaceMock<int, int32_t>> converter_;
+ std::unique_ptr<RangedConverter<int, int32_t>> dut_;
+
+ const int32_t min_ = -11;
+ const int32_t max_ = 10;
+ const int32_t step_ = 3;
+};
+
+TEST_F(RangedConverterTest, NormalConversion) {
+ // A value that's in range and on step.
+ ExpectConvert(max_ - step_, max_ - step_);
+}
+
+TEST_F(RangedConverterTest, RoundingConversion) {
+ // A value that's in range but off step.
+ ExpectConvert(max_ - step_ + 1, max_ - step_);
+}
+
+TEST_F(RangedConverterTest, ClampUpConversion) {
+ // A value that's below range.
+ ExpectConvert(min_ - 1, min_);
+}
+
+TEST_F(RangedConverterTest, ClampDownConversion) {
+ // A value that's above range (even after fitting to step).
+ ExpectConvert(max_ + step_, max_);
+}
+
+TEST_F(RangedConverterTest, ConversionError) {
+ int initial = 99;
+ int err = -99;
+ EXPECT_CALL(*converter_, MetadataToV4L2(initial, _)).WillOnce(Return(err));
+
+ int32_t unused;
+ EXPECT_EQ(dut_->MetadataToV4L2(initial, &unused), err);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/scaling_converter.h b/modules/camera/3_4/metadata/scaling_converter.h
new file mode 100644
index 0000000..3087167
--- /dev/null
+++ b/modules/camera/3_4/metadata/scaling_converter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_SCALING_CONVERTER_H_
+#define V4L2_CAMERA_HAL_METADATA_SCALING_CONVERTER_H_
+
+#include "../common.h"
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+// An ScalingConverter scales values up or down.
+template <typename TMetadata, typename TV4L2>
+class ScalingConverter : public ConverterInterface<TMetadata, TV4L2> {
+ public:
+ ScalingConverter(TMetadata v4l2_to_metadata_numerator,
+ TMetadata v4l2_to_metadata_denominator);
+
+ virtual int MetadataToV4L2(TMetadata value, TV4L2* conversion) override;
+ virtual int V4L2ToMetadata(TV4L2 value, TMetadata* conversion) override;
+
+ private:
+ const TMetadata v4l2_to_metadata_numerator_;
+ const TMetadata v4l2_to_metadata_denominator_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScalingConverter);
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename TMetadata, typename TV4L2>
+ScalingConverter<TMetadata, TV4L2>::ScalingConverter(
+ TMetadata v4l2_to_metadata_numerator,
+ TMetadata v4l2_to_metadata_denominator)
+ : v4l2_to_metadata_numerator_(v4l2_to_metadata_numerator),
+ v4l2_to_metadata_denominator_(v4l2_to_metadata_denominator) {
+ HAL_LOG_ENTER();
+}
+
+template <typename TMetadata, typename TV4L2>
+int ScalingConverter<TMetadata, TV4L2>::MetadataToV4L2(TMetadata value,
+ TV4L2* conversion) {
+ HAL_LOG_ENTER();
+
+ *conversion = static_cast<TV4L2>(value * v4l2_to_metadata_denominator_ /
+ v4l2_to_metadata_numerator_);
+ return 0;
+}
+
+template <typename TMetadata, typename TV4L2>
+int ScalingConverter<TMetadata, TV4L2>::V4L2ToMetadata(TV4L2 value,
+ TMetadata* conversion) {
+ HAL_LOG_ENTER();
+
+ *conversion = static_cast<TMetadata>(value) * v4l2_to_metadata_numerator_ /
+ v4l2_to_metadata_denominator_;
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_SCALING_CONVERTER_H_
diff --git a/modules/camera/3_4/metadata/slider_control_options.h b/modules/camera/3_4/metadata/slider_control_options.h
new file mode 100644
index 0000000..2815dad
--- /dev/null
+++ b/modules/camera/3_4/metadata/slider_control_options.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_SLIDER_CONTROL_OPTIONS_H_
+#define V4L2_CAMERA_HAL_METADATA_SLIDER_CONTROL_OPTIONS_H_
+
+#include <errno.h>
+
+#include <vector>
+
+#include "../common.h"
+#include "control_options_interface.h"
+
+namespace v4l2_camera_hal {
+
+// SliderControlOptions offer a range of acceptable values, inclusive.
+template <typename T>
+class SliderControlOptions : public ControlOptionsInterface<T> {
+ public:
+ // |min| must be <= |max|.
+ SliderControlOptions(T min, T max) : min_(min), max_(max) {}
+
+ virtual std::vector<T> MetadataRepresentation() override {
+ return {min_, max_};
+ };
+ virtual bool IsSupported(const T& option) override {
+ return option >= min_ && option <= max_;
+ };
+ virtual int DefaultValueForTemplate(int template_type,
+ T* default_value) override {
+ // TODO(b/31017806): More complex logic, depend on template_type.
+ if (min_ > max_) {
+ HAL_LOGE("No valid default slider option, min is greater than max.");
+ return -ENODEV;
+ }
+ // Default to the min value.
+ *default_value = min_;
+ return 0;
+ }
+
+ private:
+ T min_;
+ T max_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_SLIDER_CONTROL_OPTIONS_H_
diff --git a/modules/camera/3_4/metadata/slider_control_options_test.cpp b/modules/camera/3_4/metadata/slider_control_options_test.cpp
new file mode 100644
index 0000000..a241ad6
--- /dev/null
+++ b/modules/camera/3_4/metadata/slider_control_options_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "slider_control_options.h"
+
+#include <memory>
+
+#include <gtest/gtest.h>
+#include <hardware/camera3.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+class SliderControlOptionsTest : public Test {
+ protected:
+ virtual void SetUp() {
+ dut_.reset(new SliderControlOptions<int>(min_, max_));
+ }
+
+ std::unique_ptr<SliderControlOptions<int>> dut_;
+ const int min_ = 1;
+ const int max_ = 10;
+};
+
+TEST_F(SliderControlOptionsTest, MetadataRepresentation) {
+ // Technically order doesn't matter, but this is faster to write,
+ // and still passes.
+ std::vector<int> expected{min_, max_};
+ EXPECT_EQ(dut_->MetadataRepresentation(), expected);
+}
+
+TEST_F(SliderControlOptionsTest, IsSupported) {
+ for (int i = min_; i <= max_; ++i) {
+ EXPECT_TRUE(dut_->IsSupported(i));
+ }
+ // Out of range unsupported.
+ EXPECT_FALSE(dut_->IsSupported(min_ - 1));
+ EXPECT_FALSE(dut_->IsSupported(max_ + 1));
+}
+
+TEST_F(SliderControlOptionsTest, DefaultValue) {
+ // All default values should be supported.
+ // For some reason, the templates have values in the range [1, COUNT).
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
+ int value = -1;
+ EXPECT_EQ(dut_->DefaultValueForTemplate(i, &value), 0);
+ EXPECT_TRUE(dut_->IsSupported(value));
+ }
+}
+
+TEST_F(SliderControlOptionsTest, NoDefaultValue) {
+ // Invalid options don't have a valid default.
+ SliderControlOptions<int> bad_options(10, 9); // min > max.
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
+ int value = -1;
+ EXPECT_EQ(bad_options.DefaultValueForTemplate(i, &value), -ENODEV);
+ }
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/state.h b/modules/camera/3_4/metadata/state.h
new file mode 100644
index 0000000..54f66e4
--- /dev/null
+++ b/modules/camera/3_4/metadata/state.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_STATE_H_
+#define V4L2_CAMERA_HAL_METADATA_STATE_H_
+
+#include "../common.h"
+#include "metadata_common.h"
+#include "partial_metadata_interface.h"
+#include "state_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A State is a PartialMetadata that only has a single dynamic value.
+template <typename T>
+class State : public PartialMetadataInterface {
+ public:
+ State(int32_t tag, std::unique_ptr<StateDelegateInterface<T>> delegate)
+ : tag_(tag), delegate_(std::move(delegate)){};
+
+ virtual std::vector<int32_t> StaticTags() const override { return {}; };
+ virtual std::vector<int32_t> ControlTags() const override { return {}; };
+ virtual std::vector<int32_t> DynamicTags() const override { return {tag_}; };
+
+ virtual int PopulateStaticFields(
+ android::CameraMetadata* metadata) const override;
+ virtual int PopulateDynamicFields(
+ android::CameraMetadata* metadata) const override;
+ virtual int PopulateTemplateRequest(
+ int template_type, android::CameraMetadata* metadata) const override;
+ virtual bool SupportsRequestValues(
+ const android::CameraMetadata& metadata) const override;
+ virtual int SetRequestValues(
+ const android::CameraMetadata& metadata) override;
+
+ private:
+ int32_t tag_;
+ std::unique_ptr<StateDelegateInterface<T>> delegate_;
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename T>
+int State<T>::PopulateStaticFields(android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+ return 0;
+}
+
+template <typename T>
+int State<T>::PopulateDynamicFields(android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+
+ T value;
+ int res = delegate_->GetValue(&value);
+ if (res) {
+ return res;
+ }
+ return UpdateMetadata(metadata, tag_, value);
+};
+
+template <typename T>
+int State<T>::PopulateTemplateRequest(int template_type,
+ android::CameraMetadata* metadata) const {
+ HAL_LOG_ENTER();
+ return 0;
+};
+
+template <typename T>
+bool State<T>::SupportsRequestValues(
+ const android::CameraMetadata& metadata) const {
+ HAL_LOG_ENTER();
+ return true;
+};
+
+template <typename T>
+int State<T>::SetRequestValues(const android::CameraMetadata& metadata) {
+ HAL_LOG_ENTER();
+ return 0;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_STATE_H_
diff --git a/modules/camera/3_4/metadata/state_delegate_interface.h b/modules/camera/3_4/metadata/state_delegate_interface.h
new file mode 100644
index 0000000..c18ee3c
--- /dev/null
+++ b/modules/camera/3_4/metadata/state_delegate_interface.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_STATE_DELEGATE_INTERFACE_H_
+#define V4L2_CAMERA_HAL_METADATA_STATE_DELEGATE_INTERFACE_H_
+
+namespace v4l2_camera_hal {
+
+// A StateDelegate is simply a dynamic value that can be queried.
+// The value may change between queries.
+template <typename T>
+class StateDelegateInterface {
+ public:
+ virtual ~StateDelegateInterface(){};
+ // Returns 0 on success, error code on failure.
+ virtual int GetValue(T* value) = 0;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_STATE_DELEGATE_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/state_delegate_interface_mock.h b/modules/camera/3_4/metadata/state_delegate_interface_mock.h
new file mode 100644
index 0000000..5064b83
--- /dev/null
+++ b/modules/camera/3_4/metadata/state_delegate_interface_mock.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for state delegate interfaces.
+
+#ifndef V4L2_CAMERA_HAL_METADATA_STATE_DELEGATE_INTERFACE_MOCK_H_
+#define V4L2_CAMERA_HAL_METADATA_STATE_DELEGATE_INTERFACE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "state_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+template <typename T>
+class StateDelegateInterfaceMock : public StateDelegateInterface<T> {
+ public:
+ StateDelegateInterfaceMock(){};
+ MOCK_METHOD1_T(GetValue, int(T*));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/state_test.cpp b/modules/camera/3_4/metadata/state_test.cpp
new file mode 100644
index 0000000..5c308bc
--- /dev/null
+++ b/modules/camera/3_4/metadata/state_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "state.h"
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "metadata_common.h"
+#include "state_delegate_interface_mock.h"
+#include "test_common.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class StateTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_delegate_.reset(new StateDelegateInterfaceMock<uint8_t>());
+ // Nullify state so an error will be thrown if a test doesn't call
+ // PrepareState.
+ state_.reset();
+ }
+
+ virtual void PrepareState() {
+ // Use this method after all the EXPECT_CALLs to pass ownership of the mocks
+ // to the device.
+ state_.reset(new State<uint8_t>(tag_, std::move(mock_delegate_)));
+ }
+
+ std::unique_ptr<State<uint8_t>> state_;
+ std::unique_ptr<StateDelegateInterfaceMock<uint8_t>> mock_delegate_;
+
+ // Need tag that matches the data type (uint8_t) being passed.
+ const int32_t tag_ = ANDROID_CONTROL_AF_STATE;
+};
+
+TEST_F(StateTest, Tags) {
+ PrepareState();
+ EXPECT_TRUE(state_->StaticTags().empty());
+ EXPECT_TRUE(state_->ControlTags().empty());
+ ASSERT_EQ(state_->DynamicTags().size(), 1);
+ EXPECT_EQ(state_->DynamicTags()[0], tag_);
+}
+
+TEST_F(StateTest, PopulateStatic) {
+ PrepareState();
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state_->PopulateStaticFields(&metadata), 0);
+ EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(StateTest, PopulateDynamic) {
+ uint8_t expected = 99;
+ EXPECT_CALL(*mock_delegate_, GetValue(_))
+ .WillOnce(DoAll(SetArgPointee<0>(expected), Return(0)));
+
+ PrepareState();
+
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state_->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, tag_, expected);
+}
+
+TEST_F(StateTest, PopulateDynamicFail) {
+ int err = 123;
+ EXPECT_CALL(*mock_delegate_, GetValue(_)).WillOnce(Return(err));
+
+ PrepareState();
+
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state_->PopulateDynamicFields(&metadata), err);
+}
+
+TEST_F(StateTest, PopulateTemplate) {
+ int template_type = 3;
+ PrepareState();
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state_->PopulateTemplateRequest(template_type, &metadata), 0);
+ EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(StateTest, SupportsRequest) {
+ PrepareState();
+ android::CameraMetadata metadata;
+ EXPECT_TRUE(state_->SupportsRequestValues(metadata));
+}
+
+TEST_F(StateTest, SetRequest) {
+ PrepareState();
+ android::CameraMetadata metadata;
+ ASSERT_EQ(state_->SetRequestValues(metadata), 0);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/tagged_control_delegate.h b/modules/camera/3_4/metadata/tagged_control_delegate.h
new file mode 100644
index 0000000..40677f9
--- /dev/null
+++ b/modules/camera/3_4/metadata/tagged_control_delegate.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_TAGGED_CONTROL_DELEGATE_H_
+#define V4L2_CAMERA_HAL_METADATA_TAGGED_CONTROL_DELEGATE_H_
+
+#include <memory>
+
+#include "control_delegate_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A TaggedControlDelegate wraps a ControlDelegate and adds a tag.
+template <typename T>
+class TaggedControlDelegate : public ControlDelegateInterface<T> {
+ public:
+ TaggedControlDelegate(int32_t tag,
+ std::unique_ptr<ControlDelegateInterface<T>> delegate)
+ : tag_(tag), delegate_(std::move(delegate)){};
+
+ int32_t tag() { return tag_; };
+
+ virtual int GetValue(T* value) override {
+ return delegate_->GetValue(value);
+ };
+ virtual int SetValue(const T& value) override {
+ return delegate_->SetValue(value);
+ };
+
+ private:
+ const int32_t tag_;
+ std::unique_ptr<ControlDelegateInterface<T>> delegate_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_DELEGATE_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/tagged_control_delegate_test.cpp b/modules/camera/3_4/metadata/tagged_control_delegate_test.cpp
new file mode 100644
index 0000000..ba29ab7
--- /dev/null
+++ b/modules/camera/3_4/metadata/tagged_control_delegate_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tagged_control_delegate.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "control_delegate_interface_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class TaggedControlDelegateTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_delegate_.reset(new ControlDelegateInterfaceMock<uint8_t>());
+ // Nullify dut so an error will be thrown if a test doesn't call PrepareDUT.
+ dut_.reset();
+ }
+
+ virtual void PrepareDUT() {
+ // Use this method after all the EXPECT_CALLs to pass ownership of the
+ // delegate
+ // to the device.
+ dut_.reset(
+ new TaggedControlDelegate<uint8_t>(tag_, std::move(mock_delegate_)));
+ }
+
+ std::unique_ptr<TaggedControlDelegate<uint8_t>> dut_;
+ std::unique_ptr<ControlDelegateInterfaceMock<uint8_t>> mock_delegate_;
+ const int32_t tag_ = 123;
+};
+
+TEST_F(TaggedControlDelegateTest, GetTag) {
+ PrepareDUT();
+ EXPECT_EQ(dut_->tag(), tag_);
+}
+
+TEST_F(TaggedControlDelegateTest, GetSuccess) {
+ uint8_t expected = 3;
+ EXPECT_CALL(*mock_delegate_, GetValue(_))
+ .WillOnce(DoAll(SetArgPointee<0>(expected), Return(0)));
+ PrepareDUT();
+ uint8_t actual = expected + 1; // Initialize to an incorrect value.
+ ASSERT_EQ(dut_->GetValue(&actual), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(TaggedControlDelegateTest, GetFailure) {
+ int err = 3;
+ EXPECT_CALL(*mock_delegate_, GetValue(_)).WillOnce(Return(err));
+ PrepareDUT();
+ uint8_t unused = 0;
+ ASSERT_EQ(dut_->GetValue(&unused), err);
+}
+
+TEST_F(TaggedControlDelegateTest, SetSuccess) {
+ uint8_t value = 3;
+ EXPECT_CALL(*mock_delegate_, SetValue(value)).WillOnce(Return(0));
+ PrepareDUT();
+ ASSERT_EQ(dut_->SetValue(value), 0);
+}
+
+TEST_F(TaggedControlDelegateTest, SetFailure) {
+ int err = 3;
+ uint8_t value = 12;
+ EXPECT_CALL(*mock_delegate_, SetValue(value)).WillOnce(Return(err));
+ PrepareDUT();
+ ASSERT_EQ(dut_->SetValue(value), err);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/tagged_control_options.h b/modules/camera/3_4/metadata/tagged_control_options.h
new file mode 100644
index 0000000..9204fea
--- /dev/null
+++ b/modules/camera/3_4/metadata/tagged_control_options.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_TAGGED_CONTROL_OPTIONS_H_
+#define V4L2_CAMERA_HAL_METADATA_TAGGED_CONTROL_OPTIONS_H_
+
+#include <memory>
+
+#include "control_options_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A TaggedControlOptions wraps a ControlOptions and adds a tag.
+template <typename T>
+class TaggedControlOptions : public ControlOptionsInterface<T> {
+ public:
+ TaggedControlOptions(int32_t tag,
+ std::unique_ptr<ControlOptionsInterface<T>> options)
+ : tag_(tag), options_(std::move(options)){};
+
+ int32_t tag() { return tag_; };
+
+ virtual std::vector<T> MetadataRepresentation() override {
+ return options_->MetadataRepresentation();
+ };
+ virtual bool IsSupported(const T& value) override {
+ return options_->IsSupported(value);
+ };
+ virtual int DefaultValueForTemplate(int template_type,
+ T* default_value) override {
+ return options_->DefaultValueForTemplate(template_type, default_value);
+ }
+
+ private:
+ const int32_t tag_;
+ std::unique_ptr<ControlOptionsInterface<T>> options_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_OPTIONS_INTERFACE_H_
diff --git a/modules/camera/3_4/metadata/tagged_control_options_test.cpp b/modules/camera/3_4/metadata/tagged_control_options_test.cpp
new file mode 100644
index 0000000..845426a
--- /dev/null
+++ b/modules/camera/3_4/metadata/tagged_control_options_test.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tagged_control_options.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "control_options_interface_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class TaggedControlOptionsTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_options_.reset(new ControlOptionsInterfaceMock<uint8_t>());
+ // Nullify dut so an error will be thrown if a test doesn't call PrepareDUT.
+ dut_.reset();
+ }
+
+ virtual void PrepareDUT() {
+ // Use this method after all the EXPECT_CALLs to pass ownership of the
+ // options
+ // to the device.
+ dut_.reset(
+ new TaggedControlOptions<uint8_t>(tag_, std::move(mock_options_)));
+ }
+
+ std::unique_ptr<TaggedControlOptions<uint8_t>> dut_;
+ std::unique_ptr<ControlOptionsInterfaceMock<uint8_t>> mock_options_;
+ const int32_t tag_ = 123;
+};
+
+TEST_F(TaggedControlOptionsTest, GetTag) {
+ PrepareDUT();
+ EXPECT_EQ(dut_->tag(), tag_);
+}
+
+TEST_F(TaggedControlOptionsTest, MetadataRepresentation) {
+ std::vector<uint8_t> expected{3, 4, 5};
+ EXPECT_CALL(*mock_options_, MetadataRepresentation())
+ .WillOnce(Return(expected));
+ PrepareDUT();
+ ASSERT_EQ(dut_->MetadataRepresentation(), expected);
+}
+
+TEST_F(TaggedControlOptionsTest, IsSupportedTrue) {
+ bool supported = true;
+ uint8_t value = 3;
+ EXPECT_CALL(*mock_options_, IsSupported(value)).WillOnce(Return(supported));
+ PrepareDUT();
+ ASSERT_EQ(dut_->IsSupported(value), supported);
+}
+
+TEST_F(TaggedControlOptionsTest, IsSupportedFalse) {
+ bool supported = false;
+ uint8_t value = 3;
+ EXPECT_CALL(*mock_options_, IsSupported(value)).WillOnce(Return(supported));
+ PrepareDUT();
+ ASSERT_EQ(dut_->IsSupported(value), supported);
+}
+
+TEST_F(TaggedControlOptionsTest, DefaultValue) {
+ uint8_t value = 99;
+ int template_id = 3;
+ EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(value), Return(0)));
+ PrepareDUT();
+ uint8_t actual = value + 1;
+ EXPECT_EQ(dut_->DefaultValueForTemplate(template_id, &actual), 0);
+ EXPECT_EQ(actual, value);
+}
+
+TEST_F(TaggedControlOptionsTest, DefaultValueFail) {
+ int err = 12;
+ int template_id = 3;
+ EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_id, _))
+ .WillOnce(Return(err));
+ PrepareDUT();
+ uint8_t unused;
+ EXPECT_EQ(dut_->DefaultValueForTemplate(template_id, &unused), err);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/test_common.h b/modules/camera/3_4/metadata/test_common.h
new file mode 100644
index 0000000..489990f
--- /dev/null
+++ b/modules/camera/3_4/metadata/test_common.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_TEST_COMMON_H_
+#define V4L2_CAMERA_HAL_METADATA_TEST_COMMON_H_
+
+#include <array>
+#include <vector>
+
+#include <camera/CameraMetadata.h>
+#include <gtest/gtest.h>
+
+#include "array_vector.h"
+#include "metadata_common.h"
+
+namespace v4l2_camera_hal {
+
+// Check that metadata of a given tag matches expectations.
+// Generic.
+template <typename T>
+static void ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ const T* expected,
+ size_t size) {
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ ASSERT_EQ(entry.count, size);
+ const T* data = nullptr;
+ GetDataPointer(entry, &data);
+ ASSERT_NE(data, nullptr);
+ for (size_t i = 0; i < size; ++i) {
+ EXPECT_EQ(data[i], expected[i]);
+ }
+}
+
+// Single item.
+template <typename T>
+static void ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ T expected) {
+ ExpectMetadataEq(metadata, tag, &expected, 1);
+}
+
+// Vector of items.
+template <typename T>
+static void ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ const std::vector<T>& expected) {
+ ExpectMetadataEq(metadata, tag, expected.data(), expected.size());
+}
+
+// Array of items.
+template <typename T, size_t N>
+static void ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ const std::array<T, N>& expected) {
+ ExpectMetadataEq(metadata, tag, expected.data(), N);
+}
+
+// ArrayVector.
+template <typename T, size_t N>
+static void ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ const ArrayVector<T, N>& expected) {
+ ExpectMetadataEq(
+ metadata, tag, expected.data(), expected.total_num_elements());
+}
+
+// Vector of arrays.
+template <typename T, size_t N>
+static int ExpectMetadataEq(const android::CameraMetadata& metadata,
+ int32_t tag,
+ const std::vector<std::array<T, N>>& expected) {
+ // Convert to array vector so we know all the elements are contiguous.
+ ArrayVector<T, N> array_vector;
+ for (const auto& array : expected) {
+ array_vector.push_back(array);
+ }
+ ExpectMetadataEq(metadata, tag, array_vector);
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_TEST_COMMON_H_
diff --git a/modules/camera/3_4/metadata/v4l2_control_delegate.h b/modules/camera/3_4/metadata/v4l2_control_delegate.h
new file mode 100644
index 0000000..3f45f9c
--- /dev/null
+++ b/modules/camera/3_4/metadata/v4l2_control_delegate.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_V4L2_CONTROL_DELEGATE_H_
+#define V4L2_CAMERA_HAL_METADATA_V4L2_CONTROL_DELEGATE_H_
+
+#include "../v4l2_wrapper.h"
+#include "control_delegate_interface.h"
+#include "converter_interface.h"
+
+namespace v4l2_camera_hal {
+
+// A V4L2ControlDelegate routes getting and setting through V4L2
+template <typename TMetadata, typename TV4L2 = int32_t>
+class V4L2ControlDelegate : public ControlDelegateInterface<TMetadata> {
+ public:
+ V4L2ControlDelegate(
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<TMetadata, TV4L2>> converter)
+ : device_(std::move(device)),
+ control_id_(control_id),
+ converter_(std::move(converter)){};
+
+ int GetValue(TMetadata* value) override {
+ TV4L2 v4l2_value;
+ int res = device_->GetControl(control_id_, &v4l2_value);
+ if (res) {
+ HAL_LOGE("Failed to get device value for control %d.", control_id_);
+ return res;
+ }
+ return converter_->V4L2ToMetadata(v4l2_value, value);
+ };
+
+ int SetValue(const TMetadata& value) override {
+ TV4L2 v4l2_value;
+ int res = converter_->MetadataToV4L2(value, &v4l2_value);
+ if (res) {
+ HAL_LOGE("Failed to convert metadata value to V4L2.");
+ return res;
+ }
+ return device_->SetControl(control_id_, v4l2_value);
+ };
+
+ private:
+ std::shared_ptr<V4L2Wrapper> device_;
+ int control_id_;
+ std::shared_ptr<ConverterInterface<TMetadata, TV4L2>> converter_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_V4L2_CONTROL_DELEGATE_H_
diff --git a/modules/camera/3_4/metadata/v4l2_control_delegate_test.cpp b/modules/camera/3_4/metadata/v4l2_control_delegate_test.cpp
new file mode 100644
index 0000000..2f14d6f
--- /dev/null
+++ b/modules/camera/3_4/metadata/v4l2_control_delegate_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "v4l2_control_delegate.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "../v4l2_wrapper_mock.h"
+#include "converter_interface_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class V4L2ControlDelegateTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_device_.reset(new V4L2WrapperMock());
+ mock_converter_.reset(new ConverterInterfaceMock<uint8_t, int32_t>());
+ dut_.reset(new V4L2ControlDelegate<uint8_t>(
+ mock_device_, control_id_, mock_converter_));
+ }
+
+ std::unique_ptr<V4L2ControlDelegate<uint8_t>> dut_;
+ std::shared_ptr<V4L2WrapperMock> mock_device_;
+ std::shared_ptr<ConverterInterfaceMock<uint8_t, int32_t>> mock_converter_;
+ const int control_id_ = 123;
+};
+
+TEST_F(V4L2ControlDelegateTest, GetSuccess) {
+ int32_t device_result = 99;
+ uint8_t conversion_result = 10;
+ EXPECT_CALL(*mock_device_, GetControl(control_id_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(device_result), Return(0)));
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(device_result, _))
+ .WillOnce(DoAll(SetArgPointee<1>(conversion_result), Return(0)));
+
+ uint8_t actual = conversion_result + 1; // Something incorrect.
+ ASSERT_EQ(dut_->GetValue(&actual), 0);
+ EXPECT_EQ(actual, conversion_result);
+}
+
+TEST_F(V4L2ControlDelegateTest, GetConverterFailure) {
+ int32_t device_result = 99;
+ EXPECT_CALL(*mock_device_, GetControl(control_id_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(device_result), Return(0)));
+ int err = -99;
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(device_result, _))
+ .WillOnce(Return(err));
+
+ uint8_t unused = 1;
+ ASSERT_EQ(dut_->GetValue(&unused), err);
+}
+
+TEST_F(V4L2ControlDelegateTest, GetDeviceFailure) {
+ int err = -99;
+ EXPECT_CALL(*mock_device_, GetControl(control_id_, _)).WillOnce(Return(err));
+
+ uint8_t unused = 1;
+ ASSERT_EQ(dut_->GetValue(&unused), err);
+}
+
+TEST_F(V4L2ControlDelegateTest, SetSuccess) {
+ uint8_t input = 10;
+ int32_t conversion_result = 99;
+ EXPECT_CALL(*mock_converter_, MetadataToV4L2(input, _))
+ .WillOnce(DoAll(SetArgPointee<1>(conversion_result), Return(0)));
+ EXPECT_CALL(*mock_device_, SetControl(control_id_, conversion_result, _))
+ .WillOnce(Return(0));
+
+ ASSERT_EQ(dut_->SetValue(input), 0);
+}
+
+TEST_F(V4L2ControlDelegateTest, SetConverterFailure) {
+ uint8_t input = 10;
+ int err = 12;
+ EXPECT_CALL(*mock_converter_, MetadataToV4L2(input, _)).WillOnce(Return(err));
+ ASSERT_EQ(dut_->SetValue(input), err);
+}
+
+TEST_F(V4L2ControlDelegateTest, SetDeviceFailure) {
+ uint8_t input = 10;
+ int32_t conversion_result = 99;
+ EXPECT_CALL(*mock_converter_, MetadataToV4L2(input, _))
+ .WillOnce(DoAll(SetArgPointee<1>(conversion_result), Return(0)));
+ int err = 66;
+ EXPECT_CALL(*mock_device_, SetControl(control_id_, conversion_result, _))
+ .WillOnce(Return(err));
+
+ ASSERT_EQ(dut_->SetValue(input), err);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/stream.cpp b/modules/camera/3_4/stream.cpp
new file mode 100644
index 0000000..97d8634
--- /dev/null
+++ b/modules/camera/3_4/stream.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/Stream.cpp
+
+#include <stdio.h>
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+#include <utils/Mutex.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Stream"
+#include <cutils/log.h>
+
+#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+#include <utils/Trace.h>
+
+#include "stream.h"
+
+namespace default_camera_hal {
+
+Stream::Stream(int id, camera3_stream_t *s)
+ : mReuse(false),
+ mId(id),
+ mStream(s),
+ mType(s->stream_type),
+ mWidth(s->width),
+ mHeight(s->height),
+ mFormat(s->format),
+ mUsage(0),
+ mRotation(s->rotation),
+ mDataSpace(s->data_space),
+ mMaxBuffers(0)
+{
+}
+
+Stream::~Stream()
+{
+}
+
+void Stream::setUsage(uint32_t usage)
+{
+ android::Mutex::Autolock al(mLock);
+ if (usage != mUsage) {
+ mUsage = usage;
+ mStream->usage = usage;
+ }
+}
+
+void Stream::setMaxBuffers(uint32_t max_buffers)
+{
+ android::Mutex::Autolock al(mLock);
+ if (max_buffers != mMaxBuffers) {
+ mMaxBuffers = max_buffers;
+ mStream->max_buffers = max_buffers;
+ }
+}
+
+void Stream::setDataSpace(android_dataspace_t data_space)
+{
+ android::Mutex::Autolock al(mLock);
+ if (data_space != mDataSpace) {
+ mDataSpace = data_space;
+ mStream->data_space = data_space;
+ }
+}
+
+bool Stream::isInputType() const
+{
+ return mType == CAMERA3_STREAM_INPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
+}
+
+bool Stream::isOutputType() const
+{
+ return mType == CAMERA3_STREAM_OUTPUT ||
+ mType == CAMERA3_STREAM_BIDIRECTIONAL;
+}
+
+const char* Stream::typeToString(int type)
+{
+ switch (type) {
+ case CAMERA3_STREAM_INPUT:
+ return "CAMERA3_STREAM_INPUT";
+ case CAMERA3_STREAM_OUTPUT:
+ return "CAMERA3_STREAM_OUTPUT";
+ case CAMERA3_STREAM_BIDIRECTIONAL:
+ return "CAMERA3_STREAM_BIDIRECTIONAL";
+ }
+ return "Invalid stream type!";
+}
+
+const char* Stream::formatToString(int format)
+{
+ // See <system/graphics.h> for full list
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return "BGRA 8888";
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return "RGBA 8888";
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return "RGBX 8888";
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return "RGB 888";
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return "RGB 565";
+ case HAL_PIXEL_FORMAT_Y8:
+ return "Y8";
+ case HAL_PIXEL_FORMAT_Y16:
+ return "Y16";
+ case HAL_PIXEL_FORMAT_YV12:
+ return "YV12";
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ return "NV16";
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ return "NV21";
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return "YUY2";
+ case HAL_PIXEL_FORMAT_RAW10:
+ return "RAW10";
+ case HAL_PIXEL_FORMAT_RAW16:
+ return "RAW16";
+ case HAL_PIXEL_FORMAT_BLOB:
+ return "BLOB";
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return "IMPLEMENTATION DEFINED";
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ return "FLEXIBLE YCbCr 420 888";
+ }
+ return "Invalid stream format!";
+}
+
+bool Stream::isValidReuseStream(int id, camera3_stream_t *s)
+{
+ if (id != mId) {
+ ALOGE("%s:%d: Invalid camera id for reuse. Got %d expect %d",
+ __func__, mId, id, mId);
+ return false;
+ }
+ if (s != mStream) {
+ ALOGE("%s:%d: Invalid stream handle for reuse. Got %p expect %p",
+ __func__, mId, s, mStream);
+ return false;
+ }
+ if (s->stream_type != mType) {
+ ALOGE("%s:%d: Mismatched type in reused stream. Got %s(%d) "
+ "expect %s(%d)", __func__, mId, typeToString(s->stream_type),
+ s->stream_type, typeToString(mType), mType);
+ return false;
+ }
+ if (s->format != mFormat) {
+ ALOGE("%s:%d: Mismatched format in reused stream. Got %s(%d) "
+ "expect %s(%d)", __func__, mId, formatToString(s->format),
+ s->format, formatToString(mFormat), mFormat);
+ return false;
+ }
+ if (s->width != mWidth) {
+ ALOGE("%s:%d: Mismatched width in reused stream. Got %d expect %d",
+ __func__, mId, s->width, mWidth);
+ return false;
+ }
+ if (s->height != mHeight) {
+ ALOGE("%s:%d: Mismatched height in reused stream. Got %d expect %d",
+ __func__, mId, s->height, mHeight);
+ return false;
+ }
+ return true;
+}
+
+void Stream::dump(int fd)
+{
+ android::Mutex::Autolock al(mLock);
+
+ dprintf(fd, "Stream ID: %d (%p)\n", mId, mStream);
+ dprintf(fd, "Stream Type: %s (%d)\n", typeToString(mType), mType);
+ dprintf(fd, "Width: %" PRIu32 " Height: %" PRIu32 "\n", mWidth, mHeight);
+ dprintf(fd, "Stream Format: %s (%d)", formatToString(mFormat), mFormat);
+ // ToDo: prettyprint usage mask flags
+ dprintf(fd, "Gralloc Usage Mask: %#" PRIx32 "\n", mUsage);
+ dprintf(fd, "Stream Rotation: %d\n", mRotation);
+ dprintf(fd, "Stream Dataspace: 0x%x\n", mDataSpace);
+ dprintf(fd, "Max Buffer Count: %" PRIu32 "\n", mMaxBuffers);
+}
+
+} // namespace default_camera_hal
diff --git a/modules/camera/3_4/stream.h b/modules/camera/3_4/stream.h
new file mode 100644
index 0000000..781f946
--- /dev/null
+++ b/modules/camera/3_4/stream.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/Stream.h
+
+#ifndef DEFAULT_CAMERA_HAL_STREAM_H_
+#define DEFAULT_CAMERA_HAL_STREAM_H_
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+#include <utils/Mutex.h>
+
+namespace default_camera_hal {
+// Stream represents a single input or output stream for a camera device.
+class Stream {
+ public:
+ Stream(int id, camera3_stream_t *s);
+ ~Stream();
+
+ // validate that astream's parameters match this stream's parameters
+ bool isValidReuseStream(int id, camera3_stream_t *s);
+
+ void setUsage(uint32_t usage);
+ void setMaxBuffers(uint32_t max_buffers);
+ void setDataSpace(android_dataspace_t data_space);
+
+ inline int getFormat() const { return mFormat; };
+ inline int getType() const { return mType; };
+ inline uint32_t getWidth() const { return mWidth; };
+ inline uint32_t getHeight() const { return mHeight; };
+ inline int getRotation() const { return mRotation; };
+
+ bool isInputType() const;
+ bool isOutputType() const;
+ const char* typeToString(int type);
+ const char* formatToString(int format);
+ void dump(int fd);
+
+ // This stream is being reused. Used in stream configuration passes
+ bool mReuse;
+
+ private:
+
+ // The camera device id this stream belongs to
+ const int mId;
+ // Handle to framework's stream, used as a cookie for buffers
+ camera3_stream_t *mStream;
+ // Stream type: CAMERA3_STREAM_* (see <hardware/camera3.h>)
+ const int mType;
+ // Width in pixels of the buffers in this stream
+ const uint32_t mWidth;
+ // Height in pixels of the buffers in this stream
+ const uint32_t mHeight;
+ // Gralloc format: HAL_PIXEL_FORMAT_* (see <system/graphics.h>)
+ const int mFormat;
+ // Gralloc usage mask : GRALLOC_USAGE_* (see <hardware/gralloc.h>)
+ uint32_t mUsage;
+ // Output rotation this stream should undergo
+ const int mRotation;
+ // Color space of image data.
+ android_dataspace_t mDataSpace;
+ // Max simultaneous in-flight buffers for this stream
+ uint32_t mMaxBuffers;
+ // Lock protecting the Stream object for modifications
+ android::Mutex mLock;
+};
+} // namespace default_camera_hal
+
+#endif // DEFAULT_CAMERA_HAL_STREAM_H_
diff --git a/modules/camera/3_4/stream_format.cpp b/modules/camera/3_4/stream_format.cpp
new file mode 100644
index 0000000..43f4cae
--- /dev/null
+++ b/modules/camera/3_4/stream_format.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stream_format.h"
+
+#include <linux/videodev2.h>
+
+#include "common.h"
+#include "stream.h"
+
+namespace v4l2_camera_hal {
+
+StreamFormat::StreamFormat(const default_camera_hal::Stream& stream)
+ // TODO(b/30000211): multiplanar support.
+ : type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
+ v4l2_pixel_format_(
+ StreamFormat::HalToV4L2PixelFormat(stream.getFormat())),
+ width_(stream.getWidth()),
+ height_(stream.getHeight()),
+ bytes_per_line_(0),
+ min_buffer_size_(0) {
+ HAL_LOG_ENTER();
+}
+
+StreamFormat::StreamFormat(const v4l2_format& format)
+ : type_(format.type),
+ // TODO(b/30000211): multiplanar support.
+ v4l2_pixel_format_(format.fmt.pix.pixelformat),
+ width_(format.fmt.pix.width),
+ height_(format.fmt.pix.height),
+ bytes_per_line_(format.fmt.pix.bytesperline),
+ min_buffer_size_(format.fmt.pix.sizeimage) {
+ HAL_LOG_ENTER();
+}
+
+void StreamFormat::FillFormatRequest(v4l2_format* format) const {
+ HAL_LOG_ENTER();
+
+ memset(format, 0, sizeof(*format));
+ format->type = type_;
+ format->fmt.pix.pixelformat = v4l2_pixel_format_;
+ format->fmt.pix.width = width_;
+ format->fmt.pix.height = height_;
+ // Bytes per line and min buffer size are outputs set by the driver,
+ // not part of the request.
+}
+
+FormatCategory StreamFormat::Category() const {
+ switch (v4l2_pixel_format_) {
+ case V4L2_PIX_FMT_JPEG:
+ return kFormatCategoryStalling;
+ case V4L2_PIX_FMT_YUV420:
+ return kFormatCategoryNonStalling;
+ default:
+ // Note: currently no supported RAW formats.
+ return kFormatCategoryUnknown;
+ }
+}
+
+bool StreamFormat::operator==(const StreamFormat& other) const {
+ // Used to check that a requested format was actually set, so
+ // don't compare bytes per line or min buffer size.
+ return (type_ == other.type_ &&
+ v4l2_pixel_format_ == other.v4l2_pixel_format_ &&
+ width_ == other.width_ && height_ == other.height_);
+}
+
+bool StreamFormat::operator!=(const StreamFormat& other) const {
+ return !(*this == other);
+}
+
+int StreamFormat::V4L2ToHalPixelFormat(uint32_t v4l2_pixel_format) {
+ // Translate V4L2 format to HAL format.
+ int hal_pixel_format = -1;
+ switch (v4l2_pixel_format) {
+ case V4L2_PIX_FMT_JPEG:
+ hal_pixel_format = HAL_PIXEL_FORMAT_BLOB;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ hal_pixel_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ break;
+ default:
+ // Unrecognized format.
+ break;
+ }
+ return hal_pixel_format;
+}
+
+uint32_t StreamFormat::HalToV4L2PixelFormat(int hal_pixel_format) {
+ // Translate HAL format to V4L2 format.
+ uint32_t v4l2_pixel_format = 0;
+ switch (hal_pixel_format) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: // fall-through.
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ v4l2_pixel_format = V4L2_PIX_FMT_YUV420;
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ v4l2_pixel_format = V4L2_PIX_FMT_JPEG;
+ break;
+ default:
+ // Unrecognized format.
+ break;
+ }
+ return v4l2_pixel_format;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/stream_format.h b/modules/camera/3_4/stream_format.h
new file mode 100644
index 0000000..9358d3d
--- /dev/null
+++ b/modules/camera/3_4/stream_format.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_STREAM_FORMAT_H_
+#define V4L2_CAMERA_HAL_STREAM_FORMAT_H_
+
+#include <linux/videodev2.h>
+
+#include "common.h"
+#include "stream.h"
+
+namespace v4l2_camera_hal {
+
+enum FormatCategory {
+ kFormatCategoryRaw,
+ kFormatCategoryStalling,
+ kFormatCategoryNonStalling,
+ kFormatCategoryUnknown,
+};
+
+class StreamFormat {
+ public:
+ StreamFormat(const default_camera_hal::Stream& stream);
+ StreamFormat(const v4l2_format& format);
+ virtual ~StreamFormat() = default;
+ // Only uint32_t members, use default generated copy and assign.
+
+ void FillFormatRequest(v4l2_format* format) const;
+ FormatCategory Category() const;
+
+ // Accessors.
+ inline uint32_t type() const { return type_; };
+ inline uint32_t bytes_per_line() const { return bytes_per_line_; };
+
+ bool operator==(const StreamFormat& other) const;
+ bool operator!=(const StreamFormat& other) const;
+
+ // HAL <-> V4L2 conversions
+ // Returns 0 for unrecognized.
+ static uint32_t HalToV4L2PixelFormat(int hal_pixel_format);
+ // Returns -1 for unrecognized.
+ static int V4L2ToHalPixelFormat(uint32_t v4l2_pixel_format);
+
+ private:
+ uint32_t type_;
+ uint32_t v4l2_pixel_format_;
+ uint32_t width_;
+ uint32_t height_;
+ uint32_t bytes_per_line_;
+ uint32_t min_buffer_size_;
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_STREAM_FORMAT_H_
diff --git a/modules/camera/3_4/v4l2_camera.cpp b/modules/camera/3_4/v4l2_camera.cpp
new file mode 100644
index 0000000..521f835
--- /dev/null
+++ b/modules/camera/3_4/v4l2_camera.cpp
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "v4l2_camera.h"
+
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cstdlib>
+
+#include <camera/CameraMetadata.h>
+#include <hardware/camera3.h>
+
+#include "common.h"
+#include "metadata/metadata_common.h"
+#include "stream_format.h"
+#include "v4l2_metadata_factory.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+namespace v4l2_camera_hal {
+
+// Helper function for managing metadata.
+static std::vector<int32_t> getMetadataKeys(const camera_metadata_t* metadata) {
+ std::vector<int32_t> keys;
+ size_t num_entries = get_camera_metadata_entry_count(metadata);
+ for (size_t i = 0; i < num_entries; ++i) {
+ camera_metadata_ro_entry_t entry;
+ get_camera_metadata_ro_entry(metadata, i, &entry);
+ keys.push_back(entry.tag);
+ }
+ return keys;
+}
+
+V4L2Camera* V4L2Camera::NewV4L2Camera(int id, const std::string path) {
+ HAL_LOG_ENTER();
+
+ std::shared_ptr<V4L2Wrapper> v4l2_wrapper(V4L2Wrapper::NewV4L2Wrapper(path));
+ if (!v4l2_wrapper) {
+ HAL_LOGE("Failed to initialize V4L2 wrapper.");
+ return nullptr;
+ }
+
+ std::unique_ptr<Metadata> metadata;
+ int res = GetV4L2Metadata(v4l2_wrapper, &metadata);
+ if (res) {
+ HAL_LOGE("Failed to initialize V4L2 metadata: %d", res);
+ return nullptr;
+ }
+
+ return new V4L2Camera(id, std::move(v4l2_wrapper), std::move(metadata));
+}
+
+V4L2Camera::V4L2Camera(int id,
+ std::shared_ptr<V4L2Wrapper> v4l2_wrapper,
+ std::unique_ptr<Metadata> metadata)
+ : default_camera_hal::Camera(id),
+ device_(std::move(v4l2_wrapper)),
+ metadata_(std::move(metadata)),
+ max_input_streams_(0),
+ max_output_streams_({{0, 0, 0}}) {
+ HAL_LOG_ENTER();
+}
+
+V4L2Camera::~V4L2Camera() {
+ HAL_LOG_ENTER();
+}
+
+int V4L2Camera::connect() {
+ HAL_LOG_ENTER();
+
+ if (connection_) {
+ HAL_LOGE("Already connected. Please disconnect and try again.");
+ return -EIO;
+ }
+
+ connection_.reset(new V4L2Wrapper::Connection(device_));
+ if (connection_->status()) {
+ HAL_LOGE("Failed to connect to device.");
+ return connection_->status();
+ }
+
+ // TODO(b/29185945): confirm this is a supported device.
+ // This is checked by the HAL, but the device at |device_|'s path may
+ // not be the same one that was there when the HAL was loaded.
+ // (Alternatively, better hotplugging support may make this unecessary
+ // by disabling cameras that get disconnected and checking newly connected
+ // cameras, so connect() is never called on an unsupported camera)
+
+ // TODO(b/29158098): Inform service of any flashes that are no longer
+ // available because this camera is in use.
+ return 0;
+}
+
+void V4L2Camera::disconnect() {
+ HAL_LOG_ENTER();
+
+ connection_.reset();
+
+ // TODO(b/29158098): Inform service of any flashes that are available again
+ // because this camera is no longer in use.
+}
+
+int V4L2Camera::initStaticInfo(android::CameraMetadata* out) {
+ HAL_LOG_ENTER();
+
+ int res = metadata_->FillStaticMetadata(out);
+ if (res) {
+ HAL_LOGE("Failed to get static metadata.");
+ return res;
+ }
+
+ // Extract max streams for use in verifying stream configs.
+ res = SingleTagValue(
+ *out, ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &max_input_streams_);
+ if (res) {
+ HAL_LOGE("Failed to get max num input streams from static metadata.");
+ return res;
+ }
+ res = SingleTagValue(
+ *out, ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, &max_output_streams_);
+ if (res) {
+ HAL_LOGE("Failed to get max num output streams from static metadata.");
+ return res;
+ }
+
+ return 0;
+}
+
+int V4L2Camera::initTemplate(int type, android::CameraMetadata* out) {
+ HAL_LOG_ENTER();
+
+ return metadata_->GetRequestTemplate(type, out);
+}
+
+void V4L2Camera::initDeviceInfo(camera_info_t* info) {
+ HAL_LOG_ENTER();
+
+ // TODO(b/31044975): move this into device interface.
+ // For now, just constants.
+ info->resource_cost = 100;
+ info->conflicting_devices = nullptr;
+ info->conflicting_devices_length = 0;
+}
+
+int V4L2Camera::initDevice() {
+ HAL_LOG_ENTER();
+ // Nothing to do.
+ return 0;
+}
+
+int V4L2Camera::enqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
+ HAL_LOG_ENTER();
+
+ int res = device_->EnqueueBuffer(camera_buffer);
+ if (res) {
+ HAL_LOGE("Device failed to enqueue buffer.");
+ return res;
+ }
+
+ // Turn on the stream.
+ // TODO(b/29334616): Lock around stream on/off access, only start stream
+ // if not already on. (For now, since it's synchronous, it will always be
+ // turned off before another call to this function).
+ res = device_->StreamOn();
+ if (res) {
+ HAL_LOGE("Device failed to turn on stream.");
+ return res;
+ }
+
+ // TODO(b/29334616): Enqueueing and dequeueing should be separate worker
+ // threads, not in the same function.
+
+ // Dequeue the buffer.
+ v4l2_buffer result_buffer;
+ res = device_->DequeueBuffer(&result_buffer);
+ if (res) {
+ HAL_LOGE("Device failed to dequeue buffer.");
+ return res;
+ }
+
+ // All done, cleanup.
+ // TODO(b/29334616): Lock around stream on/off access, only stop stream if
+ // buffer queue is empty (synchronously, there's only ever 1 buffer in the
+ // queue at a time, so this is safe).
+ res = device_->StreamOff();
+ if (res) {
+ HAL_LOGE("Device failed to turn off stream.");
+ return res;
+ }
+
+ return 0;
+}
+
+int V4L2Camera::getResultSettings(android::CameraMetadata* metadata,
+ uint64_t* timestamp) {
+ HAL_LOG_ENTER();
+
+ // Get the results.
+ int res = metadata_->FillResultMetadata(metadata);
+ if (res) {
+ HAL_LOGE("Failed to fill result metadata.");
+ return res;
+ }
+
+ // Extract the timestamp.
+ int64_t frame_time = 0;
+ res = SingleTagValue(*metadata, ANDROID_SENSOR_TIMESTAMP, &frame_time);
+ if (res) {
+ HAL_LOGE("Failed to extract timestamp from result metadata");
+ return res;
+ }
+ *timestamp = static_cast<uint64_t>(frame_time);
+
+ return 0;
+}
+
+bool V4L2Camera::isSupportedStreamSet(default_camera_hal::Stream** streams,
+ int count,
+ uint32_t mode) {
+ HAL_LOG_ENTER();
+
+ if (mode != CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE) {
+ HAL_LOGE("Unsupported stream configuration mode: %d", mode);
+ return false;
+ }
+
+ // This should be checked by the caller, but put here as a sanity check.
+ if (count < 1) {
+ HAL_LOGE("Must request at least 1 stream");
+ return false;
+ }
+
+ // Count the number of streams of each type.
+ int32_t num_input = 0;
+ int32_t num_raw = 0;
+ int32_t num_stalling = 0;
+ int32_t num_non_stalling = 0;
+ for (int i = 0; i < count; ++i) {
+ default_camera_hal::Stream* stream = streams[i];
+
+ if (stream->isInputType()) {
+ ++num_input;
+ }
+
+ if (stream->isOutputType()) {
+ StreamFormat format(*stream);
+ switch (format.Category()) {
+ case kFormatCategoryRaw:
+ ++num_raw;
+ case kFormatCategoryStalling:
+ ++num_stalling;
+ break;
+ case kFormatCategoryNonStalling:
+ ++num_non_stalling;
+ break;
+ case kFormatCategoryUnknown: // Fall through.
+ default:
+ HAL_LOGE(
+ "Unsupported format for stream %d: %d", i, stream->getFormat());
+ return false;
+ }
+ }
+ }
+
+ if (num_input > max_input_streams_ || num_raw > max_output_streams_[0] ||
+ num_non_stalling > max_output_streams_[1] ||
+ num_stalling > max_output_streams_[2]) {
+ HAL_LOGE(
+ "Invalid stream configuration: %d input, %d RAW, %d non-stalling, "
+ "%d stalling (max supported: %d input, %d RAW, %d non-stalling, "
+ "%d stalling)",
+ max_input_streams_,
+ max_output_streams_[0],
+ max_output_streams_[1],
+ max_output_streams_[2],
+ num_input,
+ num_raw,
+ num_non_stalling,
+ num_stalling);
+ return false;
+ }
+
+ // TODO(b/29939583): The above logic should be all that's necessary,
+ // but V4L2 doesn't actually support more than 1 stream at a time. So for now,
+ // if not all streams are the same format and size, error. Note that this
+ // means the HAL is not spec-compliant; the requested streams are technically
+ // valid and it is not technically allowed to error once it has reached this
+ // point.
+ int format = streams[0]->getFormat();
+ uint32_t width = streams[0]->getWidth();
+ uint32_t height = streams[0]->getHeight();
+ for (int i = 1; i < count; ++i) {
+ const default_camera_hal::Stream* stream = streams[i];
+ if (stream->getFormat() != format || stream->getWidth() != width ||
+ stream->getHeight() != height) {
+ HAL_LOGE(
+ "V4L2 only supports 1 stream configuration at a time "
+ "(stream 0 is format %d, width %u, height %u, "
+ "stream %d is format %d, width %u, height %u).",
+ format,
+ width,
+ height,
+ i,
+ stream->getFormat(),
+ stream->getWidth(),
+ stream->getHeight());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int V4L2Camera::setupStream(default_camera_hal::Stream* stream,
+ uint32_t* max_buffers) {
+ HAL_LOG_ENTER();
+
+ if (stream->getRotation() != CAMERA3_STREAM_ROTATION_0) {
+ HAL_LOGE("Rotation %d not supported", stream->getRotation());
+ return -EINVAL;
+ }
+
+ // Doesn't matter what was requested, we always use dataspace V0_JFIF.
+ // Note: according to camera3.h, this isn't allowed, but etalvala@google.com
+ // claims it's underdocumented; the implementation lets the HAL overwrite it.
+ stream->setDataSpace(HAL_DATASPACE_V0_JFIF);
+
+ int res = device_->SetFormat(*stream, max_buffers);
+ if (res) {
+ HAL_LOGE("Failed to set device to correct format for stream.");
+ return res;
+ }
+ // Sanity check.
+ if (*max_buffers < 1) {
+ HAL_LOGE("Setting format resulted in an invalid maximum of %u buffers.",
+ *max_buffers);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+bool V4L2Camera::isValidCaptureSettings(
+ const android::CameraMetadata& settings) {
+ HAL_LOG_ENTER();
+
+ return metadata_->IsValidRequest(settings);
+}
+
+int V4L2Camera::setSettings(const android::CameraMetadata& new_settings) {
+ HAL_LOG_ENTER();
+
+ return metadata_->SetRequestSettings(new_settings);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_camera.h b/modules/camera/3_4/v4l2_camera.h
new file mode 100644
index 0000000..804012b
--- /dev/null
+++ b/modules/camera/3_4/v4l2_camera.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Loosely based on hardware/libhardware/modules/camera/ExampleCamera.h
+
+#ifndef V4L2_CAMERA_HAL_V4L2_CAMERA_H_
+#define V4L2_CAMERA_HAL_V4L2_CAMERA_H_
+
+#include <array>
+#include <string>
+
+#include <camera/CameraMetadata.h>
+
+#include "camera.h"
+#include "common.h"
+#include "metadata/metadata.h"
+#include "v4l2_wrapper.h"
+
+namespace v4l2_camera_hal {
+// V4L2Camera is a specific V4L2-supported camera device. The Camera object
+// contains all logic common between all cameras (e.g. front and back cameras),
+// while a specific camera device (e.g. V4L2Camera) holds all specific
+// metadata and logic about that device.
+class V4L2Camera : public default_camera_hal::Camera {
+ public:
+ // Use this method to create V4L2Camera objects. Functionally equivalent
+ // to "new V4L2Camera", except that it may return nullptr in case of failure.
+ static V4L2Camera* NewV4L2Camera(int id, const std::string path);
+ ~V4L2Camera();
+
+ private:
+ // Constructor private to allow failing on bad input.
+ // Use NewV4L2Camera instead.
+ V4L2Camera(int id,
+ std::shared_ptr<V4L2Wrapper> v4l2_wrapper,
+ std::unique_ptr<Metadata> metadata);
+
+ // default_camera_hal::Camera virtual methods.
+ // Connect to the device: open dev nodes, etc.
+ int connect() override;
+ // Disconnect from the device: close dev nodes, etc.
+ void disconnect() override;
+ // Initialize static camera characteristics for individual device.
+ int initStaticInfo(android::CameraMetadata* out) override;
+ // Initialize a template of the given type.
+ int initTemplate(int type, android::CameraMetadata* out) override;
+ // Initialize device info: resource cost and conflicting devices
+ // (/conflicting devices length).
+ void initDeviceInfo(camera_info_t* info) override;
+ // Extra initialization of device when opened.
+ int initDevice() override;
+ // Verify stream configuration is device-compatible.
+ bool isSupportedStreamSet(default_camera_hal::Stream** streams,
+ int count,
+ uint32_t mode) override;
+ // Set up the device for a stream, and get the maximum number of
+ // buffers that stream can handle (max_buffers is an output parameter).
+ int setupStream(default_camera_hal::Stream* stream,
+ uint32_t* max_buffers) override;
+ // Verify settings are valid for a capture with this device.
+ bool isValidCaptureSettings(const android::CameraMetadata& settings) override;
+ // Set settings for a capture.
+ int setSettings(const android::CameraMetadata& new_settings) override;
+ // Enqueue a buffer to receive data from the camera.
+ int enqueueBuffer(const camera3_stream_buffer_t* camera_buffer) override;
+ // Get the shutter time and updated settings for the most recent frame.
+ // The metadata parameter is both an input and output; frame-specific
+ // result fields should be appended to what is passed in.
+ int getResultSettings(android::CameraMetadata* metadata, uint64_t* timestamp);
+
+ // V4L2 helper.
+ std::shared_ptr<V4L2Wrapper> device_;
+ std::unique_ptr<V4L2Wrapper::Connection> connection_;
+ std::unique_ptr<Metadata> metadata_;
+
+ int32_t max_input_streams_;
+ std::array<int, 3> max_output_streams_; // {raw, non-stalling, stalling}.
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2Camera);
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_CAMERA_H
diff --git a/modules/camera/3_4/v4l2_camera_hal.cpp b/modules/camera/3_4/v4l2_camera_hal.cpp
new file mode 100644
index 0000000..bfc8712
--- /dev/null
+++ b/modules/camera/3_4/v4l2_camera_hal.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/CameraHAL.cpp
+
+#include "v4l2_camera_hal.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <unordered_set>
+
+#include <android-base/parseint.h>
+
+#include "common.h"
+#include "v4l2_camera.h"
+
+/*
+ * This file serves as the entry point to the HAL. It is modified from the
+ * example default HAL available in hardware/libhardware/modules/camera.
+ * It contains the module structure and functions used by the framework
+ * to load and interface to this HAL, as well as the handles to the individual
+ * camera devices.
+ */
+
+namespace v4l2_camera_hal {
+
+// Default global camera hal.
+static V4L2CameraHAL gCameraHAL;
+
+V4L2CameraHAL::V4L2CameraHAL() : mCameras(), mCallbacks(NULL) {
+ HAL_LOG_ENTER();
+ // Adds all available V4L2 devices.
+ // List /dev nodes.
+ DIR* dir = opendir("/dev");
+ if (dir == NULL) {
+ HAL_LOGE("Failed to open /dev");
+ return;
+ }
+ // Find /dev/video* nodes.
+ dirent* ent;
+ std::vector<std::string> nodes;
+ while ((ent = readdir(dir))) {
+ std::string desired = "video";
+ size_t len = desired.size();
+ if (strncmp(desired.c_str(), ent->d_name, len) == 0) {
+ if (strlen(ent->d_name) > len && isdigit(ent->d_name[len])) {
+ // ent is a numbered video node.
+ nodes.push_back(std::string("/dev/") + ent->d_name);
+ HAL_LOGV("Found video node %s.", nodes.back().c_str());
+ }
+ }
+ }
+ // Test each for V4L2 support and uniqueness.
+ std::unordered_set<std::string> buses;
+ std::string bus;
+ v4l2_capability cap;
+ int fd;
+ int id = 0;
+ for (const auto& node : nodes) {
+ // Open the node.
+ fd = TEMP_FAILURE_RETRY(open(node.c_str(), O_RDWR));
+ if (fd < 0) {
+ HAL_LOGE("failed to open %s (%s).", node.c_str(), strerror(errno));
+ continue;
+ }
+ // Read V4L2 capabilities.
+ if (TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_QUERYCAP, &cap)) != 0) {
+ HAL_LOGE(
+ "VIDIOC_QUERYCAP on %s fail: %s.", node.c_str(), strerror(errno));
+ } else if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+ HAL_LOGE("%s is not a V4L2 video capture device.", node.c_str());
+ } else {
+ // If the node is unique, add a camera for it.
+ bus = reinterpret_cast<char*>(cap.bus_info);
+ if (buses.insert(bus).second) {
+ HAL_LOGV("Found unique bus at %s.", node.c_str());
+ std::unique_ptr<V4L2Camera> cam(V4L2Camera::NewV4L2Camera(id++, node));
+ if (cam) {
+ mCameras.push_back(std::move(cam));
+ } else {
+ HAL_LOGE("Failed to initialize camera at %s.", node.c_str());
+ }
+ }
+ }
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+}
+
+V4L2CameraHAL::~V4L2CameraHAL() {
+ HAL_LOG_ENTER();
+}
+
+int V4L2CameraHAL::getNumberOfCameras() {
+ HAL_LOGV("returns %d", mCameras.size());
+ return mCameras.size();
+}
+
+int V4L2CameraHAL::getCameraInfo(int id, camera_info_t* info) {
+ HAL_LOG_ENTER();
+ if (id < 0 || id >= mCameras.size()) {
+ return -EINVAL;
+ }
+ // TODO(b/29185945): Hotplugging: return -EINVAL if unplugged.
+ return mCameras[id]->getInfo(info);
+}
+
+int V4L2CameraHAL::setCallbacks(const camera_module_callbacks_t* callbacks) {
+ HAL_LOG_ENTER();
+ mCallbacks = callbacks;
+ return 0;
+}
+
+void V4L2CameraHAL::getVendorTagOps(vendor_tag_ops_t* ops) {
+ HAL_LOG_ENTER();
+ // No vendor ops for this HAL. From <hardware/camera_common.h>:
+ // "leave ops unchanged if no vendor tags are defined."
+}
+
+int V4L2CameraHAL::openLegacy(const hw_module_t* module,
+ const char* id,
+ uint32_t halVersion,
+ hw_device_t** device) {
+ HAL_LOG_ENTER();
+ // Not supported.
+ return -ENOSYS;
+}
+
+int V4L2CameraHAL::setTorchMode(const char* camera_id, bool enabled) {
+ HAL_LOG_ENTER();
+ // TODO(b/29158098): HAL is required to respond appropriately if
+ // the desired camera actually does support flash.
+ return -ENOSYS;
+}
+
+int V4L2CameraHAL::openDevice(const hw_module_t* module,
+ const char* name,
+ hw_device_t** device) {
+ HAL_LOG_ENTER();
+
+ if (module != &HAL_MODULE_INFO_SYM.common) {
+ HAL_LOGE(
+ "Invalid module %p expected %p", module, &HAL_MODULE_INFO_SYM.common);
+ return -EINVAL;
+ }
+
+ int id;
+ if (!android::base::ParseInt(name, &id, 0, getNumberOfCameras() - 1)) {
+ return -EINVAL;
+ }
+ // TODO(b/29185945): Hotplugging: return -EINVAL if unplugged.
+ return mCameras[id]->openDevice(module, device);
+}
+
+/*
+ * The framework calls the following wrappers, which in turn
+ * call the corresponding methods of the global HAL object.
+ */
+
+static int get_number_of_cameras() {
+ return gCameraHAL.getNumberOfCameras();
+}
+
+static int get_camera_info(int id, struct camera_info* info) {
+ return gCameraHAL.getCameraInfo(id, info);
+}
+
+static int set_callbacks(const camera_module_callbacks_t* callbacks) {
+ return gCameraHAL.setCallbacks(callbacks);
+}
+
+static void get_vendor_tag_ops(vendor_tag_ops_t* ops) {
+ return gCameraHAL.getVendorTagOps(ops);
+}
+
+static int open_legacy(const hw_module_t* module,
+ const char* id,
+ uint32_t halVersion,
+ hw_device_t** device) {
+ return gCameraHAL.openLegacy(module, id, halVersion, device);
+}
+
+static int set_torch_mode(const char* camera_id, bool enabled) {
+ return gCameraHAL.setTorchMode(camera_id, enabled);
+}
+
+static int open_dev(const hw_module_t* module,
+ const char* name,
+ hw_device_t** device) {
+ return gCameraHAL.openDevice(module, name, device);
+}
+
+} // namespace v4l2_camera_hal
+
+static hw_module_methods_t v4l2_module_methods = {
+ .open = v4l2_camera_hal::open_dev};
+
+camera_module_t HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = CAMERA_HARDWARE_MODULE_ID,
+ .name = "V4L2 Camera HAL v3",
+ .author = "The Android Open Source Project",
+ .methods = &v4l2_module_methods,
+ .dso = nullptr,
+ .reserved = {0},
+ },
+ .get_number_of_cameras = v4l2_camera_hal::get_number_of_cameras,
+ .get_camera_info = v4l2_camera_hal::get_camera_info,
+ .set_callbacks = v4l2_camera_hal::set_callbacks,
+ .get_vendor_tag_ops = v4l2_camera_hal::get_vendor_tag_ops,
+ .open_legacy = v4l2_camera_hal::open_legacy,
+ .set_torch_mode = v4l2_camera_hal::set_torch_mode,
+ .init = nullptr,
+ .reserved = {nullptr, nullptr, nullptr, nullptr, nullptr}};
diff --git a/modules/camera/3_4/v4l2_camera_hal.h b/modules/camera/3_4/v4l2_camera_hal.h
new file mode 100644
index 0000000..1b4ef0f
--- /dev/null
+++ b/modules/camera/3_4/v4l2_camera_hal.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified from hardware/libhardware/modules/camera/CameraHAL.h
+
+#ifndef V4L2_CAMERA_HAL_V4L2_CAMERA_HAL_H_
+#define V4L2_CAMERA_HAL_V4L2_CAMERA_HAL_H_
+
+#include <vector>
+
+#include <hardware/camera_common.h>
+#include <hardware/hardware.h>
+
+#include "camera.h"
+#include "common.h"
+
+namespace v4l2_camera_hal {
+/*
+ * V4L2CameraHAL contains all module state that isn't specific to an
+ * individual camera device. This class is based off of the sample
+ * default CameraHAL from /hardware/libhardware/modules/camera.
+ */
+class V4L2CameraHAL {
+ public:
+ V4L2CameraHAL();
+ ~V4L2CameraHAL();
+
+ // Camera Module Interface (see <hardware/camera_common.h>).
+ int getNumberOfCameras();
+ int getCameraInfo(int camera_id, camera_info_t* info);
+ int setCallbacks(const camera_module_callbacks_t* callbacks);
+ void getVendorTagOps(vendor_tag_ops_t* ops);
+ int openLegacy(const hw_module_t* module,
+ const char* id,
+ uint32_t halVersion,
+ hw_device_t** device);
+ int setTorchMode(const char* camera_id, bool enabled);
+
+ // Hardware Module Interface (see <hardware/hardware.h>).
+ int openDevice(const hw_module_t* mod, const char* name, hw_device_t** dev);
+
+ private:
+ // Vector of cameras.
+ std::vector<std::unique_ptr<default_camera_hal::Camera>> mCameras;
+ // Callback handle.
+ const camera_module_callbacks_t* mCallbacks;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2CameraHAL);
+};
+
+} // namespace v4l2_camera_hal
+
+extern camera_module_t HAL_MODULE_INFO_SYM;
+
+#endif // V4L2_CAMERA_HAL_V4L2_CAMERA_HAL_H_
diff --git a/modules/camera/3_4/v4l2_gralloc.cpp b/modules/camera/3_4/v4l2_gralloc.cpp
new file mode 100644
index 0000000..5812649
--- /dev/null
+++ b/modules/camera/3_4/v4l2_gralloc.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "v4l2_gralloc.h"
+
+#include <linux/videodev2.h>
+
+#include <cstdlib>
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+#include "common.h"
+
+namespace v4l2_camera_hal {
+
+// Copy |height| lines from |src| to |dest|,
+// where |src| and |dest| may have different line lengths.
+void copyWithPadding(uint8_t* dest, const uint8_t* src, size_t dest_stride,
+ size_t src_stride, size_t height) {
+ size_t copy_stride = dest_stride;
+ if (copy_stride > src_stride) {
+ // Adding padding, not reducing. 0 out the extra memory.
+ memset(dest, 0, src_stride * height);
+ copy_stride = src_stride;
+ }
+ uint8_t* dest_line_start = dest;
+ const uint8_t* src_line_start = src;
+ for (size_t row = 0; row < height; ++row,
+ dest_line_start += dest_stride, src_line_start += src_stride) {
+ memcpy(dest_line_start, src_line_start, copy_stride);
+ }
+}
+
+V4L2Gralloc* V4L2Gralloc::NewV4L2Gralloc() {
+ HAL_LOG_ENTER();
+
+ // Initialize and check the gralloc module.
+ const hw_module_t* module = nullptr;
+ int res = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (res || !module) {
+ HAL_LOGE("Couldn't get gralloc module.");
+ return nullptr;
+ }
+ const gralloc_module_t* gralloc =
+ reinterpret_cast<const gralloc_module_t*>(module);
+
+ // This class only supports Gralloc v0, not Gralloc V1.
+ if (gralloc->common.module_api_version > GRALLOC_MODULE_API_VERSION_0_3) {
+ HAL_LOGE("Invalid gralloc version %x. Only 0.3 (%x) "
+ "and below are supported by this HAL.",
+ gralloc->common.module_api_version,
+ GRALLOC_MODULE_API_VERSION_0_3);
+ return nullptr;
+ }
+
+ return new V4L2Gralloc(gralloc);
+}
+
+// Private. As checked by above factory, module will be non-null
+// and a supported version.
+V4L2Gralloc::V4L2Gralloc(const gralloc_module_t* module)
+ : mModule(module) {
+ HAL_LOG_ENTER();
+}
+
+V4L2Gralloc::~V4L2Gralloc() {
+ HAL_LOG_ENTER();
+
+ // Unlock buffers that are still locked.
+ unlockAllBuffers();
+}
+
+int V4L2Gralloc::lock(const camera3_stream_buffer_t* camera_buffer,
+ uint32_t bytes_per_line,
+ v4l2_buffer* device_buffer) {
+ HAL_LOG_ENTER();
+
+ // Lock the camera buffer (varies depending on if the buffer is YUV or not).
+ std::unique_ptr<BufferData> buffer_data(new BufferData {
+ camera_buffer, nullptr, bytes_per_line});
+ buffer_handle_t buffer = *camera_buffer->buffer;
+ void* data;
+ camera3_stream_t* stream = camera_buffer->stream;
+ switch(stream->format) {
+ // TODO(b/30119452): support more YCbCr formats.
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ android_ycbcr yuv_data;
+ mModule->lock_ycbcr(mModule, buffer, stream->usage, 0, 0,
+ stream->width, stream->height, &yuv_data);
+
+ // Check if gralloc format matches v4l2 format
+ // (same padding, not interleaved, contiguous).
+ if (yuv_data.ystride == bytes_per_line &&
+ yuv_data.cstride == bytes_per_line / 2 &&
+ yuv_data.chroma_step == 1 &&
+ (reinterpret_cast<uint8_t*>(yuv_data.cb) ==
+ reinterpret_cast<uint8_t*>(yuv_data.y) +
+ (stream->height * yuv_data.ystride)) &&
+ (reinterpret_cast<uint8_t*>(yuv_data.cr) ==
+ reinterpret_cast<uint8_t*>(yuv_data.cb) +
+ (stream->height / 2 * yuv_data.cstride))) {
+ // If so, great, point to the beginning.
+ HAL_LOGV("V4L2 YUV matches gralloc YUV.");
+ data = yuv_data.y;
+ } else {
+ // If not, allocate a contiguous buffer of appropriate size
+ // (to be transformed back upon unlock).
+ HAL_LOGV("Need to transform V4L2 YUV to gralloc YUV.");
+ data = new uint8_t[device_buffer->length];
+ // Make a dynamically-allocated copy of yuv_data,
+ // since it will be needed at transform time.
+ buffer_data->transform_dest.reset(new android_ycbcr(yuv_data));
+ }
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ // Jpeg buffers are just contiguous blobs; lock length * 1.
+ mModule->lock(mModule, buffer, stream->usage, 0, 0, device_buffer->length, 1, &data);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ // Set up the device buffer.
+ static_assert(sizeof(unsigned long) >= sizeof(void*),
+ "void* must be able to fit in the v4l2_buffer m.userptr "
+ "field (unsigned long) for this code to work");
+ device_buffer->m.userptr = reinterpret_cast<unsigned long>(data);
+
+ // Note the mapping of data:buffer info for when unlock is called.
+ mBufferMap.emplace(data, buffer_data.release());
+
+ return 0;
+}
+
+int V4L2Gralloc::unlock(const v4l2_buffer* device_buffer) {
+ HAL_LOG_ENTER();
+
+ // TODO(b/30000211): support multi-planar data (video_capture_mplane).
+ if (device_buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+
+ void* data = reinterpret_cast<void*>(device_buffer->m.userptr);
+
+ // Find and pop the matching entry in the map.
+ auto map_entry = mBufferMap.find(data);
+ if (map_entry == mBufferMap.end()) {
+ HAL_LOGE("No matching buffer for data at %p", data);
+ return -EINVAL;
+ }
+ std::unique_ptr<const BufferData> buffer_data(map_entry->second);
+ mBufferMap.erase(map_entry);
+
+ const camera3_stream_buffer_t* camera_buffer = buffer_data->camera_buffer;
+ const buffer_handle_t buffer = *camera_buffer->buffer;
+
+ // Check for transform.
+ if (buffer_data->transform_dest) {
+ HAL_LOGV("Transforming V4L2 YUV to gralloc YUV.");
+ // In this case data was allocated by this class, put it in a unique_ptr
+ // to ensure it gets cleaned up no matter which way this function exits.
+ std::unique_ptr<uint8_t[]> data_cleanup(reinterpret_cast<uint8_t*>(data));
+
+ uint32_t bytes_per_line = buffer_data->v4l2_bytes_per_line;
+ android_ycbcr* yuv_data = buffer_data->transform_dest.get();
+
+ // Should only occur in error situations.
+ if (device_buffer->bytesused == 0) {
+ return -EINVAL;
+ }
+
+ // Transform V4L2 to Gralloc, copying each plane to the correct place,
+ // adjusting padding, and interleaving if necessary.
+ uint32_t height = camera_buffer->stream->height;
+ // Y data first.
+ size_t y_len = bytes_per_line * height;
+ if (yuv_data->ystride == bytes_per_line) {
+ // Data should match exactly.
+ memcpy(yuv_data->y, data, y_len);
+ } else {
+ HAL_LOGV("Changing padding on Y plane from %u to %u.",
+ bytes_per_line, yuv_data->ystride);
+ // Wrong padding from V4L2.
+ copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->y),
+ reinterpret_cast<uint8_t*>(data),
+ yuv_data->ystride, bytes_per_line, height);
+ }
+ // C data.
+ // TODO(b/30119452): These calculations assume YCbCr_420_888.
+ size_t c_len = y_len / 4;
+ uint32_t c_bytes_per_line = bytes_per_line / 2;
+ // V4L2 is packed, meaning the data is stored as contiguous {y, cb, cr}.
+ uint8_t* cb_device = reinterpret_cast<uint8_t*>(data) + y_len;
+ uint8_t* cr_device = cb_device + c_len;
+ size_t step = yuv_data->chroma_step;
+ if (step == 1) {
+ // Still planar.
+ if (yuv_data->cstride == c_bytes_per_line) {
+ // Data should match exactly.
+ memcpy(yuv_data->cb, cb_device, c_len);
+ memcpy(yuv_data->cr, cr_device, c_len);
+ } else {
+ HAL_LOGV("Changing padding on C plane from %u to %u.",
+ c_bytes_per_line, yuv_data->cstride);
+ // Wrong padding from V4L2.
+ copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->cb),
+ cb_device, yuv_data->cstride,
+ c_bytes_per_line, height / 2);
+ copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->cr),
+ cr_device, yuv_data->cstride,
+ c_bytes_per_line, height / 2);
+ }
+ } else {
+ // Desire semiplanar (cb and cr interleaved).
+ HAL_LOGV("Interleaving cb and cr. Padding going from %u to %u.",
+ c_bytes_per_line, yuv_data->cstride);
+ uint32_t c_height = height / 2;
+ uint32_t c_width = camera_buffer->stream->width / 2;
+ // Zero out destination
+ uint8_t* cb_gralloc = reinterpret_cast<uint8_t*>(yuv_data->cb);
+ uint8_t* cr_gralloc = reinterpret_cast<uint8_t*>(yuv_data->cr);
+ memset(cb_gralloc, 0, c_width * c_height * step);
+
+ // Interleaving means we need to copy the cb and cr bytes one by one.
+ for (size_t line = 0; line < c_height; ++line,
+ cb_gralloc += yuv_data->cstride, cr_gralloc += yuv_data->cstride,
+ cb_device += c_bytes_per_line, cr_device += c_bytes_per_line) {
+ for (size_t i = 0; i < c_width; ++i) {
+ *(cb_gralloc + (i * step)) = *(cb_device + i);
+ *(cr_gralloc + (i * step)) = *(cr_device + i);
+ }
+ }
+ }
+ }
+
+ // Unlock.
+ int res = mModule->unlock(mModule, buffer);
+ if (res) {
+ HAL_LOGE("Failed to unlock buffer at %p", buffer);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int V4L2Gralloc::unlockAllBuffers() {
+ HAL_LOG_ENTER();
+
+ bool failed = false;
+ for (auto const& entry : mBufferMap) {
+ int res = mModule->unlock(mModule, *entry.second->camera_buffer->buffer);
+ if (res) {
+ failed = true;
+ }
+ // When there is a transform to be made, the buffer returned by lock()
+ // is dynamically allocated (to hold the pre-transform data).
+ if (entry.second->transform_dest) {
+ delete [] reinterpret_cast<uint8_t*>(entry.first);
+ }
+ // The BufferData entry is always dynamically allocated in lock().
+ delete entry.second;
+ }
+
+ // If any unlock failed, return error.
+ if (failed) {
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+} // namespace default_camera_hal
diff --git a/modules/camera/3_4/v4l2_gralloc.h b/modules/camera/3_4/v4l2_gralloc.h
new file mode 100644
index 0000000..7ece59d
--- /dev/null
+++ b/modules/camera/3_4/v4l2_gralloc.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_V4L2_GRALLOC_H_
+#define V4L2_CAMERA_HAL_V4L2_GRALLOC_H_
+
+#include <linux/videodev2.h>
+
+#include <unordered_map>
+
+#include <hardware/camera3.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+namespace v4l2_camera_hal {
+
+// Generously allow up to 6MB (the largest JPEG on the RPi camera is about 5MB).
+static constexpr size_t V4L2_MAX_JPEG_SIZE = 6000000;
+
+// V4L2Gralloc is a wrapper around relevant parts of a gralloc module,
+// with some assistive transformations.
+class V4L2Gralloc {
+public:
+ // Use this method to create V4L2Gralloc objects. Functionally equivalent
+ // to "new V4L2Gralloc", except that it may return nullptr in case of failure.
+ static V4L2Gralloc* NewV4L2Gralloc();
+ virtual ~V4L2Gralloc();
+
+ // Lock a camera buffer. Uses device buffer length, sets user pointer.
+ int lock(const camera3_stream_buffer_t* camera_buffer,
+ uint32_t bytes_per_line,
+ v4l2_buffer* device_buffer);
+ // Unlock a buffer that was locked by this helper (equality determined
+ // based on buffer user pointer, not the specific object).
+ int unlock(const v4l2_buffer* device_buffer);
+ // Release all held locks.
+ int unlockAllBuffers();
+
+private:
+ // Constructor is private to allow failing on bad input.
+ // Use NewV4L2Gralloc instead.
+ V4L2Gralloc(const gralloc_module_t* module);
+
+ const gralloc_module_t* mModule;
+
+ struct BufferData {
+ const camera3_stream_buffer_t* camera_buffer;
+ // Below fields only used when a ycbcr format transform is necessary.
+ std::unique_ptr<android_ycbcr> transform_dest; // nullptr if no transform.
+ uint32_t v4l2_bytes_per_line;
+ };
+ // Map data pointer : BufferData about that buffer.
+ std::unordered_map<void*, const BufferData*> mBufferMap;
+};
+
+} // namespace default_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_GRALLOC_H_
diff --git a/modules/camera/3_4/v4l2_metadata_factory.cpp b/modules/camera/3_4/v4l2_metadata_factory.cpp
new file mode 100644
index 0000000..b9c64be
--- /dev/null
+++ b/modules/camera/3_4/v4l2_metadata_factory.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "v4l2_metadata_factory.h"
+
+#include <camera/CameraMetadata.h>
+
+#include "common.h"
+#include "format_metadata_factory.h"
+#include "metadata/control.h"
+#include "metadata/enum_converter.h"
+#include "metadata/metadata_common.h"
+#include "metadata/partial_metadata_factory.h"
+#include "metadata/property.h"
+#include "metadata/scaling_converter.h"
+#include "v4l2_gralloc.h"
+
+namespace v4l2_camera_hal {
+
+// According to spec, each unit of V4L2_CID_AUTO_EXPOSURE_BIAS is 0.001 EV.
+const camera_metadata_rational_t kAeCompensationUnit = {1, 1000};
+// According to spec, each unit of V4L2_CID_EXPOSURE_ABSOLUTE is 100 us.
+const int64_t kV4L2ExposureTimeStepNs = 100000;
+// According to spec, each unit of V4L2_CID_ISO_SENSITIVITY is ISO/1000.
+const int32_t kV4L2SensitivityDenominator = 1000;
+
+int GetV4L2Metadata(std::shared_ptr<V4L2Wrapper> device,
+ std::unique_ptr<Metadata>* result) {
+ HAL_LOG_ENTER();
+
+ // Open a temporary connection to the device for all the V4L2 querying
+ // that will be happening (this could be done for each component individually,
+ // but doing it here prevents connecting and disconnecting for each one).
+ V4L2Wrapper::Connection temp_connection = V4L2Wrapper::Connection(device);
+ if (temp_connection.status()) {
+ HAL_LOGE("Failed to connect to device: %d.", temp_connection.status());
+ return temp_connection.status();
+ }
+
+ // TODO(b/30035628): Add states.
+
+ PartialMetadataSet components;
+
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+ {ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY}));
+
+ // TODO(b/30510395): subcomponents of 3A.
+ // In general, default to ON/AUTO since they imply pretty much nothing,
+ // while OFF implies guarantees about not hindering performance.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::array<int32_t, 3>>(ANDROID_CONTROL_MAX_REGIONS,
+ {{/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0}})));
+ // TODO(b/30921166): V4L2_CID_AUTO_EXPOSURE_BIAS is an int menu, so
+ // this will be falling back to NoEffect until int menu support is added.
+ components.insert(V4L2ControlOrDefault<int32_t>(
+ ControlType::kSlider,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+ device,
+ V4L2_CID_AUTO_EXPOSURE_BIAS,
+ // No scaling necessary, AE_COMPENSATION_STEP handles this.
+ std::make_shared<ScalingConverter<int32_t, int32_t>>(1, 1),
+ 0));
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<camera_metadata_rational_t>(
+ ANDROID_CONTROL_AE_COMPENSATION_STEP, kAeCompensationUnit)));
+ // TODO(b/31021522): Autofocus subcomponent, AFTrigger.
+ components.insert(
+ NoEffectMenuControl<uint8_t>(ANDROID_CONTROL_AF_MODE,
+ ANDROID_CONTROL_AF_AVAILABLE_MODES,
+ {ANDROID_CONTROL_AF_MODE_OFF}));
+ // TODO(b/31021522): Should read autofocus state from
+ // V4L2_CID_AUTO_FOCUS_STATUS bitmask. The framework gets a little more
+ // complex than that does; there's a whole state-machine table in
+ // the docs (system/media/camera/docs/docs.html).
+ components.insert(FixedState<uint8_t>(ANDROID_CONTROL_AF_STATE,
+ ANDROID_CONTROL_AF_STATE_INACTIVE));
+ // TODO(b/31022735): AE & AF triggers.
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_AVAILABLE_MODES,
+ device,
+ V4L2_CID_EXPOSURE_AUTO,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE_ON},
+ {V4L2_EXPOSURE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF}})),
+ ANDROID_CONTROL_AE_MODE_ON));
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+ device,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
+ new EnumConverter({{V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF},
+ {V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ},
+ {V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ},
+ {V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}})),
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO));
+ std::unique_ptr<PartialMetadataInterface> exposure_time =
+ V4L2Control<int64_t>(ControlType::kSlider,
+ ANDROID_SENSOR_EXPOSURE_TIME,
+ ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
+ device,
+ V4L2_CID_EXPOSURE_ABSOLUTE,
+ std::make_shared<ScalingConverter<int64_t, int32_t>>(
+ kV4L2ExposureTimeStepNs, 1));
+ // TODO(b/31037072): Sensitivity has additional V4L2 controls
+ // (V4L2_CID_ISO_SENSITIVITY_AUTO), so this control currently has
+ // undefined behavior.
+ // TODO(b/30921166): V4L2_CID_ISO_SENSITIVITY is an int menu, so
+ // this will return nullptr until that is added.
+ std::unique_ptr<PartialMetadataInterface> sensitivity =
+ V4L2Control<int32_t>(ControlType::kSlider,
+ ANDROID_SENSOR_SENSITIVITY,
+ ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
+ device,
+ V4L2_CID_ISO_SENSITIVITY,
+ std::make_shared<ScalingConverter<int32_t, int32_t>>(
+ 1, kV4L2SensitivityDenominator));
+ if (exposure_time && sensitivity) {
+ // TODO(b/30510395): as part of coordinated 3A component,
+ // if these aren't available don't advertise AE mode OFF, only AUTO.
+ components.insert(std::move(exposure_time));
+ components.insert(std::move(sensitivity));
+ }
+ // Can't get AE status from V4L2.
+ // TODO(b/30510395): If AE mode is OFF, this should switch to INACTIVE.
+ components.insert(FixedState<uint8_t>(ANDROID_CONTROL_AE_STATE,
+ ANDROID_CONTROL_AE_STATE_CONVERGED));
+ // V4L2 offers multiple white balance interfaces. Try the advanced one before
+ // falling
+ // back to the simpler version.
+ // Modes from each API that don't match up:
+ // Android: WARM_FLUORESCENT, TWILIGHT.
+ // V4L2: FLUORESCENT_H, HORIZON, FLASH.
+ std::unique_ptr<PartialMetadataInterface> awb(V4L2Control<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+ device,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_WHITE_BALANCE_MANUAL, ANDROID_CONTROL_AWB_MODE_OFF},
+ {V4L2_WHITE_BALANCE_AUTO, ANDROID_CONTROL_AWB_MODE_AUTO},
+ {V4L2_WHITE_BALANCE_INCANDESCENT,
+ ANDROID_CONTROL_AWB_MODE_INCANDESCENT},
+ {V4L2_WHITE_BALANCE_FLUORESCENT,
+ ANDROID_CONTROL_AWB_MODE_FLUORESCENT},
+ {V4L2_WHITE_BALANCE_DAYLIGHT, ANDROID_CONTROL_AWB_MODE_DAYLIGHT},
+ {V4L2_WHITE_BALANCE_CLOUDY,
+ ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT},
+ {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}}))));
+ if (awb) {
+ components.insert(std::move(awb));
+ } else {
+ // Fall back to simpler AWB or even just an ignored control.
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+ device,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
+ new EnumConverter({{0, ANDROID_CONTROL_AWB_MODE_OFF},
+ {1, ANDROID_CONTROL_AWB_MODE_AUTO}})),
+ ANDROID_CONTROL_AWB_MODE_AUTO));
+ }
+ // TODO(b/31041577): Handle AWB state machine correctly.
+ components.insert(FixedState<uint8_t>(ANDROID_CONTROL_AWB_STATE,
+ ANDROID_CONTROL_AWB_STATE_CONVERGED));
+ // TODO(b/31022153): 3A locks.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE)));
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE)));
+ // TODO(b/30510395): subcomponents of scene modes
+ // (may itself be a subcomponent of 3A).
+ // Modes from each API that don't match up:
+ // Android: FACE_PRIORITY, ACTION, NIGHT_PORTRAIT, THEATRE, STEADYPHOTO,
+ // BARCODE, HIGH_SPEED_VIDEO.
+ // V4L2: BACKLIGHT, DAWN_DUSK, FALL_COLORS, TEXT.
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_SCENE_MODE,
+ ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+ device,
+ V4L2_CID_SCENE_MODE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_SCENE_MODE_NONE, ANDROID_CONTROL_SCENE_MODE_DISABLED},
+ {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_BEACH},
+ {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_SNOW},
+ {V4L2_SCENE_MODE_CANDLE_LIGHT,
+ ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT},
+ {V4L2_SCENE_MODE_FIREWORKS, ANDROID_CONTROL_SCENE_MODE_FIREWORKS},
+ {V4L2_SCENE_MODE_LANDSCAPE, ANDROID_CONTROL_SCENE_MODE_LANDSCAPE},
+ {V4L2_SCENE_MODE_NIGHT, ANDROID_CONTROL_SCENE_MODE_NIGHT},
+ {V4L2_SCENE_MODE_PARTY_INDOOR, ANDROID_CONTROL_SCENE_MODE_PARTY},
+ {V4L2_SCENE_MODE_SPORTS, ANDROID_CONTROL_SCENE_MODE_SPORTS},
+ {V4L2_SCENE_MODE_SUNSET, ANDROID_CONTROL_SCENE_MODE_SUNSET}})),
+ ANDROID_CONTROL_SCENE_MODE_DISABLED));
+ // TODO(b/31022612): Scene mode overrides.
+ // Modes from each API that don't match up:
+ // Android: POSTERIZE, WHITEBOARD, BLACKBOARD.
+ // V4L2: ANTIQUE, ART_FREEZE, EMBOSS, GRASS_GREEN, SKETCH, SKIN_WHITEN,
+ // SKY_BLUE, SILHOUETTE, VIVID, SET_CBCR.
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_EFFECT_MODE,
+ ANDROID_CONTROL_AVAILABLE_EFFECTS,
+ device,
+ V4L2_CID_COLORFX,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_COLORFX_NONE, ANDROID_CONTROL_EFFECT_MODE_OFF},
+ {V4L2_COLORFX_BW, ANDROID_CONTROL_EFFECT_MODE_MONO},
+ {V4L2_COLORFX_NEGATIVE, ANDROID_CONTROL_EFFECT_MODE_NEGATIVE},
+ {V4L2_COLORFX_SOLARIZATION, ANDROID_CONTROL_EFFECT_MODE_SOLARIZE},
+ {V4L2_COLORFX_SEPIA, ANDROID_CONTROL_EFFECT_MODE_SEPIA},
+ {V4L2_COLORFX_AQUA, ANDROID_CONTROL_EFFECT_MODE_AQUA}})),
+ ANDROID_CONTROL_EFFECT_MODE_OFF));
+ // TODO(b/31021654): This should behave as a top level switch, not no effect.
+ components.insert(
+ NoEffectMenuControl<uint8_t>(ANDROID_CONTROL_MODE,
+ ANDROID_CONTROL_AVAILABLE_MODES,
+ {ANDROID_CONTROL_MODE_AUTO}));
+
+ // Not sure if V4L2 does or doesn't do this, but HAL documentation says
+ // all devices must support FAST, and FAST can be equivalent to OFF, so
+ // either way it's fine to list.
+ components.insert(
+ NoEffectMenuControl<uint8_t>(ANDROID_EDGE_MODE,
+ ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+ {ANDROID_EDGE_MODE_FAST}));
+
+ // TODO(b/31023454): subcomponents of flash.
+ // Missing android.flash.mode control, since it uses a different enum.
+ components.insert(
+ std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
+ ANDROID_FLASH_INFO_AVAILABLE, ANDROID_FLASH_INFO_AVAILABLE_FALSE)));
+ components.insert(FixedState<uint8_t>(ANDROID_FLASH_STATE,
+ ANDROID_FLASH_STATE_UNAVAILABLE));
+
+ // TODO(30510395): subcomponents of hotpixel.
+ // No known V4L2 hot pixel correction. But it might be happening,
+ // so we report FAST/HIGH_QUALITY.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_HOT_PIXEL_MODE,
+ ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
+ {ANDROID_HOT_PIXEL_MODE_FAST, ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY}));
+ // ON only needs to be supported for RAW capable devices.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+ ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+ {ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF}));
+
+ // TODO(30510395): subcomponents focus/lens.
+ // No way to actually get the aperture and focal length
+ // in V4L2, but they're required keys, so fake them.
+ components.insert(
+ NoEffectMenuControl<float>(ANDROID_LENS_APERTURE,
+ ANDROID_LENS_INFO_AVAILABLE_APERTURES,
+ {2.0})); // RPi camera v2 is f/2.0.
+ // Always assume external-facing.
+ components.insert(
+ std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
+ ANDROID_LENS_FACING, ANDROID_LENS_FACING_EXTERNAL)));
+ components.insert(
+ NoEffectMenuControl<float>(ANDROID_LENS_FOCAL_LENGTH,
+ ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
+ {3.04})); // RPi camera v2 is 3.04mm.
+ // No known way to get filter densities from V4L2,
+ // report 0 to indicate this control is not supported.
+ components.insert(
+ NoEffectMenuControl<float>(ANDROID_LENS_FILTER_DENSITY,
+ ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
+ {0.0}));
+ // V4L2 focal units do not correspond to a particular physical unit.
+ components.insert(
+ std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED)));
+ // TODO(b/31022711): Focus distance component.
+ // Using a NoEffectMenuControl for now because for
+ // fixed-focus it meets expectations. Framework may allow
+ // setting any value and expect it to be clamped to 0, in which
+ // case this will have unexpected behavior (failing on non-0 settings).
+ components.insert(
+ NoEffectMenuControl<float>(ANDROID_LENS_FOCUS_DISTANCE,
+ ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
+ {0}));
+ // info.hyperfocalDistance not required for UNCALIBRATED.
+ // No way to know when the lens is moving or not in V4L2.
+ components.insert(
+ FixedState<uint8_t>(ANDROID_LENS_STATE, ANDROID_LENS_STATE_STATIONARY));
+ // No known V4L2 lens shading. But it might be happening,
+ // so report FAST/HIGH_QUALITY.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_SHADING_MODE,
+ ANDROID_SHADING_AVAILABLE_MODES,
+ {ANDROID_SHADING_MODE_FAST, ANDROID_SHADING_MODE_HIGH_QUALITY}));
+ // ON only needs to be supported for RAW capable devices.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+ ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+ {ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF}));
+ // V4L2 doesn't differentiate between OPTICAL and VIDEO stabilization,
+ // so only report one (and report the other as OFF).
+ components.insert(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+ device,
+ V4L2_CID_IMAGE_STABILIZATION,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{0, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF},
+ {1, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON}})),
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF));
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+ ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+ {ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF}));
+ // TODO(b/31017806): This should definitely have a different default depending
+ // on template.
+ components.insert(NoEffectOptionlessControl<uint8_t>(
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE));
+
+ // Unable to control noise reduction in V4L2 devices,
+ // but FAST is allowed to be the same as OFF.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+ {ANDROID_NOISE_REDUCTION_MODE_FAST}));
+
+ // TODO(30510395): subcomponents of formats/streams.
+ // For now, no thumbnails available (only [0,0], the "no thumbnail" size).
+ // TODO(b/29580107): Could end up with a mismatch between request & result,
+ // since V4L2 doesn't actually allow for thumbnail size control.
+ components.insert(NoEffectMenuControl<std::array<int32_t, 2>>(
+ ANDROID_JPEG_THUMBNAIL_SIZE,
+ ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+ {{{0, 0}}}));
+ // TODO(b/31022752): Get this from the device,
+ // not constant (from V4L2Gralloc.h).
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<int32_t>(ANDROID_JPEG_MAX_SIZE, V4L2_MAX_JPEG_SIZE)));
+ // TODO(b/31021672): Other JPEG controls (GPS, quality, orientation).
+ // TODO(b/29939583): V4L2 can only support 1 stream at a time.
+ // For now, just reporting minimum allowable for LIMITED devices.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::array<int32_t, 3>>(
+ ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+ {{/* Raw */ 0, /* Non-stalling */ 2, /* Stalling */ 1}})));
+ // Reprocessing not supported.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<int32_t>(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, 0)));
+ // No way to know pipeline depth for V4L2, so fake with max allowable latency.
+ // Doesn't mean much without per-frame controls anyways.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, 4)));
+ // "LIMITED devices are strongly encouraged to use a non-negative value.
+ // If UNKNOWN is used here then app developers do not have a way to know
+ // when sensor settings have been applied." - Unfortunately, V4L2 doesn't
+ // really help here either. Could even be that adjusting settings mid-stream
+ // blocks in V4L2, and should be avoided.
+ components.insert(
+ std::unique_ptr<PartialMetadataInterface>(new Property<int32_t>(
+ ANDROID_SYNC_MAX_LATENCY, ANDROID_SYNC_MAX_LATENCY_UNKNOWN)));
+ // Never know when controls are synced.
+ components.insert(FixedState<int64_t>(ANDROID_SYNC_FRAME_NUMBER,
+ ANDROID_SYNC_FRAME_NUMBER_UNKNOWN));
+
+ // TODO(b/31022480): subcomponents of cropping/sensors.
+ // Need ANDROID_SCALER_CROP_REGION control support.
+ // V4L2 VIDIOC_CROPCAP doesn't give a way to query this;
+ // it's driver dependent. For now, assume freeform, and
+ // some cameras may just behave badly.
+ // TODO(b/29579652): Figure out a way to determine this.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<float>(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, 1)));
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_SCALER_CROPPING_TYPE,
+ ANDROID_SCALER_CROPPING_TYPE_FREEFORM)));
+ // Spoof pixel array size for now, eventually get from CROPCAP.
+ std::array<int32_t, 2> pixel_array_size = {{640, 480}};
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::array<int32_t, 2>>(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+ pixel_array_size)));
+ // Active array size is {x-offset, y-offset, width, height}, relative to
+ // the pixel array size, with {0, 0} being the top left. Since there's no way
+ // to get this in V4L2, assume the full pixel array is the active array.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::array<int32_t, 4>>(
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ {{0, 0, pixel_array_size[0], pixel_array_size[1]}})));
+ // No way to get in V4L2, so faked. RPi camera v2 is 3.674 x 2.760 mm.
+ // Physical size is used in framework calculations (field of view,
+ // pixel pitch, etc.), so faking it may have unexpected results.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::array<float, 2>>(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
+ {{3.674, 2.760}})));
+ // HAL uses BOOTTIME timestamps.
+ // TODO(b/29457051): make sure timestamps are consistent throughout the HAL.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN)));
+ // TODO(b/29457051): Actually get a timestamp here. For now spoofing as non-0.
+ components.insert(FixedState<int64_t>(ANDROID_SENSOR_TIMESTAMP, 1));
+ // No way to actually get shutter skew from V4L2.
+ components.insert(
+ FixedState<int64_t>(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, 0));
+ // No way to actually get orientation from V4L2.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<int32_t>(ANDROID_SENSOR_ORIENTATION, 0)));
+ // TODO(b/31023611): Should actually do something for this, and range should
+ // be dependent on the stream configuration being used.
+ components.insert(NoEffectOptionlessControl<int64_t>(
+ ANDROID_SENSOR_FRAME_DURATION, 33333333L)); // 1/30 s.
+
+ // TODO(30510395): subcomponents of face detection.
+ // Face detection not supported.
+ components.insert(NoEffectMenuControl<uint8_t>(
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+ {ANDROID_STATISTICS_FACE_DETECT_MODE_OFF}));
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<int32_t>(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, 0)));
+
+ // TOOD(b/31023265): V4L2_CID_FLASH_INDICATOR_INTENSITY could be queried
+ // to see if there's a transmit LED. Would need to translate HAL off/on
+ // enum to slider min/max value. For now, no LEDs available.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_LED_AVAILABLE_LEDS, {})));
+
+ /* Capabilities. */
+ // The V4L2Metadata pretends to at least meet the
+ // "LIMITED" and "BACKWARD_COMPATIBLE" functionality requirements.
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<uint8_t>(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)));
+ components.insert(std::unique_ptr<PartialMetadataInterface>(
+ new Property<std::vector<uint8_t>>(
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})));
+
+ // Request is unused, and can be any value,
+ // but that value needs to be propagated.
+ components.insert(NoEffectOptionlessControl<int32_t>(ANDROID_REQUEST_ID, 0));
+
+ int res =
+ AddFormatComponents(device, std::inserter(components, components.end()));
+ if (res) {
+ HAL_LOGE("Failed to initialize format components.");
+ return res;
+ }
+
+ *result = std::make_unique<Metadata>(std::move(components));
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata_factory.h b/modules/camera/3_4/v4l2_metadata_factory.h
new file mode 100644
index 0000000..f25a370
--- /dev/null
+++ b/modules/camera/3_4/v4l2_metadata_factory.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_
+#define V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_
+
+#include <memory>
+
+#include "metadata/metadata.h"
+#include "v4l2_wrapper.h"
+
+namespace v4l2_camera_hal {
+
+// A static function to get a Metadata object populated with V4L2 or other
+// controls as appropriate.
+int GetV4L2Metadata(std::shared_ptr<V4L2Wrapper> device,
+ std::unique_ptr<Metadata>* result);
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_
diff --git a/modules/camera/3_4/v4l2_wrapper.cpp b/modules/camera/3_4/v4l2_wrapper.cpp
new file mode 100644
index 0000000..3d7ba85
--- /dev/null
+++ b/modules/camera/3_4/v4l2_wrapper.cpp
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "v4l2_wrapper.h"
+
+#include <algorithm>
+#include <array>
+#include <limits>
+#include <vector>
+
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <mutex>
+
+#include <nativehelper/ScopedFd.h>
+
+#include "common.h"
+#include "stream.h"
+#include "stream_format.h"
+#include "v4l2_gralloc.h"
+
+namespace v4l2_camera_hal {
+
+const int32_t kStandardSizes[][2] = {
+ {1920, 1080}, {1280, 720}, {640, 480}, {320, 240}};
+
+V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
+ HAL_LOG_ENTER();
+
+ std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
+ if (!gralloc) {
+ HAL_LOGE("Failed to initialize gralloc helper.");
+ return nullptr;
+ }
+
+ return new V4L2Wrapper(device_path, std::move(gralloc));
+}
+
+V4L2Wrapper::V4L2Wrapper(const std::string device_path,
+ std::unique_ptr<V4L2Gralloc> gralloc)
+ : device_path_(std::move(device_path)),
+ gralloc_(std::move(gralloc)),
+ max_buffers_(0),
+ connection_count_(0) {
+ HAL_LOG_ENTER();
+}
+
+V4L2Wrapper::~V4L2Wrapper() {
+ HAL_LOG_ENTER();
+}
+
+int V4L2Wrapper::Connect() {
+ HAL_LOG_ENTER();
+ std::lock_guard<std::mutex> lock(connection_lock_);
+
+ if (connected()) {
+ HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
+ ++connection_count_;
+ return 0;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR));
+ if (fd < 0) {
+ HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
+ return -ENODEV;
+ }
+ device_fd_.reset(fd);
+ ++connection_count_;
+
+ // Check if this connection has the extended control query capability.
+ v4l2_query_ext_ctrl query;
+ query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
+
+ // TODO(b/29185945): confirm this is a supported device.
+ // This is checked by the HAL, but the device at device_path_ may
+ // not be the same one that was there when the HAL was loaded.
+ // (Alternatively, better hotplugging support may make this unecessary
+ // by disabling cameras that get disconnected and checking newly connected
+ // cameras, so Connect() is never called on an unsupported camera)
+ return 0;
+}
+
+void V4L2Wrapper::Disconnect() {
+ HAL_LOG_ENTER();
+ std::lock_guard<std::mutex> lock(connection_lock_);
+
+ if (connection_count_ == 0) {
+ // Not connected.
+ HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
+ device_path_.c_str());
+ return;
+ }
+
+ --connection_count_;
+ if (connection_count_ > 0) {
+ HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
+ device_path_.c_str());
+ return;
+ }
+
+ device_fd_.reset(); // Includes close().
+ format_.reset();
+ max_buffers_ = 0;
+ // Closing the device releases all queued buffers back to the user.
+ gralloc_->unlockAllBuffers();
+}
+
+// Helper function. Should be used instead of ioctl throughout this class.
+template <typename T>
+int V4L2Wrapper::IoctlLocked(int request, T data) {
+ // Potentially called so many times logging entry is a bad idea.
+ std::lock_guard<std::mutex> lock(device_lock_);
+
+ if (!connected()) {
+ HAL_LOGE("Device %s not connected.", device_path_.c_str());
+ return -ENODEV;
+ }
+ return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
+}
+
+int V4L2Wrapper::StreamOn() {
+ HAL_LOG_ENTER();
+
+ if (!format_) {
+ HAL_LOGE("Stream format must be set before turning on stream.");
+ return -EINVAL;
+ }
+
+ int32_t type = format_->type();
+ if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
+ HAL_LOGE("STREAMON fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int V4L2Wrapper::StreamOff() {
+ HAL_LOG_ENTER();
+
+ if (!format_) {
+ HAL_LOGE("Stream format must be set to turn off stream.");
+ return -ENODEV;
+ }
+
+ int32_t type = format_->type();
+ int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
+ // Calling STREAMOFF releases all queued buffers back to the user.
+ int gralloc_res = gralloc_->unlockAllBuffers();
+ if (res < 0) {
+ HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ if (gralloc_res < 0) {
+ HAL_LOGE("Failed to unlock all buffers after turning stream off.");
+ return gralloc_res;
+ }
+
+ return 0;
+}
+
+int V4L2Wrapper::QueryControl(uint32_t control_id,
+ v4l2_query_ext_ctrl* result) {
+ HAL_LOG_ENTER();
+ int res;
+
+ memset(result, 0, sizeof(*result));
+
+ if (extended_query_supported_) {
+ result->id = control_id;
+ res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
+ // Assuming the operation was supported (not ENOTTY), no more to do.
+ if (errno != ENOTTY) {
+ if (res) {
+ HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ return 0;
+ }
+ }
+
+ // Extended control querying not supported, fall back to basic control query.
+ v4l2_queryctrl query;
+ query.id = control_id;
+ if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
+ HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Convert the basic result to the extended result.
+ result->id = query.id;
+ result->type = query.type;
+ memcpy(result->name, query.name, sizeof(query.name));
+ result->minimum = query.minimum;
+ if (query.type == V4L2_CTRL_TYPE_BITMASK) {
+ // According to the V4L2 documentation, when type is BITMASK,
+ // max and default should be interpreted as __u32. Practically,
+ // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
+ result->maximum = static_cast<uint32_t>(query.maximum);
+ result->default_value = static_cast<uint32_t>(query.default_value);
+ } else {
+ result->maximum = query.maximum;
+ result->default_value = query.default_value;
+ }
+ result->step = static_cast<uint32_t>(query.step);
+ result->flags = query.flags;
+ result->elems = 1;
+ switch (result->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ result->elem_size = sizeof(int64_t);
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ result->elem_size = result->maximum + 1;
+ break;
+ default:
+ result->elem_size = sizeof(int32_t);
+ break;
+ }
+
+ return 0;
+}
+
+int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
+ HAL_LOG_ENTER();
+
+ // For extended controls (any control class other than "user"),
+ // G_EXT_CTRL must be used instead of G_CTRL.
+ if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
+ v4l2_ext_control control;
+ v4l2_ext_controls controls;
+ memset(&control, 0, sizeof(control));
+ memset(&controls, 0, sizeof(controls));
+
+ control.id = control_id;
+ controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
+ controls.count = 1;
+ controls.controls = &control;
+
+ if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
+ HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ *value = control.value;
+ } else {
+ v4l2_control control{control_id, 0};
+ if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
+ HAL_LOGE("G_CTRL fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ *value = control.value;
+ }
+ return 0;
+}
+
+int V4L2Wrapper::SetControl(uint32_t control_id,
+ int32_t desired,
+ int32_t* result) {
+ HAL_LOG_ENTER();
+ int32_t result_value = 0;
+
+ // TODO(b/29334616): When async, this may need to check if the stream
+ // is on, and if so, lock it off while setting format. Need to look
+ // into if V4L2 supports adjusting controls while the stream is on.
+
+ // For extended controls (any control class other than "user"),
+ // S_EXT_CTRL must be used instead of S_CTRL.
+ if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
+ v4l2_ext_control control;
+ v4l2_ext_controls controls;
+ memset(&control, 0, sizeof(control));
+ memset(&controls, 0, sizeof(controls));
+
+ control.id = control_id;
+ control.value = desired;
+ controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
+ controls.count = 1;
+ controls.controls = &control;
+
+ if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
+ HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ result_value = control.value;
+ } else {
+ v4l2_control control{control_id, desired};
+ if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
+ HAL_LOGE("S_CTRL fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+ result_value = control.value;
+ }
+
+ // If the caller wants to know the result, pass it back.
+ if (result != nullptr) {
+ *result = result_value;
+ }
+ return 0;
+}
+
+int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
+ HAL_LOG_ENTER();
+
+ v4l2_fmtdesc format_query;
+ memset(&format_query, 0, sizeof(format_query));
+ // TODO(b/30000211): multiplanar support.
+ format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
+ v4l2_formats->insert(format_query.pixelformat);
+ ++format_query.index;
+ }
+
+ if (errno != EINVAL) {
+ HAL_LOGE(
+ "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
+ std::set<std::array<int32_t, 2>>* sizes) {
+ HAL_LOG_ENTER();
+
+ v4l2_frmsizeenum size_query;
+ memset(&size_query, 0, sizeof(size_query));
+ size_query.pixel_format = v4l2_format;
+ if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
+ HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+ if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
+ // Assuming that a driver with discrete frame sizes has a reasonable number
+ // of them.
+ do {
+ sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
+ static_cast<int32_t>(size_query.discrete.height)}}});
+ ++size_query.index;
+ } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
+ if (errno != EINVAL) {
+ HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
+ size_query.index,
+ strerror(errno));
+ return -ENODEV;
+ }
+ } else {
+ // Continuous/Step-wise: based on the stepwise struct returned by the query.
+ // Fully listing all possible sizes, with large enough range/small enough
+ // step size, may produce far too many potential sizes. Instead, find the
+ // closest to a set of standard sizes plus largest possible.
+ sizes->insert({{{static_cast<int32_t>(size_query.stepwise.max_width),
+ static_cast<int32_t>(size_query.stepwise.max_height)}}});
+ for (const auto size : kStandardSizes) {
+ // Find the closest size, rounding up.
+ uint32_t desired_width = size[0];
+ uint32_t desired_height = size[1];
+ if (desired_width < size_query.stepwise.min_width ||
+ desired_height < size_query.stepwise.min_height) {
+ HAL_LOGV("Standard size %u x %u is too small for format %d",
+ desired_width,
+ desired_height,
+ v4l2_format);
+ continue;
+ } else if (desired_width > size_query.stepwise.max_width &&
+ desired_height > size_query.stepwise.max_height) {
+ HAL_LOGV("Standard size %u x %u is too big for format %d",
+ desired_width,
+ desired_height,
+ v4l2_format);
+ continue;
+ }
+
+ // Round up.
+ uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
+ size_query.stepwise.step_width - 1) /
+ size_query.stepwise.step_width;
+ uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
+ size_query.stepwise.step_height - 1) /
+ size_query.stepwise.step_height;
+ sizes->insert(
+ {{{static_cast<int32_t>(size_query.stepwise.min_width +
+ width_steps * size_query.stepwise.step_width),
+ static_cast<int32_t>(size_query.stepwise.min_height +
+ height_steps *
+ size_query.stepwise.step_height)}}});
+ }
+ }
+ return 0;
+}
+
+// Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
+inline int64_t FractToNs(const v4l2_fract& fract) {
+ return (1000000000LL * fract.numerator) / fract.denominator;
+}
+
+int V4L2Wrapper::GetFormatFrameDurationRange(
+ uint32_t v4l2_format,
+ const std::array<int32_t, 2>& size,
+ std::array<int64_t, 2>* duration_range) {
+ // Potentially called so many times logging entry is a bad idea.
+
+ v4l2_frmivalenum duration_query;
+ memset(&duration_query, 0, sizeof(duration_query));
+ duration_query.pixel_format = v4l2_format;
+ duration_query.width = size[0];
+ duration_query.height = size[1];
+ if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
+ HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ int64_t min = std::numeric_limits<int64_t>::max();
+ int64_t max = std::numeric_limits<int64_t>::min();
+ if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
+ do {
+ min = std::min(min, FractToNs(duration_query.discrete));
+ max = std::max(max, FractToNs(duration_query.discrete));
+ ++duration_query.index;
+ } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
+ if (errno != EINVAL) {
+ HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
+ duration_query.index,
+ strerror(errno));
+ return -ENODEV;
+ }
+ } else {
+ // Continuous/Step-wise: simply convert the given min and max.
+ min = FractToNs(duration_query.stepwise.min);
+ max = FractToNs(duration_query.stepwise.max);
+ }
+ (*duration_range)[0] = min;
+ (*duration_range)[1] = max;
+ return 0;
+}
+
+int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream,
+ uint32_t* result_max_buffers) {
+ HAL_LOG_ENTER();
+
+ // Should be checked earlier; sanity check.
+ if (stream.isInputType()) {
+ HAL_LOGE("Input streams not supported.");
+ return -EINVAL;
+ }
+
+ StreamFormat desired_format(stream);
+ if (format_ && desired_format == *format_) {
+ HAL_LOGV("Already in correct format, skipping format setting.");
+ return 0;
+ }
+
+ // Not in the correct format, set our format.
+ v4l2_format new_format;
+ desired_format.FillFormatRequest(&new_format);
+ // TODO(b/29334616): When async, this will need to check if the stream
+ // is on, and if so, lock it off while setting format.
+ if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
+ HAL_LOGE("S_FMT failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Check that the driver actually set to the requested values.
+ if (desired_format != new_format) {
+ HAL_LOGE("Device doesn't support desired stream configuration.");
+ return -EINVAL;
+ }
+
+ // Keep track of our new format.
+ format_.reset(new StreamFormat(new_format));
+
+ // Format changed, setup new buffers.
+ int res = SetupBuffers();
+ if (res) {
+ HAL_LOGE("Failed to set up buffers for new format.");
+ return res;
+ }
+ *result_max_buffers = max_buffers_;
+ return 0;
+}
+
+int V4L2Wrapper::SetupBuffers() {
+ HAL_LOG_ENTER();
+
+ if (!format_) {
+ HAL_LOGE("Stream format must be set before setting up buffers.");
+ return -ENODEV;
+ }
+
+ // "Request" a buffer (since we're using a userspace buffer, this just
+ // tells V4L2 to switch into userspace buffer mode).
+ v4l2_requestbuffers req_buffers;
+ memset(&req_buffers, 0, sizeof(req_buffers));
+ req_buffers.type = format_->type();
+ req_buffers.memory = V4L2_MEMORY_USERPTR;
+ req_buffers.count = 1;
+
+ int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
+ // Calling REQBUFS releases all queued buffers back to the user.
+ int gralloc_res = gralloc_->unlockAllBuffers();
+ if (res < 0) {
+ HAL_LOGE("REQBUFS failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+ if (gralloc_res < 0) {
+ HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
+ return gralloc_res;
+ }
+
+ // V4L2 will set req_buffers.count to a number of buffers it can handle.
+ max_buffers_ = req_buffers.count;
+ // Sanity check.
+ if (max_buffers_ < 1) {
+ HAL_LOGE("REQBUFS claims it can't handle any buffers.");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
+ HAL_LOG_ENTER();
+
+ if (!format_) {
+ HAL_LOGE("Stream format must be set before enqueuing buffers.");
+ return -ENODEV;
+ }
+
+ // Set up a v4l2 buffer struct.
+ v4l2_buffer device_buffer;
+ memset(&device_buffer, 0, sizeof(device_buffer));
+ device_buffer.type = format_->type();
+ // TODO(b/29334616): when this is async, actually limit the number
+ // of buffers used to the known max, and set this according to the
+ // queue length.
+ device_buffer.index = 0;
+
+ // Use QUERYBUF to ensure our buffer/device is in good shape,
+ // and fill out remaining fields.
+ if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
+ HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Lock the buffer for writing (fills in the user pointer field).
+ int res =
+ gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
+ if (res) {
+ HAL_LOGE("Gralloc failed to lock buffer.");
+ return res;
+ }
+ if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
+ HAL_LOGE("QBUF fails: %s", strerror(errno));
+ gralloc_->unlock(&device_buffer);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int V4L2Wrapper::DequeueBuffer(v4l2_buffer* buffer) {
+ HAL_LOG_ENTER();
+
+ if (!format_) {
+ HAL_LOGE("Stream format must be set before dequeueing buffers.");
+ return -ENODEV;
+ }
+
+ memset(buffer, 0, sizeof(*buffer));
+ buffer->type = format_->type();
+ buffer->memory = V4L2_MEMORY_USERPTR;
+ if (IoctlLocked(VIDIOC_DQBUF, buffer) < 0) {
+ HAL_LOGE("DQBUF fails: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // Now that we're done painting the buffer, we can unlock it.
+ int res = gralloc_->unlock(buffer);
+ if (res) {
+ HAL_LOGE("Gralloc failed to unlock buffer after dequeueing.");
+ return res;
+ }
+
+ return 0;
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_wrapper.h b/modules/camera/3_4/v4l2_wrapper.h
new file mode 100644
index 0000000..3798c14
--- /dev/null
+++ b/modules/camera/3_4/v4l2_wrapper.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_V4L2_WRAPPER_H_
+#define V4L2_CAMERA_HAL_V4L2_WRAPPER_H_
+
+#include <array>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string>
+
+#include <nativehelper/ScopedFd.h>
+
+#include "common.h"
+#include "stream.h"
+#include "stream_format.h"
+#include "v4l2_gralloc.h"
+
+namespace v4l2_camera_hal {
+class V4L2Wrapper {
+ public:
+ // Use this method to create V4L2Wrapper objects. Functionally equivalent
+ // to "new V4L2Wrapper", except that it may return nullptr in case of failure.
+ static V4L2Wrapper* NewV4L2Wrapper(const std::string device_path);
+ virtual ~V4L2Wrapper();
+
+ // Helper class to ensure all opened connections are closed.
+ class Connection {
+ public:
+ Connection(std::shared_ptr<V4L2Wrapper> device)
+ : device_(std::move(device)), connect_result_(device_->Connect()) {}
+ ~Connection() {
+ if (connect_result_ == 0)
+ device_->Disconnect();
+ }
+ // Check whether the connection succeeded or not.
+ inline int status() const { return connect_result_; }
+
+ private:
+ std::shared_ptr<V4L2Wrapper> device_;
+ const int connect_result_;
+ };
+
+ // Turn the stream on or off.
+ virtual int StreamOn();
+ virtual int StreamOff();
+ // Manage controls.
+ virtual int QueryControl(uint32_t control_id, v4l2_query_ext_ctrl* result);
+ virtual int GetControl(uint32_t control_id, int32_t* value);
+ virtual int SetControl(uint32_t control_id,
+ int32_t desired,
+ int32_t* result = nullptr);
+ // Manage format.
+ virtual int GetFormats(std::set<uint32_t>* v4l2_formats);
+ virtual int GetFormatFrameSizes(uint32_t v4l2_format,
+ std::set<std::array<int32_t, 2>>* sizes);
+ // Durations are returned in ns.
+ virtual int GetFormatFrameDurationRange(
+ uint32_t v4l2_format,
+ const std::array<int32_t, 2>& size,
+ std::array<int64_t, 2>* duration_range);
+ virtual int SetFormat(const default_camera_hal::Stream& stream,
+ uint32_t* result_max_buffers);
+ // Manage buffers.
+ virtual int EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer);
+ virtual int DequeueBuffer(v4l2_buffer* buffer);
+
+ private:
+ // Constructor is private to allow failing on bad input.
+ // Use NewV4L2Wrapper instead.
+ V4L2Wrapper(const std::string device_path,
+ std::unique_ptr<V4L2Gralloc> gralloc);
+
+ // Connect or disconnect to the device. Access by creating/destroying
+ // a V4L2Wrapper::Connection object.
+ int Connect();
+ void Disconnect();
+ // Perform an ioctl call in a thread-safe fashion.
+ template <typename T>
+ int IoctlLocked(int request, T data);
+ // Adjust buffers any time a device is connected/reformatted.
+ int SetupBuffers();
+
+ inline bool connected() { return device_fd_.get() >= 0; }
+
+ // The camera device path. For example, /dev/video0.
+ const std::string device_path_;
+ // The opened device fd.
+ ScopedFd device_fd_;
+ // The underlying gralloc module.
+ std::unique_ptr<V4L2Gralloc> gralloc_;
+ // Whether or not the device supports the extended control query.
+ bool extended_query_supported_;
+ // The format this device is set up for.
+ std::unique_ptr<StreamFormat> format_;
+ // The maximum number of buffers this device can handle in its current format.
+ uint32_t max_buffers_;
+ // Lock protecting use of the device.
+ std::mutex device_lock_;
+ // Lock protecting connecting/disconnecting the device.
+ std::mutex connection_lock_;
+ // Reference count connections.
+ int connection_count_;
+
+ friend class Connection;
+ friend class V4L2WrapperMock;
+
+ DISALLOW_COPY_AND_ASSIGN(V4L2Wrapper);
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_WRAPPER_H_
diff --git a/modules/camera/3_4/v4l2_wrapper_mock.h b/modules/camera/3_4/v4l2_wrapper_mock.h
new file mode 100644
index 0000000..c717d32
--- /dev/null
+++ b/modules/camera/3_4/v4l2_wrapper_mock.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for wrapper class used to communicate with V4L2 devices.
+
+#ifndef V4L2_CAMERA_HAL_V4L2_WRAPPER_MOCK_H_
+#define V4L2_CAMERA_HAL_V4L2_WRAPPER_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "v4l2_wrapper.h"
+
+namespace v4l2_camera_hal {
+
+class V4L2WrapperMock : public V4L2Wrapper {
+ public:
+ V4L2WrapperMock() : V4L2Wrapper("", nullptr){};
+ MOCK_METHOD0(StreamOn, int());
+ MOCK_METHOD0(StreamOff, int());
+ MOCK_METHOD2(QueryControl,
+ int(uint32_t control_id, v4l2_query_ext_ctrl* result));
+ MOCK_METHOD2(GetControl, int(uint32_t control_id, int32_t* value));
+ MOCK_METHOD3(SetControl,
+ int(uint32_t control_id, int32_t desired, int32_t* result));
+ MOCK_METHOD1(GetFormats, int(std::set<uint32_t>*));
+ MOCK_METHOD2(GetFormatFrameSizes,
+ int(uint32_t, std::set<std::array<int32_t, 2>>*));
+ MOCK_METHOD3(GetFormatFrameDurationRange,
+ int(uint32_t,
+ const std::array<int32_t, 2>&,
+ std::array<int64_t, 2>*));
+ MOCK_METHOD2(SetFormat,
+ int(const default_camera_hal::Stream& stream,
+ uint32_t* result_max_buffers));
+ MOCK_METHOD1(EnqueueBuffer,
+ int(const camera3_stream_buffer_t* camera_buffer));
+ MOCK_METHOD1(DequeueBuffer, int(v4l2_buffer* buffer));
+};
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_V4L2_WRAPPER_MOCK_H_