300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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());
 | |
|     }
 | |
| }
 |