[go: nahoru, domu]

blob: 2a626c19ecd006d934bfab1779acfb4759488cd4 [file] [log] [blame]
/*
* Copyright 2019 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.
*/
package androidx.camera.integration.antelope.cameracontrollers
import android.content.Context
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CameraMetadata
import android.hardware.camera2.CaptureRequest
import androidx.camera.integration.antelope.CameraParams
import androidx.camera.integration.antelope.FocusMode
import androidx.camera.integration.antelope.MainActivity
import androidx.camera.integration.antelope.MainActivity.Companion.logd
import androidx.camera.integration.antelope.PrefHelper
import androidx.camera.integration.antelope.TestConfig
import androidx.camera.integration.antelope.TestType
import androidx.camera.integration.antelope.getOrientation
import androidx.camera.integration.antelope.setAutoFlash
import java.lang.Thread.sleep
import java.util.Arrays
/** State of the camera during an image capture - */
internal enum class CameraState {
UNINITIALIZED,
PREVIEW_RUNNING,
WAITING_FOCUS_LOCK,
WAITING_EXPOSURE_LOCK,
IMAGE_REQUESTED
}
/**
* Opens the camera using the Camera 2 API and starts the open counter. The open call will complete
* in the DeviceStateCallback asynchronously. For switch tests, the camera id will be swizzling so
* the original camera id is saved.
*/
fun camera2OpenCamera(activity: MainActivity, params: CameraParams?, testConfig: TestConfig) {
if (null == params)
return
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
// TODO make the switch test methodology more robust and handle physical cameras
if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
(testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
testConfig.switchTestRealCameraId = params.id // Save the original camera ID
params.id = testConfig.switchTestCurrentCamera
}
// Might be a new test, update callbacks to match the test config
params.camera2DeviceStateCallback = Camera2DeviceStateCallback(params, activity, testConfig)
params.camera2CaptureSessionCallback =
Camera2CaptureSessionCallback(activity, params, testConfig)
params.timer.openStart = System.currentTimeMillis()
logd("openCamera: " + params.id + " running test: " +
testConfig.currentRunningTest.toString())
manager.openCamera(params.id, params.camera2DeviceStateCallback!!, params.backgroundHandler)
} catch (e: CameraAccessException) {
logd("openCamera CameraAccessException: " + params.id)
e.printStackTrace()
} catch (e: SecurityException) {
logd("openCamera SecurityException: " + params.id)
e.printStackTrace()
}
}
/**
* Setup the camera preview session and output surface.
*/
fun createCameraPreviewSession(
activity: MainActivity,
params: CameraParams,
testConfig: TestConfig
) {
logd("In createCameraPreviewSession.")
if (!params.isOpen) {
return
}
try {
val surface = params.previewSurfaceView?.holder?.surface
if (null == surface)
return
val imageSurface = params.imageReader?.surface
if (null == imageSurface)
return
params.captureRequestBuilder =
params.device?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
if (params.previewSurfaceView?.holder?.surface != null)
params.captureRequestBuilder?.removeTarget(params.previewSurfaceView?.holder?.surface!!)
params.captureRequestBuilder?.addTarget(surface)
params.device?.createCaptureSession(Arrays.asList(surface, imageSurface),
Camera2PreviewSessionStateCallback(activity, params, testConfig), null)
} catch (e: CameraAccessException) {
MainActivity.logd("createCameraPreviewSession CameraAccessException: " + e.message)
e.printStackTrace()
} catch (e: IllegalStateException) {
MainActivity.logd("createCameraPreviewSession IllegalStateException: " + e.message)
e.printStackTrace()
}
}
/**
* Set up timers for a still capture. The preview stream is allowed to run here in order to fill the
* pipeline with images to simulate more realistic camera conditions.
*/
fun initializeStillCapture(activity: MainActivity, params: CameraParams, testConfig: TestConfig) {
logd("TakePicture: capture start.")
if (!params.isOpen) {
return
}
if (params.timer.isFirstPhoto) {
params.timer.isFirstPhoto = false
}
logd("Camera2 initializeStillCapture: 1st photo in a multi-photo test. " +
"Pausing for " + PrefHelper.getPreviewBuffer(activity) + "ms to let preview run.")
params.timer.previewFillStart = System.currentTimeMillis()
sleep(PrefHelper.getPreviewBuffer(activity))
params.timer.previewFillEnd = System.currentTimeMillis()
params.timer.captureStart = System.currentTimeMillis()
params.timer.autofocusStart = System.currentTimeMillis()
lockFocus(activity, params, testConfig)
}
/**
* Initiate the auto-focus routine if required.
*/
fun lockFocus(activity: MainActivity, params: CameraParams, testConfig: TestConfig) {
logd("In lockFocus.")
if (!params.isOpen) {
return
}
try {
if (null != params.device) {
setAutoFlash(params, params.captureRequestBuilder)
if (params.imageReader?.surface != null)
params.captureRequestBuilder?.addTarget(params.imageReader?.surface!!)
// If this lens can focus, we need to start a focus search and wait for focus lock
if (params.hasAF &&
FocusMode.AUTO == testConfig.focusMode) {
logd("In lockFocus. About to request focus lock and call capture.")
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_AUTO)
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
params.camera2CaptureSession?.capture(params.captureRequestBuilder?.build()!!,
params.camera2CaptureSessionCallback, params.backgroundHandler)
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_AUTO)
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START)
params.state = CameraState.WAITING_FOCUS_LOCK
params.autoFocusStuckCounter = 0
params.camera2CaptureSession?.capture(params.captureRequestBuilder?.build()!!,
params.camera2CaptureSessionCallback, params.backgroundHandler)
} else {
// If no auto-focus requested, go ahead to the still capture routine
logd("In lockFocus. Fixed focus or continuous focus, calling captureStillPicture.")
params.state = CameraState.IMAGE_REQUESTED
captureStillPicture(activity, params, testConfig)
}
}
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
/**
* Request pre-capture auto-exposure (AE) metering
*/
fun runPrecaptureSequence(params: CameraParams) {
if (!params.isOpen) {
return
}
try {
if (null != params.device) {
setAutoFlash(params, params.captureRequestBuilder)
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START)
params.state = CameraState.WAITING_EXPOSURE_LOCK
params.camera2CaptureSession?.capture(params.captureRequestBuilder?.build()!!,
params.camera2CaptureSessionCallback, params.backgroundHandler)
}
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
/**
* Make a still capture request. At this point, AF and AE should be converged or unnecessary.
*/
fun captureStillPicture(activity: MainActivity, params: CameraParams, testConfig: TestConfig) {
if (!params.isOpen) {
return
}
try {
logd("In captureStillPicture. Current test: " + testConfig.currentRunningTest.toString())
if (null != params.device) {
params.timer.autofocusEnd = System.currentTimeMillis()
params.captureRequestBuilder =
params.device?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
if (params.imageReader?.surface != null)
params.captureRequestBuilder?.addTarget(params.imageReader?.surface!!)
when (testConfig.focusMode) {
FocusMode.CONTINUOUS -> {
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
}
FocusMode.AUTO -> {
params.captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_IDLE)
}
FocusMode.FIXED -> {
}
}
// Disable HDR+ for Pixel devices
// This is a hack, Pixel devices do not have Sepia mode, but this forces HDR+ off
if (android.os.Build.MANUFACTURER.equals("Google")) {
// params.captureRequestBuilder?.set(CaptureRequest.CONTROL_EFFECT_MODE,
// CaptureRequest.CONTROL_EFFECT_MODE_SEPIA)
}
// Orientation
val rotation = activity.windowManager.defaultDisplay.rotation
val capturedImageRotation = getOrientation(params, rotation)
params.captureRequestBuilder
?.set(CaptureRequest.JPEG_ORIENTATION, capturedImageRotation)
// Flash
setAutoFlash(params, params.captureRequestBuilder)
val captureCallback = Camera2CaptureCallback(activity, params, testConfig)
params.camera2CaptureSession?.capture(params.captureRequestBuilder?.build()!!,
captureCallback, params.backgroundHandler)
}
} catch (e: CameraAccessException) {
e.printStackTrace()
} catch (e: IllegalStateException) {
logd("captureStillPicture IllegalStateException, aborting: " + e.message)
}
}
/**
* Close preview stream and camera device. If this was a switch test, restore the camera id
*/
fun camera2CloseCamera(params: CameraParams?, testConfig: TestConfig) {
if (params == null)
return
MainActivity.logd("closePreviewAndCamera: " + params.id)
if (params.isPreviewing) {
params.timer.previewCloseStart = System.currentTimeMillis()
params.camera2CaptureSession?.close()
} else {
params.timer.cameraCloseStart = System.currentTimeMillis()
params.device?.close()
}
if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
(testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
params.id = testConfig.switchTestRealCameraId // Restore the actual camera ID
}
}
/**
* An abort request has been received. Abandon everything
*/
fun camera2Abort(activity: MainActivity, params: CameraParams) {
params.camera2CaptureSession?.abortCaptures()
activity.stopBackgroundThread(params)
}