| /* | |
| * Copyright (C) 2017 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #define LOG_NDEBUG 0 | |
| #define LOG_TAG "CameraZSLTests" | |
| #include <gtest/gtest.h> | |
| #include <binder/ProcessState.h> | |
| #include <utils/Errors.h> | |
| #include <utils/Log.h> | |
| #include <gui/Surface.h> | |
| #include <gui/SurfaceComposerClient.h> | |
| #include <camera/CameraParameters.h> | |
| #include <camera/CameraMetadata.h> | |
| #include <camera/Camera.h> | |
| #include <android/hardware/ICameraService.h> | |
| using namespace android; | |
| using namespace android::hardware; | |
| class CameraZSLTests : public ::testing::Test, | |
| public ::android::hardware::BnCameraClient { | |
| protected: | |
| CameraZSLTests() : numCameras(0), mPreviewBufferCount(0), | |
| mAutoFocusMessage(false), mSnapshotNotification(false) {} | |
| //Gtest interface | |
| void SetUp() override; | |
| void TearDown() override; | |
| //CameraClient interface | |
| void notifyCallback(int32_t msgType, int32_t, int32_t) override; | |
| void dataCallback(int32_t msgType, const sp<IMemory>&, | |
| camera_frame_metadata_t *) override; | |
| void dataCallbackTimestamp(nsecs_t, int32_t, | |
| const sp<IMemory>&) override {}; | |
| void recordingFrameHandleCallbackTimestamp(nsecs_t, | |
| native_handle_t*) override {}; | |
| void recordingFrameHandleCallbackTimestampBatch( | |
| const std::vector<nsecs_t>&, | |
| const std::vector<native_handle_t*>&) override {}; | |
| status_t waitForPreviewStart(); | |
| status_t waitForEvent(Mutex &mutex, Condition &condition, bool &flag); | |
| mutable Mutex mPreviewLock; | |
| mutable Condition mPreviewCondition; | |
| mutable Mutex mAutoFocusLock; | |
| mutable Condition mAutoFocusCondition; | |
| mutable Mutex mSnapshotLock; | |
| mutable Condition mSnapshotCondition; | |
| int32_t numCameras; | |
| size_t mPreviewBufferCount; | |
| sp<ICameraService> mCameraService; | |
| sp<SurfaceComposerClient> mComposerClient; | |
| bool mAutoFocusMessage; | |
| bool mSnapshotNotification; | |
| static const int32_t kPreviewThreshold = 8; | |
| static const nsecs_t kPreviewTimeout = 5000000000; // 5 [s.] | |
| static const nsecs_t kEventTimeout = 10000000000; // 10 [s.] | |
| }; | |
| void CameraZSLTests::SetUp() { | |
| ::android::binder::Status rc; | |
| ProcessState::self()->startThreadPool(); | |
| sp<IServiceManager> sm = defaultServiceManager(); | |
| sp<IBinder> binder = sm->getService(String16("media.camera")); | |
| mCameraService = interface_cast<ICameraService>(binder); | |
| rc = mCameraService->getNumberOfCameras( | |
| hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras); | |
| EXPECT_TRUE(rc.isOk()); | |
| mComposerClient = new SurfaceComposerClient; | |
| ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); | |
| } | |
| void CameraZSLTests::TearDown() { | |
| mCameraService.clear(); | |
| mComposerClient->dispose(); | |
| } | |
| void CameraZSLTests::notifyCallback(int32_t msgType, int32_t, | |
| int32_t) { | |
| if (CAMERA_MSG_FOCUS == msgType) { | |
| Mutex::Autolock l(mAutoFocusLock); | |
| mAutoFocusMessage = true; | |
| mAutoFocusCondition.broadcast(); | |
| } else { | |
| ALOGV("%s: msgType: %d", __FUNCTION__, msgType); | |
| } | |
| }; | |
| void CameraZSLTests::dataCallback(int32_t msgType, const sp<IMemory>& /*data*/, | |
| camera_frame_metadata_t *) { | |
| switch (msgType) { | |
| case CAMERA_MSG_PREVIEW_FRAME: { | |
| Mutex::Autolock l(mPreviewLock); | |
| mPreviewBufferCount++; | |
| mPreviewCondition.broadcast(); | |
| break; | |
| } | |
| case CAMERA_MSG_COMPRESSED_IMAGE: { | |
| Mutex::Autolock l(mSnapshotLock); | |
| mSnapshotNotification = true; | |
| //TODO: Add checks on incoming Jpeg | |
| mSnapshotCondition.broadcast(); | |
| break; | |
| } | |
| default: | |
| ALOGV("%s: msgType: %d", __FUNCTION__, msgType); | |
| } | |
| }; | |
| status_t CameraZSLTests::waitForPreviewStart() { | |
| status_t rc = NO_ERROR; | |
| Mutex::Autolock l(mPreviewLock); | |
| mPreviewBufferCount = 0; | |
| while (mPreviewBufferCount < kPreviewThreshold) { | |
| rc = mPreviewCondition.waitRelative(mPreviewLock, | |
| kPreviewTimeout); | |
| if (NO_ERROR != rc) { | |
| break; | |
| } | |
| } | |
| return rc; | |
| } | |
| status_t CameraZSLTests::waitForEvent(Mutex &mutex, | |
| Condition &condition, bool &flag) { | |
| status_t rc = NO_ERROR; | |
| Mutex::Autolock l(mutex); | |
| flag = false; | |
| while (!flag) { | |
| rc = condition.waitRelative(mutex, | |
| kEventTimeout); | |
| if (NO_ERROR != rc) { | |
| break; | |
| } | |
| } | |
| return rc; | |
| } | |
| TEST_F(CameraZSLTests, TestAllPictureSizes) { | |
| ::android::binder::Status rc; | |
| for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) { | |
| sp<Surface> previewSurface; | |
| sp<SurfaceControl> surfaceControl; | |
| sp<ICamera> cameraDevice; | |
| String16 cameraIdStr = String16(String8::format("%d", cameraId)); | |
| bool isSupported = false; | |
| rc = mCameraService->supportsCameraApi(cameraIdStr, | |
| hardware::ICameraService::API_VERSION_1, &isSupported); | |
| EXPECT_TRUE(rc.isOk()); | |
| // We only care about camera Camera1 ZSL support. | |
| if (!isSupported) { | |
| continue; | |
| } | |
| CameraMetadata metadata; | |
| rc = mCameraService->getCameraCharacteristics(cameraIdStr, | |
| /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false, | |
| &metadata); | |
| if (!rc.isOk()) { | |
| // The test is relevant only for cameras with Hal 3.x | |
| // support. | |
| continue; | |
| } | |
| EXPECT_FALSE(metadata.isEmpty()); | |
| camera_metadata_entry_t availableCapabilities = | |
| metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); | |
| EXPECT_TRUE(0 < availableCapabilities.count); | |
| bool isReprocessSupported = false; | |
| const uint8_t *caps = availableCapabilities.data.u8; | |
| for (size_t i = 0; i < availableCapabilities.count; i++) { | |
| if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == | |
| caps[i]) { | |
| isReprocessSupported = true; | |
| break; | |
| } | |
| } | |
| if (!isReprocessSupported) { | |
| // ZSL relies on this feature | |
| continue; | |
| } | |
| rc = mCameraService->connect(this, cameraId, | |
| String16("ZSLTest"), hardware::ICameraService::USE_CALLING_UID, | |
| hardware::ICameraService::USE_CALLING_PID, | |
| /*targetSdkVersion*/__ANDROID_API_FUTURE__, | |
| /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, &cameraDevice); | |
| EXPECT_TRUE(rc.isOk()); | |
| CameraParameters params(cameraDevice->getParameters()); | |
| String8 focusModes(params.get( | |
| CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); | |
| bool isAFSupported = false; | |
| const char *focusMode = nullptr; | |
| if (focusModes.contains(CameraParameters::FOCUS_MODE_AUTO)) { | |
| // If supported 'auto' should be set by default | |
| isAFSupported = true; | |
| } else if (focusModes.contains( | |
| CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE)) { | |
| isAFSupported = true; | |
| focusMode = CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE; | |
| } else if (focusModes.contains( | |
| CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO)) { | |
| isAFSupported = true; | |
| focusMode = CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO; | |
| } else if (focusModes.contains(CameraParameters::FOCUS_MODE_MACRO)) { | |
| isAFSupported = true; | |
| focusMode = CameraParameters::FOCUS_MODE_MACRO; | |
| } | |
| if (!isAFSupported) { | |
| // AF state is needed | |
| continue; | |
| } | |
| if (nullptr != focusMode) { | |
| params.set(CameraParameters::KEY_FOCUS_MODE, focusMode); | |
| ASSERT_EQ(NO_ERROR, cameraDevice->setParameters(params.flatten())); | |
| } | |
| int previewWidth, previewHeight; | |
| params.getPreviewSize(&previewWidth, &previewHeight); | |
| ASSERT_TRUE((0 < previewWidth) && (0 < previewHeight)); | |
| surfaceControl = mComposerClient->createSurface( | |
| String8("Test Surface"), | |
| previewWidth, previewHeight, | |
| CameraParameters::previewFormatToEnum( | |
| params.getPreviewFormat()), | |
| GRALLOC_USAGE_HW_RENDER); | |
| ASSERT_TRUE(nullptr != surfaceControl.get()); | |
| ASSERT_TRUE(surfaceControl->isValid()); | |
| SurfaceComposerClient::Transaction{} | |
| .setLayer(surfaceControl, 0x7fffffff) | |
| .show(surfaceControl) | |
| .apply(); | |
| previewSurface = surfaceControl->getSurface(); | |
| ASSERT_TRUE(previewSurface != NULL); | |
| ASSERT_EQ(NO_ERROR, cameraDevice->setPreviewTarget( | |
| previewSurface->getIGraphicBufferProducer())); | |
| cameraDevice->setPreviewCallbackFlag( | |
| CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER); | |
| Vector<Size> pictureSizes; | |
| params.getSupportedPictureSizes(pictureSizes); | |
| for (size_t i = 0; i < pictureSizes.size(); i++) { | |
| params.setPictureSize(pictureSizes[i].width, | |
| pictureSizes[i].height); | |
| ASSERT_EQ(NO_ERROR, cameraDevice->setParameters(params.flatten())); | |
| ASSERT_EQ(NO_ERROR, cameraDevice->startPreview()); | |
| ASSERT_EQ(NO_ERROR, waitForPreviewStart()); | |
| ASSERT_EQ(NO_ERROR, cameraDevice->autoFocus()); | |
| ASSERT_EQ(NO_ERROR, waitForEvent(mAutoFocusLock, | |
| mAutoFocusCondition, mAutoFocusMessage)); | |
| ASSERT_EQ(NO_ERROR, | |
| cameraDevice->takePicture(CAMERA_MSG_COMPRESSED_IMAGE)); | |
| ASSERT_EQ(NO_ERROR, waitForEvent(mSnapshotLock, mSnapshotCondition, | |
| mSnapshotNotification)); | |
| } | |
| cameraDevice->stopPreview(); | |
| rc = cameraDevice->disconnect(); | |
| EXPECT_TRUE(rc.isOk()); | |
| } | |
| } |