| /* |
| * 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 <fcntl.h> |
| |
| #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__); |
| return; |
| } |
| if (device->mDeviceCallback == nullptr) { |
| ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__); |
| return; |
| } |
| 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 |