Camera: Add external camera provider

Bug: 64874137 63873538

Change-Id: I4309874a7dedd3dd71d4bd0c2004d460421db679
This commit is contained in:
Yin-Chia Yeh
2017-10-19 17:30:11 -07:00
parent 30170d5590
commit 1903059507
13 changed files with 3909 additions and 16 deletions

View File

@@ -134,6 +134,65 @@ void HandleImporter::closeFence(int fd) const {
}
}
YCbCrLayout HandleImporter::lockYCbCr(
buffer_handle_t& buf, uint64_t cpuUsage,
const IMapper::Rect& accessRegion) {
Mutex::Autolock lock(mLock);
YCbCrLayout layout = {};
if (!mInitialized) {
initializeLocked();
}
if (mMapper == nullptr) {
ALOGE("%s: mMapper is null!", __FUNCTION__);
return layout;
}
hidl_handle acquireFenceHandle;
auto buffer = const_cast<native_handle_t*>(buf);
mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpLayout) {
if (tmpError == MapperError::NONE) {
layout = tmpLayout;
} else {
ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
}
});
ALOGV("%s: layout y %p cb %p cr %p y_str %d c_str %d c_step %d",
__FUNCTION__, layout.y, layout.cb, layout.cr,
layout.yStride, layout.cStride, layout.chromaStep);
return layout;
}
int HandleImporter::unlock(buffer_handle_t& buf) {
int releaseFence = -1;
auto buffer = const_cast<native_handle_t*>(buf);
mMapper->unlock(
buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
if (tmpError == MapperError::NONE) {
auto fenceHandle = tmpReleaseFence.getNativeHandle();
if (fenceHandle) {
if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
ALOGE("%s: bad release fence numInts %d numFds %d",
__FUNCTION__, fenceHandle->numInts, fenceHandle->numFds);
return;
}
releaseFence = dup(fenceHandle->data[0]);
if (releaseFence <= 0) {
ALOGE("%s: bad release fence FD %d",
__FUNCTION__, releaseFence);
}
}
} else {
ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
}
});
return releaseFence;
}
} // namespace helper
} // namespace V1_0
} // namespace common

View File

@@ -22,6 +22,7 @@
#include <cutils/native_handle.h>
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
namespace android {
namespace hardware {
@@ -43,6 +44,12 @@ public:
bool importFence(const native_handle_t* handle, int& fd) const;
void closeFence(int fd) const;
// Assume caller has done waiting for acquire fences
YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
const IMapper::Rect& accessRegion);
int unlock(buffer_handle_t& buf); // returns release fence
private:
void initializeLocked();
void cleanup();
@@ -60,4 +67,4 @@ private:
} // namespace hardware
} // namespace android
#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H

View File

@@ -17,7 +17,13 @@
cc_library_headers {
name: "camera.device@3.4-impl_headers",
vendor: true,
export_include_dirs: ["include/device_v3_4_impl"],
export_include_dirs: ["include/device_v3_4_impl"]
}
cc_library_headers {
name: "camera.device@3.4-external-impl_headers",
vendor: true,
export_include_dirs: ["include/ext_device_v3_4_impl"]
}
cc_library_shared {
@@ -55,3 +61,40 @@ cc_library_shared {
"libfmq",
],
}
cc_library_shared {
name: "camera.device@3.4-external-impl",
defaults: ["hidl_defaults"],
proprietary: true,
vendor: true,
srcs: [
"ExternalCameraDevice.cpp",
"ExternalCameraDeviceSession.cpp"
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"libcutils",
"camera.device@3.2-impl",
"camera.device@3.3-impl",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"liblog",
"libhardware",
"libcamera_metadata",
"libfmq",
"libsync",
"libyuv",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
],
local_include_dirs: ["include/ext_device_v3_4_impl"],
export_shared_lib_headers: [
"libfmq",
],
}

View File

