/* * 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, &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, &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::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(0x7fffffff)); ASSERT_EQ(NO_ERROR, surfaceControl->show()); SurfaceComposerClient::closeGlobalTransaction(); 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()); } }