mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Revise IAllocator and IMapper to reduce IPC and to support gralloc0
devices.
Specifically, IAllocator is trimmed down to have essentially only
allocate(BufferDescriptor descriptor, uint32_t count)
generates (Error error,
uint32_t stride,
vec<handle> buffers);
The ability to allocate buffers with shared backing store is
removed. ProducerUsage and ConsumerUsage are moved to the
graphics.common package and are merged and renamed to BufferUsage.
BufferUsage's bits follow gralloc0.
IMapper gains
typedef vec<uint32_t> BufferDescriptor;
createDescriptor(BufferDescriptorInfo descriptorInfo)
generates (Error error,
BufferDescriptor descriptor);
where BufferDescriptor is an implementation-defined blob. lockFlex
is replaced by lockYCbCr. All getters are removed.
Reference counting with retain/release is replaced by
importBuffer/freeBuffer.
Most if not all gralloc1 features are not used by the runtime yet.
There is also not too much test written for them. As such, they
tend to behave differently between implementations and cannot be
used reliably.
Bug: 36481301
Test: builds and boots on Pixel
Change-Id: I1d31105120517ea2c128c7a19297acf3bfd312bb
1005 lines
36 KiB
C++
1005 lines
36 KiB
C++
/*
|
|
* 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 "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 = HandleImporter::getInstance();
|
|
|
|
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());
|
|
close();
|
|
}
|
|
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());
|
|
close();
|
|
}
|
|
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*) {
|
|
// TODO: make sure lock_buffer is indeed a no-op (and will always be)
|
|
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;
|
|
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);
|
|
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 == VideoNativeHandleMetadata::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.
|
|
// TODO: figure out should we override here or let
|
|
// camera service handle it.
|
|
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 = mMemoryMap.at(memId);
|
|
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 == VideoNativeHandleMetadata::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() {
|
|
ALOGI("Closing camera %s", mCameraId.c_str());
|
|
Mutex::Autolock _l(mLock);
|
|
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;
|
|
}
|
|
return Void();
|
|
}
|
|
|
|
} // namespace implementation
|
|
} // namespace V1_0
|
|
} // namespace device
|
|
} // namespace camera
|
|
} // namespace hardware
|
|
} // namespace android
|