@@ -0,0 +1,793 @@
/*
* Copyright (C) 2018 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.
*/
#define LOG_TAG "ExtCamDev@3.4"
#define LOG_NDEBUG 0
#include <log/log.h>
#include <array>
#include <linux/videodev2.h>
#include "android-base/macros.h"
#include "CameraMetadata.h"
#include "../../3.2/default/include/convert.h"
#include "ExternalCameraDevice_3_4.h"
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V3_4 {
namespace implementation {
namespace {
// Only support MJPEG for now as it seems to be the one supports higher fps
// Other formats to consider in the future:
// * V4L2_PIX_FMT_YVU420 (== YV12)
// * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
const std::array<uint32_t, /*size*/1> kSupportedFourCCs {{
V4L2_PIX_FMT_MJPEG
}}; // double braces required in C++11
// TODO: b/72261897
// Define max size/fps this Android device can advertise (and streaming at reasonable speed)
// Also make sure that can be done without editing source code
// TODO: b/72261675: make it dynamic since this affects memory usage
const int kMaxJpegSize = {13 * 1024 * 1024}; // 13MB
} // anonymous namespace
ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
mCameraId(cameraId) {
status_t ret = initCameraCharacteristics();
if (ret != OK) {
ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
mInitFailed = true;
}
}
ExternalCameraDevice::~ExternalCameraDevice() {}
bool ExternalCameraDevice::isInitFailed() {
return mInitFailed;
}
Return<void> ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
CameraResourceCost resCost;
resCost.resourceCost = 100;
_hidl_cb(Status::OK, resCost);
return Void();
}
Return<void> ExternalCameraDevice::getCameraCharacteristics(
getCameraCharacteristics_cb _hidl_cb) {
Mutex::Autolock _l(mLock);
V3_2::CameraMetadata hidlChars;
if (isInitFailed()) {
_hidl_cb(Status::INTERNAL_ERROR, hidlChars);
return Void();
}
const camera_metadata_t* rawMetadata = mCameraCharacteristics.getAndLock();
V3_2::implementation::convertToHidl(rawMetadata, &hidlChars);
_hidl_cb(Status::OK, hidlChars);
mCameraCharacteristics.unlock(rawMetadata);
return Void();
}
Return<Status> ExternalCameraDevice::setTorchMode(TorchMode) {
return Status::METHOD_NOT_SUPPORTED;
}
Return<void> ExternalCameraDevice::open(
const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
Status status = Status::OK;
sp<ExternalCameraDeviceSession> session = nullptr;
if (callback == nullptr) {
ALOGE("%s: cannot open camera %s. callback is null!",
__FUNCTION__, mCameraId.c_str());
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
}
if (isInitFailed()) {
ALOGE("%s: cannot open camera %s. camera init failed!",
__FUNCTION__, mCameraId.c_str());
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
mLock.lock();
ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
session = mSession.promote();
if (session != nullptr && !session->isClosed()) {
ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
mLock.unlock();
_hidl_cb(Status::CAMERA_IN_USE, nullptr);
return Void();
}
unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
if (fd.get() < 0) {
ALOGE("%s: v4l2 device open %s failed: %s",
__FUNCTION__, mCameraId.c_str(), strerror(errno));
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
session = new ExternalCameraDeviceSession(
callback, mSupportedFormats, mCameraCharacteristics, std::move(fd));
if (session == nullptr) {
ALOGE("%s: camera device session allocation failed", __FUNCTION__);
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
if (session->isInitFailed()) {
ALOGE("%s: camera device session init failed", __FUNCTION__);
session = nullptr;
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
mSession = session;
mLock.unlock();
_hidl_cb(status, session->getInterface());
return Void();
}
Return<void> ExternalCameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) {
Mutex::Autolock _l(mLock);
if (handle.getNativeHandle() == nullptr) {
ALOGE("%s: handle must not be null", __FUNCTION__);
return Void();
}
if (handle->numFds != 1 || handle->numInts != 0) {
ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
__FUNCTION__, handle->numFds, handle->numInts);
return Void();
}
int fd = handle->data[0];
if (mSession == nullptr) {
dprintf(fd, "No active camera device session instance\n");
return Void();
}
auto session = mSession.promote();
if (session == nullptr) {
dprintf(fd, "No active camera device session instance\n");
return Void();
}
// Call into active session to dump states
session->dumpState(handle);
return Void();
}
status_t ExternalCameraDevice::initCameraCharacteristics() {
if (mCameraCharacteristics.isEmpty()) {
// init camera characteristics
unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
if (fd.get() < 0) {
ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
return DEAD_OBJECT;
}
status_t ret;
ret = initDefaultCharsKeys(&mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
if (ret != OK) {
ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
mCameraCharacteristics.clear();
return ret;
}
}
return OK;
}
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define UPDATE(tag, data, size) \
do { \
if (metadata->update((tag), (data), (size))) { \
ALOGE("Update " #tag " failed!"); \
return -EINVAL; \
} \
} while (0)
status_t ExternalCameraDevice::initDefaultCharsKeys(
::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
// TODO: changed to HARDWARELEVEL_EXTERNAL later
const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
// android.colorCorrection
const uint8_t availableAberrationModes[] = {
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF};
UPDATE(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
availableAberrationModes, ARRAY_SIZE(availableAberrationModes));
// android.control
const uint8_t antibandingMode =
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
&antibandingMode, 1);
const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions,
ARRAY_SIZE(controlMaxRegions));
const uint8_t videoStabilizationMode =
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
UPDATE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
&videoStabilizationMode, 1);
const uint8_t awbAvailableMode = ANDROID_CONTROL_AWB_MODE_AUTO;
UPDATE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &awbAvailableMode, 1);
const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
const uint8_t availableFffect = ANDROID_CONTROL_EFFECT_MODE_OFF;
UPDATE(ANDROID_CONTROL_AVAILABLE_EFFECTS, &availableFffect, 1);
const uint8_t controlAvailableModes[] = {ANDROID_CONTROL_MODE_OFF,
ANDROID_CONTROL_MODE_AUTO};
UPDATE(ANDROID_CONTROL_AVAILABLE_MODES, controlAvailableModes,
ARRAY_SIZE(controlAvailableModes));
// android.edge
const uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
UPDATE(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &edgeMode, 1);
// android.flash
const uint8_t flashInfo = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
UPDATE(ANDROID_FLASH_INFO_AVAILABLE, &flashInfo, 1);
// android.hotPixel
const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
// android.jpeg
// TODO: b/72261675 See if we can provide thumbnail size for all jpeg aspect ratios
const int32_t jpegAvailableThumbnailSizes[] = {0, 0, 240, 180};
UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
ARRAY_SIZE(jpegAvailableThumbnailSizes));
const int32_t jpegMaxSize = kMaxJpegSize;
UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
const uint8_t jpegQuality = 90;
UPDATE(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
UPDATE(ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
const int32_t jpegOrientation = 0;
UPDATE(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
// android.lens
const uint8_t focusDistanceCalibration =
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
UPDATE(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &focusDistanceCalibration, 1);
const uint8_t opticalStabilizationMode =
ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
&opticalStabilizationMode, 1);
const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;
UPDATE(ANDROID_LENS_FACING, &facing, 1);
// android.noiseReduction
const uint8_t noiseReductionMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
UPDATE(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
&noiseReductionMode, 1);
UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
// android.request
const uint8_t availableCapabilities[] = {
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE};
UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities,
ARRAY_SIZE(availableCapabilities));
const int32_t partialResultCount = 1;
UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
// This means pipeline latency of X frame intervals. The maximum number is 4.
const uint8_t requestPipelineMaxDepth = 4;
UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
UPDATE(ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
// Three numbers represent the maximum numbers of different types of output
// streams simultaneously. The types are raw sensor, processed (but not
// stalling), and processed (but stalling). For usb limited mode, raw sensor
// is not supported. Stalling stream is JPEG. Non-stalling streams are
// YUV_420_888 or YV12.
const int32_t requestMaxNumOutputStreams[] = {
/*RAW*/0,
/*Processed*/ExternalCameraDeviceSession::kMaxProcessedStream,
/*Stall*/ExternalCameraDeviceSession::kMaxStallStream};
UPDATE(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, requestMaxNumOutputStreams,
ARRAY_SIZE(requestMaxNumOutputStreams));
// Limited mode doesn't support reprocessing.
const int32_t requestMaxNumInputStreams = 0;
UPDATE(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &requestMaxNumInputStreams,
1);
// android.scaler
// TODO: b/72263447 V4L2_CID_ZOOM_*
const float scalerAvailableMaxDigitalZoom[] = {1};
UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
scalerAvailableMaxDigitalZoom,
ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
UPDATE(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
const int32_t testPatternModes[] = {
ANDROID_SENSOR_TEST_PATTERN_MODE_OFF};
UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
ARRAY_SIZE(testPatternModes));
UPDATE(ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes[0], 1);
const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1);
// Orientation probably isn't useful for external facing camera?
const int32_t orientation = 0;
UPDATE(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
// android.shading
const uint8_t availabeMode = ANDROID_SHADING_MODE_OFF;
UPDATE(ANDROID_SHADING_AVAILABLE_MODES, &availabeMode, 1);
// android.statistics
const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode,
1);
const int32_t maxFaceCount = 0;
UPDATE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
const uint8_t availableHotpixelMode =
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
&availableHotpixelMode, 1);
const uint8_t lensShadingMapMode =
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
&lensShadingMapMode, 1);
// android.sync
const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
/* Other sensor/RAW realted keys:
* android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
* android.sensor.info.physicalSize -> not available
* android.sensor.info.whiteLevel -> not available/not needed
* android.sensor.info.lensShadingApplied -> not needed
* android.sensor.info.preCorrectionActiveArraySize -> not available/not needed
* android.sensor.blackLevelPattern -> not available/not needed
*/
const int32_t availableRequestKeys[] = {
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
ANDROID_CONTROL_AE_LOCK,
ANDROID_CONTROL_AE_MODE,
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
ANDROID_CONTROL_AF_MODE,
ANDROID_CONTROL_AF_TRIGGER,
ANDROID_CONTROL_AWB_LOCK,
ANDROID_CONTROL_AWB_MODE,
ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_EFFECT_MODE,
ANDROID_CONTROL_MODE,
ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
ANDROID_FLASH_MODE,
ANDROID_JPEG_ORIENTATION,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_THUMBNAIL_QUALITY,
ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_SCALER_CROP_REGION,
ANDROID_SENSOR_TEST_PATTERN_MODE,
ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE};
UPDATE(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys,
ARRAY_SIZE(availableRequestKeys));
const int32_t availableResultKeys[] = {
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
ANDROID_CONTROL_AE_LOCK,
ANDROID_CONTROL_AE_MODE,
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
ANDROID_CONTROL_AE_STATE,
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
ANDROID_CONTROL_AF_MODE,
ANDROID_CONTROL_AF_STATE,
ANDROID_CONTROL_AF_TRIGGER,
ANDROID_CONTROL_AWB_LOCK,
ANDROID_CONTROL_AWB_MODE,
ANDROID_CONTROL_AWB_STATE,
ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_EFFECT_MODE,
ANDROID_CONTROL_MODE,
ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
ANDROID_FLASH_MODE,
ANDROID_FLASH_STATE,
ANDROID_JPEG_ORIENTATION,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_THUMBNAIL_QUALITY,
ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_REQUEST_PIPELINE_DEPTH,
ANDROID_SCALER_CROP_REGION,
ANDROID_SENSOR_TIMESTAMP,
ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
ANDROID_STATISTICS_SCENE_FLICKER};
UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
ARRAY_SIZE(availableResultKeys));
const int32_t availableCharacteristicsKeys[] = {
ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
ANDROID_CONTROL_AE_AVAILABLE_MODES,
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
ANDROID_CONTROL_AE_COMPENSATION_RANGE,
ANDROID_CONTROL_AE_COMPENSATION_STEP,
ANDROID_CONTROL_AE_LOCK_AVAILABLE,
ANDROID_CONTROL_AF_AVAILABLE_MODES,
ANDROID_CONTROL_AVAILABLE_EFFECTS,
ANDROID_CONTROL_AVAILABLE_MODES,
ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
ANDROID_CONTROL_AWB_AVAILABLE_MODES,
ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
ANDROID_CONTROL_MAX_REGIONS,
ANDROID_FLASH_INFO_AVAILABLE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
ANDROID_LENS_FACING,
ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
ANDROID_SCALER_CROPPING_TYPE,
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
ANDROID_SENSOR_ORIENTATION,
ANDROID_SHADING_AVAILABLE_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
ANDROID_SYNC_MAX_LATENCY};
UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
availableCharacteristicsKeys,
ARRAY_SIZE(availableCharacteristicsKeys));
return OK;
}
status_t ExternalCameraDevice::initCameraControlsCharsKeys(int,
::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
/**
* android.sensor.info.sensitivityRange -> V4L2_CID_ISO_SENSITIVITY
* android.sensor.info.exposureTimeRange -> V4L2_CID_EXPOSURE_ABSOLUTE
* android.sensor.info.maxFrameDuration -> TBD
* android.lens.info.minimumFocusDistance -> V4L2_CID_FOCUS_ABSOLUTE
* android.lens.info.hyperfocalDistance
* android.lens.info.availableFocalLengths -> not available?
*/
// android.control
// No AE compensation support for now.
// TODO: V4L2_CID_EXPOSURE_BIAS
const int32_t controlAeCompensationRange[] = {0, 0};
UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
ARRAY_SIZE(controlAeCompensationRange));
const camera_metadata_rational_t controlAeCompensationStep[] = {{0, 1}};
UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
ARRAY_SIZE(controlAeCompensationStep));
// TODO: Check V4L2_CID_AUTO_FOCUS_*.
const uint8_t afAvailableModes[] = {ANDROID_CONTROL_AF_MODE_AUTO,
ANDROID_CONTROL_AF_MODE_OFF};
UPDATE(ANDROID_CONTROL_AF_AVAILABLE_MODES, afAvailableModes,
ARRAY_SIZE(afAvailableModes));
// TODO: V4L2_CID_SCENE_MODE
const uint8_t availableSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
UPDATE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &availableSceneMode, 1);
// TODO: V4L2_CID_3A_LOCK
const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
UPDATE(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
UPDATE(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
// TODO: V4L2_CID_ZOOM_*
const float scalerAvailableMaxDigitalZoom[] = {1};
UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
scalerAvailableMaxDigitalZoom,
ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
return OK;
}
status_t ExternalCameraDevice::initOutputCharsKeys(int fd,
::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
initSupportedFormatsLocked(fd);
if (mSupportedFormats.empty()) {
ALOGE("%s: Init supported format list failed", __FUNCTION__);
return UNKNOWN_ERROR;
}
std::vector<int32_t> streamConfigurations;
std::vector<int64_t> minFrameDurations;
std::vector<int64_t> stallDurations;
int64_t maxFrameDuration = 0;
int32_t maxFps = std::numeric_limits<int32_t>::min();
int32_t minFps = std::numeric_limits<int32_t>::max();
std::set<int32_t> framerates;
std::array<int, /*size*/3> halFormats{{
HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_YCbCr_420_888,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
for (const auto& supportedFormat : mSupportedFormats) {
for (const auto& format : halFormats) {
streamConfigurations.push_back(format);
streamConfigurations.push_back(supportedFormat.width);
streamConfigurations.push_back(supportedFormat.height);
streamConfigurations.push_back(
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
}
int64_t min_frame_duration = std::numeric_limits<int64_t>::max();
for (const auto& frameRate : supportedFormat.frameRates) {
int64_t frame_duration = 1000000000LL / frameRate;
if (frame_duration < min_frame_duration) {
min_frame_duration = frame_duration;
}
if (frame_duration > maxFrameDuration) {
maxFrameDuration = frame_duration;
}
int32_t frameRateInt = static_cast<int32_t>(frameRate);
if (minFps > frameRateInt) {
minFps = frameRateInt;
}
if (maxFps < frameRateInt) {
maxFps = frameRateInt;
}
framerates.insert(frameRateInt);
}
for (const auto& format : halFormats) {
minFrameDurations.push_back(format);
minFrameDurations.push_back(supportedFormat.width);
minFrameDurations.push_back(supportedFormat.height);
minFrameDurations.push_back(min_frame_duration);
}
// The stall duration is 0 for non-jpeg formats. For JPEG format, stall
// duration can be 0 if JPEG is small. Here we choose 1 sec for JPEG.
// TODO: b/72261675. Maybe set this dynamically
for (const auto& format : halFormats) {
const int64_t NS_TO_SECOND = 1000000000;
int64_t stall_duration =
(format == HAL_PIXEL_FORMAT_BLOB) ? NS_TO_SECOND : 0;
stallDurations.push_back(format);
stallDurations.push_back(supportedFormat.width);
stallDurations.push_back(supportedFormat.height);
stallDurations.push_back(stall_duration);
}
}
// The document in aeAvailableTargetFpsRanges section says the minFps should
// not be larger than 15.
// We cannot support fixed 30fps but Android requires (min, max) and
// (max, max) ranges.
// TODO: populate more, right now this does not support 30,30 if the device
// has higher than 30 fps modes
std::vector<int32_t> fpsRanges;
// Variable range
fpsRanges.push_back(minFps);
fpsRanges.push_back(maxFps);
// Fixed ranges
for (const auto& framerate : framerates) {
fpsRanges.push_back(framerate);
fpsRanges.push_back(framerate);
}
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(),
fpsRanges.size());
UPDATE(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
streamConfigurations.data(), streamConfigurations.size());
UPDATE(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
minFrameDurations.data(), minFrameDurations.size());
UPDATE(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, stallDurations.data(),
stallDurations.size());
UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
SupportedV4L2Format maximumFormat {.width = 0, .height = 0};
for (const auto& supportedFormat : mSupportedFormats) {
if (supportedFormat.width >= maximumFormat.width &&
supportedFormat.height >= maximumFormat.height) {
maximumFormat = supportedFormat;
}
}
int32_t activeArraySize[] = {0, 0,
static_cast<int32_t>(maximumFormat.width),
static_cast<int32_t>(maximumFormat.height)};
UPDATE(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
activeArraySize, ARRAY_SIZE(activeArraySize));
UPDATE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArraySize,
ARRAY_SIZE(activeArraySize));
int32_t pixelArraySize[] = {static_cast<int32_t>(maximumFormat.width),
static_cast<int32_t>(maximumFormat.height)};
UPDATE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize,
ARRAY_SIZE(pixelArraySize));
return OK;
}
#undef ARRAY_SIZE
#undef UPDATE
void ExternalCameraDevice::getFrameRateList(
int fd, SupportedV4L2Format* format) {
format->frameRates.clear();
v4l2_frmivalenum frameInterval {
.pixel_format = format->fourcc,
.width = format->width,
.height = format->height,
.index = 0
};
for (frameInterval.index = 0;
TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) == 0;
++frameInterval.index) {
if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
if (frameInterval.discrete.numerator != 0) {
float framerate = frameInterval.discrete.denominator /
static_cast<float>(frameInterval.discrete.numerator);
ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
frameInterval.index,
frameInterval.pixel_format & 0xFF,
(frameInterval.pixel_format >> 8) & 0xFF,
(frameInterval.pixel_format >> 16) & 0xFF,
(frameInterval.pixel_format >> 24) & 0xFF,
frameInterval.width, frameInterval.height, framerate);
format->frameRates.push_back(framerate);
}
}
}
if (format->frameRates.empty()) {
ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d",
__FUNCTION__,
frameInterval.pixel_format & 0xFF,
(frameInterval.pixel_format >> 8) & 0xFF,
(frameInterval.pixel_format >> 16) & 0xFF,
(frameInterval.pixel_format >> 24) & 0xFF,
frameInterval.width, frameInterval.height);
}
}
void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
struct v4l2_fmtdesc fmtdesc {
.index = 0,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
int ret = 0;
while (ret == 0) {
ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
ALOGD("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
fmtdesc.pixelformat & 0xFF,
(fmtdesc.pixelformat >> 8) & 0xFF,
(fmtdesc.pixelformat >> 16) & 0xFF,
(fmtdesc.pixelformat >> 24) & 0xFF);
if (ret == 0 && !(fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
auto it = std::find (
kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
if (it != kSupportedFourCCs.end()) {
// Found supported format
v4l2_frmsizeenum frameSize {
.index = 0,
.pixel_format = fmtdesc.pixelformat};
for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
++frameSize.index) {
if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
ALOGD("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
fmtdesc.pixelformat & 0xFF,
(fmtdesc.pixelformat >> 8) & 0xFF,
(fmtdesc.pixelformat >> 16) & 0xFF,
(fmtdesc.pixelformat >> 24) & 0xFF,
frameSize.discrete.width, frameSize.discrete.height);
// Disregard h > w formats so all aspect ratio (h/w) <= 1.0
// This will simplify the crop/scaling logic down the road
if (frameSize.discrete.height > frameSize.discrete.width) {
continue;
}
SupportedV4L2Format format {
.width = frameSize.discrete.width,
.height = frameSize.discrete.height,
.fourcc = fmtdesc.pixelformat
};
getFrameRateList(fd, &format);
if (!format.frameRates.empty()) {
mSupportedFormats.push_back(format);
}
}
}
}
}
fmtdesc.index++;
}
}
} // namespace implementation
} // namespace V3_4
} // namespace device
} // namespace camera
} // namespace hardware
} // namespace android

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,441 @@
/*
* Copyright (C) 2018 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <fmq/MessageQueue.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <include/convert.h>
#include <chrono>
#include <condition_variable>
#include <list>
#include <unordered_map>
#include <unordered_set>
#include "CameraMetadata.h"
#include "HandleImporter.h"
#include "utils/KeyedVector.h"
#include "utils/Mutex.h"
#include "utils/Thread.h"
#include "android-base/unique_fd.h"
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V3_4 {
namespace implementation {
using ::android::hardware::camera::device::V3_2::BufferCache;
using ::android::hardware::camera::device::V3_2::BufferStatus;
using ::android::hardware::camera::device::V3_2::CameraMetadata;
using ::android::hardware::camera::device::V3_2::CaptureRequest;
using ::android::hardware::camera::device::V3_2::CaptureResult;
using ::android::hardware::camera::device::V3_2::ErrorCode;
using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
using ::android::hardware::camera::device::V3_2::MsgType;
using ::android::hardware::camera::device::V3_2::NotifyMsg;
using ::android::hardware::camera::device::V3_2::RequestTemplate;
using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::camera::device::V3_4::StreamConfiguration;
using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
using ::android::hardware::camera::device::V3_2::StreamRotation;
using ::android::hardware::camera::device::V3_2::StreamType;
using ::android::hardware::camera::device::V3_2::DataspaceFlags;
using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::MessageQueue;
using ::android::hardware::MQDescriptorSync;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
using ::android::Mutex;
using ::android::base::unique_fd;
// TODO: put V4L2 related structs into separate header?
struct SupportedV4L2Format {
uint32_t width;
uint32_t height;
uint32_t fourcc;
// All supported frame rate for this w/h/fourcc combination
std::vector<float> frameRates;
};
// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
class V4L2Frame : public virtual VirtualLightRefBase {
public:
V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize);
~V4L2Frame() override;
const uint32_t mWidth;
const uint32_t mHeight;
const uint32_t mFourcc;
const int mBufferIndex; // for later enqueue
int map(uint8_t** data, size_t* dataSize);
int unmap();
private:
Mutex mLock;
const int mFd; // used for mmap but doesn't claim ownership
const size_t mDataSize;
uint8_t* mData = nullptr;
bool mMapped = false;
};
// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
// when generating output images.
class AllocatedFrame : public virtual VirtualLightRefBase {
public:
AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
~AllocatedFrame() override;
const uint32_t mWidth;
const uint32_t mHeight;
const uint32_t mFourcc; // Only support YU12 format for now
int allocate(YCbCrLayout* out = nullptr);
int getLayout(YCbCrLayout* out);
int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
private:
Mutex mLock;
std::vector<uint8_t> mData;
};
struct Size {
uint32_t width;
uint32_t height;
bool operator==(const Size& other) const {
return (width == other.width && height == other.height);
}
};
struct SizeHasher {
size_t operator()(const Size& sz) const {
size_t result = 1;
result = 31 * result + sz.width;
result = 31 * result + sz.height;
return result;
}
};
enum CroppingType {
HORIZONTAL = 0,
VERTICAL = 1
};
struct ExternalCameraDeviceSession : public virtual RefBase {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
const std::vector<SupportedV4L2Format>& supportedFormats,
const common::V1_0::helper::CameraMetadata& chars,
unique_fd v4l2Fd);
virtual ~ExternalCameraDeviceSession();
// Call by CameraDevice to dump active device states
void dumpState(const native_handle_t*);
// Caller must use this method to check if CameraDeviceSession ctor failed
bool isInitFailed() { return mInitFail; }
bool isClosed();
// Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
// dealing with minor version revs and simultaneous implementation and interface inheritance
virtual sp<ICameraDeviceSession> getInterface() {
return new TrampolineSessionInterface_3_4(this);
}
static const int kMaxProcessedStream = 2;
static const int kMaxStallStream = 1;
protected:
// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
Return<void> constructDefaultRequestSettings(
RequestTemplate,
ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb);
Return<void> configureStreams(
const V3_2::StreamConfiguration&,
ICameraDeviceSession::configureStreams_cb);
Return<void> getCaptureRequestMetadataQueue(
ICameraDeviceSession::getCaptureRequestMetadataQueue_cb);
Return<void> getCaptureResultMetadataQueue(
ICameraDeviceSession::getCaptureResultMetadataQueue_cb);
Return<void> processCaptureRequest(
const hidl_vec<CaptureRequest>&,
const hidl_vec<BufferCache>&,
ICameraDeviceSession::processCaptureRequest_cb);
Return<Status> flush();
Return<void> close();
Return<void> configureStreams_3_3(
const V3_2::StreamConfiguration&,
ICameraDeviceSession::configureStreams_3_3_cb);
Return<void> configureStreams_3_4(
const V3_4::StreamConfiguration& requestedConfiguration,
ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb);
Return<void> processCaptureRequest_3_4(
const hidl_vec<V3_4::CaptureRequest>& requests,
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
protected:
struct HalStreamBuffer {
int32_t streamId;
uint64_t bufferId;
uint32_t width;
uint32_t height;
PixelFormat format;
V3_2::BufferUsageFlags usage;
buffer_handle_t* bufPtr;
int acquireFence;
bool fenceTimeout;
};
struct HalRequest {
uint32_t frameNumber;
common::V1_0::helper::CameraMetadata setting;
sp<V4L2Frame> frameIn;
nsecs_t shutterTs;
std::vector<HalStreamBuffer> buffers;
};
static std::vector<SupportedV4L2Format> sortFormats(
const std::vector<SupportedV4L2Format>&);
static CroppingType initCroppingType(const std::vector<SupportedV4L2Format>&);
bool initialize();
Status initStatus() const;
status_t initDefaultRequests();
status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out);
int configureV4l2StreamLocked(const SupportedV4L2Format& fmt);
int v4l2StreamOffLocked();
// TODO: change to unique_ptr for better tracking
sp<V4L2Frame> dequeueV4l2FrameLocked(); // Called with mLock hold
void enqueueV4l2Frame(const sp<V4L2Frame>&);
// Check if input Stream is one of supported stream setting on this device
bool isSupported(const Stream&);
// Validate and import request's output buffers and acquire fence
Status importRequest(
const CaptureRequest& request,
hidl_vec<buffer_handle_t*>& allBufPtrs,
hidl_vec<int>& allFences);
static void cleanupInflightFences(
hidl_vec<int>& allFences, size_t numFences);
void cleanupBuffersLocked(int id);
void updateBufferCaches(const hidl_vec<BufferCache>& cachesToRemove);
Status processOneCaptureRequest(const CaptureRequest& request);
Status processCaptureResult(HalRequest&);
Status processCaptureRequestError(HalRequest&);
void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
void invokeProcessCaptureResultCallback(
hidl_vec<CaptureResult> &results, bool tryWriteFmq);
static void freeReleaseFences(hidl_vec<CaptureResult>&);
class OutputThread : public android::Thread {
public:
OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
~OutputThread();
Status allocateIntermediateBuffers(
const Size& v4lSize, const hidl_vec<Stream>& streams);
Status submitRequest(const HalRequest&);
void flush();
virtual bool threadLoop() override;
private:
static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
static_cast<uint32_t>('X') << 24;
// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
static uint32_t getFourCcFromLayout(const YCbCrLayout&);
static int getCropRect(
CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
static const int kReqWaitTimeoutSec = 3;
void waitForNextRequest(HalRequest* out);
int cropAndScaleLocked(
sp<AllocatedFrame>& in, const HalStreamBuffer& halBuf,
YCbCrLayout* out);
int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
Size sz, uint32_t format);
mutable std::mutex mLock;
std::condition_variable mRequestCond;
wp<ExternalCameraDeviceSession> mParent;
CroppingType mCroppingType;
std::list<HalRequest> mRequestList;
// V4L2 frameIn
// (MJPG decode)-> mYu12Frame
// (Scale)-> mScaledYu12Frames
// (Format convert) -> output gralloc frames
sp<AllocatedFrame> mYu12Frame;
std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
YCbCrLayout mYu12FrameLayout;
};
// Protect (most of) HIDL interface methods from synchronized-entering
mutable Mutex mInterfaceLock;
mutable Mutex mLock; // Protect all private members except otherwise noted
const sp<ICameraDeviceCallback> mCallback;
const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
unique_fd mV4l2Fd;
// device is closed either
// - closed by user
// - init failed
// - camera disconnected
bool mClosed = false;
bool mInitFail = false;
bool mFirstRequest = false;
common::V1_0::helper::CameraMetadata mLatestReqSetting;
bool mV4l2Streaming = false;
SupportedV4L2Format mV4l2StreamingFmt;
std::vector<unique_fd> mV4l2Buffers;
static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
std::mutex mV4l2BufferLock; // protect the buffer count and condition below
std::condition_variable mV4L2BufferReturned;
size_t mNumDequeuedV4l2Buffers = 0;
const std::vector<SupportedV4L2Format> mSupportedFormats;
const CroppingType mCroppingType;
sp<OutputThread> mOutputThread;
// Stream ID -> Camera3Stream cache
std::unordered_map<int, Stream> mStreamMap;
std::unordered_set<uint32_t> mInflightFrames;
// buffers currently circulating between HAL and camera service
// key: bufferId sent via HIDL interface
// value: imported buffer_handle_t
// Buffer will be imported during processCaptureRequest and will be freed
// when the its stream is deleted or camera device session is closed
typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
// Stream ID -> circulating buffers map
std::map<int, CirculatingBuffers> mCirculatingBuffers;
static HandleImporter sHandleImporter;
/* Beginning of members not changed after initialize() */
using RequestMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue;
using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
// Protect against invokeProcessCaptureResultCallback()
Mutex mProcessCaptureResultLock;
std::unordered_map<int, CameraMetadata> mDefaultRequests;
/* End of members not changed after initialize() */
private:
struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
TrampolineSessionInterface_3_4(sp<ExternalCameraDeviceSession> parent) :
mParent(parent) {}
virtual Return<void> constructDefaultRequestSettings(
V3_2::RequestTemplate type,
V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
return mParent->constructDefaultRequestSettings(type, _hidl_cb);
}
virtual Return<void> configureStreams(
const V3_2::StreamConfiguration& requestedConfiguration,
V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
return mParent->configureStreams(requestedConfiguration, _hidl_cb);
}
virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
}
virtual Return<void> getCaptureRequestMetadataQueue(
V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override {
return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
}
virtual Return<void> getCaptureResultMetadataQueue(
V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
return mParent->getCaptureResultMetadataQueue(_hidl_cb);
}
virtual Return<Status> flush() override {
return mParent->flush();
}
virtual Return<void> close() override {
return mParent->close();
}
virtual Return<void> configureStreams_3_3(
const V3_2::StreamConfiguration& requestedConfiguration,
configureStreams_3_3_cb _hidl_cb) override {
return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
}
virtual Return<void> configureStreams_3_4(
const V3_4::StreamConfiguration& requestedConfiguration,
configureStreams_3_4_cb _hidl_cb) override {
return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
}
virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
}
private:
sp<ExternalCameraDeviceSession> mParent;
};
};
} // namespace implementation
} // namespace V3_4
} // namespace device
} // namespace camera
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2018 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 ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H
#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H
#include "utils/Mutex.h"
#include "CameraMetadata.h"
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
#include "ExternalCameraDeviceSession.h"
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V3_4 {
namespace implementation {
using namespace ::android::hardware::camera::device;
using ::android::hardware::camera::device::V3_2::ICameraDevice;
using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
using ::android::hardware::camera::common::V1_0::CameraResourceCost;
using ::android::hardware::camera::common::V1_0::TorchMode;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
/*
* The camera device HAL implementation is opened lazily (via the open call)
*/
struct ExternalCameraDevice : public ICameraDevice {
// Called by external camera provider HAL.
// Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
// be multiple CameraDevice trying to access the same physical camera. Also, provider will have
// to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
// camera is detached.
ExternalCameraDevice(const std::string& cameraId);
~ExternalCameraDevice();
// Caller must use this method to check if CameraDevice ctor failed
bool isInitFailed();
/* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
// The following method can be called without opening the actual camera device
Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
Return<Status> setTorchMode(TorchMode) override;
// Open the device HAL and also return a default capture session
Return<void> open(const sp<ICameraDeviceCallback>&, open_cb) override;
// Forward the dump call to the opened session, or do nothing
Return<void> dumpState(const ::android::hardware::hidl_handle&) override;
/* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
protected:
void getFrameRateList(int fd, SupportedV4L2Format* format);
// Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
void initSupportedFormatsLocked(int fd);
status_t initCameraCharacteristics();
// Init non-device dependent keys
status_t initDefaultCharsKeys(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
// Init camera control chars keys. Caller still owns fd
status_t initCameraControlsCharsKeys(int fd,
::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
// Init camera output configuration related keys. Caller still owns fd
status_t initOutputCharsKeys(int fd,
::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
Mutex mLock;
bool mInitFailed = false;
std::string mCameraId;
std::vector<SupportedV4L2Format> mSupportedFormats;
wp<ExternalCameraDeviceSession> mSession = nullptr;
::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics;
};
} // namespace implementation
} // namespace V3_4
} // namespace device
} // namespace camera
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H

View File

@@ -3,7 +3,8 @@ cc_library_shared {
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["CameraProvider.cpp"],
srcs: ["CameraProvider.cpp",
"ExternalCameraProvider.cpp"],
shared_libs: [
"libhidlbase",
"libhidltransport",
@@ -17,6 +18,7 @@ cc_library_shared {
"camera.device@3.2-impl",
"camera.device@3.3-impl",
"camera.device@3.4-impl",
"camera.device@3.4-external-impl",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.common@1.0",
"android.hardware.graphics.mapper@2.0",
@@ -28,6 +30,7 @@ cc_library_shared {
],
header_libs: [
"camera.device@3.4-impl_headers",
"camera.device@3.4-external-impl_headers"
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
@@ -56,3 +59,25 @@ cc_binary {
"android.hardware.camera.common@1.0",
],
}
cc_binary {
name: "android.hardware.camera.provider@2.4-external-service",
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["external-service.cpp"],
compile_multilib: "32",
init_rc: ["android.hardware.camera.provider@2.4-external-service.rc"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libbinder",
"liblog",
"libutils",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.common@1.0",
],
}

View File

@@ -19,6 +19,7 @@
#include <android/log.h>
#include "CameraProvider.h"
#include "ExternalCameraProvider.h"
#include "CameraDevice_1_0.h"
#include "CameraDevice_3_3.h"
#include "CameraDevice_3_4.h"
@@ -36,6 +37,7 @@ namespace implementation {
namespace {
const char *kLegacyProviderName = "legacy/0";
const char *kExternalProviderName = "external/0";
// "device@<version>/legacy/<id>"
const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
const char *kHAL3_2 = "3.2";
@@ -571,20 +573,24 @@ Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
}
ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
if (strcmp(name, kLegacyProviderName) != 0) {
return nullptr;
if (strcmp(name, kLegacyProviderName) == 0) {
CameraProvider* provider = new CameraProvider();
if (provider == nullptr) {
ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
return nullptr;
}
if (provider->isInitFailed()) {
ALOGE("%s: camera provider init failed!", __FUNCTION__);
delete provider;
return nullptr;
}
return provider;
} else if (strcmp(name, kExternalProviderName) == 0) {
ExternalCameraProvider* provider = new ExternalCameraProvider();
return provider;
}
CameraProvider* provider = new CameraProvider();
if (provider == nullptr) {
ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
return nullptr;
}
if (provider->isInitFailed()) {
ALOGE("%s: camera provider init failed!", __FUNCTION__);
delete provider;
return nullptr;
}
return provider;
ALOGE("%s: unknown instance name: %s", __FUNCTION__, name);
return nullptr;
}
} // namespace implementation

View File

@@ -0,0 +1,276 @@
/*
* Copyright (C) 2018 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.
*/
#define LOG_TAG "CamPvdr@2.4-external"
//#define LOG_NDEBUG 0
#include <log/log.h>
#include <regex>
#include <sys/inotify.h>
#include <errno.h>
#include <linux/videodev2.h>
#include "ExternalCameraProvider.h"
#include "ExternalCameraDevice_3_4.h"
namespace android {
namespace hardware {
namespace camera {
namespace provider {
namespace V2_4 {
namespace implementation {
namespace {
// "device@<version>/external/<id>"
const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
const int kMaxDevicePathLen = 256;
const char* kDevicePath = "/dev/";
bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
std::string* cameraId) {
std::string deviceNameStd(deviceName.c_str());
std::smatch sm;
if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
if (deviceVersion != nullptr) {
*deviceVersion = sm[1];
}
if (cameraId != nullptr) {
*cameraId = sm[2];
}
return true;
}
return false;
}
} // anonymous namespace
ExternalCameraProvider::ExternalCameraProvider() : mHotPlugThread(this) {
mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
}
ExternalCameraProvider::~ExternalCameraProvider() {
mHotPlugThread.requestExit();
}
Return<Status> ExternalCameraProvider::setCallback(
const sp<ICameraProviderCallback>& callback) {
Mutex::Autolock _l(mLock);
mCallbacks = callback;
return Status::OK;
}
Return<void> ExternalCameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
// No vendor tag support for USB camera
hidl_vec<VendorTagSection> zeroSections;
_hidl_cb(Status::OK, zeroSections);
return Void();
}
Return<void> ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
std::vector<hidl_string> deviceNameList;
for (auto const& kvPair : mCameraStatusMap) {
if (kvPair.second == CameraDeviceStatus::PRESENT) {
deviceNameList.push_back(kvPair.first);
}
}
hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
ALOGV("ExtCam: number of cameras is %zu", deviceNameList.size());
_hidl_cb(Status::OK, hidlDeviceNameList);
return Void();
}
Return<void> ExternalCameraProvider::isSetTorchModeSupported(
isSetTorchModeSupported_cb _hidl_cb) {
// No torch mode support for USB camera
_hidl_cb (Status::OK, false);
return Void();
}
Return<void> ExternalCameraProvider::getCameraDeviceInterface_V1_x(
const hidl_string&,
getCameraDeviceInterface_V1_x_cb _hidl_cb) {
// External Camera HAL does not support HAL1
_hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr);
return Void();
}
Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x(
const hidl_string& cameraDeviceName,
getCameraDeviceInterface_V3_x_cb _hidl_cb) {
std::string cameraId, deviceVersion;
bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
if (!match) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
}
if (mCameraStatusMap.count(cameraDeviceName) == 0 ||
mCameraStatusMap[cameraDeviceName] != CameraDeviceStatus::PRESENT) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
}
ALOGV("Constructing v3.4 external camera device");
sp<device::V3_2::ICameraDevice> device;
sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
new device::V3_4::implementation::ExternalCameraDevice(
cameraId);
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
device = nullptr;
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
device = deviceImpl;
_hidl_cb (Status::OK, device);
return Void();
}
void ExternalCameraProvider::addExternalCamera(const char* devName) {
ALOGE("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName = std::string("device@3.4/external/") + devName;
mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
if (mCallbacks != nullptr) {
mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
}
}
void ExternalCameraProvider::deviceAdded(const char* devName) {
int fd = -1;
if ((fd = ::open(devName, O_RDWR)) < 0) {
ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
return;
}
do {
struct v4l2_capability capability;
int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);
if (ret < 0) {
ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
break;
}
if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
break;
}
addExternalCamera(devName);
} while (0);
close(fd);
return;
}
void ExternalCameraProvider::deviceRemoved(const char* devName) {
Mutex::Autolock _l(mLock);
std::string deviceName = std::string("device@3.4/external/") + devName;
if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
mCameraStatusMap.erase(deviceName);
if (mCallbacks != nullptr) {
mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
}
} else {
ALOGE("%s: cannot find camera device %s", __FUNCTION__, devName);
}
}
ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
Thread(/*canCallJava*/false), mParent(parent) {}
ExternalCameraProvider::HotplugThread::~HotplugThread() {}
bool ExternalCameraProvider::HotplugThread::threadLoop() {
// Find existing /dev/video* devices
DIR* devdir = opendir(kDevicePath);
if(devdir == 0) {
ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
return false;
}
struct dirent* de;
// This list is device dependent. TODO: b/72261897 allow setting it from setprop/device boot
std::string internalDevices = "0,1";
while ((de = readdir(devdir)) != 0) {
// Find external v4l devices that's existing before we start watching and add them
if (!strncmp("video", de->d_name, 5)) {
// TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
// is added.
if (internalDevices.find(de->d_name + 5) == std::string::npos) {
ALOGV("Non-internal v4l device %s found", de->d_name);
char v4l2DevicePath[kMaxDevicePathLen];
snprintf(v4l2DevicePath, kMaxDevicePathLen,
"%s%s", kDevicePath, de->d_name);
mParent->deviceAdded(v4l2DevicePath);
}
}
}
closedir(devdir);
// Watch new video devices
mINotifyFD = inotify_init();
if (mINotifyFD < 0) {
ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
return true;
}
mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
if (mWd < 0) {
ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
return true;
}
ALOGI("%s start monitoring new V4L2 devices", __FUNCTION__);
bool done = false;
char eventBuf[512];
while (!done) {
int offset = 0;
int ret = read(mINotifyFD, eventBuf, sizeof(eventBuf));
if (ret >= (int)sizeof(struct inotify_event)) {
while (offset < ret) {
struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
if (event->wd == mWd) {
if (!strncmp("video", event->name, 5)) {
char v4l2DevicePath[kMaxDevicePathLen];
snprintf(v4l2DevicePath, kMaxDevicePathLen,
"%s%s", kDevicePath, event->name);
if (event->mask & IN_CREATE) {
mParent->deviceAdded(v4l2DevicePath);
}
if (event->mask & IN_DELETE) {
mParent->deviceRemoved(v4l2DevicePath);
}
}
}
offset += sizeof(struct inotify_event) + event->len;
}
}
}
return true;
}
} // namespace implementation
} // namespace V2_4
} // namespace provider
} // namespace camera
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 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 ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
#include <unordered_map>
#include "utils/Mutex.h"
#include "utils/Thread.h"
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
namespace android {
namespace hardware {
namespace camera {
namespace provider {
namespace V2_4 {
namespace implementation {
using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::VendorTagSection;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
using ::android::Mutex;
struct ExternalCameraProvider : public ICameraProvider {
ExternalCameraProvider();
~ExternalCameraProvider();
// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override;
Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override;
Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override;
Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override;
Return<void> getCameraDeviceInterface_V1_x(
const hidl_string&,
getCameraDeviceInterface_V1_x_cb) override;
Return<void> getCameraDeviceInterface_V3_x(
const hidl_string&,
getCameraDeviceInterface_V3_x_cb) override;
private:
void addExternalCamera(const char* devName);
void deviceAdded(const char* devName);
void deviceRemoved(const char* devName);
class HotplugThread : public android::Thread {
public:
HotplugThread(ExternalCameraProvider* parent);
~HotplugThread();
virtual bool threadLoop() override;
private:
ExternalCameraProvider* mParent = nullptr;
int mINotifyFD = -1;
int mWd = -1;
} mHotPlugThread;
Mutex mLock;
sp<ICameraProviderCallback> mCallbacks = nullptr;
std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
};
} // namespace implementation
} // namespace V2_4
} // namespace provider
} // namespace camera
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H

View File

@@ -0,0 +1,7 @@
service vendor.camera-provider-2-4-ext /vendor/bin/hw/android.hardware.camera.provider@2.4-external-service
class hal
user cameraserver
group audio camera input drmrpc usb
ioprio rt 4
capabilities SYS_NICE
writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2018 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.
*/
#define LOG_TAG "android.hardware.camera.provider@2.4-external-service"
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <hidl/LegacySupport.h>
#include <binder/ProcessState.h>
using android::hardware::camera::provider::V2_4::ICameraProvider;
using android::hardware::defaultPassthroughServiceImplementation;
int main()
{
ALOGI("External camera provider service is starting.");
// The camera HAL may communicate to other vendor components via
// /dev/vndbinder
android::ProcessState::initWithDriver("/dev/vndbinder");
return defaultPassthroughServiceImplementation<ICameraProvider>("external/0", /*maxThreads*/ 6);
}