You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1022 lines
36 KiB
1022 lines
36 KiB
/* |
|
* Copyright (C) 2017 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 "CamDev@1.0-impl" |
|
#include <hardware/camera.h> |
|
#include <hardware/gralloc1.h> |
|
#include <hidlmemory/mapping.h> |
|
#include <log/log.h> |
|
#include <utils/Trace.h> |
|
|
|
#include <media/hardware/HardwareAPI.h> // For VideoNativeHandleMetadata |
|
#include "CameraDevice_1_0.h" |
|
|
|
namespace android { |
|
namespace hardware { |
|
namespace camera { |
|
namespace device { |
|
namespace V1_0 { |
|
namespace implementation { |
|
|
|
using ::android::hardware::graphics::common::V1_0::BufferUsage; |
|
using ::android::hardware::graphics::common::V1_0::PixelFormat; |
|
|
|
HandleImporter CameraDevice::sHandleImporter; |
|
|
|
Status CameraDevice::getHidlStatus(const int& status) { |
|
switch (status) { |
|
case 0: return Status::OK; |
|
case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED; |
|
case -EBUSY : return Status::CAMERA_IN_USE; |
|
case -EUSERS: return Status::MAX_CAMERAS_IN_USE; |
|
case -ENODEV: return Status::INTERNAL_ERROR; |
|
case -EINVAL: return Status::ILLEGAL_ARGUMENT; |
|
default: |
|
ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status); |
|
return Status::INTERNAL_ERROR; |
|
} |
|
} |
|
|
|
status_t CameraDevice::getStatusT(const Status& s) { |
|
switch(s) { |
|
case Status::OK: |
|
return OK; |
|
case Status::ILLEGAL_ARGUMENT: |
|
return BAD_VALUE; |
|
case Status::CAMERA_IN_USE: |
|
return -EBUSY; |
|
case Status::MAX_CAMERAS_IN_USE: |
|
return -EUSERS; |
|
case Status::METHOD_NOT_SUPPORTED: |
|
return UNKNOWN_TRANSACTION; |
|
case Status::OPERATION_NOT_SUPPORTED: |
|
return INVALID_OPERATION; |
|
case Status::CAMERA_DISCONNECTED: |
|
return DEAD_OBJECT; |
|
case Status::INTERNAL_ERROR: |
|
return INVALID_OPERATION; |
|
} |
|
ALOGW("Unexpected HAL status code %d", s); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
Status CameraDevice::initStatus() const { |
|
Mutex::Autolock _l(mLock); |
|
Status status = Status::OK; |
|
if (mInitFail) { |
|
status = Status::INTERNAL_ERROR; |
|
} else if (mDisconnected) { |
|
status = Status::CAMERA_DISCONNECTED; |
|
} |
|
return status; |
|
} |
|
|
|
CameraDevice::CameraDevice( |
|
sp<CameraModule> module, const std::string& cameraId, |
|
const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) : |
|
mModule(module), |
|
mCameraId(cameraId), |
|
mDisconnected(false), |
|
mCameraDeviceNames(cameraDeviceNames) { |
|
mCameraIdInt = atoi(mCameraId.c_str()); |
|
// Should not reach here as provider also validate ID |
|
if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) { |
|
ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str()); |
|
mInitFail = true; |
|
} |
|
|
|
mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt); |
|
if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && !mModule->isOpenLegacyDefined()) { |
|
ALOGI("%s: Camera id %s does not support HAL1.0", |
|
__FUNCTION__, mCameraId.c_str()); |
|
mInitFail = true; |
|
} |
|
|
|
mAshmemAllocator = IAllocator::getService("ashmem"); |
|
if (mAshmemAllocator == nullptr) { |
|
ALOGI("%s: cannot get ashmemAllocator", __FUNCTION__); |
|
mInitFail = true; |
|
} |
|
} |
|
|
|
CameraDevice::~CameraDevice() { |
|
Mutex::Autolock _l(mLock); |
|
if (mDevice != nullptr) { |
|
ALOGW("%s: camera %s is deleted while open", __FUNCTION__, mCameraId.c_str()); |
|
closeLocked(); |
|
} |
|
mHalPreviewWindow.cleanUpCirculatingBuffers(); |
|
} |
|
|
|
|
|
void CameraDevice::setConnectionStatus(bool connected) { |
|
Mutex::Autolock _l(mLock); |
|
mDisconnected = !connected; |
|
if (mDevice == nullptr) { |
|
return; |
|
} |
|
if (!connected) { |
|
ALOGW("%s: camera %s is disconneted. Closing", __FUNCTION__, mCameraId.c_str()); |
|
closeLocked(); |
|
} |
|
return; |
|
} |
|
|
|
void CameraDevice::CameraPreviewWindow::cleanUpCirculatingBuffers() { |
|
Mutex::Autolock _l(mLock); |
|
for (auto pair : mCirculatingBuffers) { |
|
sHandleImporter.freeBuffer(pair.second); |
|
} |
|
mCirculatingBuffers.clear(); |
|
mBufferIdMap.clear(); |
|
} |
|
|
|
int CameraDevice::sDequeueBuffer(struct preview_stream_ops* w, |
|
buffer_handle_t** buffer, int *stride) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
if (buffer == nullptr || stride == nullptr) { |
|
ALOGE("%s: buffer (%p) and stride (%p) must not be null!", __FUNCTION__, buffer, stride); |
|
return BAD_VALUE; |
|
} |
|
|
|
Status s; |
|
object->mPreviewCallback->dequeueBuffer( |
|
[&](auto status, uint64_t bufferId, const auto& buf, uint32_t strd) { |
|
s = status; |
|
if (s == Status::OK) { |
|
Mutex::Autolock _l(object->mLock); |
|
if (object->mCirculatingBuffers.count(bufferId) == 0) { |
|
buffer_handle_t importedBuf = buf.getNativeHandle(); |
|
sHandleImporter.importBuffer(importedBuf); |
|
if (importedBuf == nullptr) { |
|
ALOGE("%s: preview buffer import failed!", __FUNCTION__); |
|
s = Status::INTERNAL_ERROR; |
|
return; |
|
} else { |
|
object->mCirculatingBuffers[bufferId] = importedBuf; |
|
object->mBufferIdMap[&(object->mCirculatingBuffers[bufferId])] = bufferId; |
|
} |
|
} |
|
*buffer = &(object->mCirculatingBuffers[bufferId]); |
|
*stride = strd; |
|
} |
|
}); |
|
return getStatusT(s); |
|
} |
|
|
|
int CameraDevice::sLockBuffer(struct preview_stream_ops*, buffer_handle_t*) { |
|
return 0; |
|
} |
|
|
|
int CameraDevice::sEnqueueBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
uint64_t bufferId = object->mBufferIdMap.at(buffer); |
|
return getStatusT(object->mPreviewCallback->enqueueBuffer(bufferId)); |
|
} |
|
|
|
int CameraDevice::sCancelBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
uint64_t bufferId = object->mBufferIdMap.at(buffer); |
|
return getStatusT(object->mPreviewCallback->cancelBuffer(bufferId)); |
|
} |
|
|
|
int CameraDevice::sSetBufferCount(struct preview_stream_ops* w, int count) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
object->cleanUpCirculatingBuffers(); |
|
return getStatusT(object->mPreviewCallback->setBufferCount(count)); |
|
} |
|
|
|
int CameraDevice::sSetBuffersGeometry(struct preview_stream_ops* w, |
|
int width, int height, int format) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
object->cleanUpCirculatingBuffers(); |
|
return getStatusT( |
|
object->mPreviewCallback->setBuffersGeometry(width, height, (PixelFormat) format)); |
|
} |
|
|
|
int CameraDevice::sSetCrop(struct preview_stream_ops *w, |
|
int left, int top, int right, int bottom) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
return getStatusT(object->mPreviewCallback->setCrop(left, top, right, bottom)); |
|
} |
|
|
|
int CameraDevice::sSetTimestamp(struct preview_stream_ops *w, int64_t timestamp) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
return getStatusT(object->mPreviewCallback->setTimestamp(timestamp)); |
|
} |
|
|
|
int CameraDevice::sSetUsage(struct preview_stream_ops* w, int usage) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
object->cleanUpCirculatingBuffers(); |
|
return getStatusT(object->mPreviewCallback->setUsage((BufferUsage)usage)); |
|
} |
|
|
|
int CameraDevice::sSetSwapInterval(struct preview_stream_ops *w, int interval) { |
|
CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
|
|
return getStatusT(object->mPreviewCallback->setSwapInterval(interval)); |
|
} |
|
|
|
int CameraDevice::sGetMinUndequeuedBufferCount( |
|
const struct preview_stream_ops *w, |
|
int *count) { |
|
const CameraPreviewWindow* object = static_cast<const CameraPreviewWindow*>(w); |
|
if (object->mPreviewCallback == nullptr) { |
|
ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); |
|
return INVALID_OPERATION; |
|
} |
|
if (count == nullptr) { |
|
ALOGE("%s: count is null!", __FUNCTION__); |
|
return BAD_VALUE; |
|
} |
|
|
|
Status s; |
|
object->mPreviewCallback->getMinUndequeuedBufferCount( |
|
[&](auto status, uint32_t cnt) { |
|
s = status; |
|
if (s == Status::OK) { |
|
*count = cnt; |
|
} |
|
}); |
|
return getStatusT(s); |
|
} |
|
|
|
CameraDevice::CameraHeapMemory::CameraHeapMemory( |
|
int fd, size_t buf_size, uint_t num_buffers) : |
|
mBufSize(buf_size), |
|
mNumBufs(num_buffers) { |
|
mHidlHandle = native_handle_create(1,0); |
|
mHidlHandle->data[0] = fcntl(fd, F_DUPFD_CLOEXEC, 0); |
|
const size_t pagesize = getpagesize(); |
|
size_t size = ((buf_size * num_buffers + pagesize-1) & ~(pagesize-1)); |
|
mHidlHeap = hidl_memory("ashmem", mHidlHandle, size); |
|
commonInitialization(); |
|
} |
|
|
|
CameraDevice::CameraHeapMemory::CameraHeapMemory( |
|
sp<IAllocator> ashmemAllocator, |
|
size_t buf_size, uint_t num_buffers) : |
|
mBufSize(buf_size), |
|
mNumBufs(num_buffers) { |
|
const size_t pagesize = getpagesize(); |
|
size_t size = ((buf_size * num_buffers + pagesize-1) & ~(pagesize-1)); |
|
ashmemAllocator->allocate(size, |
|
[&](bool success, const hidl_memory& mem) { |
|
if (!success) { |
|
ALOGE("%s: allocating ashmem of %zu bytes failed!", |
|
__FUNCTION__, buf_size * num_buffers); |
|
return; |
|
} |
|
mHidlHandle = native_handle_clone(mem.handle()); |
|
mHidlHeap = hidl_memory("ashmem", mHidlHandle, size); |
|
}); |
|
|
|
commonInitialization(); |
|
} |
|
|
|
void CameraDevice::CameraHeapMemory::commonInitialization() { |
|
mHidlHeapMemory = mapMemory(mHidlHeap); |
|
if (mHidlHeapMemory == nullptr) { |
|
ALOGE("%s: memory map failed!", __FUNCTION__); |
|
native_handle_close(mHidlHandle); // close FD for the shared memory |
|
native_handle_delete(mHidlHandle); |
|
mHidlHeap = hidl_memory(); |
|
mHidlHandle = nullptr; |
|
return; |
|
} |
|
mHidlHeapMemData = mHidlHeapMemory->getPointer(); |
|
handle.data = mHidlHeapMemData; |
|
handle.size = mBufSize * mNumBufs; |
|
handle.handle = this; |
|
handle.release = sPutMemory; |
|
} |
|
|
|
CameraDevice::CameraHeapMemory::~CameraHeapMemory() { |
|
if (mHidlHeapMemory != nullptr) { |
|
mHidlHeapMemData = nullptr; |
|
mHidlHeapMemory.clear(); // The destructor will trigger munmap |
|
} |
|
|
|
if (mHidlHandle) { |
|
native_handle_close(mHidlHandle); // close FD for the shared memory |
|
native_handle_delete(mHidlHandle); |
|
} |
|
} |
|
|
|
// shared memory methods |
|
camera_memory_t* CameraDevice::sGetMemory(int fd, size_t buf_size, uint_t num_bufs, void *user) { |
|
ALOGV("%s", __FUNCTION__); |
|
CameraDevice* object = static_cast<CameraDevice*>(user); |
|
if (object->mDeviceCallback == nullptr) { |
|
ALOGE("%s: camera HAL request memory while camera is not opened!", __FUNCTION__); |
|
return nullptr; |
|
} |
|
|
|
CameraHeapMemory* mem; |
|
if (fd < 0) { |
|
mem = new CameraHeapMemory(object->mAshmemAllocator, buf_size, num_bufs); |
|
} else { |
|
mem = new CameraHeapMemory(fd, buf_size, num_bufs); |
|
} |
|
mem->incStrong(mem); |
|
hidl_handle hidlHandle = mem->mHidlHandle; |
|
MemoryId id = object->mDeviceCallback->registerMemory(hidlHandle, buf_size, num_bufs); |
|
mem->handle.mId = id; |
|
|
|
{ |
|
Mutex::Autolock _l(object->mMemoryMapLock); |
|
if (object->mMemoryMap.count(id) != 0) { |
|
ALOGE("%s: duplicate MemoryId %d returned by client!", __FUNCTION__, id); |
|
} |
|
object->mMemoryMap[id] = mem; |
|
} |
|
mem->handle.mDevice = object; |
|
return &mem->handle; |
|
} |
|
|
|
void CameraDevice::sPutMemory(camera_memory_t *data) { |
|
if (!data) |
|
return; |
|
|
|
CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle); |
|
CameraDevice* device = mem->handle.mDevice; |
|
if (device == nullptr) { |
|
ALOGE("%s: camera HAL return memory for a null device!", __FUNCTION__); |
|
} |
|
if (device->mDeviceCallback == nullptr) { |
|
ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__); |
|
} |
|
device->mDeviceCallback->unregisterMemory(mem->handle.mId); |
|
{ |
|
Mutex::Autolock _l(device->mMemoryMapLock); |
|
device->mMemoryMap.erase(mem->handle.mId); |
|
} |
|
mem->decStrong(mem); |
|
} |
|
|
|
// Callback forwarding methods |
|
void CameraDevice::sNotifyCb(int32_t msg_type, int32_t ext1, int32_t ext2, void *user) { |
|
ALOGV("%s", __FUNCTION__); |
|
CameraDevice* object = static_cast<CameraDevice*>(user); |
|
if (object->mDeviceCallback != nullptr) { |
|
object->mDeviceCallback->notifyCallback((NotifyCallbackMsg) msg_type, ext1, ext2); |
|
} |
|
} |
|
|
|
void CameraDevice::sDataCb(int32_t msg_type, const camera_memory_t *data, unsigned int index, |
|
camera_frame_metadata_t *metadata, void *user) { |
|
ALOGV("%s", __FUNCTION__); |
|
CameraDevice* object = static_cast<CameraDevice*>(user); |
|
sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle)); |
|
if (index >= mem->mNumBufs) { |
|
ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__, |
|
index, mem->mNumBufs); |
|
return; |
|
} |
|
if (object->mDeviceCallback != nullptr) { |
|
CameraFrameMetadata hidlMetadata; |
|
if (metadata) { |
|
hidlMetadata.faces.resize(metadata->number_of_faces); |
|
for (size_t i = 0; i < hidlMetadata.faces.size(); i++) { |
|
hidlMetadata.faces[i].score = metadata->faces[i].score; |
|
hidlMetadata.faces[i].id = metadata->faces[i].id; |
|
for (int k = 0; k < 4; k++) { |
|
hidlMetadata.faces[i].rect[k] = metadata->faces[i].rect[k]; |
|
} |
|
for (int k = 0; k < 2; k++) { |
|
hidlMetadata.faces[i].leftEye[k] = metadata->faces[i].left_eye[k]; |
|
} |
|
for (int k = 0; k < 2; k++) { |
|
hidlMetadata.faces[i].rightEye[k] = metadata->faces[i].right_eye[k]; |
|
} |
|
for (int k = 0; k < 2; k++) { |
|
hidlMetadata.faces[i].mouth[k] = metadata->faces[i].mouth[k]; |
|
} |
|
} |
|
} |
|
CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle); |
|
object->mDeviceCallback->dataCallback( |
|
(DataCallbackMsg) msg_type, mem->handle.mId, index, hidlMetadata); |
|
} |
|
} |
|
|
|
void CameraDevice::handleCallbackTimestamp( |
|
nsecs_t timestamp, int32_t msg_type, |
|
MemoryId memId , unsigned index, native_handle_t* handle) { |
|
uint32_t batchSize = 0; |
|
{ |
|
Mutex::Autolock _l(mBatchLock); |
|
batchSize = mBatchSize; |
|
} |
|
|
|
if (batchSize == 0) { // non-batch mode |
|
mDeviceCallback->handleCallbackTimestamp( |
|
(DataCallbackMsg) msg_type, handle, memId, index, timestamp); |
|
} else { // batch mode |
|
Mutex::Autolock _l(mBatchLock); |
|
size_t inflightSize = mInflightBatch.size(); |
|
if (inflightSize == 0) { |
|
mBatchMsgType = msg_type; |
|
} else if (mBatchMsgType != msg_type) { |
|
ALOGE("%s: msg_type change (from %d to %d) is not supported!", |
|
__FUNCTION__, mBatchMsgType, msg_type); |
|
return; |
|
} |
|
mInflightBatch.push_back({handle, memId, index, timestamp}); |
|
|
|
// Send batched frames to camera framework |
|
if (mInflightBatch.size() >= batchSize) { |
|
mDeviceCallback->handleCallbackTimestampBatch( |
|
(DataCallbackMsg) mBatchMsgType, mInflightBatch); |
|
mInflightBatch.clear(); |
|
} |
|
} |
|
} |
|
|
|
void CameraDevice::sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type, |
|
const camera_memory_t *data, unsigned index, void *user) { |
|
ALOGV("%s", __FUNCTION__); |
|
CameraDevice* object = static_cast<CameraDevice*>(user); |
|
// Start refcounting the heap object from here on. When the clients |
|
// drop all references, it will be destroyed (as well as the enclosed |
|
// MemoryHeapBase. |
|
sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle)); |
|
if (index >= mem->mNumBufs) { |
|
ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__, |
|
index, mem->mNumBufs); |
|
return; |
|
} |
|
|
|
native_handle_t* handle = nullptr; |
|
if (object->mMetadataMode) { |
|
if (mem->mBufSize == sizeof(VideoNativeHandleMetadata)) { |
|
VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) |
|
((uint8_t*) mem->mHidlHeapMemData + index * mem->mBufSize); |
|
if (md->eType == kMetadataBufferTypeNativeHandleSource) { |
|
handle = md->pHandle; |
|
} |
|
} |
|
} |
|
|
|
if (object->mDeviceCallback != nullptr) { |
|
if (handle == nullptr) { |
|
object->mDeviceCallback->dataCallbackTimestamp( |
|
(DataCallbackMsg) msg_type, mem->handle.mId, index, timestamp); |
|
} else { |
|
object->handleCallbackTimestamp(timestamp, msg_type, mem->handle.mId, index, handle); |
|
} |
|
} |
|
} |
|
|
|
void CameraDevice::initHalPreviewWindow() |
|
{ |
|
mHalPreviewWindow.cancel_buffer = sCancelBuffer; |
|
mHalPreviewWindow.lock_buffer = sLockBuffer; |
|
mHalPreviewWindow.dequeue_buffer = sDequeueBuffer; |
|
mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer; |
|
mHalPreviewWindow.set_buffer_count = sSetBufferCount; |
|
mHalPreviewWindow.set_buffers_geometry = sSetBuffersGeometry; |
|
mHalPreviewWindow.set_crop = sSetCrop; |
|
mHalPreviewWindow.set_timestamp = sSetTimestamp; |
|
mHalPreviewWindow.set_usage = sSetUsage; |
|
mHalPreviewWindow.set_swap_interval = sSetSwapInterval; |
|
|
|
mHalPreviewWindow.get_min_undequeued_buffer_count = |
|
sGetMinUndequeuedBufferCount; |
|
} |
|
|
|
// Methods from ::android::hardware::camera::device::V1_0::ICameraDevice follow. |
|
Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { |
|
Status status = initStatus(); |
|
CameraResourceCost resCost; |
|
if (status == Status::OK) { |
|
int cost = 100; |
|
std::vector<std::string> conflicting_devices; |
|
struct camera_info info; |
|
|
|
// If using post-2.4 module version, query the cost + conflicting devices from the HAL |
|
if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { |
|
int ret = mModule->getCameraInfo(mCameraIdInt, &info); |
|
if (ret == OK) { |
|
cost = info.resource_cost; |
|
for (size_t i = 0; i < info.conflicting_devices_length; i++) { |
|
std::string cameraId(info.conflicting_devices[i]); |
|
for (const auto& pair : mCameraDeviceNames) { |
|
if (cameraId == pair.first) { |
|
conflicting_devices.push_back(pair.second); |
|
} |
|
} |
|
} |
|
} else { |
|
status = Status::INTERNAL_ERROR; |
|
} |
|
} |
|
|
|
if (status == Status::OK) { |
|
resCost.resourceCost = cost; |
|
resCost.conflictingDevices.resize(conflicting_devices.size()); |
|
for (size_t i = 0; i < conflicting_devices.size(); i++) { |
|
resCost.conflictingDevices[i] = conflicting_devices[i]; |
|
ALOGV("CamDevice %s is conflicting with camDevice %s", |
|
mCameraId.c_str(), resCost.conflictingDevices[i].c_str()); |
|
} |
|
} |
|
} |
|
_hidl_cb(status, resCost); |
|
return Void(); |
|
} |
|
|
|
Return<void> CameraDevice::getCameraInfo(getCameraInfo_cb _hidl_cb) { |
|
Status status = initStatus(); |
|
CameraInfo cameraInfo; |
|
if (status == Status::OK) { |
|
struct camera_info info; |
|
int ret = mModule->getCameraInfo(mCameraIdInt, &info); |
|
if (ret == OK) { |
|
cameraInfo.facing = (CameraFacing) info.facing; |
|
// Device 1.0 does not support external camera facing. |
|
// The closest approximation would be front camera. |
|
if (cameraInfo.facing == CameraFacing::EXTERNAL) { |
|
cameraInfo.facing = CameraFacing::FRONT; |
|
} |
|
cameraInfo.orientation = info.orientation; |
|
} else { |
|
ALOGE("%s: get camera info failed!", __FUNCTION__); |
|
status = Status::INTERNAL_ERROR; |
|
} |
|
} |
|
_hidl_cb(status, cameraInfo); |
|
return Void(); |
|
} |
|
|
|
Return<Status> CameraDevice::setTorchMode(TorchMode mode) { |
|
if (!mModule->isSetTorchModeSupported()) { |
|
return Status::METHOD_NOT_SUPPORTED; |
|
} |
|
|
|
Status status = initStatus(); |
|
if (status == Status::OK) { |
|
bool enable = (mode == TorchMode::ON) ? true : false; |
|
status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable)); |
|
} |
|
return status; |
|
} |
|
|
|
Return<Status> CameraDevice::dumpState(const hidl_handle& handle) { |
|
Mutex::Autolock _l(mLock); |
|
if (handle.getNativeHandle() == nullptr) { |
|
ALOGE("%s: handle must not be null", __FUNCTION__); |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
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 Status::ILLEGAL_ARGUMENT; |
|
} |
|
int fd = handle->data[0]; |
|
|
|
if (mDevice != nullptr) { |
|
if (mDevice->ops->dump) { // It's fine if the HAL doesn't implement dump() |
|
return getHidlStatus(mDevice->ops->dump(mDevice, fd)); |
|
} |
|
} |
|
return Status::OK; |
|
} |
|
|
|
Return<Status> CameraDevice::open(const sp<ICameraDeviceCallback>& callback) { |
|
ALOGI("Opening camera %s", mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
|
|
camera_info info; |
|
status_t res = mModule->getCameraInfo(mCameraIdInt, &info); |
|
if (res != OK) { |
|
ALOGE("Could not get camera info: %s: %d", mCameraId.c_str(), res); |
|
return getHidlStatus(res); |
|
} |
|
|
|
int rc = OK; |
|
if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 && |
|
info.device_version > CAMERA_DEVICE_API_VERSION_1_0) { |
|
// Open higher version camera device as HAL1.0 device. |
|
rc = mModule->openLegacy(mCameraId.c_str(), |
|
CAMERA_DEVICE_API_VERSION_1_0, |
|
(hw_device_t **)&mDevice); |
|
} else { |
|
rc = mModule->open(mCameraId.c_str(), (hw_device_t **)&mDevice); |
|
} |
|
if (rc != OK) { |
|
mDevice = nullptr; |
|
ALOGE("Could not open camera %s: %d", mCameraId.c_str(), rc); |
|
return getHidlStatus(rc); |
|
} |
|
|
|
initHalPreviewWindow(); |
|
mDeviceCallback = callback; |
|
|
|
if (mDevice->ops->set_callbacks) { |
|
mDevice->ops->set_callbacks(mDevice, |
|
sNotifyCb, sDataCb, sDataCbTimestamp, sGetMemory, this); |
|
} |
|
|
|
return getHidlStatus(rc); |
|
} |
|
|
|
Return<Status> CameraDevice::setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
|
|
mHalPreviewWindow.mPreviewCallback = window; |
|
if (mDevice->ops->set_preview_window) { |
|
return getHidlStatus(mDevice->ops->set_preview_window(mDevice, |
|
(window == nullptr) ? nullptr : &mHalPreviewWindow)); |
|
} |
|
return Status::INTERNAL_ERROR; // HAL should provide set_preview_window |
|
} |
|
|
|
Return<void> CameraDevice::enableMsgType(uint32_t msgType) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Void(); |
|
} |
|
if (mDevice->ops->enable_msg_type) { |
|
mDevice->ops->enable_msg_type(mDevice, msgType); |
|
} |
|
return Void(); |
|
} |
|
|
|
Return<void> CameraDevice::disableMsgType(uint32_t msgType) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Void(); |
|
} |
|
if (mDevice->ops->disable_msg_type) { |
|
mDevice->ops->disable_msg_type(mDevice, msgType); |
|
} |
|
return Void(); |
|
} |
|
|
|
Return<bool> CameraDevice::msgTypeEnabled(uint32_t msgType) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return false; |
|
} |
|
if (mDevice->ops->msg_type_enabled) { |
|
return mDevice->ops->msg_type_enabled(mDevice, msgType); |
|
} |
|
return false; |
|
} |
|
|
|
Return<Status> CameraDevice::startPreview() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->start_preview) { |
|
return getHidlStatus(mDevice->ops->start_preview(mDevice)); |
|
} |
|
return Status::INTERNAL_ERROR; // HAL should provide start_preview |
|
} |
|
|
|
Return<void> CameraDevice::stopPreview() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Void(); |
|
} |
|
if (mDevice->ops->stop_preview) { |
|
mDevice->ops->stop_preview(mDevice); |
|
} |
|
return Void(); |
|
} |
|
|
|
Return<bool> CameraDevice::previewEnabled() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return false; |
|
} |
|
if (mDevice->ops->preview_enabled) { |
|
return mDevice->ops->preview_enabled(mDevice); |
|
} |
|
return false; |
|
} |
|
|
|
Return<Status> CameraDevice::storeMetaDataInBuffers(bool enable) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->store_meta_data_in_buffers) { |
|
status_t s = mDevice->ops->store_meta_data_in_buffers(mDevice, enable); |
|
if (s == OK && enable) { |
|
mMetadataMode = true; |
|
} |
|
return getHidlStatus(s); |
|
} |
|
return enable ? Status::ILLEGAL_ARGUMENT : Status::OK; |
|
} |
|
|
|
Return<Status> CameraDevice::startRecording() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->start_recording) { |
|
return getHidlStatus(mDevice->ops->start_recording(mDevice)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<void> CameraDevice::stopRecording() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Void(); |
|
} |
|
if (mDevice->ops->stop_recording) { |
|
mDevice->ops->stop_recording(mDevice); |
|
} |
|
return Void(); |
|
} |
|
|
|
Return<bool> CameraDevice::recordingEnabled() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return false; |
|
} |
|
if (mDevice->ops->recording_enabled) { |
|
return mDevice->ops->recording_enabled(mDevice); |
|
} |
|
return false; |
|
} |
|
|
|
void CameraDevice::releaseRecordingFrameLocked( |
|
uint32_t memId, uint32_t bufferIndex, const native_handle_t* handle) { |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return; |
|
} |
|
if (mDevice->ops->release_recording_frame) { |
|
CameraHeapMemory* camMemory; |
|
{ |
|
Mutex::Autolock _l(mMemoryMapLock); |
|
auto it = mMemoryMap.find(memId); |
|
if (it == mMemoryMap.end() || it->second == nullptr) { |
|
ALOGE("%s unknown memoryId %d", __FUNCTION__, memId); |
|
return; |
|
} |
|
camMemory = it->second; |
|
} |
|
if (bufferIndex >= camMemory->mNumBufs) { |
|
ALOGE("%s: bufferIndex %d exceeds number of buffers %d", |
|
__FUNCTION__, bufferIndex, camMemory->mNumBufs); |
|
return; |
|
} |
|
void *data = ((uint8_t *) camMemory->mHidlHeapMemData) + bufferIndex * camMemory->mBufSize; |
|
if (handle) { |
|
VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) data; |
|
if (md->eType == kMetadataBufferTypeNativeHandleSource) { |
|
// Input handle will be closed by HIDL transport later, so clone it |
|
// HAL implementation is responsible to close/delete the clone |
|
native_handle_t* clone = native_handle_clone(handle); |
|
if (!clone) { |
|
ALOGE("%s: failed to clone buffer %p", __FUNCTION__, handle); |
|
return; |
|
} |
|
md->pHandle = clone; |
|
} else { |
|
ALOGE("%s:Malform VideoNativeHandleMetadata at memId %d, bufferId %d", |
|
__FUNCTION__, memId, bufferIndex); |
|
return; |
|
} |
|
} |
|
mDevice->ops->release_recording_frame(mDevice, data); |
|
} |
|
} |
|
|
|
Return<void> CameraDevice::releaseRecordingFrame(uint32_t memId, uint32_t bufferIndex) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
releaseRecordingFrameLocked(memId, bufferIndex, nullptr); |
|
return Void(); |
|
} |
|
|
|
Return<void> CameraDevice::releaseRecordingFrameHandle( |
|
uint32_t memId, uint32_t bufferIndex, const hidl_handle& frame) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
releaseRecordingFrameLocked( |
|
memId, bufferIndex, frame.getNativeHandle()); |
|
return Void(); |
|
} |
|
|
|
Return<void> CameraDevice::releaseRecordingFrameHandleBatch( |
|
const hidl_vec<VideoFrameMessage>& msgs) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
for (auto& msg : msgs) { |
|
releaseRecordingFrameLocked( |
|
msg.data, msg.bufferIndex, msg.frameData.getNativeHandle()); |
|
} |
|
return Void(); |
|
} |
|
|
|
Return<Status> CameraDevice::autoFocus() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->auto_focus) { |
|
return getHidlStatus(mDevice->ops->auto_focus(mDevice)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<Status> CameraDevice::cancelAutoFocus() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->cancel_auto_focus) { |
|
return getHidlStatus(mDevice->ops->cancel_auto_focus(mDevice)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<Status> CameraDevice::takePicture() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->take_picture) { |
|
return getHidlStatus(mDevice->ops->take_picture(mDevice)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<Status> CameraDevice::cancelPicture() { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->cancel_picture) { |
|
return getHidlStatus(mDevice->ops->cancel_picture(mDevice)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<Status> CameraDevice::setParameters(const hidl_string& params) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->set_parameters) { |
|
return getHidlStatus(mDevice->ops->set_parameters(mDevice, params.c_str())); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<void> CameraDevice::getParameters(getParameters_cb _hidl_cb) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
hidl_string outStr; |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
_hidl_cb(outStr); |
|
return Void(); |
|
} |
|
if (mDevice->ops->get_parameters) { |
|
char *temp = mDevice->ops->get_parameters(mDevice); |
|
outStr = temp; |
|
if (mDevice->ops->put_parameters) { |
|
mDevice->ops->put_parameters(mDevice, temp); |
|
} else { |
|
free(temp); |
|
} |
|
} |
|
_hidl_cb(outStr); |
|
return Void(); |
|
} |
|
|
|
Return<Status> CameraDevice::sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) { |
|
ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); |
|
Mutex::Autolock _l(mLock); |
|
if (!mDevice) { |
|
ALOGE("%s called while camera is not opened", __FUNCTION__); |
|
return Status::OPERATION_NOT_SUPPORTED; |
|
} |
|
if (mDevice->ops->send_command) { |
|
return getHidlStatus(mDevice->ops->send_command(mDevice, (int32_t) cmd, arg1, arg2)); |
|
} |
|
return Status::ILLEGAL_ARGUMENT; |
|
} |
|
|
|
Return<void> CameraDevice::close() { |
|
Mutex::Autolock _l(mLock); |
|
closeLocked(); |
|
return Void(); |
|
} |
|
|
|
void CameraDevice::closeLocked() { |
|
ALOGI("Closing camera %s", mCameraId.c_str()); |
|
if(mDevice) { |
|
int rc = mDevice->common.close(&mDevice->common); |
|
if (rc != OK) { |
|
ALOGE("Could not close camera %s: %d", mCameraId.c_str(), rc); |
|
} |
|
mDevice = nullptr; |
|
} |
|
} |
|
|
|
} // namespace implementation |
|
} // namespace V1_0 |
|
} // namespace device |
|
} // namespace camera |
|
} // namespace hardware |
|
} // namespace android
|
|
|