blob: 5daccb7608242d1ae158a9f93ac3f9e18ff404cd [file] [log] [blame]
/*
* Copyright (C) 2015 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 "NativeCamera"
#include <log/log.h>
#include <chrono>
#include <condition_variable>
#include <string>
#include <map>
#include <mutex>
#include <vector>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <set>
#include <android/native_window_jni.h>
#include "camera/NdkCameraError.h"
#include "camera/NdkCameraManager.h"
#include "camera/NdkCameraDevice.h"
#include "camera/NdkCameraCaptureSession.h"
#include "media/NdkImage.h"
#include "media/NdkImageReader.h"
#define LOG_ERROR(buf, ...) sprintf(buf, __VA_ARGS__); \
ALOGE("%s", buf);
namespace {
const int MAX_ERROR_STRING_LEN = 512;
char errorString[MAX_ERROR_STRING_LEN];
}
template <>
struct std::default_delete<ACameraMetadata> {
inline void operator()(ACameraMetadata* chars) const { ACameraMetadata_free(chars); }
};
class CameraServiceListener {
public:
static void onAvailable(void* obj, const char* cameraId) {
ALOGV("Camera %s onAvailable", cameraId);
if (obj == nullptr) {
return;
}
CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnAvailableCount++;
thiz->mAvailableMap[cameraId] = true;
return;
}
static void onUnavailable(void* obj, const char* cameraId) {
ALOGV("Camera %s onUnavailable", cameraId);
if (obj == nullptr) {
return;
}
CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnUnavailableCount++;
thiz->mAvailableMap[cameraId] = false;
return;
}
static void onCameraAccessPrioritiesChanged(void* obj) {
ALOGV("onCameraAccessPrioritiesChanged");
if (obj == nullptr) {
return;
}
CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnCameraAccessPrioritiesChangedCount++;
return;
}
void resetCount() {
std::lock_guard<std::mutex> lock(mMutex);
mOnAvailableCount = 0;
mOnUnavailableCount = 0;
mOnCameraAccessPrioritiesChangedCount = 0;
return;
}
int getAvailableCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnAvailableCount;
}
int getUnavailableCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnUnavailableCount;
}
int getCameraAccessPrioritiesChangedCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnCameraAccessPrioritiesChangedCount;
}
bool isAvailable(const char* cameraId) {
std::lock_guard<std::mutex> lock(mMutex);
if (mAvailableMap.count(cameraId) == 0) {
return false;
}
return mAvailableMap[cameraId];
}
private:
std::mutex mMutex;
int mOnAvailableCount = 0;
int mOnUnavailableCount = 0;
int mOnCameraAccessPrioritiesChangedCount = 0;
std::map<std::string, bool> mAvailableMap;
};
class CameraDeviceListener {
public:
static void onDisconnected(void* obj, ACameraDevice* device) {
ALOGV("Camera %s is disconnected!", ACameraDevice_getId(device));
if (obj == nullptr) {
return;
}
CameraDeviceListener* thiz = reinterpret_cast<CameraDeviceListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnDisconnect++;
return;
}
static void onError(void* obj, ACameraDevice* device, int errorCode) {
ALOGV("Camera %s receive error %d!", ACameraDevice_getId(device), errorCode);
if (obj == nullptr) {
return;
}
CameraDeviceListener* thiz = reinterpret_cast<CameraDeviceListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnError++;
thiz->mLatestError = errorCode;
return;
}
private:
std::mutex mMutex;
int mOnDisconnect = 0;
int mOnError = 0;
int mLatestError = 0;
};
class CaptureSessionListener {
public:
static void onClosed(void* obj, ACameraCaptureSession *session) {
// TODO: might want an API to query cameraId even session is closed?
ALOGV("Session %p is closed!", session);
if (obj == nullptr) {
return;
}
CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mIsClosed = true;
thiz->mOnClosed++; // Should never > 1
}
static void onReady(void* obj, ACameraCaptureSession *session) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
ACameraDevice* device = nullptr;
camera_status_t ret = ACameraCaptureSession_getDevice(session, &device);
// There will be one onReady fired after session closed
if (ret != ACAMERA_OK && !thiz->mIsClosed) {
ALOGE("%s Getting camera device from session callback failed!",
__FUNCTION__);
thiz->mInError = true;
}
ALOGV("Session for camera %s is ready!", ACameraDevice_getId(device));
thiz->mIsIdle = true;
thiz->mOnReady++;
}
static void onActive(void* obj, ACameraCaptureSession *session) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
ACameraDevice* device = nullptr;
camera_status_t ret = ACameraCaptureSession_getDevice(session, &device);
if (ret != ACAMERA_OK) {
ALOGE("%s Getting camera device from session callback failed!",
__FUNCTION__);
thiz->mInError = true;
}
ALOGV("Session for camera %s is busy!", ACameraDevice_getId(device));
thiz->mIsIdle = false;
thiz->mOnActive;
}
bool isClosed() {
std::lock_guard<std::mutex> lock(mMutex);
return mIsClosed;
}
bool isIdle() {
std::lock_guard<std::mutex> lock(mMutex);
return mIsIdle;
}
bool isInError() {
std::lock_guard<std::mutex> lock(mMutex);
return mInError;
}
int onClosedCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnClosed;
}
int onReadyCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnReady;
}
int onActiveCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnActive;
}
void reset() {
std::lock_guard<std::mutex> lock(mMutex);
mIsClosed = false;
mIsIdle = true;
mInError = false;
mOnClosed = 0;
mOnReady = 0;
mOnActive = 0;
}
private:
std::mutex mMutex;
bool mIsClosed = false;
bool mIsIdle = true;
bool mInError = false; // should always stay false
int mOnClosed = 0;
int mOnReady = 0;
int mOnActive = 0;
};
class CaptureResultListener {
public:
~CaptureResultListener() {
std::unique_lock<std::mutex> l(mMutex);
clearSavedRequestsLocked();
clearFailedFrameNumbersLocked();
}
static void onCaptureStart(void* /*obj*/, ACameraCaptureSession* /*session*/,
const ACaptureRequest* /*request*/, int64_t /*timestamp*/) {
//Not used for now
}
static void onCaptureProgressed(void* /*obj*/, ACameraCaptureSession* /*session*/,
ACaptureRequest* /*request*/, const ACameraMetadata* /*result*/) {
//Not used for now
}
static void onCaptureCompleted(void* obj, ACameraCaptureSession* /*session*/,
ACaptureRequest* request, const ACameraMetadata* result) {
ALOGV("%s", __FUNCTION__);
if ((obj == nullptr) || (result == nullptr)) {
return;
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
ACameraMetadata_const_entry entry;
auto ret = ACameraMetadata_getConstEntry(result, ACAMERA_SYNC_FRAME_NUMBER, &entry);
if (ret != ACAMERA_OK) {
ALOGE("Error: Sync frame number missing from result!");
return;
}
ACameraMetadata* copy = ACameraMetadata_copy(result);
ACameraMetadata_const_entry entryCopy;
ret = ACameraMetadata_getConstEntry(copy, ACAMERA_SYNC_FRAME_NUMBER, &entryCopy);
if (ret != ACAMERA_OK) {
ALOGE("Error: Sync frame number missing from result copy!");
return;
}
if (entry.data.i64[0] != entryCopy.data.i64[0]) {
ALOGE("Error: Sync frame number %" PRId64 " mismatch result copy %" PRId64,
entry.data.i64[0], entryCopy.data.i64[0]);
return;
}
ACameraMetadata_free(copy);
if (thiz->mSaveCompletedRequests) {
thiz->mCompletedRequests.push_back(ACaptureRequest_copy(request));
}
thiz->mLastCompletedFrameNumber = entry.data.i64[0];
thiz->mResultCondition.notify_one();
}
static void onLogicalCameraCaptureCompleted(void* obj, ACameraCaptureSession* /*session*/,
ACaptureRequest* request, const ACameraMetadata* result,
size_t physicalResultCount, const char** physicalCameraIds,
const ACameraMetadata** physicalResults) {
ALOGV("%s", __FUNCTION__);
if ((obj == nullptr) || (result == nullptr)) {
return;
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
ACameraMetadata_const_entry entry;
auto ret = ACameraMetadata_getConstEntry(result, ACAMERA_SYNC_FRAME_NUMBER, &entry);
if (ret != ACAMERA_OK) {
ALOGE("Error: Sync frame number missing from result!");
return;
}
ACameraMetadata* copy = ACameraMetadata_copy(result);
ACameraMetadata_const_entry entryCopy;
ret = ACameraMetadata_getConstEntry(copy, ACAMERA_SYNC_FRAME_NUMBER, &entryCopy);
if (ret != ACAMERA_OK) {
ALOGE("Error: Sync frame number missing from result copy!");
return;
}
if (entry.data.i64[0] != entryCopy.data.i64[0]) {
ALOGE("Error: Sync frame number %" PRId64 " mismatch result copy %" PRId64,
entry.data.i64[0], entryCopy.data.i64[0]);
return;
}
if (thiz->mRegisteredPhysicalIds.size() != physicalResultCount) {
ALOGE("Error: Number of registered physical camera Ids %zu is different than received"
" physical camera Ids %zu", thiz->mRegisteredPhysicalIds.size(),
physicalResultCount);
return;
}
for (size_t i = 0; i < physicalResultCount; i++) {
if (physicalCameraIds[i] == nullptr) {
ALOGE("Error: Invalid physical camera id in capture result");
return;
}
if (physicalResults[i] == nullptr) {
ALOGE("Error: Invalid physical camera metadata in capture result");
return;
}
ACameraMetadata_const_entry physicalEntry;
auto ret = ACameraMetadata_getConstEntry(physicalResults[i], ACAMERA_SYNC_FRAME_NUMBER,
&physicalEntry);
if (ret != ACAMERA_OK) {
ALOGE("Error: Sync frame number missing from physical camera result metadata!");
return;
}
if (physicalEntry.data.i64[0] != entryCopy.data.i64[0]) {
ALOGE("Error: Physical camera sync frame number %" PRId64
" mismatch result copy %" PRId64,
physicalEntry.data.i64[0], entryCopy.data.i64[0]);
return;
}
auto foundId = std::find(thiz->mRegisteredPhysicalIds.begin(),
thiz->mRegisteredPhysicalIds.end(), physicalCameraIds[i]);
if (foundId == thiz->mRegisteredPhysicalIds.end()) {
ALOGE("Error: Returned physical camera Id %s is not registered",
physicalCameraIds[i]);
return;
}
}
ACameraMetadata_free(copy);
if (thiz->mSaveCompletedRequests) {
thiz->mCompletedRequests.push_back(ACaptureRequest_copy(request));
}
thiz->mLastCompletedFrameNumber = entry.data.i64[0];
thiz->mResultCondition.notify_one();
}
static void onCaptureFailed(void* obj, ACameraCaptureSession* /*session*/,
ACaptureRequest* /*request*/, ACameraCaptureFailure* failure) {
ALOGV("%s", __FUNCTION__);
if ((obj == nullptr) || (failure == nullptr)) {
return;
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mFailedFrameNumbers.insert(failure->frameNumber);
thiz->mResultCondition.notify_one();
}
static void onLogicalCameraCaptureFailed(void* obj, ACameraCaptureSession* /*session*/,
ACaptureRequest* /*request*/, ALogicalCameraCaptureFailure* failure) {
ALOGV("%s", __FUNCTION__);
if ((obj == nullptr) || (failure == nullptr)) {
return;
}
if (failure->physicalCameraId != nullptr) {
ALOGV("%s: physicalCameraId: %s", __FUNCTION__, failure->physicalCameraId);
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mFailedFrameNumbers.insert(failure->captureFailure.frameNumber);
thiz->mResultCondition.notify_one();
}
static void onCaptureSequenceCompleted(void* obj, ACameraCaptureSession* /*session*/,
int sequenceId, int64_t frameNumber) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mLastSequenceIdCompleted = sequenceId;
thiz->mLastSequenceFrameNumber = frameNumber;
thiz->mResultCondition.notify_one();
}
static void onCaptureSequenceAborted(void* /*obj*/, ACameraCaptureSession* /*session*/,
int /*sequenceId*/) {
//Not used for now
}
static void onCaptureBufferLost(void* obj, ACameraCaptureSession* /*session*/,
ACaptureRequest* /*request*/, ANativeWindow* /*window*/, int64_t frameNumber) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mLastLostFrameNumber = frameNumber;
thiz->mResultCondition.notify_one();
}
int64_t getCaptureSequenceLastFrameNumber(int64_t sequenceId, uint32_t timeoutSec) {
int64_t ret = -1;
std::unique_lock<std::mutex> l(mMutex);
while (mLastSequenceIdCompleted != sequenceId) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(timeoutSec);
if (std::cv_status::timeout == mResultCondition.wait_until(l, timeout)) {
break;
}
}
if (mLastSequenceIdCompleted == sequenceId) {
ret = mLastSequenceFrameNumber;
}
return ret;
}
bool waitForFrameNumber(int64_t frameNumber, uint32_t timeoutSec) {
bool ret = false;
std::unique_lock<std::mutex> l(mMutex);
while ((mLastCompletedFrameNumber != frameNumber) &&
(mLastLostFrameNumber != frameNumber) && !checkForFailureLocked(frameNumber)) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(timeoutSec);
if (std::cv_status::timeout == mResultCondition.wait_until(l, timeout)) {
break;
}
}
if ((mLastCompletedFrameNumber == frameNumber) ||
(mLastLostFrameNumber == frameNumber) || checkForFailureLocked(frameNumber)) {
ret = true;
}
return ret;
}
void setRequestSave(bool enable) {
std::unique_lock<std::mutex> l(mMutex);
if (!enable) {
clearSavedRequestsLocked();
}
mSaveCompletedRequests = enable;
}
// The lifecycle of returned ACaptureRequest* is still managed by CaptureResultListener
void getCompletedRequests(std::vector<ACaptureRequest*>* out) {
std::unique_lock<std::mutex> l(mMutex);
*out = mCompletedRequests;
}
void registerPhysicalResults(size_t physicalIdCnt, const char*const* physicalOutputs) {
std::unique_lock<std::mutex> l(mMutex);
mRegisteredPhysicalIds.clear();
for (size_t i = 0; i < physicalIdCnt; i++) {
mRegisteredPhysicalIds.push_back(physicalOutputs[i]);
}
}
bool checkForFailure(int64_t frameNumber) {
std::lock_guard<std::mutex> lock(mMutex);
return checkForFailureLocked(frameNumber);
}
void reset() {
std::lock_guard<std::mutex> lock(mMutex);
mLastSequenceIdCompleted = -1;
mLastSequenceFrameNumber = -1;
mLastCompletedFrameNumber = -1;
mLastLostFrameNumber = -1;
mSaveCompletedRequests = false;
clearSavedRequestsLocked();
clearFailedFrameNumbersLocked();
}
private:
std::mutex mMutex;
std::condition_variable mResultCondition;
int mLastSequenceIdCompleted = -1;
int64_t mLastSequenceFrameNumber = -1;
int64_t mLastCompletedFrameNumber = -1;
int64_t mLastLostFrameNumber = -1;
std::set<int64_t> mFailedFrameNumbers;
bool mSaveCompletedRequests = false;
std::vector<ACaptureRequest*> mCompletedRequests;
// Registered physical camera Ids that are being requested upon.
std::vector<std::string> mRegisteredPhysicalIds;
void clearSavedRequestsLocked() {
for (ACaptureRequest* req : mCompletedRequests) {
ACaptureRequest_free(req);
}
mCompletedRequests.clear();
}
void clearFailedFrameNumbersLocked() {
mFailedFrameNumbers.clear();
}
bool checkForFailureLocked(int64_t frameNumber) {
return mFailedFrameNumbers.find(frameNumber) != mFailedFrameNumbers.end();
}
};
class ImageReaderListener {
public:
// count, acquire, validate, and delete AImage when a new image is available
static void validateImageCb(void* obj, AImageReader* reader) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
ImageReaderListener* thiz = reinterpret_cast<ImageReaderListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnImageAvailableCount++;
AImage* img = nullptr;
media_status_t ret = AImageReader_acquireNextImage(reader, &img);
if (ret != AMEDIA_OK || img == nullptr) {
ALOGE("%s: acquire image from reader %p failed! ret: %d, img %p",
__FUNCTION__, reader, ret, img);
return;
}
// TODO: validate image content
int32_t format = -1;
ret = AImage_getFormat(img, &format);
if (ret != AMEDIA_OK || format == -1) {
ALOGE("%s: get format for image %p failed! ret: %d, format %d",
__FUNCTION__, img, ret, format);
}
// Save jpeg to SD card
if (thiz->mDumpFilePathBase && format == AIMAGE_FORMAT_JPEG) {
int32_t numPlanes = 0;
ret = AImage_getNumberOfPlanes(img, &numPlanes);
if (ret != AMEDIA_OK || numPlanes != 1) {
ALOGE("%s: get numPlanes for image %p failed! ret: %d, numPlanes %d",
__FUNCTION__, img, ret, numPlanes);
AImage_delete(img);
return;
}
int32_t width = -1, height = -1;
ret = AImage_getWidth(img, &width);
if (ret != AMEDIA_OK || width <= 0) {
ALOGE("%s: get width for image %p failed! ret: %d, width %d",
__FUNCTION__, img, ret, width);
AImage_delete(img);
return;
}
ret = AImage_getHeight(img, &height);
if (ret != AMEDIA_OK || height <= 0) {
ALOGE("%s: get height for image %p failed! ret: %d, height %d",
__FUNCTION__, img, ret, height);
AImage_delete(img);
return;
}
uint8_t* data = nullptr;
int dataLength = 0;
ret = AImage_getPlaneData(img, /*planeIdx*/0, &data, &dataLength);
if (ret != AMEDIA_OK || data == nullptr || dataLength <= 0) {
ALOGE("%s: get jpeg data for image %p failed! ret: %d, data %p, len %d",
__FUNCTION__, img, ret, data, dataLength);
AImage_delete(img);
return;
}
#if 0
char dumpFilePath[512];
sprintf(dumpFilePath, "%s/%dx%d.jpg", thiz->mDumpFilePathBase, width, height);
ALOGI("Writing jpeg file to %s", dumpFilePath);
FILE* file = fopen(dumpFilePath,"w+");
if (file != nullptr) {
fwrite(data, 1, dataLength, file);
fflush(file);
fclose(file);
}
#endif
}
AImage_delete(img);
}
// count, acquire image but not delete the image
static void acquireImageCb(void* obj, AImageReader* reader) {
ALOGV("%s", __FUNCTION__);
if (obj == nullptr) {
return;
}
ImageReaderListener* thiz = reinterpret_cast<ImageReaderListener*>(obj);
std::lock_guard<std::mutex> lock(thiz->mMutex);
thiz->mOnImageAvailableCount++;
// Acquire, but not closing.
AImage* img = nullptr;
media_status_t ret = AImageReader_acquireNextImage(reader, &img);
if (ret != AMEDIA_OK || img == nullptr) {
ALOGE("%s: acquire image from reader %p failed! ret: %d, img %p",
__FUNCTION__, reader, ret, img);
return;
}
return;
}
int onImageAvailableCount() {
std::lock_guard<std::mutex> lock(mMutex);
return mOnImageAvailableCount;
}
void setDumpFilePathBase(const char* path) {
std::lock_guard<std::mutex> lock(mMutex);
mDumpFilePathBase = path;
}
private:
// TODO: add mReader to make sure each listener is associated to one reader?
std::mutex mMutex;
int mOnImageAvailableCount = 0;
const char* mDumpFilePathBase = nullptr;
};
class StaticInfo {
public:
explicit StaticInfo(ACameraMetadata* chars) : mChars(chars) {}
bool isColorOutputSupported() {
return isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
}
bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) {
ACameraMetadata_const_entry entry;
ACameraMetadata_getConstEntry(mChars, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
for (uint32_t i = 0; i < entry.count; i++) {
if (entry.data.u8[i] == cap) {
return true;
}
}
return false;
}
int64_t getMinFrameDurationFor(int64_t format, int64_t width, int64_t height) {
int32_t minFrameDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS :
(format == AIMAGE_FORMAT_DEPTH_JPEG) ?
ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS :
ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
return getDurationFor(minFrameDurationTag, format, width, height);
}
int64_t getStallDurationFor(int64_t format, int64_t width, int64_t height) {
int32_t stallDurationTag = (format == AIMAGE_FORMAT_HEIC) ?
ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS : (format == AIMAGE_FORMAT_DEPTH_JPEG) ?
ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS :
ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS;
return getDurationFor(stallDurationTag, format, width, height);
}
bool getMaxSizeForFormat(int32_t format, int32_t *width, int32_t *height) {
ACameraMetadata_const_entry entry;
int32_t streamConfigTag, streamConfigOutputTag;
switch (format) {
case AIMAGE_FORMAT_HEIC:
streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
break;
case AIMAGE_FORMAT_DEPTH_JPEG:
streamConfigTag = ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS;
streamConfigOutputTag =
ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_OUTPUT;
break;
case AIMAGE_FORMAT_JPEG:
case AIMAGE_FORMAT_Y8:
default:
streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
break;
}
bool supported = false;
camera_status_t status = ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
if (status == ACAMERA_ERROR_METADATA_NOT_FOUND) {
return supported;
}
int32_t w = 0, h = 0;
for (uint32_t i = 0; i < entry.count; i += 4) {
if (entry.data.i32[i] == format &&
entry.data.i32[i+3] == streamConfigOutputTag &&
entry.data.i32[i+1] * entry.data.i32[i+2] > w * h) {
w = entry.data.i32[i+1];
h = entry.data.i32[i+2];
supported = true;
}
}
if (supported) {
*width = w;
*height = h;
}
return supported;
}
bool isSizeSupportedForFormat(int32_t format, int32_t width, int32_t height) {
ACameraMetadata_const_entry entry;
int32_t streamConfigTag, streamConfigOutputTag;
switch (format) {
case AIMAGE_FORMAT_HEIC:
streamConfigTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS;
streamConfigOutputTag = ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT;
break;
case AIMAGE_FORMAT_JPEG:
case AIMAGE_FORMAT_Y8:
default:
streamConfigTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
streamConfigOutputTag = ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
break;
}
auto ret = ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
if (ret != ACAMERA_OK) {
return false;
}
for (uint32_t i = 0; i < entry.count; i += 4) {
if (entry.data.i32[i] == format &&
entry.data.i32[i+3] == streamConfigOutputTag &&
entry.data.i32[i+1] == width &&
entry.data.i32[i+2] == height) {
return true;
}
}
return false;
}
private:
int64_t getDurationFor(uint32_t tag, int64_t format, int64_t width, int64_t height) {
if (tag != ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS &&
tag != ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS &&
tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS &&
tag != ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS &&
tag != ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS &&
tag != ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS &&
tag != ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS &&
tag != ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS) {
return -1;
}
ACameraMetadata_const_entry entry;
ACameraMetadata_getConstEntry(mChars, tag, &entry);
for (uint32_t i = 0; i < entry.count; i += 4) {
if (entry.data.i64[i] == format &&
entry.data.i64[i+1] == width &&
entry.data.i64[i+2] == height) {
return entry.data.i64[i+3];
}
}
return -1;
}
const ACameraMetadata* mChars;
};
class PreviewTestCase {
public:
~PreviewTestCase() {
resetCamera();
deInit();
if (mCameraManager) {
ACameraManager_delete(mCameraManager);
mCameraManager = nullptr;
}
}
PreviewTestCase() {
// create is guaranteed to succeed;
createManager();
}
// Free all resources except camera manager
void resetCamera() {
mSessionListener.reset();
mResultListener.reset();
if (mSession) {
ACameraCaptureSession_close(mSession);
mSession = nullptr;
}
if (mDevice) {
ACameraDevice_close(mDevice);
mDevice = nullptr;
}
if (mImgReader) {
AImageReader_delete(mImgReader);
// No need to call ANativeWindow_release on imageReaderAnw
mImgReaderAnw = nullptr;
mImgReader = nullptr;
}
if (mPreviewAnw) {
ANativeWindow_release(mPreviewAnw);
mPreviewAnw = nullptr;
}
if (mOutputs) {
ACaptureSessionOutputContainer_free(mOutputs);
mOutputs = nullptr;
}
if (mPreviewOutput) {
ACaptureSessionOutput_free(mPreviewOutput);
mPreviewOutput = nullptr;
}
if (mImgReaderOutput) {
ACaptureSessionOutput_free(mImgReaderOutput);
mImgReaderOutput = nullptr;
}
if (mPreviewRequest) {
ACaptureRequest_free(mPreviewRequest);
mPreviewRequest = nullptr;
}
if (mStillRequest) {
ACaptureRequest_free(mStillRequest);
mStillRequest = nullptr;
}
if (mReqPreviewOutput) {
ACameraOutputTarget_free(mReqPreviewOutput);
mReqPreviewOutput = nullptr;
}
if (mReqImgReaderOutput) {
ACameraOutputTarget_free(mReqImgReaderOutput);
mReqImgReaderOutput = nullptr;
}
mImgReaderInited = false;
mPreviewInited = false;
}
camera_status_t initWithErrorLog() {
camera_status_t ret = ACameraManager_getCameraIdList(
mCameraManager, &mCameraIdList);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get camera id list failed: ret %d", ret);
return ret;
}
ret = ACameraManager_registerAvailabilityCallback(mCameraManager, &mServiceCb);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Register availability callback failed: ret %d", ret);
return ret;
}
mMgrInited = true;
return ACAMERA_OK;
}
camera_status_t deInit () {
if (!mMgrInited) {
return ACAMERA_OK;
}
camera_status_t ret = ACameraManager_unregisterAvailabilityCallback(
mCameraManager, &mServiceCb);
if (ret != ACAMERA_OK) {
ALOGE("Unregister availability callback failed: ret %d", ret);
return ret;
}
if (mCameraIdList) {
ACameraManager_deleteCameraIdList(mCameraIdList);
mCameraIdList = nullptr;
}
mMgrInited = false;
return ACAMERA_OK;
}
int getNumCameras() {
if (!mMgrInited || !mCameraIdList) {
return -1;
}
return mCameraIdList->numCameras;
}
const char* getCameraId(int idx) {
if (!mMgrInited || !mCameraIdList || idx < 0 || idx >= mCameraIdList->numCameras) {
return nullptr;
}
return mCameraIdList->cameraIds[idx];
}
// Caller is responsible to free returned characteristics metadata
ACameraMetadata* getCameraChars(int idx) {
if (!mMgrInited || !mCameraIdList || idx < 0 || idx >= mCameraIdList->numCameras) {
return nullptr;
}
ACameraMetadata* chars;
camera_status_t ret = ACameraManager_getCameraCharacteristics(
mCameraManager, mCameraIdList->cameraIds[idx], &chars);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get camera characteristics failed: ret %d", ret);
return nullptr;
}
return chars;
}
// Caller is responsible to free returned characteristics metadata.
ACameraMetadata* getCameraChars(const char* id) {
if (!mMgrInited || id == nullptr) {
return nullptr;
}
ACameraMetadata* chars;
camera_status_t ret = ACameraManager_getCameraCharacteristics(mCameraManager, id, &chars);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get camera characteristics failed: ret %d", ret);
return nullptr;
}
return chars;
}
camera_status_t updateOutput(JNIEnv* env, ACaptureSessionOutput *output) {
if (mSession == nullptr) {
ALOGE("Testcase cannot update output configuration session %p",
mSession);
return ACAMERA_ERROR_UNKNOWN;
}
return ACameraCaptureSession_updateSharedOutput(mSession, output);
}
camera_status_t openCamera(const char* cameraId) {
if (mDevice) {
ALOGE("Cannot open camera before closing previously open one");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
mCameraId = cameraId;
return ACameraManager_openCamera(mCameraManager, cameraId, &mDeviceCb, &mDevice);
}
camera_status_t closeCamera() {
camera_status_t ret = ACameraDevice_close(mDevice);
mDevice = nullptr;
return ret;
}
bool isCameraAvailable(const char* cameraId) {
if (!mMgrInited) {
ALOGE("Camera service listener has not been registered!");
}
return mServiceListener.isAvailable(cameraId);
}
media_status_t initImageReaderWithErrorLog(
int32_t width, int32_t height, int32_t format, int32_t maxImages,
AImageReader_ImageListener* listener) {
if (mImgReader || mImgReaderAnw) {
LOG_ERROR(errorString, "Cannot init image reader before closing existing one");
return AMEDIA_ERROR_UNKNOWN;
}
media_status_t ret = initImageReaderWithErrorLog(
width, height, format, maxImages, listener, &mImgReader,
&mImgReaderAnw);
if (ret != AMEDIA_OK) {
return ret;
}
mImgReaderInited = true;
return AMEDIA_OK;
}
media_status_t initImageReaderWithErrorLog(
int32_t width, int32_t height, int32_t format, int32_t maxImages,
AImageReader_ImageListener* listener, AImageReader **imgReader,
ANativeWindow **imgReaderAnw) {
media_status_t ret = AImageReader_new(
width, height, format,
maxImages, imgReader);
if (ret != AMEDIA_OK) {
LOG_ERROR(errorString, "Create image reader. ret %d", ret);
return ret;
}
if (*imgReader == nullptr) {
LOG_ERROR(errorString, "null image reader created");
return AMEDIA_ERROR_UNKNOWN;
}
ret = AImageReader_setImageListener(*imgReader, listener);
if (ret != AMEDIA_OK) {
LOG_ERROR(errorString, "Set AImageReader listener failed. ret %d", ret);
return ret;
}
ret = AImageReader_getWindow(*imgReader, imgReaderAnw);
if (ret != AMEDIA_OK) {
LOG_ERROR(errorString, "AImageReader_getWindow failed. ret %d", ret);
return ret;
}
if (*imgReaderAnw == nullptr) {
LOG_ERROR(errorString, "Null ANW from AImageReader!");
return AMEDIA_ERROR_UNKNOWN;
}
return AMEDIA_OK;
}
ANativeWindow* initPreviewAnw(JNIEnv* env, jobject jSurface) {
if (mPreviewAnw) {
ALOGE("Cannot init preview twice!");
return nullptr;
}
mPreviewAnw = ANativeWindow_fromSurface(env, jSurface);
mPreviewInited = true;
return mPreviewAnw;
}
camera_status_t createCaptureSessionWithLog(bool isPreviewShared = false,
ACaptureRequest *sessionParameters = nullptr) {
std::vector<ACaptureSessionOutput*> extraOutputs;
return createCaptureSessionWithLog(extraOutputs, isPreviewShared, sessionParameters);
}
camera_status_t createCaptureSessionOutputContainer(
const std::vector<ACaptureSessionOutput*> extraOutputs,
ACaptureSessionOutputContainer** outputs,
bool isPreviewShared = false, ACaptureRequest *sessionParameters = nullptr) {
if (!mMgrInited || (!mImgReaderInited && !mPreviewInited) || !outputs) {
LOG_ERROR(errorString, "Cannot create session output container. mgrInit %d "
"readerInit %d previewInit %d outputs %p",
mMgrInited, mImgReaderInited, mPreviewInited, outputs);
return ACAMERA_ERROR_UNKNOWN;
}
camera_status_t ret = ACaptureSessionOutputContainer_create(outputs);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Create capture session output container failed. ret %d", ret);
return ret;
}
if (mImgReaderInited) {
ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
if (ret != ACAMERA_OK || mImgReaderOutput == nullptr) {
LOG_ERROR(errorString,
"Session image reader output create fail! ret %d output %p",
ret, mImgReaderOutput);
if (ret == ACAMERA_OK) {
ret = ACAMERA_ERROR_UNKNOWN; // ret OK but output is null
}
return ret;
}
ret = ACaptureSessionOutputContainer_add(*outputs, mImgReaderOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Session image reader output add failed! ret %d", ret);
return ret;
}
}
for (auto extraOutput : extraOutputs) {
ret = ACaptureSessionOutputContainer_add(*outputs, extraOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Session image reader output add failed! ret %d", ret);
return ret;
}
}
if (mPreviewInited) {
if (isPreviewShared) {
ret = ACaptureSessionSharedOutput_create(mPreviewAnw, &mPreviewOutput);
} else {
ret = ACaptureSessionOutput_create(mPreviewAnw, &mPreviewOutput);
}
if (ret != ACAMERA_OK || mPreviewOutput == nullptr) {
LOG_ERROR(errorString,
"Session preview output create fail! ret %d output %p",
ret, mPreviewOutput);
if (ret == ACAMERA_OK) {
ret = ACAMERA_ERROR_UNKNOWN; // ret OK but output is null
}
return ret;
}
ret = ACaptureSessionOutputContainer_add(*outputs, mPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Session preview output add failed! ret %d", ret);
return ret;
}
}
return ret;
}
camera_status_t createCaptureSessionWithLog(
const std::vector<ACaptureSessionOutput*> extraOutputs,
bool isPreviewShared = false, ACaptureRequest *sessionParameters = nullptr,
bool sessionConfigurationDefault = true) {
if (mSession) {
LOG_ERROR(errorString, "Cannot create session before closing existing one");
return ACAMERA_ERROR_UNKNOWN;
}
camera_status_t ret = createCaptureSessionOutputContainer(
extraOutputs, &mOutputs, isPreviewShared, sessionParameters);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Failed to create session output container! ret %d", ret);
return ret;
}
ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs);
if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION &&
ret != ACAMERA_ERROR_STREAM_CONFIGURE_FAIL) {
LOG_ERROR(errorString, "isSessionConfigurationSupported must return either OK "
", UNSUPPORTED_OPERATION, or STREAM_CONFIGURE_FAIL, but returns %d", ret);
return ret;
}
// If session configuration is not supported by default, return early
// when camera device doesn't explicitly claim support.
if (ret != ACAMERA_OK && !sessionConfigurationDefault) {
return ret;
}
ret = ACameraDevice_createCaptureSessionWithSessionParameters(
mDevice, mOutputs, sessionParameters, &mSessionCb, &mSession);
if (ret != ACAMERA_OK || mSession == nullptr) {
LOG_ERROR(errorString, "Create session for camera %s failed. ret %d session %p",
mCameraId, ret, mSession);
if (ret == ACAMERA_OK) {
ret = ACAMERA_ERROR_UNKNOWN; // ret OK but session is null
}
return ret;
}
return ACAMERA_OK;
}
void closeSession() {
if (mSession != nullptr) {
ACameraCaptureSession_close(mSession);
}
if (mOutputs) {
ACaptureSessionOutputContainer_free(mOutputs);
mOutputs = nullptr;
}
if (mPreviewOutput) {
ACaptureSessionOutput_free(mPreviewOutput);
mPreviewOutput = nullptr;
}
if (mImgReaderOutput) {
ACaptureSessionOutput_free(mImgReaderOutput);
mImgReaderOutput = nullptr;
}
mSession = nullptr;
}
camera_status_t createRequestsWithErrorLog() {
std::vector<ACameraOutputTarget*> extraOutputs;
return createRequestsWithErrorLog(extraOutputs);
}
camera_status_t createRequestsWithErrorLog(
const std::vector<ACameraOutputTarget*> extraOutputs,
const ACameraIdList* physicalCameraIdList = nullptr) {
if (mPreviewRequest || mStillRequest) {
LOG_ERROR(errorString, "Cannot create requests before deleteing existing one");
return ACAMERA_ERROR_UNKNOWN;
}
if (mDevice == nullptr || (!mPreviewInited && !mImgReaderInited)) {
LOG_ERROR(errorString,
"Cannot create request. device %p previewInit %d readeInit %d",
mDevice, mPreviewInited, mImgReaderInited);
return ACAMERA_ERROR_UNKNOWN;
}
camera_status_t ret;
bool usePhysicalSettings = (physicalCameraIdList != nullptr);
if (mPreviewInited) {
if (!usePhysicalSettings) {
ret = ACameraDevice_createCaptureRequest(
mDevice, TEMPLATE_PREVIEW, &mPreviewRequest);
} else {
ret = ACameraDevice_createCaptureRequest_withPhysicalIds(
mDevice, TEMPLATE_PREVIEW, physicalCameraIdList, &mPreviewRequest);
}
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s create preview request failed. ret %d",
mCameraId, ret);
return ret;
}
if (usePhysicalSettings) {
for (int i = 0; i < physicalCameraIdList->numCameras; i++) {
// Check physical camera specific metadata functions.
uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON;
ret = ACaptureRequest_setEntry_physicalCamera_u8(mPreviewRequest,
physicalCameraIdList->cameraIds[i], ACAMERA_CONTROL_AE_MODE,
1 /*count*/, &aeMode);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Error: Camera %s update AE mode key fail. ret %d",
physicalCameraIdList->cameraIds[i], ret);
return ret;
}
ACameraMetadata_const_entry entry;
ret = ACaptureRequest_getConstEntry_physicalCamera(mPreviewRequest,
physicalCameraIdList->cameraIds[i],
ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get AE mode key for physicalCamera %s failed."
" ret %d", physicalCameraIdList->cameraIds[i], ret);
return ret;
}
if (entry.data.u8[0] != aeMode) {
LOG_ERROR(errorString,
"Error: AE mode key is not updated. expect %d but get %d",
aeMode, entry.data.u8[0]);
return ACAMERA_ERROR_UNKNOWN;
}
}
}
ret = ACameraOutputTarget_create(mPreviewAnw, &mReqPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Camera %s create request preview output target failed. ret %d",
mCameraId, ret);
return ret;
}
ret = ACaptureRequest_addTarget(mPreviewRequest, mReqPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d",
mCameraId, ret);
return ret;
}
// Add extraOutputs to the request
for (auto extraOutput : extraOutputs) {
ret = ACaptureRequest_addTarget(mPreviewRequest, extraOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s add extra request output failed. ret %d",
mCameraId, ret);
return ret;
}
}
} else {
ALOGI("Preview not inited. Will not create preview request!");
}
if (mImgReaderInited) {
ret = ACameraDevice_createCaptureRequest(
mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s create still request failed. ret %d",
mCameraId, ret);
return ret;
}
ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Camera %s create request reader output target failed. ret %d",
mCameraId, ret);
return ret;
}
ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s add still request output failed. ret %d",
mCameraId, ret);
return ret;
}
if (mPreviewInited) {
ret = ACaptureRequest_addTarget(mStillRequest, mReqPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Camera %s add still request preview output failed. ret %d",
mCameraId, ret);
return ret;
}
}
} else {
ALOGI("AImageReader not inited. Will not create still request!");
}
return ACAMERA_OK;
}
// The output ACaptureRequest* is still managed by testcase class
camera_status_t getStillRequest(ACaptureRequest** out) {
if (mStillRequest == nullptr) {
ALOGE("Camera %s Still capture request hasn't been created", mCameraId);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
*out = mStillRequest;
return ACAMERA_OK;
}
camera_status_t getPreviewRequest(ACaptureRequest** out) {
if (mPreviewRequest == nullptr) {
ALOGE("Camera %s Preview capture request hasn't been created", mCameraId);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
*out = mPreviewRequest;
return ACAMERA_OK;
}
camera_status_t startPreview(int *sequenceId = nullptr, size_t physicalIdCnt = 0,
const char*const* extraPhysicalOutputs = nullptr) {
if (mSession == nullptr || mPreviewRequest == nullptr) {
ALOGE("Testcase cannot start preview: session %p, preview request %p",
mSession, mPreviewRequest);
return ACAMERA_ERROR_UNKNOWN;
}
int previewSeqId;
camera_status_t ret;
if (sequenceId == nullptr) {
ret = ACameraCaptureSession_setRepeatingRequest(
mSession, nullptr, 1, &mPreviewRequest, &previewSeqId);
} else if (physicalIdCnt == 0) {
ret = ACameraCaptureSession_setRepeatingRequest(
mSession, &mResultCb, 1, &mPreviewRequest, sequenceId);
} else {
if (extraPhysicalOutputs == nullptr) {
ALOGE("Testcase missing valid physical camera Ids for logical camera");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
CaptureResultListener* resultListener =
static_cast<CaptureResultListener*>(mLogicalCameraResultCb.context);
resultListener->registerPhysicalResults(physicalIdCnt, extraPhysicalOutputs);
ret = ACameraCaptureSession_logicalCamera_setRepeatingRequest(
mSession, &mLogicalCameraResultCb, 1, &mPreviewRequest, sequenceId);
}
return ret;
}
camera_status_t startRepeatingRequest(int *sequenceId, ACaptureRequest *request,
ACameraCaptureSession_captureCallbacks *resultCb) {
if (mSession == nullptr || request == nullptr || resultCb == nullptr) {
ALOGE("Testcase cannot start repeating request: session %p, request %p resultCb %p",
mSession, request, resultCb);
return ACAMERA_ERROR_UNKNOWN;
}
return ACameraCaptureSession_setRepeatingRequest(mSession, resultCb, 1, &request,
sequenceId);
}
camera_status_t stopPreview() {
if (mSession == nullptr) {
ALOGE("Testcase cannot stop preview: session %p", mSession);
return ACAMERA_ERROR_UNKNOWN;
}
return ACameraCaptureSession_stopRepeating(mSession);
}
camera_status_t updateRepeatingRequest(ACaptureRequest *updatedRequest,
int *sequenceId = nullptr) {
if (mSession == nullptr || updatedRequest == nullptr) {
ALOGE("Testcase cannot update repeating request: session %p, updated request %p",
mSession, updatedRequest);
return ACAMERA_ERROR_UNKNOWN;
}
int previewSeqId;
camera_status_t ret;
if (sequenceId == nullptr) {
ret = ACameraCaptureSession_setRepeatingRequest(
mSession, nullptr, 1, &updatedRequest, &previewSeqId);
} else {
ret = ACameraCaptureSession_setRepeatingRequest(
mSession, &mResultCb, 1, &updatedRequest, sequenceId);
}
return ret;
}
int64_t getCaptureSequenceLastFrameNumber(int64_t sequenceId, uint32_t timeoutSec) {
return mResultListener.getCaptureSequenceLastFrameNumber(sequenceId, timeoutSec);
}
bool waitForFrameNumber(int64_t frameNumber, uint32_t timeoutSec) {
return mResultListener.waitForFrameNumber(frameNumber, timeoutSec);
}
camera_status_t takePicture() {
if (mSession == nullptr || mStillRequest == nullptr) {
ALOGE("Testcase cannot take picture: session %p, still request %p",
mSession, mStillRequest);
return ACAMERA_ERROR_UNKNOWN;
}
int seqId;
return ACameraCaptureSession_capture(
mSession, nullptr, 1, &mStillRequest, &seqId);
}
camera_status_t capture(ACaptureRequest* request,
ACameraCaptureSession_captureCallbacks* listener,
/*out*/int* seqId) {
if (mSession == nullptr || request == nullptr) {
ALOGE("Testcase cannot capture session: session %p, request %p",
mSession, request);
return ACAMERA_ERROR_UNKNOWN;
}
return ACameraCaptureSession_capture(
mSession, listener, 1, &request, seqId);
}
camera_status_t resetWithErrorLog() {
camera_status_t ret;
closeSession();
for (int i = 0; i < 50; i++) {
usleep(100000); // sleep 100ms
if (mSessionListener.isClosed()) {
ALOGI("Session take ~%d ms to close", i*100);
break;
}
}
if (!mSessionListener.isClosed() || mSessionListener.onClosedCount() != 1) {
LOG_ERROR(errorString,
"Session for camera %s close error. isClosde %d close count %d",
mCameraId, mSessionListener.isClosed(), mSessionListener.onClosedCount());
return ACAMERA_ERROR_UNKNOWN;
}
mSessionListener.reset();
mResultListener.reset();
ret = closeCamera();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Close camera device %s failure. ret %d", mCameraId, ret);
return ret;
}
resetCamera();
return ACAMERA_OK;
}
CaptureSessionListener* getSessionListener() {
return &mSessionListener;
}
ACameraDevice* getCameraDevice() {
return mDevice;
}
ACaptureSessionOutput *getPreviewOutput() {
return mPreviewOutput;
}
private:
ACameraManager* createManager() {
if (!mCameraManager) {
mCameraManager = ACameraManager_create();
}
return mCameraManager;
}
CameraServiceListener mServiceListener;
ACameraManager_AvailabilityCallbacks mServiceCb {
&mServiceListener,
CameraServiceListener::onAvailable,
CameraServiceListener::onUnavailable
};
CameraDeviceListener mDeviceListener;
ACameraDevice_StateCallbacks mDeviceCb {
&mDeviceListener,
CameraDeviceListener::onDisconnected,
CameraDeviceListener::onError
};
CaptureSessionListener mSessionListener;
ACameraCaptureSession_stateCallbacks mSessionCb {
&mSessionListener,
CaptureSessionListener::onClosed,
CaptureSessionListener::onReady,
CaptureSessionListener::onActive
};
CaptureResultListener mResultListener;
ACameraCaptureSession_captureCallbacks mResultCb {
&mResultListener,
CaptureResultListener::onCaptureStart,
CaptureResultListener::onCaptureProgressed,
CaptureResultListener::onCaptureCompleted,
CaptureResultListener::onCaptureFailed,
CaptureResultListener::onCaptureSequenceCompleted,
CaptureResultListener::onCaptureSequenceAborted,
CaptureResultListener::onCaptureBufferLost
};
ACameraCaptureSession_logicalCamera_captureCallbacks mLogicalCameraResultCb {
&mResultListener,
CaptureResultListener::onCaptureStart,
CaptureResultListener::onCaptureProgressed,
CaptureResultListener::onLogicalCameraCaptureCompleted,
CaptureResultListener::onLogicalCameraCaptureFailed,
CaptureResultListener::onCaptureSequenceCompleted,
CaptureResultListener::onCaptureSequenceAborted,
CaptureResultListener::onCaptureBufferLost
};
ACameraIdList* mCameraIdList = nullptr;
ACameraDevice* mDevice = nullptr;
AImageReader* mImgReader = nullptr;
ANativeWindow* mImgReaderAnw = nullptr;
ANativeWindow* mPreviewAnw = nullptr;
ACameraManager* mCameraManager = nullptr;
ACaptureSessionOutputContainer* mOutputs = nullptr;
ACaptureSessionOutput* mPreviewOutput = nullptr;
ACaptureSessionOutput* mImgReaderOutput = nullptr;
ACameraCaptureSession* mSession = nullptr;
ACaptureRequest* mPreviewRequest = nullptr;
ACaptureRequest* mStillRequest = nullptr;
ACameraOutputTarget* mReqPreviewOutput = nullptr;
ACameraOutputTarget* mReqImgReaderOutput = nullptr;
const char* mCameraId;
bool mMgrInited = false; // cameraId, serviceListener
bool mImgReaderInited = false;
bool mPreviewInited = false;
};
jint throwAssertionError(JNIEnv* env, const char* message)
{
jclass assertionClass;
const char* className = "junit/framework/AssertionFailedError";
assertionClass = env->FindClass(className);
if (assertionClass == nullptr) {
ALOGE("Native throw error: cannot find class %s", className);
return -1;
}
return env->ThrowNew(assertionClass, message);
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraManagerTest_\
testCameraManagerGetAndCloseNative(
JNIEnv* env, jclass /*clazz*/) {
bool pass = false;
ALOGV("%s", __FUNCTION__);
ACameraManager* cameraManager2 = nullptr;
ACameraManager* cameraManager3 = nullptr;
ACameraManager* cameraManager4 = nullptr;
camera_status_t ret = ACAMERA_OK;
ACameraManager* cameraManager = ACameraManager_create();
if (cameraManager == nullptr) {
LOG_ERROR(errorString, "ACameraManager_create returns nullptr");
goto cleanup;
}
ACameraManager_delete(cameraManager);
cameraManager = nullptr;
// Test get/close multiple instances
cameraManager = ACameraManager_create();
cameraManager2 = ACameraManager_create();
if (cameraManager2 == nullptr) {
LOG_ERROR(errorString, "ACameraManager_create 2 returns nullptr");
goto cleanup;
}
ACameraManager_delete(cameraManager);
cameraManager = nullptr;
cameraManager3 = ACameraManager_create();
if (cameraManager3 == nullptr) {
LOG_ERROR(errorString, "ACameraManager_create 3 returns nullptr");
goto cleanup;
}
cameraManager4 = ACameraManager_create();
if (cameraManager4 == nullptr) {
LOG_ERROR(errorString, "ACameraManager_create 4 returns nullptr");
goto cleanup;
}
ACameraManager_delete(cameraManager3);
ACameraManager_delete(cameraManager2);
ACameraManager_delete(cameraManager4);
pass = true;
cleanup:
if (cameraManager) {
ACameraManager_delete(cameraManager);
}
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "fail");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraManagerTest_\
testCameraManagerGetCameraIdsNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
bool pass = false;
ACameraManager* mgr = ACameraManager_create();
ACameraIdList *cameraIdList = nullptr;
camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList);
if (ret != ACAMERA_OK || cameraIdList == nullptr) {
LOG_ERROR(errorString, "Get camera id list failed: ret %d, cameraIdList %p",
ret, cameraIdList);
goto cleanup;
}
ALOGI("Number of cameras: %d", cameraIdList->numCameras);
for (int i = 0; i < cameraIdList->numCameras; i++) {
ALOGI("Camera ID: %s", cameraIdList->cameraIds[i]);
}
ACameraManager_deleteCameraIdList(cameraIdList);
cameraIdList = nullptr;
pass = true;
cleanup:
if (mgr) {
ACameraManager_delete(mgr);
}
if (cameraIdList) {
ACameraManager_deleteCameraIdList(cameraIdList);
}
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "fail");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraManagerTest_\
testCameraManagerAvailabilityCallbackNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
bool pass = false;
ACameraManager* mgr = ACameraManager_create();
ACameraIdList *cameraIdList = nullptr;
camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList);
int numCameras = cameraIdList->numCameras;
CameraServiceListener listener;
ACameraManager_AvailabilityCallbacks cbs {
&listener,
CameraServiceListener::onAvailable,
CameraServiceListener::onUnavailable};
ret = ACameraManager_registerAvailabilityCallback(mgr, &cbs);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Register availability callback failed: ret %d", ret);
goto cleanup;
}
sleep(1); // sleep a second to give some time for callbacks to happen
// Should at least get onAvailable for each camera once
if (listener.getAvailableCount() < numCameras) {
LOG_ERROR(errorString, "Expect at least %d available callback but only got %d",
numCameras, listener.getAvailableCount());
goto cleanup;
}
ret = ACameraManager_unregisterAvailabilityCallback(mgr, &cbs);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Unregister availability callback failed: ret %d", ret);
goto cleanup;
}
pass = true;
cleanup:
if (cameraIdList) {
ACameraManager_deleteCameraIdList(cameraIdList);
}
if (mgr) {
ACameraManager_delete(mgr);
}
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraManagerTest_\
testCameraManagerCharacteristicsNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
bool pass = false;
ACameraManager* mgr = ACameraManager_create();
ACameraIdList *cameraIdList = nullptr;
ACameraMetadata* chars = nullptr;
ACameraMetadata* copy = nullptr;
int numCameras = 0;
camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList);
if (ret != ACAMERA_OK || cameraIdList == nullptr) {
LOG_ERROR(errorString, "Get camera id list failed: ret %d, cameraIdList %p",
ret, cameraIdList);
goto cleanup;
}
numCameras = cameraIdList->numCameras;
for (int i = 0; i < numCameras; i++) {
ret = ACameraManager_getCameraCharacteristics(
mgr, cameraIdList->cameraIds[i], &chars);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get camera characteristics failed: ret %d", ret);
goto cleanup;
}
int32_t numTags = 0;
const uint32_t* tags = nullptr;
ret = ACameraMetadata_getAllTags(chars, &numTags, &tags);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get camera characteristics tags failed: ret %d", ret);
goto cleanup;
}
for (int tid = 0; tid < numTags; tid++) {
uint32_t tagId = tags[tid];
ALOGV("%s camera characteristics contains key %u", __FUNCTION__, tagId);
uint32_t sectionId = tagId >> 16;
if (sectionId >= ACAMERA_SECTION_COUNT && sectionId < ACAMERA_VENDOR) {
LOG_ERROR(errorString, "Unknown tagId %u, sectionId %u", tagId, sectionId);
goto cleanup;
}
}
ACameraMetadata_const_entry entry;
ret = ACameraMetadata_getConstEntry(chars, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get const available capabilities key failed. ret %d", ret);
goto cleanup;
}
// Check the entry is actually legit
if (entry.tag != ACAMERA_REQUEST_AVAILABLE_CAPABILITIES ||
entry.count == 0 || entry.type != ACAMERA_TYPE_BYTE || entry.data.i32 == nullptr) {
LOG_ERROR(errorString,
"Bad available capabilities key: tag: %d (expected %d), count %u (expect > 0), "
"type %d (expected %d), data %p (expected not null)",
entry.tag, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, entry.count,
entry.type, ACAMERA_TYPE_BYTE, entry.data.i32);
goto cleanup;
}
// All camera supports BC except depth only cameras
bool supportBC = false, supportDepth = false;
for (uint32_t i = 0; i < entry.count; i++) {
if (entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
supportBC = true;
}
if (entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) {
supportDepth = true;
}
}
if (!(supportBC || supportDepth)) {
LOG_ERROR(errorString, "Error: camera device %s does not support either BC or DEPTH",
cameraIdList->cameraIds[i]);
goto cleanup;
}
// Check copy works
copy = ACameraMetadata_copy(chars);
// Compare copy with original
ACameraMetadata_const_entry entryCopy;
ret = ACameraMetadata_getConstEntry(
copy, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entryCopy);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get const available capabilities key failed. ret %d", ret);
goto cleanup;
}
for (uint32_t i = 0; i < entry.count; i++) {
if (entry.data.u8[i] != entryCopy.data.u8[i]) {
LOG_ERROR(errorString,
"Copy of available capability key[%d]: %d mismatches original %d",
i, entryCopy.data.u8[i], entry.data.u8[i]);
goto cleanup;
}
}
// Check get unknown value fails
uint32_t badTag = (uint32_t) ACAMERA_VENDOR_START - 1;
ret = ACameraMetadata_getConstEntry(chars, badTag, &entry);
if (ret == ACAMERA_OK) {
LOG_ERROR(errorString, "Error: get unknown tag should fail!");
goto cleanup;
}
ACameraMetadata_free(chars);
ACameraMetadata_free(copy);
chars = nullptr;
copy = nullptr;
}
pass = true;
cleanup:
if (chars) {
ACameraMetadata_free(chars);
}
if (copy) {
ACameraMetadata_free(copy);
}
ACameraManager_deleteCameraIdList(cameraIdList);
ACameraManager_delete(mgr);
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\
testCameraDeviceOpenAndCloseNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
int numCameras = 0;
bool pass = false;
PreviewTestCase testCase;
camera_status_t ret = testCase.initWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
numCameras = testCase.getNumCameras();
if (numCameras < 0) {
LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras);
goto cleanup;
}
for (int i = 0; i < numCameras; i++) {
const char* cameraId = testCase.getCameraId(i);
if (cameraId == nullptr) {
LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i);
goto cleanup;
}
ret = testCase.openCamera(cameraId);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret);
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId);
goto cleanup;
}
ret = testCase.closeCamera();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Close camera device %s failure. ret %d", cameraId, ret);
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (!testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be available now", cameraId);
goto cleanup;
}
}
ret = testCase.deInit();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret);
goto cleanup;
}
pass = true;
cleanup:
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\
testCameraDeviceCreateCaptureRequestNative(
JNIEnv* env, jclass /*clazz*/) {
ALOGV("%s", __FUNCTION__);
bool pass = false;
ACameraManager* mgr = ACameraManager_create();
ACameraIdList* cameraIdList = nullptr;
ACameraDevice* device = nullptr;
ACaptureRequest* request = nullptr;
ACameraMetadata* chars = nullptr;
camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList);
int numCameras = cameraIdList->numCameras;
for (int i = 0; i < numCameras; i++) {
CameraDeviceListener deviceListener;
const char* cameraId = cameraIdList->cameraIds[i];
ACameraDevice_StateCallbacks deviceCb {
&deviceListener,
CameraDeviceListener::onDisconnected,
CameraDeviceListener::onError
};
ret = ACameraManager_openCamera(mgr, cameraId, &deviceCb, &device);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret);
goto cleanup;
}
ret = ACameraManager_getCameraCharacteristics(mgr, cameraId, &chars);
if (ret != ACAMERA_OK || chars == nullptr) {
LOG_ERROR(errorString, "Get camera %s characteristics failure. ret %d, chars %p",
cameraId, ret, chars);
goto cleanup;
}
StaticInfo staticInfo(chars);
for (int t = TEMPLATE_PREVIEW; t <= TEMPLATE_MANUAL; t++) {
ACameraDevice_request_template templateId =
static_cast<ACameraDevice_request_template>(t);
ret = ACameraDevice_createCaptureRequest(device, templateId, &request);
if (ret == ACAMERA_ERROR_INVALID_PARAMETER) {
// template not supported. skip
continue;
}
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Create capture request failed!: ret %d", ret);
goto cleanup;
}
int32_t numTags = 0;
const uint32_t* tags = nullptr;
ret = ACaptureRequest_getAllTags(request, &numTags, &tags);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get capture request tags failed: ret %d", ret);
goto cleanup;
}
for (int tid = 0; tid < numTags; tid++) {
uint32_t tagId = tags[tid];
ALOGV("%s capture request contains key %u", __FUNCTION__, tagId);
uint32_t sectionId = tagId >> 16;
if (sectionId >= ACAMERA_SECTION_COUNT && sectionId < ACAMERA_VENDOR) {
LOG_ERROR(errorString, "Unknown tagId %u, sectionId %u", tagId, sectionId);
goto cleanup;
}
}
void* context = nullptr;
ret = ACaptureRequest_getUserContext(request, &context);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get capture request context failed: ret %d", ret);
goto cleanup;
}
if (context != nullptr) {
LOG_ERROR(errorString, "Capture request context is not null: %p", context);
goto cleanup;
}
intptr_t magic_num = 0xBEEF;
ret = ACaptureRequest_setUserContext(request, (void*) magic_num);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Set capture request context failed: ret %d", ret);
goto cleanup;
}
ret = ACaptureRequest_getUserContext(request, &context);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get capture request context failed: ret %d", ret);
goto cleanup;
}
if (context != (void*) magic_num) {
LOG_ERROR(errorString, "Capture request context is wrong: %p", context);
goto cleanup;
}
// try get/set capture request fields
ACameraMetadata_const_entry entry;
ret = ACaptureRequest_getConstEntry_physicalCamera(request, nullptr,
ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "Get AE mode key for null physical id should fail. ret %d",
ret);
goto cleanup;
}
ret = ACaptureRequest_getConstEntry_physicalCamera(request, cameraId,
ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "Get AE mode key for physical id should fail. ret %d",
ret);
goto cleanup;
}
ret = ACaptureRequest_getConstEntry(request, ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret);
goto cleanup;
}
if (entry.tag != ACAMERA_CONTROL_AE_MODE || entry.type != ACAMERA_TYPE_BYTE ||\
entry.count != 1) {
LOG_ERROR(errorString,
"Bad AE mode key. tag 0x%x (expect 0x%x), type %d (expect %d), "
"count %d (expect %d)",
entry.tag, ACAMERA_CONTROL_AE_MODE, entry.type, ACAMERA_TYPE_BYTE,
entry.count, 1);
goto cleanup;
}
if (t == TEMPLATE_MANUAL) {
if (entry.data.u8[0] != ACAMERA_CONTROL_AE_MODE_OFF) {
LOG_ERROR(errorString, "Error: MANUAL template AE mode %d (expect %d)",
entry.data.u8[0], ACAMERA_CONTROL_AE_MODE_OFF);
goto cleanup;
}
// try set AE_MODE_ON
uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON;
ret = ACaptureRequest_setEntry_physicalCamera_u8(
request, nullptr, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "Error: camera %s setEntry_physicalCamera_u8 should "
"fail. ret %d", cameraId, ret);
goto cleanup;
}
ret = ACaptureRequest_setEntry_physicalCamera_u8(
request, cameraId, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "Error: camera %s setEntry_physicalCamera_u8 should "
"fail. ret %d", cameraId, ret);
goto cleanup;
}
ret = ACaptureRequest_setEntry_u8(
request, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Error: Camera %s template %d: update AE mode key fail. ret %d",
cameraId, t, ret);
goto cleanup;
}
ret = ACaptureRequest_getConstEntry(
request, ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret);
goto cleanup;
}
if (entry.data.u8[0] != aeMode) {
LOG_ERROR(errorString,
"Error: AE mode key is not updated. expect %d but get %d",
aeMode, entry.data.u8[0]);
goto cleanup;
}
} else {
if (staticInfo.isColorOutputSupported()) {
if (entry.data.u8[0] != ACAMERA_CONTROL_AE_MODE_ON) {
LOG_ERROR(errorString,
"Error: Template %d has wrong AE mode %d (expect %d)",
t, entry.data.u8[0], ACAMERA_CONTROL_AE_MODE_ON);
goto cleanup;
}
// try set AE_MODE_OFF
if (staticInfo.isCapabilitySupported(
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_OFF;
ret = ACaptureRequest_setEntry_u8(
request, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Error: Camera %s template %d: update AE mode key fail. ret %d",
cameraId, t, ret);
goto cleanup;
}
ret = ACaptureRequest_getConstEntry(
request, ACAMERA_CONTROL_AE_MODE, &entry);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret);
goto cleanup;
}
if (entry.data.u8[0] != aeMode) {
LOG_ERROR(errorString,
"Error: AE mode key is not updated. expect %d but get %d",
aeMode, entry.data.u8[0]);
goto cleanup;
}
}
}
}
ACaptureRequest_free(request);
request = nullptr;
}
ACameraMetadata_free(chars);
chars = nullptr;
ACameraDevice_close(device);
device = nullptr;
}
pass = true;
cleanup:
if (cameraIdList) {
ACameraManager_deleteCameraIdList(cameraIdList);
}
if (request) {
ACaptureRequest_free(request);
}
if (chars) {
ACameraMetadata_free(chars);
}
if (device) {
ACameraDevice_close(device);
}
if (mgr) {
ACameraManager_delete(mgr);
}
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\
testCameraDeviceSessionOpenAndCloseNative(
JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface) {
ALOGV("%s", __FUNCTION__);
int numCameras = 0;
bool pass = false;
PreviewTestCase testCase;
camera_status_t ret = testCase.initWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
numCameras = testCase.getNumCameras();
if (numCameras < 0) {
LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras);
goto cleanup;
}
for (int i = 0; i < numCameras; i++) {
const char* cameraId = testCase.getCameraId(i);
if (cameraId == nullptr) {
LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i);
goto cleanup;
}
{
ACameraMetadata* chars = testCase.getCameraChars(cameraId);
StaticInfo staticInfo(chars);
if (!staticInfo.isColorOutputSupported()) {
ALOGI("%s: camera %s does not support color output. skipping",
__FUNCTION__, cameraId);
ACameraMetadata_free(chars);
continue;
}
ACameraMetadata_free(chars);
}
ret = testCase.openCamera(cameraId);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret);
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId);
goto cleanup;
}
ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface);
if (previewAnw == nullptr) {
LOG_ERROR(errorString, "Null ANW from preview surface!");
goto cleanup;
}
CaptureSessionListener* sessionListener = testCase.getSessionListener();
if (sessionListener == nullptr) {
LOG_ERROR(errorString, "Session listener camera %s is null", cameraId);
goto cleanup;
}
// Try open/close session multiple times
for (int j = 0; j < 5; j++) {
ret = testCase.createCaptureSessionWithLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (!sessionListener->isIdle()) {
LOG_ERROR(errorString, "Session for camera %s should be idle right after creation",
cameraId);
goto cleanup;
}
testCase.closeSession();
usleep(100000); // sleep to give some time for callbacks to happen
if (!sessionListener->isClosed() || sessionListener->onClosedCount() != 1) {
LOG_ERROR(errorString,
"Session for camera %s close error. isClosde %d close count %d",
cameraId, sessionListener->isClosed(), sessionListener->onClosedCount());
goto cleanup;
}
sessionListener->reset();
}
// Try open/close really fast
ret = testCase.createCaptureSessionWithLog();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Create session for camera %s failed. ret %d",
cameraId, ret);
goto cleanup;
}
testCase.closeSession();
usleep(100000); // sleep to give some time for callbacks to happen
if (!sessionListener->isClosed() || sessionListener->onClosedCount() != 1) {
LOG_ERROR(errorString,
"Session for camera %s close error. isClosde %d close count %d",
cameraId, sessionListener->isClosed(), sessionListener->onClosedCount());
goto cleanup;
}
ret = testCase.resetWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (!testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be available now", cameraId);
goto cleanup;
}
}
ret = testCase.deInit();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret);
goto cleanup;
}
pass = true;
cleanup:
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed");
if (!pass) {
throwAssertionError(env, errorString);
}
return pass;
}
extern "C" jboolean
Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\
testCameraDeviceSharedOutputUpdate(
JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface, jobject jSharedSurface) {
ALOGV("%s", __FUNCTION__);
int numCameras = 0;
bool pass = false;
PreviewTestCase testCase;
int sequenceId = -1;
int64_t lastFrameNumber = 0;
bool frameArrived = false;
ANativeWindow* previewAnw = nullptr;
ANativeWindow* sharedAnw = ANativeWindow_fromSurface(env, jSharedSurface);
ACaptureRequest* updatedRequest = nullptr;
ACameraOutputTarget* reqPreviewOutput = nullptr;
ACameraOutputTarget* reqSharedOutput = nullptr;
ACaptureSessionOutput *previewOutput = nullptr;
uint32_t timeoutSec = 1;
uint32_t runPreviewSec = 2;
camera_status_t ret = testCase.initWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
numCameras = testCase.getNumCameras();
if (numCameras < 0) {
LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras);
goto cleanup;
}
for (int i = 0; i < numCameras; i++) {
const char* cameraId = testCase.getCameraId(i);
if (cameraId == nullptr) {
LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i);
goto cleanup;
}
{
ACameraMetadata* chars = testCase.getCameraChars(cameraId);
StaticInfo staticInfo(chars);
if (!staticInfo.isColorOutputSupported()) {
ALOGI("%s: camera %s does not support color output. skipping",
__FUNCTION__, cameraId);
ACameraMetadata_free(chars);
continue;
}
ACameraMetadata_free(chars);
}
ret = testCase.openCamera(cameraId);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret);
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId);
goto cleanup;
}
previewAnw = testCase.initPreviewAnw(env, jPreviewSurface);
if (previewAnw == nullptr) {
LOG_ERROR(errorString, "Null ANW from preview surface!");
goto cleanup;
}
ret = testCase.createCaptureSessionWithLog(true);
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
ret = testCase.createRequestsWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
ret = testCase.startPreview();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Start preview failed!");
goto cleanup;
}
sleep(runPreviewSec);
previewOutput = testCase.getPreviewOutput();
//Try some bad input
ret = ACaptureSessionSharedOutput_add(previewOutput, previewAnw);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "ACaptureSessionSharedOutput_add should return invalid "
"parameter! %d", ret);
goto cleanup;
}
ret = ACaptureSessionSharedOutput_remove(previewOutput, previewAnw);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "ACaptureSessionSharedOutput_remove should return invalid "
"parameter! %d", ret);
goto cleanup;
}
//Now try with valid input
ret = ACaptureSessionSharedOutput_add(previewOutput, sharedAnw);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "ACaptureSessionSharedOutput_add failed!")
goto cleanup;
}
ret = testCase.updateOutput(env, previewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Failed to update output configuration!")
goto cleanup;
}
ret = ACameraDevice_createCaptureRequest(
testCase.getCameraDevice(), TEMPLATE_PREVIEW, &updatedRequest);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s create preview request failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = ACameraOutputTarget_create(previewAnw, &reqPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Camera %s create request preview output target failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = ACaptureRequest_addTarget(updatedRequest, reqPreviewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = ACameraOutputTarget_create(sharedAnw, &reqSharedOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString,
"Camera %s create request preview output target failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = ACaptureRequest_addTarget(updatedRequest, reqSharedOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = testCase.updateRepeatingRequest(updatedRequest, &sequenceId);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s failed to update repeated request. ret %d",
cameraId, ret);
goto cleanup;
}
sleep(runPreviewSec);
ret = ACaptureSessionSharedOutput_remove(previewOutput, sharedAnw);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "ACaptureSessionSharedOutput_remove failed!");
goto cleanup;
}
//Try removing shared output which still has pending camera requests
ret = testCase.updateOutput(env, previewOutput);
if (ret != ACAMERA_ERROR_INVALID_PARAMETER) {
LOG_ERROR(errorString, "updateOutput should fail!");
goto cleanup;
}
//Remove the shared output correctly by updating the repeating request
//first
ret = ACaptureRequest_removeTarget(updatedRequest, reqSharedOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s remove target output failed. ret %d",
cameraId, ret);
goto cleanup;
}
ret = testCase.updateRepeatingRequest(updatedRequest);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Camera %s failed to update repeated request. ret %d",
cameraId, ret);
goto cleanup;
}
//Then wait for all old requests to flush
lastFrameNumber = testCase.getCaptureSequenceLastFrameNumber(sequenceId, timeoutSec);
if (lastFrameNumber < 0) {
LOG_ERROR(errorString, "Camera %s failed to acquire last frame number!",
cameraId);
goto cleanup;
}
frameArrived = testCase.waitForFrameNumber(lastFrameNumber, timeoutSec);
if (!frameArrived) {
LOG_ERROR(errorString, "Camera %s timed out waiting on last frame number!",
cameraId);
goto cleanup;
}
ret = testCase.updateOutput(env, previewOutput);
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "updateOutput failed!");
goto cleanup;
}
sleep(runPreviewSec);
ret = testCase.resetWithErrorLog();
if (ret != ACAMERA_OK) {
// Don't log error here. testcase did it
goto cleanup;
}
usleep(100000); // sleep to give some time for callbacks to happen
if (!testCase.isCameraAvailable(cameraId)) {
LOG_ERROR(errorString, "Camera %s should be available now", cameraId);
goto cleanup;
}
}
ret = testCase.deInit();
if (ret != ACAMERA_OK) {
LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret);
goto cleanup;
}
pass = true;
cleanup:
if (updatedRequest != nullptr) {
ACaptureRequest_free(updatedRequest);
updatedRequest = nullptr;
}
if (reqPreviewOutput != nullptr) {
ACameraOutputTarget_free(reqPreviewOutput);
reqPreviewOutput = nullptr;
}
if (reqSharedOutput != nullptr) {
ACameraOutputTarget_free(reqSharedOutput);
reqSharedOutput = nullptr;
}
if (sharedAnw) {
ANativeWindow_release(sharedAnw);
sharedAnw = nullptr;
}
ALOGI("%s %s", __FUNCTION__, pass ? "pass" : &