| /* |
| * 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 <string> |
| #include <map> |
| #include <mutex> |
| #include <unistd.h> |
| #include <assert.h> |
| #include <jni.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <android/native_window_jni.h> |
| |
| #include "NdkCameraError.h" |
| #include "NdkCameraManager.h" |
| #include "NdkCameraDevice.h" |
| #include "NdkCameraCaptureSession.h" |
| #include "NdkImage.h" |
| #include "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]; |
| } |
| |
| 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; |
| } |
| |
| void resetCount() { |
| std::lock_guard<std::mutex> lock(mMutex); |
| mOnAvailableCount = 0; |
| mOnUnavailableCount = 0; |
| return; |
| } |
| |
| int getAvailableCount() { |
| std::lock_guard<std::mutex> lock(mMutex); |
| return mOnAvailableCount; |
| } |
| |
| int getUnavailableCount() { |
| std::lock_guard<std::mutex> lock(mMutex); |
| return mOnUnavailableCount; |
| } |
| |
| 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; |
| 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 ImageReaderListener { |
| public: |
| static void onImageAvailable(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); |
| } |
| |
| 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; |
| } |
| |
| void reset() { |
| std::lock_guard<std::mutex> lock(mMutex); |
| mOnImageAvailableCount = 0; |
| mDumpFilePathBase = nullptr; |
| } |
| |
| 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: |
| 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; |
| } |
| private: |
| 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() { |
| mReaderListener.reset(); |
| mSessionListener.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]; |
| } |
| |
| 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) { |
| if (mImgReader || mImgReaderAnw) { |
| LOG_ERROR(errorString, "Cannot init image reader before closing existing one"); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| media_status_t ret = AImageReader_new( |
| width, height, format, |
| maxImages, &mImgReader); |
| if (ret != AMEDIA_OK) { |
| LOG_ERROR(errorString, "Create image reader. ret %d", ret); |
| return ret; |
| } |
| if (mImgReader == nullptr) { |
| LOG_ERROR(errorString, "null image reader created"); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| ret = AImageReader_setImageListener( |
| mImgReader, &mReaderCb); |
| if (ret != AMEDIA_OK) { |
| LOG_ERROR(errorString, "Set AImageReader listener failed. ret %d", ret); |
| return ret; |
| } |
| |
| ret = AImageReader_getWindow(mImgReader, &mImgReaderAnw); |
| if (ret != AMEDIA_OK) { |
| LOG_ERROR(errorString, "AImageReader_getWindow failed. ret %d", ret); |
| return ret; |
| } |
| if (mImgReaderAnw == nullptr) { |
| LOG_ERROR(errorString, "Null ANW from AImageReader!"); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| mImgReaderInited = true; |
| 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() { |
| if (mSession) { |
| LOG_ERROR(errorString, "Cannot create session before closing existing one"); |
| return ACAMERA_ERROR_UNKNOWN; |
| } |
| |
| if (!mMgrInited || (!mImgReaderInited && !mPreviewInited)) { |
| LOG_ERROR(errorString, "Cannot create session. mgrInit %d readerInit %d previewInit %d", |
| mMgrInited, mImgReaderInited, mPreviewInited); |
| return ACAMERA_ERROR_UNKNOWN; |
| } |
| |
| camera_status_t ret = ACaptureSessionOutputContainer_create(&mOutputs); |
| 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, |
| "Sesssion 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(mOutputs, mImgReaderOutput); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Sesssion image reader output add failed! ret %d", ret); |
| return ret; |
| } |
| } |
| |
| if (mPreviewInited) { |
| ret = ACaptureSessionOutput_create(mPreviewAnw, &mPreviewOutput); |
| if (ret != ACAMERA_OK || mPreviewOutput == nullptr) { |
| LOG_ERROR(errorString, |
| "Sesssion 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(mOutputs, mPreviewOutput); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Sesssion preview output add failed! ret %d", ret); |
| return ret; |
| } |
| } |
| |
| ret = ACameraDevice_createCaptureSession( |
| mDevice, mOutputs, &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() { |
| 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; |
| if (mPreviewInited) { |
| ret = ACameraDevice_createCaptureRequest( |
| mDevice, TEMPLATE_PREVIEW, &mPreviewRequest); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Camera %s create preview request failed. ret %d", |
| mCameraId, ret); |
| return ret; |
| } |
| |
| 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; |
| } |
| } 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; |
| } |
| |
| camera_status_t startPreview() { |
| if (mSession == nullptr || mPreviewRequest == nullptr) { |
| ALOGE("Testcase cannot start preview: session %p, preview request %p", |
| mSession, mPreviewRequest); |
| return ACAMERA_ERROR_UNKNOWN; |
| } |
| int previewSeqId; |
| return ACameraCaptureSession_setRepeatingRequest( |
| mSession, nullptr, 1, &mPreviewRequest, &previewSeqId); |
| } |
| |
| 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); |
| } |
| |
| int getReaderImageCount() { |
| return mReaderListener.onImageAvailableCount(); |
| } |
| |
| camera_status_t resetWithErrorLog() { |
| camera_status_t ret; |
| |
| mReaderListener.reset(); |
| 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(); |
| |
| ret = closeCamera(); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Close camera device %s failure. ret %d", mCameraId, ret); |
| return ret; |
| } |
| |
| resetCamera(); |
| return ACAMERA_OK; |
| } |
| |
| void setDumpFilePathBase(const char* path) { |
| mReaderListener.setDumpFilePathBase(path); |
| } |
| |
| CaptureSessionListener* getSessionListener() { |
| return &mSessionListener; |
| } |
| |
| 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 |
| }; |
| |
| // TODO: capture listeners |
| ImageReaderListener mReaderListener; |
| AImageReader_ImageListener mReaderCb { |
| &mReaderListener, |
| ImageReaderListener::onImageAvailable |
| }; |
| |
| 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; |
| 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 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; |
| } |
| } |
| |
| 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 get unknown value fails |
| uint32_t badTag = (uint32_t) ACAMERA_VENDOR_START - 1; |
| ret = ACameraMetadata_getConstEntry(chars, ACAMERA_VENDOR_START, &entry); |
| if (ret == ACAMERA_OK) { |
| LOG_ERROR(errorString, "Error: get unknown tag should fail!"); |
| goto cleanup; |
| } |
| |
| ACameraMetadata_free(chars); |
| chars = nullptr; |
| } |
| |
| pass = true; |
| cleanup: |
| if (chars) { |
| ACameraMetadata_free(chars); |
| } |
| 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; |
| } |
| } |
| |
| // try get/set capture request fields |
| ACameraMetadata_const_entry entry; |
| 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_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; |
| } |
| |
| 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_\ |
| testCameraDeviceSimplePreviewNative( |
| 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; |
| } |
| |
| 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; |
| } |
| |
| ret = testCase.createCaptureSessionWithLog(); |
| 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(3); |
| |
| 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_NativeImageReaderTest_\ |
| testJpegNative( |
| JNIEnv* env, jclass /*clazz*/, jstring jOutPath) { |
| ALOGV("%s", __FUNCTION__); |
| const int NUM_TEST_IMAGES = 10; |
| const int TEST_WIDTH = 640; |
| const int TEST_HEIGHT = 480; |
| media_status_t mediaRet = AMEDIA_ERROR_UNKNOWN; |
| int numCameras = 0; |
| bool pass = false; |
| PreviewTestCase testCase; |
| |
| const char* outPath = env->GetStringUTFChars(jOutPath, nullptr); |
| testCase.setDumpFilePathBase(outPath); |
| ALOGI("%s: out path is %s", __FUNCTION__, outPath); |
| |
| 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; |
| } |
| |
| mediaRet = testCase.initImageReaderWithErrorLog( |
| TEST_WIDTH, TEST_HEIGHT, AIMAGE_FORMAT_JPEG, NUM_TEST_IMAGES); |
| if (mediaRet != AMEDIA_OK) { |
| // Don't log error here. testcase did it |
| goto cleanup; |
| } |
| |
| ret = testCase.createCaptureSessionWithLog(); |
| 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; |
| } |
| |
| // Do some still capture |
| for (int capture = 0; capture < NUM_TEST_IMAGES; capture++) { |
| ret = testCase.takePicture(); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Camera %s capture(%d) failed. ret %d", |
| cameraId, capture, ret); |
| goto cleanup; |
| } |
| } |
| |
| // wait until all capture finished |
| for (int i = 0; i < 50; i++) { |
| usleep(100000); // sleep 100ms |
| if (testCase.getReaderImageCount() == NUM_TEST_IMAGES) { |
| ALOGI("Session take ~%d ms to capture %d images", |
| i*100, NUM_TEST_IMAGES); |
| break; |
| } |
| } |
| |
| if (testCase.getReaderImageCount() != NUM_TEST_IMAGES) { |
| LOG_ERROR(errorString, "Camera %s timeout capturing %d images. Got %d", |
| cameraId, NUM_TEST_IMAGES, testCase.getReaderImageCount()); |
| 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: |
| env->ReleaseStringUTFChars(jOutPath, outPath); |
| ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); |
| if (!pass) { |
| throwAssertionError(env, errorString); |
| } |
| return pass; |
| } |
| |
| |
| extern "C" jboolean |
| Java_android_hardware_camera2_cts_NativeStillCaptureTest_\ |
| testStillCaptureNative( |
| JNIEnv* env, jclass /*clazz*/, jstring jOutPath, jobject jPreviewSurface) { |
| ALOGV("%s", __FUNCTION__); |
| const int NUM_TEST_IMAGES = 10; |
| const int TEST_WIDTH = 640; |
| const int TEST_HEIGHT = 480; |
| media_status_t mediaRet = AMEDIA_ERROR_UNKNOWN; |
| int numCameras = 0; |
| bool pass = false; |
| PreviewTestCase testCase; |
| |
| const char* outPath = env->GetStringUTFChars(jOutPath, nullptr); |
| testCase.setDumpFilePathBase(outPath); |
| ALOGI("%s: out path is %s", __FUNCTION__, outPath); |
| |
| 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; |
| } |
| |
| mediaRet = testCase.initImageReaderWithErrorLog( |
| TEST_WIDTH, TEST_HEIGHT, AIMAGE_FORMAT_JPEG, NUM_TEST_IMAGES); |
| if (mediaRet != AMEDIA_OK) { |
| // Don't log error here. testcase did it |
| goto cleanup; |
| } |
| |
| ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); |
| if (previewAnw == nullptr) { |
| LOG_ERROR(errorString, "Null ANW from preview surface!"); |
| goto cleanup; |
| } |
| |
| ret = testCase.createCaptureSessionWithLog(); |
| 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; |
| } |
| |
| // Let preview run some time |
| sleep(3); |
| |
| // Do some still capture |
| for (int capture = 0; capture < NUM_TEST_IMAGES; capture++) { |
| ret = testCase.takePicture(); |
| if (ret != ACAMERA_OK) { |
| LOG_ERROR(errorString, "Camera %s capture(%d) failed. ret %d", |
| cameraId, capture, ret); |
| goto cleanup; |
| } |
| } |
| |
| // wait until all capture finished |
| for (int i = 0; i < 50; i++) { |
| usleep(100000); // sleep 100ms |
| if (testCase.getReaderImageCount() == NUM_TEST_IMAGES) { |
| ALOGI("Session take ~%d ms to capture %d images", |
| i*100, NUM_TEST_IMAGES); |
| break; |
| } |
| } |
| |
| if (testCase.getReaderImageCount() != NUM_TEST_IMAGES) { |
| LOG_ERROR(errorString, "Camera %s timeout capturing %d images. Got %d", |
| cameraId, NUM_TEST_IMAGES, testCase.getReaderImageCount()); |
| 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: |
| env->ReleaseStringUTFChars(jOutPath, outPath); |
| ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); |
| if (!pass) { |
| throwAssertionError(env, errorString); |
| } |
| return pass; |
| } |
| |