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.
1714 lines
68 KiB
1714 lines
68 KiB
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "ACameraDeviceVendor"
|
|
|
|
#include <vector>
|
|
#include <inttypes.h>
|
|
#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
|
|
#include <android/frameworks/cameraservice/device/2.0/types.h>
|
|
#include <CameraMetadata.h>
|
|
|
|
#include "ndk_vendor/impl/ACameraDevice.h"
|
|
#include "ACameraCaptureSession.h"
|
|
#include "ACameraMetadata.h"
|
|
#include "ACaptureRequest.h"
|
|
#include "utils.h"
|
|
|
|
#include "ACameraCaptureSession.inc"
|
|
|
|
#define CHECK_TRANSACTION_AND_RET(remoteRet, status, callName) \
|
|
if (!remoteRet.isOk()) { \
|
|
ALOGE("%s: Transaction error during %s call %s", __FUNCTION__, callName, \
|
|
remoteRet.description().c_str()); \
|
|
return ACAMERA_ERROR_UNKNOWN; \
|
|
} \
|
|
if (status != Status::NO_ERROR) { \
|
|
ALOGE("%s: %s call failed", __FUNCTION__, callName); \
|
|
return utils::convertFromHidl(status); \
|
|
}
|
|
|
|
using namespace android;
|
|
|
|
ACameraDevice::~ACameraDevice() {
|
|
mDevice->stopLooperAndDisconnect();
|
|
}
|
|
|
|
namespace android {
|
|
namespace acam {
|
|
|
|
using HCameraMetadata = frameworks::cameraservice::device::V2_0::CameraMetadata;
|
|
using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
|
|
using SessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
|
|
using hardware::Void;
|
|
|
|
// Static member definitions
|
|
const char* CameraDevice::kContextKey = "Context";
|
|
const char* CameraDevice::kDeviceKey = "Device";
|
|
const char* CameraDevice::kErrorCodeKey = "ErrorCode";
|
|
const char* CameraDevice::kCallbackFpKey = "Callback";
|
|
const char* CameraDevice::kSessionSpKey = "SessionSp";
|
|
const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
|
|
const char* CameraDevice::kTimeStampKey = "TimeStamp";
|
|
const char* CameraDevice::kCaptureResultKey = "CaptureResult";
|
|
const char* CameraDevice::kPhysicalCaptureResultKey = "PhysicalCaptureResult";
|
|
const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
|
|
const char* CameraDevice::kSequenceIdKey = "SequenceId";
|
|
const char* CameraDevice::kFrameNumberKey = "FrameNumber";
|
|
const char* CameraDevice::kAnwKey = "Anw";
|
|
const char* CameraDevice::kFailingPhysicalCameraId= "FailingPhysicalCameraId";
|
|
|
|
/**
|
|
* CameraDevice Implementation
|
|
*/
|
|
CameraDevice::CameraDevice(
|
|
const char* id,
|
|
ACameraDevice_StateCallbacks* cb,
|
|
sp<ACameraMetadata> chars,
|
|
ACameraDevice* wrapper) :
|
|
mCameraId(id),
|
|
mAppCallbacks(*cb),
|
|
mChars(std::move(chars)),
|
|
mServiceCallback(new ServiceCallback(this)),
|
|
mWrapper(wrapper),
|
|
mInError(false),
|
|
mError(ACAMERA_OK),
|
|
mIdle(true),
|
|
mCurrentSession(nullptr) {
|
|
mClosing = false;
|
|
// Setup looper thread to perfrom device callbacks to app
|
|
mCbLooper = new ALooper;
|
|
mCbLooper->setName("C2N-dev-looper");
|
|
status_t err = mCbLooper->start(
|
|
/*runOnCallingThread*/false,
|
|
/*canCallJava*/ true,
|
|
PRIORITY_DEFAULT);
|
|
if (err != OK) {
|
|
ALOGE("%s: Unable to start camera device callback looper: %s (%d)",
|
|
__FUNCTION__, strerror(-err), err);
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
|
|
}
|
|
mHandler = new CallbackHandler(id);
|
|
mCbLooper->registerHandler(mHandler);
|
|
|
|
const CameraMetadata& metadata = mChars->getInternalData();
|
|
camera_metadata_ro_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
|
|
if (entry.count != 1) {
|
|
ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
|
|
mPartialResultCount = 1;
|
|
} else {
|
|
mPartialResultCount = entry.data.i32[0];
|
|
}
|
|
|
|
entry = metadata.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
|
|
if (entry.count != 2) {
|
|
ALOGW("%s: bad count %zu for shading map size", __FUNCTION__, entry.count);
|
|
mShadingMapSize[0] = 0;
|
|
mShadingMapSize[1] = 0;
|
|
} else {
|
|
mShadingMapSize[0] = entry.data.i32[0];
|
|
mShadingMapSize[1] = entry.data.i32[1];
|
|
}
|
|
}
|
|
|
|
CameraDevice::~CameraDevice() { }
|
|
|
|
void
|
|
CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
|
|
msg->post();
|
|
msg.clear();
|
|
sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
|
|
cleanupMsg->post();
|
|
}
|
|
|
|
// TODO: cached created request?
|
|
camera_status_t
|
|
CameraDevice::createCaptureRequest(
|
|
ACameraDevice_request_template templateId,
|
|
const ACameraIdList* physicalCameraIdList,
|
|
ACaptureRequest** request) const {
|
|
Mutex::Autolock _l(mDeviceLock);
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
return ret;
|
|
}
|
|
if (mRemote == nullptr) {
|
|
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
|
|
}
|
|
CameraMetadata rawRequest;
|
|
Status status = Status::UNKNOWN_ERROR;
|
|
auto remoteRet = mRemote->createDefaultRequest(
|
|
utils::convertToHidl(templateId),
|
|
[&status, &rawRequest](auto s, const hidl_vec<uint8_t> &metadata) {
|
|
status = s;
|
|
if (status == Status::NO_ERROR && utils::convertFromHidlCloned(metadata, &rawRequest)) {
|
|
} else {
|
|
ALOGE("%s: Couldn't create default request", __FUNCTION__);
|
|
}
|
|
});
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, status, "createDefaultRequest()")
|
|
ACaptureRequest* outReq = new ACaptureRequest();
|
|
outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
|
|
if (physicalCameraIdList != nullptr) {
|
|
for (auto i = 0; i < physicalCameraIdList->numCameras; i++) {
|
|
outReq->physicalSettings.emplace(physicalCameraIdList->cameraIds[i],
|
|
new ACameraMetadata(*(outReq->settings)));
|
|
}
|
|
}
|
|
outReq->targets = new ACameraOutputTargets();
|
|
*request = outReq;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::createCaptureSession(
|
|
const ACaptureSessionOutputContainer* outputs,
|
|
const ACaptureRequest* sessionParameters,
|
|
const ACameraCaptureSession_stateCallbacks* callbacks,
|
|
/*out*/ACameraCaptureSession** session) {
|
|
sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
|
|
Mutex::Autolock _l(mDeviceLock);
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
return ret;
|
|
}
|
|
|
|
if (currentSession != nullptr) {
|
|
currentSession->closeByDevice();
|
|
stopRepeatingLocked();
|
|
}
|
|
|
|
// Create new session
|
|
ret = configureStreamsLocked(outputs, sessionParameters);
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Fail to create new session. cannot configure streams");
|
|
return ret;
|
|
}
|
|
|
|
ACameraCaptureSession* newSession = new ACameraCaptureSession(
|
|
mNextSessionId++, outputs, callbacks, this);
|
|
|
|
// set new session as current session
|
|
newSession->incStrong((void *) ACameraDevice_createCaptureSession);
|
|
mCurrentSession = newSession;
|
|
mFlushing = false;
|
|
*session = newSession;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t CameraDevice::isSessionConfigurationSupported(
|
|
const ACaptureSessionOutputContainer* sessionOutputContainer) const {
|
|
Mutex::Autolock _l(mDeviceLock);
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
return ret;
|
|
}
|
|
|
|
SessionConfiguration sessionConfig;
|
|
sessionConfig.inputWidth = 0;
|
|
sessionConfig.inputHeight = 0;
|
|
sessionConfig.inputFormat = -1;
|
|
sessionConfig.operationMode = StreamConfigurationMode::NORMAL_MODE;
|
|
sessionConfig.outputStreams.resize(sessionOutputContainer->mOutputs.size());
|
|
size_t index = 0;
|
|
for (const auto& output : sessionOutputContainer->mOutputs) {
|
|
sessionConfig.outputStreams[index].rotation = utils::convertToHidl(output.mRotation);
|
|
sessionConfig.outputStreams[index].windowGroupId = -1;
|
|
sessionConfig.outputStreams[index].windowHandles.resize(output.mSharedWindows.size() + 1);
|
|
sessionConfig.outputStreams[index].windowHandles[0] = output.mWindow;
|
|
sessionConfig.outputStreams[index].physicalCameraId = output.mPhysicalCameraId;
|
|
index++;
|
|
}
|
|
|
|
bool configSupported = false;
|
|
Status status = Status::UNKNOWN_ERROR;
|
|
auto remoteRet = mRemote->isSessionConfigurationSupported(sessionConfig,
|
|
[&status, &configSupported](auto s, auto supported) {
|
|
status = s;
|
|
configSupported = supported;
|
|
});
|
|
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, status, "isSessionConfigurationSupported()");
|
|
return configSupported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
|
|
}
|
|
|
|
static void addMetadataToPhysicalCameraSettings(const CameraMetadata *metadata,
|
|
const std::string &cameraId, PhysicalCameraSettings *physicalCameraSettings) {
|
|
CameraMetadata metadataCopy = *metadata;
|
|
camera_metadata_t *camera_metadata = metadataCopy.release();
|
|
HCameraMetadata hCameraMetadata;
|
|
utils::convertToHidl(camera_metadata, &hCameraMetadata, /*shouldOwn*/ true);
|
|
physicalCameraSettings->settings.metadata(std::move(hCameraMetadata));
|
|
physicalCameraSettings->id = cameraId;
|
|
}
|
|
|
|
void CameraDevice::addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
|
|
sp<CaptureRequest> &req) {
|
|
req->mPhysicalCameraSettings.resize(1 + aCaptureRequest->physicalSettings.size());
|
|
addMetadataToPhysicalCameraSettings(&(aCaptureRequest->settings->getInternalData()), getId(),
|
|
&(req->mPhysicalCameraSettings[0]));
|
|
size_t i = 1;
|
|
for (auto &physicalSetting : aCaptureRequest->physicalSettings) {
|
|
addMetadataToPhysicalCameraSettings(&(physicalSetting.second->getInternalData()),
|
|
physicalSetting.first, &(req->mPhysicalCameraSettings[i]));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
return ret;
|
|
}
|
|
|
|
if (output == nullptr) {
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!output->mIsShared) {
|
|
ALOGE("Error output configuration is not shared");
|
|
return ACAMERA_ERROR_INVALID_OPERATION;
|
|
}
|
|
|
|
int32_t streamId = -1;
|
|
for (auto& kvPair : mConfiguredOutputs) {
|
|
if (utils::isWindowNativeHandleEqual(kvPair.second.first, output->mWindow)) {
|
|
streamId = kvPair.first;
|
|
break;
|
|
}
|
|
}
|
|
if (streamId < 0) {
|
|
ALOGE("Error: Invalid output configuration");
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
OutputConfigurationWrapper outConfigW;
|
|
OutputConfiguration &outConfig = outConfigW.mOutputConfiguration;
|
|
outConfig.rotation = utils::convertToHidl(output->mRotation);
|
|
outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
|
|
outConfig.windowHandles[0] = output->mWindow;
|
|
outConfig.physicalCameraId = output->mPhysicalCameraId;
|
|
int i = 1;
|
|
for (auto& anw : output->mSharedWindows) {
|
|
outConfig.windowHandles[i++] = anw;
|
|
}
|
|
|
|
auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
|
|
if (!remoteRet.isOk()) {
|
|
ALOGE("%s: Transaction error in updating OutputConfiguration: %s", __FUNCTION__,
|
|
remoteRet.description().c_str());
|
|
return ACAMERA_ERROR_UNKNOWN;
|
|
}
|
|
|
|
switch (remoteRet) {
|
|
case Status::NO_ERROR:
|
|
break;
|
|
case Status::INVALID_OPERATION:
|
|
ALOGE("Camera device %s invalid operation", getId());
|
|
return ACAMERA_ERROR_INVALID_OPERATION;
|
|
case Status::ALREADY_EXISTS:
|
|
ALOGE("Camera device %s output surface already exists", getId());
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
case Status::ILLEGAL_ARGUMENT:
|
|
ALOGE("Camera device %s invalid input argument", getId());
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
default:
|
|
ALOGE("Camera device %s failed to add shared output", getId());
|
|
return ACAMERA_ERROR_UNKNOWN;
|
|
}
|
|
|
|
mConfiguredOutputs[streamId] = std::make_pair(output->mWindow, outConfigW);
|
|
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::allocateCaptureRequestLocked(
|
|
const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
|
|
sp<CaptureRequest> req(new CaptureRequest());
|
|
req->mCaptureRequest.physicalCameraSettings.resize(1 + request->physicalSettings.size());
|
|
|
|
size_t index = 0;
|
|
allocateOneCaptureRequestMetadata(
|
|
req->mCaptureRequest.physicalCameraSettings[index++], mCameraId, request->settings);
|
|
|
|
for (auto& physicalEntry : request->physicalSettings) {
|
|
allocateOneCaptureRequestMetadata(
|
|
req->mCaptureRequest.physicalCameraSettings[index++],
|
|
physicalEntry.first, physicalEntry.second);
|
|
}
|
|
|
|
std::vector<int32_t> requestStreamIdxList;
|
|
std::vector<int32_t> requestSurfaceIdxList;
|
|
for (auto outputTarget : request->targets->mOutputs) {
|
|
native_handle_t* anw = outputTarget.mWindow;
|
|
bool found = false;
|
|
req->mSurfaceList.push_back(anw);
|
|
// lookup stream/surface ID
|
|
for (const auto& kvPair : mConfiguredOutputs) {
|
|
int streamId = kvPair.first;
|
|
const OutputConfigurationWrapper& outConfig = kvPair.second.second;
|
|
const auto& windowHandles = outConfig.mOutputConfiguration.windowHandles;
|
|
for (int surfaceId = 0; surfaceId < (int) windowHandles.size(); surfaceId++) {
|
|
// If two native handles are equivalent, so are their surfaces.
|
|
if (utils::isWindowNativeHandleEqual(windowHandles[surfaceId].getNativeHandle(),
|
|
anw)) {
|
|
found = true;
|
|
requestStreamIdxList.push_back(streamId);
|
|
requestSurfaceIdxList.push_back(surfaceId);
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
ALOGE("Unconfigured output target %p in capture request!", anw);
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
req->mCaptureRequest.streamAndWindowIds.resize(requestStreamIdxList.size());
|
|
for (int i = 0; i < requestStreamIdxList.size(); i++) {
|
|
req->mCaptureRequest.streamAndWindowIds[i].streamId = requestStreamIdxList[i];
|
|
req->mCaptureRequest.streamAndWindowIds[i].windowId = requestSurfaceIdxList[i];
|
|
}
|
|
outReq = req;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
void CameraDevice::allocateOneCaptureRequestMetadata(
|
|
PhysicalCameraSettings& cameraSettings,
|
|
const std::string& id, const sp<ACameraMetadata>& metadata) {
|
|
cameraSettings.id = id;
|
|
// TODO: Do we really need to copy the metadata here ?
|
|
CameraMetadata metadataCopy = metadata->getInternalData();
|
|
camera_metadata_t *cameraMetadata = metadataCopy.release();
|
|
HCameraMetadata hCameraMetadata;
|
|
utils::convertToHidl(cameraMetadata, &hCameraMetadata, true);
|
|
if (metadata != nullptr) {
|
|
if (hCameraMetadata.data() != nullptr &&
|
|
mCaptureRequestMetadataQueue != nullptr &&
|
|
mCaptureRequestMetadataQueue->write(
|
|
reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
|
|
hCameraMetadata.size())) {
|
|
// The metadata field of the union would've been destructued, so no need
|
|
// to re-size it.
|
|
cameraSettings.settings.fmqMetadataSize(hCameraMetadata.size());
|
|
} else {
|
|
ALOGE("Fmq write capture result failed, falling back to hwbinder");
|
|
cameraSettings.settings.metadata(std::move(hCameraMetadata));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ACaptureRequest*
|
|
CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId) {
|
|
ACaptureRequest* pRequest = new ACaptureRequest();
|
|
for (size_t i = 0; i < req->mPhysicalCameraSettings.size(); i++) {
|
|
const std::string& id = req->mPhysicalCameraSettings[i].id;
|
|
CameraMetadata clone;
|
|
utils::convertFromHidlCloned(req->mPhysicalCameraSettings[i].settings.metadata(), &clone);
|
|
camera_metadata_t *clonep = clone.release();
|
|
if (id == deviceId) {
|
|
pRequest->settings = new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
|
|
} else {
|
|
pRequest->physicalSettings[req->mPhysicalCameraSettings[i].id] =
|
|
new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
|
|
}
|
|
}
|
|
pRequest->targets = new ACameraOutputTargets();
|
|
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
|
|
native_handle_t* anw = req->mSurfaceList[i];
|
|
ACameraOutputTarget outputTarget(anw);
|
|
pRequest->targets->mOutputs.insert(outputTarget);
|
|
}
|
|
return pRequest;
|
|
}
|
|
|
|
void
|
|
CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
|
|
if (req == nullptr) {
|
|
return;
|
|
}
|
|
req->settings.clear();
|
|
delete req->targets;
|
|
delete req;
|
|
}
|
|
|
|
void
|
|
CameraDevice::notifySessionEndOfLifeLocked(ACameraCaptureSession* session) {
|
|
if (isClosed()) {
|
|
// Device is closing already. do nothing
|
|
return;
|
|
}
|
|
|
|
if (mCurrentSession != session) {
|
|
// Session has been replaced by other seesion or device is closed
|
|
return;
|
|
}
|
|
mCurrentSession = nullptr;
|
|
|
|
// Should not happen
|
|
if (!session->mIsClosed) {
|
|
ALOGE("Error: unclosed session %p reaches end of life!", session);
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
|
|
return;
|
|
}
|
|
|
|
// No new session, unconfigure now
|
|
camera_status_t ret = configureStreamsLocked(nullptr, nullptr);
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
|
|
}
|
|
}
|
|
|
|
void
|
|
CameraDevice::disconnectLocked(sp<ACameraCaptureSession>& session) {
|
|
if (mClosing.exchange(true)) {
|
|
// Already closing, just return
|
|
ALOGW("Camera device %s is already closing.", getId());
|
|
return;
|
|
}
|
|
|
|
if (mRemote != nullptr) {
|
|
auto ret = mRemote->disconnect();
|
|
if (!ret.isOk()) {
|
|
ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
|
|
ret.description().c_str());
|
|
}
|
|
}
|
|
mRemote = nullptr;
|
|
|
|
if (session != nullptr) {
|
|
session->closeByDevice();
|
|
}
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::stopRepeatingLocked() {
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
|
|
return ret;
|
|
}
|
|
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
|
|
int repeatingSequenceId = mRepeatingSequenceId;
|
|
mRepeatingSequenceId = REQUEST_ID_NONE;
|
|
|
|
int64_t lastFrameNumber;
|
|
Status status = Status::UNKNOWN_ERROR;
|
|
auto remoteRet = mRemote->cancelRepeatingRequest(
|
|
[&status, &lastFrameNumber](Status s, auto frameNumber) {
|
|
status = s;
|
|
lastFrameNumber = frameNumber;
|
|
});
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, status, "cancelRepeatingRequest()");
|
|
checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
|
|
}
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::flushLocked(ACameraCaptureSession* session) {
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Camera %s abort captures failed! ret %d", getId(), ret);
|
|
return ret;
|
|
}
|
|
|
|
// This should never happen because creating a new session will close
|
|
// previous one and thus reject any API call from previous session.
|
|
// But still good to check here in case something unexpected happen.
|
|
if (mCurrentSession != session) {
|
|
ALOGE("Camera %s session %p is not current active session!", getId(), session);
|
|
return ACAMERA_ERROR_INVALID_OPERATION;
|
|
}
|
|
|
|
if (mFlushing) {
|
|
ALOGW("Camera %s is already aborting captures", getId());
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
mFlushing = true;
|
|
|
|
// Send onActive callback to guarantee there is always active->ready transition
|
|
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
|
|
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
|
|
msg->setObject(kSessionSpKey, session);
|
|
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
|
|
postSessionMsgAndCleanup(msg);
|
|
|
|
// If device is already idling, send callback and exit early
|
|
if (mIdle) {
|
|
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
|
|
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
|
|
msg->setObject(kSessionSpKey, session);
|
|
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onReady);
|
|
postSessionMsgAndCleanup(msg);
|
|
mFlushing = false;
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
int64_t lastFrameNumber;
|
|
Status status = Status::UNKNOWN_ERROR;
|
|
auto remoteRet = mRemote->flush([&status, &lastFrameNumber](auto s, auto frameNumber) {
|
|
status = s;
|
|
lastFrameNumber = frameNumber;
|
|
});
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, status, "flush()")
|
|
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
|
|
checkRepeatingSequenceCompleteLocked(mRepeatingSequenceId, lastFrameNumber);
|
|
}
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::waitUntilIdleLocked() {
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
|
|
return ret;
|
|
}
|
|
|
|
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
|
|
ALOGE("Camera device %s won't go to idle when there is repeating request!", getId());
|
|
return ACAMERA_ERROR_INVALID_OPERATION;
|
|
}
|
|
|
|
auto remoteRet = mRemote->waitUntilIdle();
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "waitUntilIdle()")
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
|
|
const ACaptureRequest* sessionParameters) {
|
|
ACaptureSessionOutputContainer emptyOutput;
|
|
if (outputs == nullptr) {
|
|
outputs = &emptyOutput;
|
|
}
|
|
|
|
camera_status_t ret = checkCameraClosedOrErrorLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
return ret;
|
|
}
|
|
|
|
std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> outputSet;
|
|
for (auto outConfig : outputs->mOutputs) {
|
|
native_handle_t* anw = outConfig.mWindow;
|
|
OutputConfigurationWrapper outConfigInsertW;
|
|
OutputConfiguration &outConfigInsert = outConfigInsertW.mOutputConfiguration;
|
|
outConfigInsert.rotation = utils::convertToHidl(outConfig.mRotation);
|
|
outConfigInsert.windowGroupId = -1;
|
|
outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
|
|
outConfigInsert.windowHandles[0] = anw;
|
|
outConfigInsert.physicalCameraId = outConfig.mPhysicalCameraId;
|
|
native_handle_ptr_wrapper wrap(anw);
|
|
outputSet.insert(std::make_pair(anw, outConfigInsertW));
|
|
}
|
|
std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> addSet = outputSet;
|
|
std::vector<int32_t> deleteList;
|
|
|
|
// Determine which streams need to be created, which to be deleted
|
|
for (auto& kvPair : mConfiguredOutputs) {
|
|
int32_t streamId = kvPair.first;
|
|
auto& outputPair = kvPair.second;
|
|
if (outputSet.count(outputPair)) {
|
|
deleteList.push_back(streamId); // Need to delete a no longer needed stream
|
|
} else {
|
|
addSet.erase(outputPair); // No need to add already existing stream
|
|
}
|
|
}
|
|
|
|
ret = stopRepeatingLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Camera device %s stop repeating failed, ret %d", getId(), ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = waitUntilIdleLocked();
|
|
if (ret != ACAMERA_OK) {
|
|
ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
|
|
return ret;
|
|
}
|
|
|
|
// Send onReady to previous session
|
|
// CurrentSession will be updated after configureStreamLocked, so here
|
|
// mCurrentSession is the session to be replaced by a new session
|
|
if (!mIdle && mCurrentSession != nullptr) {
|
|
if (mBusySession != mCurrentSession) {
|
|
ALOGE("Current session != busy session");
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
|
|
return ACAMERA_ERROR_CAMERA_DEVICE;
|
|
}
|
|
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
|
|
msg->setPointer(kContextKey, mBusySession->mUserSessionCallback.context);
|
|
msg->setObject(kSessionSpKey, mBusySession);
|
|
msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
|
|
mBusySession.clear();
|
|
postSessionMsgAndCleanup(msg);
|
|
}
|
|
mIdle = true;
|
|
|
|
auto remoteRet = mRemote->beginConfigure();
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "beginConfigure()")
|
|
|
|
// delete to-be-deleted streams
|
|
for (auto streamId : deleteList) {
|
|
remoteRet = mRemote->deleteStream(streamId);
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "deleteStream()")
|
|
mConfiguredOutputs.erase(streamId);
|
|
}
|
|
|
|
// add new streams
|
|
for (auto outputPair : addSet) {
|
|
int streamId;
|
|
Status status = Status::UNKNOWN_ERROR;
|
|
auto ret = mRemote->createStream(outputPair.second,
|
|
[&status, &streamId](Status s, auto stream_id) {
|
|
status = s;
|
|
streamId = stream_id;
|
|
});
|
|
CHECK_TRANSACTION_AND_RET(ret, status, "createStream()")
|
|
mConfiguredOutputs.insert(std::make_pair(streamId, outputPair));
|
|
}
|
|
|
|
CameraMetadata params;
|
|
HCameraMetadata hidlParams;
|
|
if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
|
|
params.append(sessionParameters->settings->getInternalData());
|
|
const camera_metadata_t *params_metadata = params.getAndLock();
|
|
utils::convertToHidl(params_metadata, &hidlParams);
|
|
params.unlock(params_metadata);
|
|
}
|
|
remoteRet = mRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE, hidlParams);
|
|
CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "endConfigure()")
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
void
|
|
CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
|
|
Mutex::Autolock _l(mDeviceLock);
|
|
mRemote = remote;
|
|
}
|
|
|
|
bool
|
|
CameraDevice::setDeviceMetadataQueues() {
|
|
if (mRemote == nullptr) {
|
|
ALOGE("mRemote must not be null while trying to fetch metadata queues");
|
|
return false;
|
|
}
|
|
std::shared_ptr<RequestMetadataQueue> &reqQueue = mCaptureRequestMetadataQueue;
|
|
auto ret =
|
|
mRemote->getCaptureRequestMetadataQueue(
|
|
[&reqQueue](const auto &mqDescriptor) {
|
|
reqQueue = std::make_shared<RequestMetadataQueue>(mqDescriptor);
|
|
if (!reqQueue->isValid() || reqQueue->availableToWrite() <=0) {
|
|
ALOGE("Empty fmq from cameraserver");
|
|
reqQueue = nullptr;
|
|
}
|
|
});
|
|
if (!ret.isOk()) {
|
|
ALOGE("Transaction error trying to get capture request metadata queue");
|
|
return false;
|
|
}
|
|
std::shared_ptr<ResultMetadataQueue> &resQueue = mCaptureResultMetadataQueue;
|
|
ret =
|
|
mRemote->getCaptureResultMetadataQueue(
|
|
[&resQueue](const auto &mqDescriptor) {
|
|
resQueue = std::make_shared<ResultMetadataQueue>(mqDescriptor);
|
|
if (!resQueue->isValid() || resQueue->availableToWrite() <=0) {
|
|
ALOGE("Empty fmq from cameraserver");
|
|
}
|
|
});
|
|
if (!ret.isOk()) {
|
|
ALOGE("Transaction error trying to get capture result metadata queue");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
camera_status_t
|
|
CameraDevice::checkCameraClosedOrErrorLocked() const {
|
|
if (mRemote == nullptr) {
|
|
ALOGE("%s: camera device already closed", __FUNCTION__);
|
|
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
|
|
}
|
|
if (mInError) {// triggered by onDeviceError
|
|
ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
|
|
return mError;
|
|
}
|
|
return ACAMERA_OK;
|
|
}
|
|
|
|
void
|
|
CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
|
|
mInError = true;
|
|
mError = error;
|
|
return;
|
|
}
|
|
|
|
void
|
|
CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
|
|
ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
|
|
if (isError) {
|
|
mFutureErrorSet.insert(frameNumber);
|
|
} else if (frameNumber <= mCompletedFrameNumber) {
|
|
ALOGE("Frame number %" PRId64 " decreased! current fn %" PRId64,
|
|
frameNumber, mCompletedFrameNumber);
|
|
return;
|
|
} else {
|
|
if (frameNumber != mCompletedFrameNumber + 1) {
|
|
ALOGE("Frame number out of order. Expect %" PRId64 " but get %" PRId64,
|
|
mCompletedFrameNumber + 1, frameNumber);
|
|
// Do not assert as in java implementation
|
|
}
|
|
mCompletedFrameNumber = frameNumber;
|
|
}
|
|
update();
|
|
}
|
|
|
|
void
|
|
CameraDevice::FrameNumberTracker::update() {
|
|
for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
|
|
int64_t errorFrameNumber = *it;
|
|
if (errorFrameNumber == mCompletedFrameNumber + 1) {
|
|
mCompletedFrameNumber++;
|
|
it = mFutureErrorSet.erase(it);
|
|
} else if (errorFrameNumber <= mCompletedFrameNumber) {
|
|
// This should not happen, but deal with it anyway
|
|
ALOGE("Completd frame number passed through current frame number!");
|
|
// erase the old error since it's no longer useful
|
|
it = mFutureErrorSet.erase(it);
|
|
} else {
|
|
// Normal requests hasn't catched up error frames, just break
|
|
break;
|
|
}
|
|
}
|
|
ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
|
|
}
|
|
|
|
void
|
|
CameraDevice::onCaptureErrorLocked(
|
|
ErrorCode errorCode,
|
|
const CaptureResultExtras& resultExtras) {
|
|
int sequenceId = resultExtras.requestId;
|
|
int64_t frameNumber = resultExtras.frameNumber;
|
|
int32_t burstId = resultExtras.burstId;
|
|
auto it = mSequenceCallbackMap.find(sequenceId);
|
|
if (it == mSequenceCallbackMap.end()) {
|
|
ALOGE("%s: Error: capture sequence index %d not found!",
|
|
__FUNCTION__, sequenceId);
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
return;
|
|
}
|
|
|
|
CallbackHolder cbh = (*it).second;
|
|
sp<ACameraCaptureSession> session = cbh.mSession;
|
|
if ((size_t) burstId >= cbh.mRequests.size()) {
|
|
ALOGE("%s: Error: request index %d out of bound (size %zu)",
|
|
__FUNCTION__, burstId, cbh.mRequests.size());
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
return;
|
|
}
|
|
sp<CaptureRequest> request = cbh.mRequests[burstId];
|
|
|
|
// Handle buffer error
|
|
if (errorCode == ErrorCode::CAMERA_BUFFER) {
|
|
int32_t streamId = resultExtras.errorStreamId;
|
|
ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
|
|
cbh.mOnCaptureBufferLost;
|
|
auto outputPairIt = mConfiguredOutputs.find(streamId);
|
|
if (outputPairIt == mConfiguredOutputs.end()) {
|
|
ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
|
|
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
return;
|
|
}
|
|
|
|
const auto& windowHandles = outputPairIt->second.second.mOutputConfiguration.windowHandles;
|
|
for (const auto& outHandle : windowHandles) {
|
|
for (auto streamAndWindowId : request->mCaptureRequest.streamAndWindowIds) {
|
|
int32_t windowId = streamAndWindowId.windowId;
|
|
if (utils::isWindowNativeHandleEqual(windowHandles[windowId],outHandle)) {
|
|
native_handle_t* anw =
|
|
const_cast<native_handle_t *>(windowHandles[windowId].getNativeHandle());
|
|
ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
|
|
getId(), anw, frameNumber);
|
|
|
|
sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, session);
|
|
msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
|
|
msg->setObject(kCaptureRequestKey, request);
|
|
msg->setPointer(kAnwKey, (void*) anw);
|
|
msg->setInt64(kFrameNumberKey, frameNumber);
|
|
postSessionMsgAndCleanup(msg);
|
|
}
|
|
}
|
|
}
|
|
} else { // Handle other capture failures
|
|
// Fire capture failure callback if there is one registered
|
|
ACameraCaptureSession_captureCallback_failed onError = cbh.mOnCaptureFailed;
|
|
sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
|
|
failure->frameNumber = frameNumber;
|
|
// TODO: refine this when implementing flush
|
|
failure->reason = CAPTURE_FAILURE_REASON_ERROR;
|
|
failure->sequenceId = sequenceId;
|
|
failure->wasImageCaptured = (errorCode == ErrorCode::CAMERA_RESULT);
|
|
|
|
sp<AMessage> msg = new AMessage(cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureFail :
|
|
kWhatCaptureFail, mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, session);
|
|
if (cbh.mIsLogicalCameraCallback) {
|
|
if (resultExtras.errorPhysicalCameraId.size() > 0) {
|
|
msg->setString(kFailingPhysicalCameraId, resultExtras.errorPhysicalCameraId.c_str(),
|
|
resultExtras.errorPhysicalCameraId.size());
|
|
}
|
|
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnLogicalCameraCaptureFailed);
|
|
} else {
|
|
msg->setPointer(kCallbackFpKey, (void*) onError);
|
|
}
|
|
msg->setObject(kCaptureRequestKey, request);
|
|
msg->setObject(kCaptureFailureKey, failure);
|
|
postSessionMsgAndCleanup(msg);
|
|
|
|
// Update tracker
|
|
mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
|
|
checkAndFireSequenceCompleteLocked();
|
|
}
|
|
return;
|
|
}
|
|
|
|
CameraDevice::CallbackHandler::CallbackHandler(const char *id) : mId(id) { }
|
|
|
|
void CameraDevice::CallbackHandler::onMessageReceived(
|
|
const sp<AMessage> &msg) {
|
|
switch (msg->what()) {
|
|
case kWhatOnDisconnected:
|
|
case kWhatOnError:
|
|
case kWhatSessionStateCb:
|
|
case kWhatCaptureStart:
|
|
case kWhatCaptureResult:
|
|
case kWhatLogicalCaptureResult:
|
|
case kWhatCaptureFail:
|
|
case kWhatLogicalCaptureFail:
|
|
case kWhatCaptureSeqEnd:
|
|
case kWhatCaptureSeqAbort:
|
|
case kWhatCaptureBufferLost:
|
|
ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
|
|
break;
|
|
case kWhatCleanUpSessions:
|
|
mCachedSessions.clear();
|
|
return;
|
|
default:
|
|
ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
|
|
return;
|
|
}
|
|
// Check the common part of all message
|
|
void* context;
|
|
bool found = msg->findPointer(kContextKey, &context);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find callback context!", __FUNCTION__);
|
|
return;
|
|
}
|
|
switch (msg->what()) {
|
|
case kWhatOnDisconnected:
|
|
{
|
|
ACameraDevice* dev;
|
|
found = msg->findPointer(kDeviceKey, (void**) &dev);
|
|
if (!found || dev == nullptr) {
|
|
ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
|
|
return;
|
|
}
|
|
ACameraDevice_StateCallback onDisconnected;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onDisconnected);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onDisconnected == nullptr) {
|
|
return;
|
|
}
|
|
(*onDisconnected)(context, dev);
|
|
break;
|
|
}
|
|
case kWhatOnError:
|
|
{
|
|
ACameraDevice* dev;
|
|
found = msg->findPointer(kDeviceKey, (void**) &dev);
|
|
if (!found || dev == nullptr) {
|
|
ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
|
|
return;
|
|
}
|
|
ACameraDevice_ErrorStateCallback onError;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onError);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find onError!", __FUNCTION__);
|
|
return;
|
|
}
|
|
int errorCode;
|
|
found = msg->findInt32(kErrorCodeKey, &errorCode);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find error code!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onError == nullptr) {
|
|
return;
|
|
}
|
|
(*onError)(context, dev, errorCode);
|
|
break;
|
|
}
|
|
case kWhatSessionStateCb:
|
|
case kWhatCaptureStart:
|
|
case kWhatCaptureResult:
|
|
case kWhatLogicalCaptureResult:
|
|
case kWhatCaptureFail:
|
|
case kWhatLogicalCaptureFail:
|
|
case kWhatCaptureSeqEnd:
|
|
case kWhatCaptureSeqAbort:
|
|
case kWhatCaptureBufferLost:
|
|
{
|
|
sp<RefBase> obj;
|
|
found = msg->findObject(kSessionSpKey, &obj);
|
|
if (!found || obj == nullptr) {
|
|
ALOGE("%s: Cannot find session pointer!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
|
|
mCachedSessions.push(session);
|
|
sp<CaptureRequest> requestSp = nullptr;
|
|
const char *id_cstr = mId.c_str();
|
|
switch (msg->what()) {
|
|
case kWhatCaptureStart:
|
|
case kWhatCaptureResult:
|
|
case kWhatLogicalCaptureResult:
|
|
case kWhatCaptureFail:
|
|
case kWhatLogicalCaptureFail:
|
|
case kWhatCaptureBufferLost:
|
|
found = msg->findObject(kCaptureRequestKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture request!", __FUNCTION__);
|
|
return;
|
|
}
|
|
requestSp = static_cast<CaptureRequest*>(obj.get());
|
|
break;
|
|
}
|
|
|
|
switch (msg->what()) {
|
|
case kWhatSessionStateCb:
|
|
{
|
|
ACameraCaptureSession_stateCallback onState;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onState);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find state callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onState == nullptr) {
|
|
return;
|
|
}
|
|
(*onState)(context, session.get());
|
|
break;
|
|
}
|
|
case kWhatCaptureStart:
|
|
{
|
|
ACameraCaptureSession_captureCallback_start onStart;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onStart);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture start callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onStart == nullptr) {
|
|
return;
|
|
}
|
|
int64_t timestamp;
|
|
found = msg->findInt64(kTimeStampKey, ×tamp);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
|
|
return;
|
|
}
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onStart)(context, session.get(), request, timestamp);
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
case kWhatCaptureResult:
|
|
{
|
|
ACameraCaptureSession_captureCallback_result onResult;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onResult == nullptr) {
|
|
return;
|
|
}
|
|
|
|
found = msg->findObject(kCaptureResultKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture result!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onResult)(context, session.get(), request, result.get());
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
case kWhatLogicalCaptureResult:
|
|
{
|
|
ACameraCaptureSession_logicalCamera_captureCallback_result onResult;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onResult == nullptr) {
|
|
return;
|
|
}
|
|
|
|
found = msg->findObject(kCaptureResultKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture result!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
|
|
|
|
found = msg->findObject(kPhysicalCaptureResultKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find physical capture result!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
|
|
static_cast<ACameraPhysicalCaptureResultInfo*>(obj.get()));
|
|
std::vector<PhysicalCaptureResultInfoLocal>& physicalResultInfo =
|
|
physicalResult->mPhysicalResultInfo;
|
|
|
|
std::vector<std::string> physicalCameraIds;
|
|
std::vector<sp<ACameraMetadata>> physicalMetadataCopy;
|
|
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
|
|
physicalCameraIds.push_back(physicalResultInfo[i].physicalCameraId);
|
|
|
|
CameraMetadata clone = physicalResultInfo[i].physicalMetadata;
|
|
clone.update(ANDROID_SYNC_FRAME_NUMBER,
|
|
&physicalResult->mFrameNumber, /*data_count*/1);
|
|
sp<ACameraMetadata> metadata =
|
|
new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
|
|
physicalMetadataCopy.push_back(metadata);
|
|
}
|
|
std::vector<const char*> physicalCameraIdPtrs;
|
|
std::vector<const ACameraMetadata*> physicalMetadataCopyPtrs;
|
|
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
|
|
physicalCameraIdPtrs.push_back(physicalCameraIds[i].c_str());
|
|
physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
|
|
}
|
|
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onResult)(context, session.get(), request, result.get(),
|
|
physicalResultInfo.size(), physicalCameraIdPtrs.data(),
|
|
physicalMetadataCopyPtrs.data());
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
|
|
case kWhatCaptureFail:
|
|
{
|
|
ACameraCaptureSession_captureCallback_failed onFail;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onFail == nullptr) {
|
|
return;
|
|
}
|
|
|
|
found = msg->findObject(kCaptureFailureKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<CameraCaptureFailure> failureSp(
|
|
static_cast<CameraCaptureFailure*>(obj.get()));
|
|
ACameraCaptureFailure* failure =
|
|
static_cast<ACameraCaptureFailure*>(failureSp.get());
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onFail)(context, session.get(), request, failure);
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
case kWhatLogicalCaptureFail:
|
|
{
|
|
ACameraCaptureSession_logicalCamera_captureCallback_failed onFail;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onFail == nullptr) {
|
|
return;
|
|
}
|
|
|
|
found = msg->findObject(kCaptureFailureKey, &obj);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
|
|
return;
|
|
}
|
|
sp<CameraCaptureFailure> failureSp(
|
|
static_cast<CameraCaptureFailure*>(obj.get()));
|
|
ALogicalCameraCaptureFailure failure;
|
|
AString physicalCameraId;
|
|
found = msg->findString(kFailingPhysicalCameraId, &physicalCameraId);
|
|
if (found && !physicalCameraId.empty()) {
|
|
failure.physicalCameraId = physicalCameraId.c_str();
|
|
} else {
|
|
failure.physicalCameraId = nullptr;
|
|
}
|
|
failure.captureFailure = *failureSp;
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onFail)(context, session.get(), request, &failure);
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
case kWhatCaptureSeqEnd:
|
|
{
|
|
ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onSeqEnd);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onSeqEnd == nullptr) {
|
|
return;
|
|
}
|
|
int seqId;
|
|
found = msg->findInt32(kSequenceIdKey, &seqId);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find frame number!", __FUNCTION__);
|
|
return;
|
|
}
|
|
int64_t frameNumber;
|
|
found = msg->findInt64(kFrameNumberKey, &frameNumber);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find frame number!", __FUNCTION__);
|
|
return;
|
|
}
|
|
(*onSeqEnd)(context, session.get(), seqId, frameNumber);
|
|
break;
|
|
}
|
|
case kWhatCaptureSeqAbort:
|
|
{
|
|
ACameraCaptureSession_captureCallback_sequenceAbort onSeqAbort;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onSeqAbort);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onSeqAbort == nullptr) {
|
|
return;
|
|
}
|
|
int seqId;
|
|
found = msg->findInt32(kSequenceIdKey, &seqId);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find frame number!", __FUNCTION__);
|
|
return;
|
|
}
|
|
(*onSeqAbort)(context, session.get(), seqId);
|
|
break;
|
|
}
|
|
case kWhatCaptureBufferLost:
|
|
{
|
|
ACameraCaptureSession_captureCallback_bufferLost onBufferLost;
|
|
found = msg->findPointer(kCallbackFpKey, (void**) &onBufferLost);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find buffer lost callback!", __FUNCTION__);
|
|
return;
|
|
}
|
|
if (onBufferLost == nullptr) {
|
|
return;
|
|
}
|
|
|
|
native_handle_t* anw;
|
|
found = msg->findPointer(kAnwKey, (void**) &anw);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find native_handle_t!", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
int64_t frameNumber;
|
|
found = msg->findInt64(kFrameNumberKey, &frameNumber);
|
|
if (!found) {
|
|
ALOGE("%s: Cannot find frame number!", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
|
|
(*onBufferLost)(context, session.get(), request, anw, frameNumber);
|
|
freeACaptureRequest(request);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CameraDevice::CallbackHolder::CallbackHolder(
|
|
sp<ACameraCaptureSession> session,
|
|
const Vector<sp<CaptureRequest> >& requests,
|
|
bool isRepeating,
|
|
ACameraCaptureSession_captureCallbacks* cbs) :
|
|
mSession(session), mRequests(requests),
|
|
mIsRepeating(isRepeating),
|
|
mIsLogicalCameraCallback(false) {
|
|
initCaptureCallbacks(cbs);
|
|
|
|
if (cbs != nullptr) {
|
|
mOnCaptureCompleted = cbs->onCaptureCompleted;
|
|
mOnCaptureFailed = cbs->onCaptureFailed;
|
|
}
|
|
}
|
|
|
|
CameraDevice::CallbackHolder::CallbackHolder(
|
|
sp<ACameraCaptureSession> session,
|
|
const Vector<sp<CaptureRequest> >& requests,
|
|
bool isRepeating,
|
|
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
|
|
mSession(session), mRequests(requests),
|
|
mIsRepeating(isRepeating),
|
|
mIsLogicalCameraCallback(true) {
|
|
initCaptureCallbacks(lcbs);
|
|
|
|
if (lcbs != nullptr) {
|
|
mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
|
|
mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
|
|
}
|
|
}
|
|
|
|
void
|
|
CameraDevice::checkRepeatingSequenceCompleteLocked(
|
|
const int sequenceId, const int64_t lastFrameNumber) {
|
|
ALOGV("Repeating seqId %d lastFrameNumer %" PRId64, sequenceId, lastFrameNumber);
|
|
if (lastFrameNumber == NO_FRAMES_CAPTURED) {
|
|
if (mSequenceCallbackMap.count(sequenceId) == 0) {
|
|
ALOGW("No callback found for sequenceId %d", sequenceId);
|
|
return;
|
|
}
|
|
// remove callback holder from callback map
|
|
auto cbIt = mSequenceCallbackMap.find(sequenceId);
|
|
CallbackHolder cbh = cbIt->second;
|
|
mSequenceCallbackMap.erase(cbIt);
|
|
// send seq aborted callback
|
|
sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, cbh.mSession);
|
|
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceAborted);
|
|
msg->setInt32(kSequenceIdKey, sequenceId);
|
|
postSessionMsgAndCleanup(msg);
|
|
} else {
|
|
// Use mSequenceLastFrameNumberMap to track
|
|
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
|
|
|
|
// Last frame might have arrived. Check now
|
|
checkAndFireSequenceCompleteLocked();
|
|
}
|
|
}
|
|
|
|
void
|
|
CameraDevice::checkAndFireSequenceCompleteLocked() {
|
|
int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
|
|
auto it = mSequenceLastFrameNumberMap.begin();
|
|
while (it != mSequenceLastFrameNumberMap.end()) {
|
|
int sequenceId = it->first;
|
|
int64_t lastFrameNumber = it->second;
|
|
bool seqCompleted = false;
|
|
bool hasCallback = true;
|
|
|
|
if (mRemote == nullptr) {
|
|
ALOGW("Camera %s closed while checking sequence complete", getId());
|
|
return;
|
|
}
|
|
|
|
// Check if there is callback for this sequence
|
|
// This should not happen because we always register callback (with nullptr inside)
|
|
if (mSequenceCallbackMap.count(sequenceId) == 0) {
|
|
ALOGW("No callback found for sequenceId %d", sequenceId);
|
|
hasCallback = false;
|
|
}
|
|
|
|
if (lastFrameNumber <= completedFrameNumber) {
|
|
ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
|
|
sequenceId, lastFrameNumber, completedFrameNumber);
|
|
seqCompleted = true;
|
|
}
|
|
|
|
if (seqCompleted && hasCallback) {
|
|
// remove callback holder from callback map
|
|
auto cbIt = mSequenceCallbackMap.find(sequenceId);
|
|
CallbackHolder cbh = cbIt->second;
|
|
mSequenceCallbackMap.erase(cbIt);
|
|
// send seq complete callback
|
|
sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, cbh.mSession);
|
|
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
|
|
msg->setInt32(kSequenceIdKey, sequenceId);
|
|
msg->setInt64(kFrameNumberKey, lastFrameNumber);
|
|
|
|
// Clear the session sp before we send out the message
|
|
// This will guarantee the rare case where the message is processed
|
|
// before cbh goes out of scope and causing we call the session
|
|
// destructor while holding device lock
|
|
cbh.mSession.clear();
|
|
|
|
postSessionMsgAndCleanup(msg);
|
|
}
|
|
|
|
// No need to track sequence complete if there is no callback registered
|
|
if (seqCompleted || !hasCallback) {
|
|
it = mSequenceLastFrameNumberMap.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CameraDevice::stopLooperAndDisconnect() {
|
|
Mutex::Autolock _l(mDeviceLock);
|
|
sp<ACameraCaptureSession> session = mCurrentSession.promote();
|
|
if (!isClosed()) {
|
|
disconnectLocked(session);
|
|
}
|
|
mCurrentSession = nullptr;
|
|
if (mCbLooper != nullptr) {
|
|
mCbLooper->unregisterHandler(mHandler->id());
|
|
mCbLooper->stop();
|
|
}
|
|
mCbLooper.clear();
|
|
mHandler.clear();
|
|
}
|
|
|
|
/**
|
|
* Camera service callback implementation
|
|
*/
|
|
android::hardware::Return<void>
|
|
CameraDevice::ServiceCallback::onDeviceError(
|
|
ErrorCode errorCode,
|
|
const CaptureResultExtras& resultExtras) {
|
|
ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d"
|
|
" physical camera ID %s", errorCode, resultExtras.frameNumber, resultExtras.requestId,
|
|
resultExtras.burstId, resultExtras.errorPhysicalCameraId.c_str());
|
|
auto ret = Void();
|
|
sp<CameraDevice> dev = mDevice.promote();
|
|
if (dev == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
|
|
sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
|
|
Mutex::Autolock _l(dev->mDeviceLock);
|
|
if (dev->mRemote == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
switch (errorCode) {
|
|
case ErrorCode::CAMERA_DISCONNECTED:
|
|
{
|
|
// Camera is disconnected, close the session and expect no more callbacks
|
|
if (session != nullptr) {
|
|
session->closeByDevice();
|
|
}
|
|
dev->mCurrentSession = nullptr;
|
|
sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
|
|
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
|
|
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
|
|
msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onDisconnected);
|
|
msg->post();
|
|
break;
|
|
}
|
|
default:
|
|
ALOGE("Unknown error from camera device: %d", errorCode);
|
|
[[fallthrough]];
|
|
case ErrorCode::CAMERA_DEVICE:
|
|
case ErrorCode::CAMERA_SERVICE:
|
|
{
|
|
int32_t errorVal = ::ERROR_CAMERA_DEVICE;
|
|
// We keep this switch since this block might be encountered with
|
|
// more than just 2 states. The default fallthrough could have us
|
|
// handling more unmatched error cases.
|
|
switch (errorCode) {
|
|
case ErrorCode::CAMERA_DEVICE:
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
|
|
break;
|
|
case ErrorCode::CAMERA_SERVICE:
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
errorVal = ::ERROR_CAMERA_SERVICE;
|
|
break;
|
|
default:
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
|
|
break;
|
|
}
|
|
sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
|
|
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
|
|
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
|
|
msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
|
|
msg->setInt32(kErrorCodeKey, errorVal);
|
|
msg->post();
|
|
break;
|
|
}
|
|
case ErrorCode::CAMERA_REQUEST:
|
|
case ErrorCode::CAMERA_RESULT:
|
|
case ErrorCode::CAMERA_BUFFER:
|
|
dev->onCaptureErrorLocked(errorCode, resultExtras);
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
android::hardware::Return<void>
|
|
CameraDevice::ServiceCallback::onDeviceIdle() {
|
|
ALOGV("Camera is now idle");
|
|
auto ret = Void();
|
|
sp<CameraDevice> dev = mDevice.promote();
|
|
if (dev == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
|
|
Mutex::Autolock _l(dev->mDeviceLock);
|
|
if (dev->isClosed() || dev->mRemote == nullptr) {
|
|
return ret;
|
|
}
|
|
|
|
if (dev->mIdle) {
|
|
// Already in idle state. Possibly other thread did waitUntilIdle
|
|
return ret;
|
|
}
|
|
|
|
if (dev->mCurrentSession != nullptr) {
|
|
ALOGE("onDeviceIdle sending state cb");
|
|
if (dev->mBusySession != dev->mCurrentSession) {
|
|
ALOGE("Current session != busy session");
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
|
|
return ret;
|
|
}
|
|
|
|
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
|
|
msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
|
|
msg->setObject(kSessionSpKey, dev->mBusySession);
|
|
msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
|
|
// Make sure we clear the sp first so the session destructor can
|
|
// only happen on handler thread (where we don't hold device/session lock)
|
|
dev->mBusySession.clear();
|
|
dev->postSessionMsgAndCleanup(msg);
|
|
}
|
|
dev->mIdle = true;
|
|
dev->mFlushing = false;
|
|
return ret;
|
|
}
|
|
|
|
android::hardware::Return<void>
|
|
CameraDevice::ServiceCallback::onCaptureStarted(
|
|
const CaptureResultExtras& resultExtras,
|
|
uint64_t timestamp) {
|
|
auto ret = Void();
|
|
|
|
sp<CameraDevice> dev = mDevice.promote();
|
|
if (dev == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
Mutex::Autolock _l(dev->mDeviceLock);
|
|
if (dev->isClosed() || dev->mRemote == nullptr) {
|
|
return ret;
|
|
}
|
|
|
|
int32_t sequenceId = resultExtras.requestId;
|
|
int32_t burstId = resultExtras.burstId;
|
|
|
|
auto it = dev->mSequenceCallbackMap.find(sequenceId);
|
|
if (it != dev->mSequenceCallbackMap.end()) {
|
|
CallbackHolder cbh = (*it).second;
|
|
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
|
|
sp<ACameraCaptureSession> session = cbh.mSession;
|
|
if ((size_t) burstId >= cbh.mRequests.size()) {
|
|
ALOGE("%s: Error: request index %d out of bound (size %zu)",
|
|
__FUNCTION__, burstId, cbh.mRequests.size());
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
}
|
|
sp<CaptureRequest> request = cbh.mRequests[burstId];
|
|
sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, session);
|
|
msg->setPointer(kCallbackFpKey, (void*) onStart);
|
|
msg->setObject(kCaptureRequestKey, request);
|
|
msg->setInt64(kTimeStampKey, timestamp);
|
|
dev->postSessionMsgAndCleanup(msg);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
android::hardware::Return<void>
|
|
CameraDevice::ServiceCallback::onResultReceived(
|
|
const FmqSizeOrMetadata& resultMetadata,
|
|
const CaptureResultExtras& resultExtras,
|
|
const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) {
|
|
auto ret = Void();
|
|
|
|
sp<CameraDevice> dev = mDevice.promote();
|
|
if (dev == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
int32_t sequenceId = resultExtras.requestId;
|
|
int64_t frameNumber = resultExtras.frameNumber;
|
|
int32_t burstId = resultExtras.burstId;
|
|
bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
|
|
|
|
if (!isPartialResult) {
|
|
ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
|
|
}
|
|
|
|
Mutex::Autolock _l(dev->mDeviceLock);
|
|
if (dev->mRemote == nullptr) {
|
|
return ret; // device has been disconnected
|
|
}
|
|
|
|
if (dev->isClosed()) {
|
|
if (!isPartialResult) {
|
|
dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
|
|
}
|
|
// early return to avoid callback sent to closed devices
|
|
return ret;
|
|
}
|
|
|
|
CameraMetadata metadataCopy;
|
|
camera_status_t status = readOneResultMetadata(resultMetadata,
|
|
dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
|
|
if (status != ACAMERA_OK) {
|
|
ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
|
|
metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
|
|
|
|
auto it = dev->mSequenceCallbackMap.find(sequenceId);
|
|
if (it != dev->mSequenceCallbackMap.end()) {
|
|
CallbackHolder cbh = (*it).second;
|
|
sp<ACameraCaptureSession> session = cbh.mSession;
|
|
if ((size_t) burstId >= cbh.mRequests.size()) {
|
|
ALOGE("%s: Error: request index %d out of bound (size %zu)",
|
|
__FUNCTION__, burstId, cbh.mRequests.size());
|
|
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
|
|
}
|
|
sp<CaptureRequest> request = cbh.mRequests[burstId];
|
|
sp<ACameraMetadata> result(new ACameraMetadata(
|
|
metadataCopy.release(), ACameraMetadata::ACM_RESULT));
|
|
|
|
std::vector<PhysicalCaptureResultInfoLocal> localPhysicalResult;
|
|
localPhysicalResult.resize(physicalResultInfos.size());
|
|
for (size_t i = 0; i < physicalResultInfos.size(); i++) {
|
|
localPhysicalResult[i].physicalCameraId = physicalResultInfos[i].physicalCameraId;
|
|
status = readOneResultMetadata(physicalResultInfos[i].physicalCameraMetadata,
|
|
dev->mCaptureResultMetadataQueue.get(),
|
|
&localPhysicalResult[i].physicalMetadata);
|
|
if (status != ACAMERA_OK) {
|
|
ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
}
|
|
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
|
|
new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
|
|
|
|
sp<AMessage> msg = new AMessage(
|
|
cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
|
|
dev->mHandler);
|
|
msg->setPointer(kContextKey, cbh.mContext);
|
|
msg->setObject(kSessionSpKey, session);
|
|
msg->setObject(kCaptureRequestKey, request);
|
|
msg->setObject(kCaptureResultKey, result);
|
|
if (isPartialResult) {
|
|
msg->setPointer(kCallbackFpKey,
|
|
(void *)cbh.mOnCaptureProgressed);
|
|
} else if (cbh.mIsLogicalCameraCallback) {
|
|
msg->setPointer(kCallbackFpKey,
|
|
(void *)cbh.mOnLogicalCameraCaptureCompleted);
|
|
msg->setObject(kPhysicalCaptureResultKey, physicalResult);
|
|
} else {
|
|
msg->setPointer(kCallbackFpKey,
|
|
(void *)cbh.mOnCaptureCompleted);
|
|
}
|
|
dev->postSessionMsgAndCleanup(msg);
|
|
}
|
|
|
|
if (!isPartialResult) {
|
|
dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
|
|
dev->checkAndFireSequenceCompleteLocked();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
android::hardware::Return<void>
|
|
CameraDevice::ServiceCallback::onRepeatingRequestError(
|
|
uint64_t lastFrameNumber, int32_t stoppedSequenceId) {
|
|
auto ret = Void();
|
|
|
|
sp<CameraDevice> dev = mDevice.promote();
|
|
if (dev == nullptr) {
|
|
return ret; // device has been closed
|
|
}
|
|
|
|
Mutex::Autolock _l(dev->mDeviceLock);
|
|
|
|
int repeatingSequenceId = dev->mRepeatingSequenceId;
|
|
if (stoppedSequenceId == repeatingSequenceId) {
|
|
dev->mRepeatingSequenceId = REQUEST_ID_NONE;
|
|
}
|
|
|
|
dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
|
|
|
|
return ret;
|
|
}
|
|
|
|
camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
|
|
const FmqSizeOrMetadata& fmqSizeOrMetadata, ResultMetadataQueue* metadataQueue,
|
|
CameraMetadata* metadata) {
|
|
if (metadataQueue == nullptr || metadata == nullptr) {
|
|
return ACAMERA_ERROR_INVALID_PARAMETER;
|
|
}
|
|
bool converted;
|
|
HCameraMetadata hCameraMetadata;
|
|
if (fmqSizeOrMetadata.getDiscriminator() ==
|
|
FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
|
|
hCameraMetadata.resize(fmqSizeOrMetadata.fmqMetadataSize());
|
|
bool read = metadataQueue->read(
|
|
hCameraMetadata.data(), fmqSizeOrMetadata.fmqMetadataSize());
|
|
if (!read) {
|
|
ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
|
|
return ACAMERA_ERROR_UNKNOWN;
|
|
}
|
|
// TODO: Do we actually need to clone here ?
|
|
converted = utils::convertFromHidlCloned(hCameraMetadata, metadata);
|
|
} else {
|
|
converted = utils::convertFromHidlCloned(fmqSizeOrMetadata.metadata(), metadata);
|
|
}
|
|
|
|
return converted ? ACAMERA_OK : ACAMERA_ERROR_UNKNOWN;
|
|
}
|
|
|
|
} // namespace acam
|
|
} // namespace android
|