Merge "camera: Add support for individual physical camera requests"
This commit is contained in:
commit
30170d5590
8 changed files with 536 additions and 151 deletions
|
@ -333,11 +333,10 @@ void CameraDeviceSession::ResultBatcher::setResultMetadataQueue(
|
|||
mResultMetadataQueue = q;
|
||||
}
|
||||
|
||||
void CameraDeviceSession::ResultBatcher::registerBatch(
|
||||
const hidl_vec<CaptureRequest>& requests) {
|
||||
void CameraDeviceSession::ResultBatcher::registerBatch(uint32_t frameNumber, uint32_t batchSize) {
|
||||
auto batch = std::make_shared<InflightBatch>();
|
||||
batch->mFirstFrame = requests[0].frameNumber;
|
||||
batch->mBatchSize = requests.size();
|
||||
batch->mFirstFrame = frameNumber;
|
||||
batch->mBatchSize = batchSize;
|
||||
batch->mLastFrame = batch->mFirstFrame + batch->mBatchSize - 1;
|
||||
batch->mNumPartialResults = mNumPartialResults;
|
||||
for (int id : mStreamsToBatch) {
|
||||
|
@ -1010,7 +1009,7 @@ Return<void> CameraDeviceSession::processCaptureRequest(
|
|||
}
|
||||
|
||||
if (s == Status::OK && requests.size() > 1) {
|
||||
mResultBatcher.registerBatch(requests);
|
||||
mResultBatcher.registerBatch(requests[0].frameNumber, requests.size());
|
||||
}
|
||||
|
||||
_hidl_cb(s, numRequestProcessed);
|
||||
|
@ -1111,6 +1110,7 @@ Status CameraDeviceSession::processOneCaptureRequest(const CaptureRequest& reque
|
|||
halRequest.settings = settingsOverride.getAndLock();
|
||||
}
|
||||
}
|
||||
halRequest.num_physcam_settings = 0;
|
||||
|
||||
ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
|
||||
ATRACE_BEGIN("camera3->process_capture_request");
|
||||
|
|
|
@ -184,7 +184,7 @@ protected:
|
|||
void setBatchedStreams(const std::vector<int>& streamsToBatch);
|
||||
void setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q);
|
||||
|
||||
void registerBatch(const hidl_vec<CaptureRequest>& requests);
|
||||
void registerBatch(uint32_t frameNumber, uint32_t batchSize);
|
||||
void notify(NotifyMsg& msg);
|
||||
void processCaptureResult(CaptureResult& result);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import android.hardware.camera.common@1.0::Status;
|
|||
import @3.3::ICameraDeviceSession;
|
||||
import @3.3::HalStreamConfiguration;
|
||||
import @3.2::BufferCache;
|
||||
import @3.2::CaptureRequest;
|
||||
|
||||
/**
|
||||
* Camera device active session interface.
|
||||
|
@ -72,4 +71,38 @@ interface ICameraDeviceSession extends @3.3::ICameraDeviceSession {
|
|||
configureStreams_3_4(@3.4::StreamConfiguration requestedConfiguration)
|
||||
generates (Status status,
|
||||
@3.4::HalStreamConfiguration halConfiguration);
|
||||
|
||||
/**
|
||||
* processCaptureRequest_3_4:
|
||||
*
|
||||
* Identical to @3.2::ICameraDeviceSession.processCaptureRequest, except that:
|
||||
*
|
||||
* - The capture request can include individual settings for physical camera devices
|
||||
* backing a logical multi-camera.
|
||||
*
|
||||
* @return status Status code for the operation, one of:
|
||||
* OK:
|
||||
* On a successful start to processing the capture request
|
||||
* ILLEGAL_ARGUMENT:
|
||||
* If the input is malformed (the settings are empty when not
|
||||
* allowed, the physical camera settings are invalid, there are 0
|
||||
* output buffers, etc) and capture processing
|
||||
* cannot start. Failures during request processing must be
|
||||
* handled by calling ICameraDeviceCallback::notify(). In case of
|
||||
* this error, the framework retains responsibility for the
|
||||
* stream buffers' fences and the buffer handles; the HAL must not
|
||||
* close the fences or return these buffers with
|
||||
* ICameraDeviceCallback::processCaptureResult().
|
||||
* INTERNAL_ERROR:
|
||||
* If the camera device has encountered a serious error. After this
|
||||
* error is returned, only the close() method can be successfully
|
||||
* called by the framework.
|
||||
* @return numRequestProcessed Number of requests successfully processed by
|
||||
* camera HAL. When status is OK, this must be equal to the size of
|
||||
* requests. When the call fails, this number is the number of requests
|
||||
* that HAL processed successfully before HAL runs into an error.
|
||||
*
|
||||
*/
|
||||
processCaptureRequest_3_4(vec<CaptureRequest> requests, vec<BufferCache> cachesToRemove)
|
||||
generates (Status status, uint32_t numRequestProcessed);
|
||||
};
|
||||
|
|
|
@ -201,9 +201,9 @@ void CameraDeviceSession::postProcessConfigurationLocked_3_4(
|
|||
}
|
||||
|
||||
Return<void> CameraDeviceSession::processCaptureRequest_3_4(
|
||||
const hidl_vec<CaptureRequest>& requests,
|
||||
const hidl_vec<V3_4::CaptureRequest>& requests,
|
||||
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
|
||||
ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) {
|
||||
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) {
|
||||
updateBufferCaches(cachesToRemove);
|
||||
|
||||
uint32_t numRequestProcessed = 0;
|
||||
|
@ -216,14 +216,14 @@ Return<void> CameraDeviceSession::processCaptureRequest_3_4(
|
|||
}
|
||||
|
||||
if (s == Status::OK && requests.size() > 1) {
|
||||
mResultBatcher.registerBatch(requests);
|
||||
mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size());
|
||||
}
|
||||
|
||||
_hidl_cb(s, numRequestProcessed);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& request) {
|
||||
Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request) {
|
||||
Status status = initStatus();
|
||||
if (status != Status::OK) {
|
||||
ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
|
||||
|
@ -231,15 +231,15 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
}
|
||||
|
||||
camera3_capture_request_t halRequest;
|
||||
halRequest.frame_number = request.frameNumber;
|
||||
halRequest.frame_number = request.v3_2.frameNumber;
|
||||
|
||||
bool converted = true;
|
||||
V3_2::CameraMetadata settingsFmq; // settings from FMQ
|
||||
if (request.fmqSettingsSize > 0) {
|
||||
if (request.v3_2.fmqSettingsSize > 0) {
|
||||
// non-blocking read; client must write metadata before calling
|
||||
// processOneCaptureRequest
|
||||
settingsFmq.resize(request.fmqSettingsSize);
|
||||
bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.fmqSettingsSize);
|
||||
settingsFmq.resize(request.v3_2.fmqSettingsSize);
|
||||
bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.v3_2.fmqSettingsSize);
|
||||
if (read) {
|
||||
converted = V3_2::implementation::convertFromHidl(settingsFmq, &halRequest.settings);
|
||||
} else {
|
||||
|
@ -247,7 +247,8 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
converted = false;
|
||||
}
|
||||
} else {
|
||||
converted = V3_2::implementation::convertFromHidl(request.settings, &halRequest.settings);
|
||||
converted = V3_2::implementation::convertFromHidl(request.v3_2.settings,
|
||||
&halRequest.settings);
|
||||
}
|
||||
|
||||
if (!converted) {
|
||||
|
@ -263,9 +264,9 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
|
||||
hidl_vec<buffer_handle_t*> allBufPtrs;
|
||||
hidl_vec<int> allFences;
|
||||
bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
|
||||
request.inputBuffer.bufferId != 0);
|
||||
size_t numOutputBufs = request.outputBuffers.size();
|
||||
bool hasInputBuf = (request.v3_2.inputBuffer.streamId != -1 &&
|
||||
request.v3_2.inputBuffer.bufferId != 0);
|
||||
size_t numOutputBufs = request.v3_2.outputBuffers.size();
|
||||
size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
|
||||
|
||||
if (numOutputBufs == 0) {
|
||||
|
@ -273,7 +274,7 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
status = importRequest(request, allBufPtrs, allFences);
|
||||
status = importRequest(request.v3_2, allBufPtrs, allFences);
|
||||
if (status != Status::OK) {
|
||||
return status;
|
||||
}
|
||||
|
@ -285,12 +286,12 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
{
|
||||
Mutex::Autolock _l(mInflightLock);
|
||||
if (hasInputBuf) {
|
||||
auto streamId = request.inputBuffer.streamId;
|
||||
auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
|
||||
auto streamId = request.v3_2.inputBuffer.streamId;
|
||||
auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
|
||||
auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
|
||||
convertFromHidl(
|
||||
allBufPtrs[numOutputBufs], request.inputBuffer.status,
|
||||
&mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
|
||||
allBufPtrs[numOutputBufs], request.v3_2.inputBuffer.status,
|
||||
&mStreamMap[request.v3_2.inputBuffer.streamId], allFences[numOutputBufs],
|
||||
&bufCache);
|
||||
bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
|
||||
halRequest.input_buffer = &bufCache;
|
||||
|
@ -300,11 +301,11 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
|
||||
halRequest.num_output_buffers = numOutputBufs;
|
||||
for (size_t i = 0; i < numOutputBufs; i++) {
|
||||
auto streamId = request.outputBuffers[i].streamId;
|
||||
auto key = std::make_pair(streamId, request.frameNumber);
|
||||
auto streamId = request.v3_2.outputBuffers[i].streamId;
|
||||
auto key = std::make_pair(streamId, request.v3_2.frameNumber);
|
||||
auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
|
||||
convertFromHidl(
|
||||
allBufPtrs[i], request.outputBuffers[i].status,
|
||||
allBufPtrs[i], request.v3_2.outputBuffers[i].status,
|
||||
&mStreamMap[streamId], allFences[i],
|
||||
&bufCache);
|
||||
bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
|
||||
|
@ -322,7 +323,47 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
}
|
||||
}
|
||||
|
||||
ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
|
||||
std::vector<const char *> physicalCameraIds;
|
||||
std::vector<const camera_metadata_t *> physicalCameraSettings;
|
||||
std::vector<V3_2::CameraMetadata> physicalFmq;
|
||||
size_t settingsCount = request.physicalCameraSettings.size();
|
||||
if (settingsCount > 0) {
|
||||
physicalCameraIds.reserve(settingsCount);
|
||||
physicalCameraSettings.reserve(settingsCount);
|
||||
physicalFmq.reserve(settingsCount);
|
||||
|
||||
for (size_t i = 0; i < settingsCount; i++) {
|
||||
uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize;
|
||||
const camera_metadata_t *settings;
|
||||
if (settingsSize > 0) {
|
||||
physicalFmq.push_back(V3_2::CameraMetadata(settingsSize));
|
||||
bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize);
|
||||
if (read) {
|
||||
converted = V3_2::implementation::convertFromHidl(physicalFmq[i], &settings);
|
||||
physicalCameraSettings.push_back(settings);
|
||||
} else {
|
||||
ALOGE("%s: physical camera settings metadata couldn't be read from fmq!",
|
||||
__FUNCTION__);
|
||||
converted = false;
|
||||
}
|
||||
} else {
|
||||
converted = V3_2::implementation::convertFromHidl(
|
||||
request.physicalCameraSettings[i].settings, &settings);
|
||||
physicalCameraSettings.push_back(settings);
|
||||
}
|
||||
|
||||
if (!converted) {
|
||||
ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__);
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str());
|
||||
}
|
||||
}
|
||||
halRequest.num_physcam_settings = settingsCount;
|
||||
halRequest.physcam_id = physicalCameraIds.data();
|
||||
halRequest.physcam_settings = physicalCameraSettings.data();
|
||||
|
||||
ATRACE_ASYNC_BEGIN("frame capture", request.v3_2.frameNumber);
|
||||
ATRACE_BEGIN("camera3->process_capture_request");
|
||||
status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
|
||||
ATRACE_END();
|
||||
|
@ -335,17 +376,23 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const CaptureRequest& r
|
|||
|
||||
cleanupInflightFences(allFences, numBufs);
|
||||
if (hasInputBuf) {
|
||||
auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
|
||||
auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
|
||||
mInflightBuffers.erase(key);
|
||||
}
|
||||
for (size_t i = 0; i < numOutputBufs; i++) {
|
||||
auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
|
||||
auto key = std::make_pair(request.v3_2.outputBuffers[i].streamId,
|
||||
request.v3_2.frameNumber);
|
||||
mInflightBuffers.erase(key);
|
||||
}
|
||||
if (aeCancelTriggerNeeded) {
|
||||
mInflightAETriggerOverrides.erase(request.frameNumber);
|
||||
mInflightAETriggerOverrides.erase(request.v3_2.frameNumber);
|
||||
}
|
||||
|
||||
if (ret == BAD_VALUE) {
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
} else {
|
||||
return Status::INTERNAL_ERROR;
|
||||
}
|
||||
return Status::INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
mFirstRequest = false;
|
||||
|
|
|
@ -85,10 +85,10 @@ protected:
|
|||
void postProcessConfigurationLocked_3_4(const StreamConfiguration& requestedConfiguration);
|
||||
|
||||
Return<void> processCaptureRequest_3_4(
|
||||
const hidl_vec<CaptureRequest>& requests,
|
||||
const hidl_vec<V3_4::CaptureRequest>& requests,
|
||||
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
|
||||
ICameraDeviceSession::processCaptureRequest_cb _hidl_cb);
|
||||
Status processOneCaptureRequest_3_4(const CaptureRequest& request);
|
||||
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
|
||||
Status processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request);
|
||||
|
||||
std::map<int, std::string> mPhysicalCameraIdMap;
|
||||
private:
|
||||
|
@ -109,10 +109,16 @@ private:
|
|||
return mParent->configureStreams(requestedConfiguration, _hidl_cb);
|
||||
}
|
||||
|
||||
virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
|
||||
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
|
||||
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
|
||||
return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
|
||||
}
|
||||
|
||||
virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
|
||||
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
|
||||
V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
|
||||
return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
|
||||
return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
|
||||
}
|
||||
|
||||
virtual Return<void> getCaptureRequestMetadataQueue(
|
||||
|
|
|
@ -21,6 +21,7 @@ import @3.2::StreamConfigurationMode;
|
|||
import @3.2::Stream;
|
||||
import @3.3::HalStream;
|
||||
import @3.2::CameraMetadata;
|
||||
import @3.2::CaptureRequest;
|
||||
|
||||
/**
|
||||
* Stream:
|
||||
|
@ -133,3 +134,65 @@ struct HalStream {
|
|||
struct HalStreamConfiguration {
|
||||
vec<HalStream> streams;
|
||||
};
|
||||
|
||||
/**
|
||||
* PhysicalCameraSetting:
|
||||
*
|
||||
* Individual camera settings for logical camera backed by multiple physical devices.
|
||||
* Clients are allowed to pass separate settings for each physical device.
|
||||
*/
|
||||
struct PhysicalCameraSetting {
|
||||
/**
|
||||
* If non-zero, read settings from request queue instead
|
||||
* (see ICameraDeviceSession.getCaptureRequestMetadataQueue).
|
||||
* If zero, read settings from .settings field.
|
||||
*/
|
||||
uint64_t fmqSettingsSize;
|
||||
|
||||
/**
|
||||
* Contains the physical device camera id. Any settings passed by client here
|
||||
* should be applied for this physical device. In case the physical id is invalid
|
||||
* Hal should fail the process request and return Status::ILLEGAL_ARGUMENT.
|
||||
*/
|
||||
string physicalCameraId;
|
||||
|
||||
/**
|
||||
* If fmqSettingsSize is zero, the settings buffer contains the capture and
|
||||
* processing parameters for the physical device with id 'phyCamId'.
|
||||
* In case the individual settings are empty or missing, Hal should fail the
|
||||
* request and return Status::ILLEGAL_ARGUMENT.
|
||||
*/
|
||||
CameraMetadata settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* CaptureRequest:
|
||||
*
|
||||
* A single request for image capture/buffer reprocessing, sent to the Camera
|
||||
* HAL device by the framework in processCaptureRequest().
|
||||
*
|
||||
* The request contains the settings to be used for this capture, and the set of
|
||||
* output buffers to write the resulting image data in. It may optionally
|
||||
* contain an input buffer, in which case the request is for reprocessing that
|
||||
* input buffer instead of capturing a new image with the camera sensor. The
|
||||
* capture is identified by the frameNumber.
|
||||
*
|
||||
* In response, the camera HAL device must send a CaptureResult
|
||||
* structure asynchronously to the framework, using the processCaptureResult()
|
||||
* callback.
|
||||
*
|
||||
* Identical to @3.2::CaptureRequest, except that it contains @3.4::physCamSettings vector.
|
||||
*
|
||||
*/
|
||||
struct CaptureRequest {
|
||||
/**
|
||||
* The definition of CaptureRequest from prior version.
|
||||
*/
|
||||
@3.2::CaptureRequest v3_2;
|
||||
|
||||
/**
|
||||
* A vector containing individual camera settings for logical camera backed by multiple physical
|
||||
* devices. In case the vector is empty, Hal should use the settings field in 'v3_2'.
|
||||
*/
|
||||
vec<PhysicalCameraSetting> physicalCameraSettings;
|
||||
};
|
||||
|
|
|
@ -83,6 +83,13 @@ enum CameraMetadataTag : @3.2::CameraMetadataTag {
|
|||
*/
|
||||
ANDROID_REQUEST_AVAILABLE_SESSION_KEYS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_REQUEST_END,
|
||||
|
||||
/** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden]
|
||||
*
|
||||
* <p>A subset of the available request keys that can be overriden for
|
||||
* physical devices backing a logical multi-camera.</p>
|
||||
*/
|
||||
ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
|
||||
|
||||
ANDROID_REQUEST_END_3_3,
|
||||
|
||||
/** android.statistics.oisDataMode [dynamic, enum, public]
|
||||
|
|
|
@ -537,6 +537,8 @@ public:
|
|||
Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
|
||||
|
||||
private:
|
||||
bool processCaptureResultLocked(const CaptureResult& results);
|
||||
|
||||
CameraHidlTest *mParent; // Parent object
|
||||
};
|
||||
|
||||
|
@ -637,6 +639,9 @@ public:
|
|||
std::vector<AvailableStream> &outputStreams,
|
||||
const AvailableStream *threshold = nullptr);
|
||||
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
|
||||
static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
|
||||
static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
|
||||
std::vector<std::string> *physicalIds/*out*/);
|
||||
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
|
||||
AvailableStream &hfrStream);
|
||||
static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
|
||||
|
@ -848,121 +853,7 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
|
|||
bool notify = false;
|
||||
std::unique_lock<std::mutex> l(mParent->mLock);
|
||||
for (size_t i = 0 ; i < results.size(); i++) {
|
||||
uint32_t frameNumber = results[i].frameNumber;
|
||||
|
||||
if ((results[i].result.size() == 0) &&
|
||||
(results[i].outputBuffers.size() == 0) &&
|
||||
(results[i].inputBuffer.buffer == nullptr) &&
|
||||
(results[i].fmqResultSize == 0)) {
|
||||
ALOGE("%s: No result data provided by HAL for frame %d result count: %d",
|
||||
__func__, frameNumber, (int) results[i].fmqResultSize);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
|
||||
ssize_t idx = mParent->mInflightMap.indexOfKey(frameNumber);
|
||||
if (::android::NAME_NOT_FOUND == idx) {
|
||||
ALOGE("%s: Unexpected frame number! received: %u",
|
||||
__func__, frameNumber);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
|
||||
bool isPartialResult = false;
|
||||
bool hasInputBufferInRequest = false;
|
||||
InFlightRequest *request = mParent->mInflightMap.editValueAt(idx);
|
||||
::android::hardware::camera::device::V3_2::CameraMetadata resultMetadata;
|
||||
size_t resultSize = 0;
|
||||
if (results[i].fmqResultSize > 0) {
|
||||
resultMetadata.resize(results[i].fmqResultSize);
|
||||
if (request->resultQueue == nullptr) {
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
if (!request->resultQueue->read(resultMetadata.data(),
|
||||
results[i].fmqResultSize)) {
|
||||
ALOGE("%s: Frame %d: Cannot read camera metadata from fmq,"
|
||||
"size = %" PRIu64, __func__, frameNumber,
|
||||
results[i].fmqResultSize);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
resultSize = resultMetadata.size();
|
||||
} else if (results[i].result.size() > 0) {
|
||||
resultMetadata.setToExternal(const_cast<uint8_t *>(
|
||||
results[i].result.data()), results[i].result.size());
|
||||
resultSize = resultMetadata.size();
|
||||
}
|
||||
|
||||
if (!request->usePartialResult && (resultSize > 0) &&
|
||||
(results[i].partialResult != 1)) {
|
||||
ALOGE("%s: Result is malformed for frame %d: partial_result %u "
|
||||
"must be 1 if partial result is not supported", __func__,
|
||||
frameNumber, results[i].partialResult);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
|
||||
if (results[i].partialResult != 0) {
|
||||
request->partialResultCount = results[i].partialResult;
|
||||
}
|
||||
|
||||
// Check if this result carries only partial metadata
|
||||
if (request->usePartialResult && (resultSize > 0)) {
|
||||
if ((results[i].partialResult > request->numPartialResults) ||
|
||||
(results[i].partialResult < 1)) {
|
||||
ALOGE("%s: Result is malformed for frame %d: partial_result %u"
|
||||
" must be in the range of [1, %d] when metadata is "
|
||||
"included in the result", __func__, frameNumber,
|
||||
results[i].partialResult, request->numPartialResults);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
request->collectedResult.append(
|
||||
reinterpret_cast<const camera_metadata_t*>(
|
||||
resultMetadata.data()));
|
||||
|
||||
isPartialResult =
|
||||
(results[i].partialResult < request->numPartialResults);
|
||||
}
|
||||
|
||||
hasInputBufferInRequest = request->hasInputBuffer;
|
||||
|
||||
// Did we get the (final) result metadata for this capture?
|
||||
if ((resultSize > 0) && !isPartialResult) {
|
||||
if (request->haveResultMetadata) {
|
||||
ALOGE("%s: Called multiple times with metadata for frame %d",
|
||||
__func__, frameNumber);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
request->haveResultMetadata = true;
|
||||
request->collectedResult.sort();
|
||||
}
|
||||
|
||||
uint32_t numBuffersReturned = results[i].outputBuffers.size();
|
||||
if (results[i].inputBuffer.buffer != nullptr) {
|
||||
if (hasInputBufferInRequest) {
|
||||
numBuffersReturned += 1;
|
||||
} else {
|
||||
ALOGW("%s: Input buffer should be NULL if there is no input"
|
||||
" buffer sent in the request", __func__);
|
||||
}
|
||||
}
|
||||
request->numBuffersLeft -= numBuffersReturned;
|
||||
if (request->numBuffersLeft < 0) {
|
||||
ALOGE("%s: Too many buffers returned for frame %d", __func__,
|
||||
frameNumber);
|
||||
ADD_FAILURE();
|
||||
break;
|
||||
}
|
||||
|
||||
request->resultOutputBuffers.appendArray(results[i].outputBuffers.data(),
|
||||
results[i].outputBuffers.size());
|
||||
// If shutter event is received notify the pending threads.
|
||||
if (request->shutterTimestamp != 0) {
|
||||
notify = true;
|
||||
}
|
||||
notify = processCaptureResultLocked(results[i]);
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
@ -973,6 +864,126 @@ Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
|
|||
return Void();
|
||||
}
|
||||
|
||||
bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) {
|
||||
bool notify = false;
|
||||
uint32_t frameNumber = results.frameNumber;
|
||||
|
||||
if ((results.result.size() == 0) &&
|
||||
(results.outputBuffers.size() == 0) &&
|
||||
(results.inputBuffer.buffer == nullptr) &&
|
||||
(results.fmqResultSize == 0)) {
|
||||
ALOGE("%s: No result data provided by HAL for frame %d result count: %d",
|
||||
__func__, frameNumber, (int) results.fmqResultSize);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
|
||||
ssize_t idx = mParent->mInflightMap.indexOfKey(frameNumber);
|
||||
if (::android::NAME_NOT_FOUND == idx) {
|
||||
ALOGE("%s: Unexpected frame number! received: %u",
|
||||
__func__, frameNumber);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
|
||||
bool isPartialResult = false;
|
||||
bool hasInputBufferInRequest = false;
|
||||
InFlightRequest *request = mParent->mInflightMap.editValueAt(idx);
|
||||
::android::hardware::camera::device::V3_2::CameraMetadata resultMetadata;
|
||||
size_t resultSize = 0;
|
||||
if (results.fmqResultSize > 0) {
|
||||
resultMetadata.resize(results.fmqResultSize);
|
||||
if (request->resultQueue == nullptr) {
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
if (!request->resultQueue->read(resultMetadata.data(),
|
||||
results.fmqResultSize)) {
|
||||
ALOGE("%s: Frame %d: Cannot read camera metadata from fmq,"
|
||||
"size = %" PRIu64, __func__, frameNumber,
|
||||
results.fmqResultSize);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
resultSize = resultMetadata.size();
|
||||
} else if (results.result.size() > 0) {
|
||||
resultMetadata.setToExternal(const_cast<uint8_t *>(
|
||||
results.result.data()), results.result.size());
|
||||
resultSize = resultMetadata.size();
|
||||
}
|
||||
|
||||
if (!request->usePartialResult && (resultSize > 0) &&
|
||||
(results.partialResult != 1)) {
|
||||
ALOGE("%s: Result is malformed for frame %d: partial_result %u "
|
||||
"must be 1 if partial result is not supported", __func__,
|
||||
frameNumber, results.partialResult);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
|
||||
if (results.partialResult != 0) {
|
||||
request->partialResultCount = results.partialResult;
|
||||
}
|
||||
|
||||
// Check if this result carries only partial metadata
|
||||
if (request->usePartialResult && (resultSize > 0)) {
|
||||
if ((results.partialResult > request->numPartialResults) ||
|
||||
(results.partialResult < 1)) {
|
||||
ALOGE("%s: Result is malformed for frame %d: partial_result %u"
|
||||
" must be in the range of [1, %d] when metadata is "
|
||||
"included in the result", __func__, frameNumber,
|
||||
results.partialResult, request->numPartialResults);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
request->collectedResult.append(
|
||||
reinterpret_cast<const camera_metadata_t*>(
|
||||
resultMetadata.data()));
|
||||
|
||||
isPartialResult =
|
||||
(results.partialResult < request->numPartialResults);
|
||||
}
|
||||
|
||||
hasInputBufferInRequest = request->hasInputBuffer;
|
||||
|
||||
// Did we get the (final) result metadata for this capture?
|
||||
if ((resultSize > 0) && !isPartialResult) {
|
||||
if (request->haveResultMetadata) {
|
||||
ALOGE("%s: Called multiple times with metadata for frame %d",
|
||||
__func__, frameNumber);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
request->haveResultMetadata = true;
|
||||
request->collectedResult.sort();
|
||||
}
|
||||
|
||||
uint32_t numBuffersReturned = results.outputBuffers.size();
|
||||
if (results.inputBuffer.buffer != nullptr) {
|
||||
if (hasInputBufferInRequest) {
|
||||
numBuffersReturned += 1;
|
||||
} else {
|
||||
ALOGW("%s: Input buffer should be NULL if there is no input"
|
||||
" buffer sent in the request", __func__);
|
||||
}
|
||||
}
|
||||
request->numBuffersLeft -= numBuffersReturned;
|
||||
if (request->numBuffersLeft < 0) {
|
||||
ALOGE("%s: Too many buffers returned for frame %d", __func__,
|
||||
frameNumber);
|
||||
ADD_FAILURE();
|
||||
return notify;
|
||||
}
|
||||
|
||||
request->resultOutputBuffers.appendArray(results.outputBuffers.data(),
|
||||
results.outputBuffers.size());
|
||||
// If shutter event is received notify the pending threads.
|
||||
if (request->shutterTimestamp != 0) {
|
||||
notify = true;
|
||||
}
|
||||
return notify;
|
||||
}
|
||||
|
||||
Return<void> CameraHidlTest::DeviceCb::notify(
|
||||
const hidl_vec<NotifyMsg>& messages) {
|
||||
std::lock_guard<std::mutex> l(mParent->mLock);
|
||||
|
@ -3289,6 +3300,171 @@ TEST_F(CameraHidlTest, processCaptureRequestPreview) {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate and verify a multi-camera capture request
|
||||
TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
|
||||
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
|
||||
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
|
||||
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
|
||||
uint64_t bufferId = 1;
|
||||
uint32_t frameNumber = 1;
|
||||
::android::hardware::hidl_vec<uint8_t> settings;
|
||||
::android::hardware::hidl_vec<uint8_t> emptySettings;
|
||||
hidl_string invalidPhysicalId = "-1";
|
||||
|
||||
for (const auto& name : cameraDeviceNames) {
|
||||
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
|
||||
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
|
||||
continue;
|
||||
}
|
||||
camera_metadata_t* staticMeta;
|
||||
Return<void> ret;
|
||||
sp<ICameraDeviceSession> session;
|
||||
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
|
||||
|
||||
Status rc = isLogicalMultiCamera(staticMeta);
|
||||
if (Status::METHOD_NOT_SUPPORTED == rc) {
|
||||
ret = session->close();
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
continue;
|
||||
}
|
||||
std::vector<std::string> physicalIds;
|
||||
rc = getPhysicalCameraIds(staticMeta, &physicalIds);
|
||||
ASSERT_TRUE(Status::OK == rc);
|
||||
ASSERT_TRUE(physicalIds.size() > 1);
|
||||
|
||||
free_camera_metadata(staticMeta);
|
||||
ret = session->close();
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
|
||||
V3_2::Stream previewStream;
|
||||
HalStreamConfiguration halStreamConfig;
|
||||
bool supportsPartialResults = false;
|
||||
uint32_t partialResultCount = 0;
|
||||
configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
|
||||
&previewStream /*out*/, &halStreamConfig /*out*/,
|
||||
&supportsPartialResults /*out*/,
|
||||
&partialResultCount /*out*/);
|
||||
sp<device::V3_3::ICameraDeviceSession> session3_3;
|
||||
sp<device::V3_4::ICameraDeviceSession> session3_4;
|
||||
castSession(session, deviceVersion, &session3_3, &session3_4);
|
||||
ASSERT_NE(session3_4, nullptr);
|
||||
|
||||
std::shared_ptr<ResultMetadataQueue> resultQueue;
|
||||
auto resultQueueRet =
|
||||
session->getCaptureResultMetadataQueue(
|
||||
[&resultQueue](const auto& descriptor) {
|
||||
resultQueue = std::make_shared<ResultMetadataQueue>(
|
||||
descriptor);
|
||||
if (!resultQueue->isValid() ||
|
||||
resultQueue->availableToWrite() <= 0) {
|
||||
ALOGE("%s: HAL returns empty result metadata fmq,"
|
||||
" not use it", __func__);
|
||||
resultQueue = nullptr;
|
||||
// Don't use the queue onwards.
|
||||
}
|
||||
});
|
||||
ASSERT_TRUE(resultQueueRet.isOk());
|
||||
|
||||
InFlightRequest inflightReq = {1, false, supportsPartialResults,
|
||||
partialResultCount, resultQueue};
|
||||
|
||||
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
|
||||
ret = session->constructDefaultRequestSettings(reqTemplate,
|
||||
[&](auto status, const auto& req) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
settings = req;
|
||||
});
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
|
||||
sp<GraphicBuffer> gb = new GraphicBuffer(
|
||||
previewStream.width, previewStream.height,
|
||||
static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
|
||||
android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
|
||||
halStreamConfig.streams[0].consumerUsage));
|
||||
ASSERT_NE(nullptr, gb.get());
|
||||
::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
|
||||
outputBuffers.resize(1);
|
||||
outputBuffers[0] = {halStreamConfig.streams[0].id,
|
||||
bufferId,
|
||||
hidl_handle(gb->getNativeBuffer()->handle),
|
||||
BufferStatus::OK,
|
||||
nullptr,
|
||||
nullptr};
|
||||
|
||||
StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
|
||||
nullptr};
|
||||
hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
|
||||
camSettings.resize(2);
|
||||
camSettings[0] = {0, hidl_string(physicalIds[0]), settings};
|
||||
camSettings[1] = {0, hidl_string(physicalIds[1]), settings};
|
||||
V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
|
||||
emptyInputBuffer, outputBuffers}, camSettings};
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mLock);
|
||||
mInflightMap.clear();
|
||||
mInflightMap.add(frameNumber, &inflightReq);
|
||||
}
|
||||
|
||||
Status stat = Status::INTERNAL_ERROR;
|
||||
uint32_t numRequestProcessed = 0;
|
||||
hidl_vec<BufferCache> cachesToRemove;
|
||||
Return<void> returnStatus = session3_4->processCaptureRequest_3_4(
|
||||
{request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
|
||||
stat = s;
|
||||
numRequestProcessed = n;
|
||||
});
|
||||
ASSERT_TRUE(returnStatus.isOk());
|
||||
ASSERT_EQ(Status::OK, stat);
|
||||
ASSERT_EQ(numRequestProcessed, 1u);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mLock);
|
||||
while (!inflightReq.errorCodeValid &&
|
||||
((0 < inflightReq.numBuffersLeft) ||
|
||||
(!inflightReq.haveResultMetadata))) {
|
||||
auto timeout = std::chrono::system_clock::now() +
|
||||
std::chrono::seconds(kStreamBufferTimeoutSec);
|
||||
ASSERT_NE(std::cv_status::timeout,
|
||||
mResultCondition.wait_until(l, timeout));
|
||||
}
|
||||
|
||||
ASSERT_FALSE(inflightReq.errorCodeValid);
|
||||
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
|
||||
ASSERT_EQ(halStreamConfig.streams[0].id,
|
||||
inflightReq.resultOutputBuffers[0].streamId);
|
||||
}
|
||||
|
||||
// Empty physical camera settings should fail process requests
|
||||
camSettings[1] = {0, hidl_string(physicalIds[1]), emptySettings};
|
||||
frameNumber++;
|
||||
request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
|
||||
emptyInputBuffer, outputBuffers}, camSettings};
|
||||
returnStatus = session3_4->processCaptureRequest_3_4(
|
||||
{request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
|
||||
stat = s;
|
||||
numRequestProcessed = n;
|
||||
});
|
||||
ASSERT_TRUE(returnStatus.isOk());
|
||||
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
|
||||
|
||||
// Invalid physical camera id should fail process requests
|
||||
camSettings[1] = {0, invalidPhysicalId, settings};
|
||||
request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
|
||||
emptyInputBuffer, outputBuffers}, camSettings};
|
||||
returnStatus = session3_4->processCaptureRequest_3_4(
|
||||
{request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
|
||||
stat = s;
|
||||
numRequestProcessed = n;
|
||||
});
|
||||
ASSERT_TRUE(returnStatus.isOk());
|
||||
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
|
||||
|
||||
ret = session->close();
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
}
|
||||
}
|
||||
|
||||
// Test whether an incorrect capture request with missing settings will
|
||||
// be reported correctly.
|
||||
TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
|
||||
|
@ -3636,6 +3812,59 @@ Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
|
|||
return Status::OK;
|
||||
}
|
||||
|
||||
// Check if the camera device has logical multi-camera capability.
|
||||
Status CameraHidlTest::isLogicalMultiCamera(camera_metadata_t *staticMeta) {
|
||||
Status ret = Status::METHOD_NOT_SUPPORTED;
|
||||
if (nullptr == staticMeta) {
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
camera_metadata_ro_entry entry;
|
||||
int rc = find_camera_metadata_ro_entry(staticMeta,
|
||||
ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
|
||||
if (0 != rc) {
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entry.count; i++) {
|
||||
if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA == entry.data.u8[i]) {
|
||||
ret = Status::OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Generate a list of physical camera ids backing a logical multi-camera.
|
||||
Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
|
||||
std::vector<std::string> *physicalIds) {
|
||||
if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
camera_metadata_ro_entry entry;
|
||||
int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
|
||||
&entry);
|
||||
if (0 != rc) {
|
||||
return Status::ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
const uint8_t* ids = entry.data.u8;
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < entry.count; i++) {
|
||||
if (ids[i] == '\0') {
|
||||
if (start != i) {
|
||||
std::string currentId(reinterpret_cast<const char *> (ids + start));
|
||||
physicalIds->push_back(currentId);
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
// Check if constrained mode is supported by using the static
|
||||
// camera characteristics.
|
||||
Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {
|
||||
|
|
Loading…
Reference in a new issue