blob: d37a3d95cb727f55fe3534b5bde960c3a2c35c2a [file] [log] [blame]
/*
* Copyright 2020 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.camera2.pipe.integration.adapter
import android.hardware.camera2.CameraMetadata
import android.hardware.camera2.CaptureResult
import android.hardware.camera2.TotalCaptureResult
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.FrameInfo
import androidx.camera.camera2.pipe.FrameMetadata
import androidx.camera.camera2.pipe.FrameNumber
import androidx.camera.camera2.pipe.RequestMetadata
import androidx.camera.camera2.pipe.UnsafeWrapper
import androidx.camera.camera2.pipe.core.Log
import androidx.camera.camera2.pipe.integration.impl.CAMERAX_TAG_BUNDLE
import androidx.camera.core.impl.CameraCaptureMetaData.AeMode
import androidx.camera.core.impl.CameraCaptureMetaData.AeState
import androidx.camera.core.impl.CameraCaptureMetaData.AfMode
import androidx.camera.core.impl.CameraCaptureMetaData.AfState
import androidx.camera.core.impl.CameraCaptureMetaData.AwbMode
import androidx.camera.core.impl.CameraCaptureMetaData.AwbState
import androidx.camera.core.impl.CameraCaptureMetaData.FlashState
import androidx.camera.core.impl.CameraCaptureResult
import androidx.camera.core.impl.TagBundle
import androidx.camera.core.impl.utils.ExifData
import java.nio.BufferUnderflowException
import kotlin.reflect.KClass
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
class PartialCaptureResultAdapter(
private val requestMetadata: RequestMetadata,
private val frameNumber: FrameNumber,
private val result: FrameMetadata,
) : CameraCaptureResult, UnsafeWrapper {
override fun getAfMode(): AfMode = result.getAfMode()
override fun getAfState(): AfState = result.getAfState()
override fun getAeMode(): AeMode = result.getAeMode()
override fun getAeState(): AeState = result.getAeState()
override fun getAwbMode(): AwbMode = result.getAwbMode()
override fun getAwbState(): AwbState = result.getAwbState()
override fun getFlashState(): FlashState = result.getFlashState()
override fun getTimestamp(): Long = result.getTimestamp()
override fun getTagBundle(): TagBundle {
return requestMetadata.getOrDefault(CAMERAX_TAG_BUNDLE, TagBundle.emptyBundle())
}
override fun populateExifData(exifBuilder: ExifData.Builder) {
super.populateExifData(exifBuilder)
result.populateExifData(exifBuilder)
}
override fun getCaptureResult(): CaptureResult =
checkNotNull(unwrapAs(CaptureResult::class)) { "Failed to unwrap $this as CaptureResult" }
override fun <T : Any> unwrapAs(type: KClass<T>): T? = result.unwrapAs(type)
}
/**
* Adapts the [CameraCaptureResult] interface to [CameraPipe].
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
class CaptureResultAdapter(
private val requestMetadata: RequestMetadata,
private val frameNumber: FrameNumber,
private val result: FrameInfo
) : CameraCaptureResult, UnsafeWrapper {
override fun getAfMode(): AfMode = result.metadata.getAfMode()
override fun getAfState(): AfState = result.metadata.getAfState()
override fun getAeMode(): AeMode = result.metadata.getAeMode()
override fun getAeState(): AeState = result.metadata.getAeState()
override fun getAwbMode(): AwbMode = result.metadata.getAwbMode()
override fun getAwbState(): AwbState = result.metadata.getAwbState()
override fun getFlashState(): FlashState = result.metadata.getFlashState()
override fun getTimestamp(): Long = result.metadata.getTimestamp()
override fun getTagBundle(): TagBundle {
return requestMetadata.getOrDefault(CAMERAX_TAG_BUNDLE, TagBundle.emptyBundle())
}
override fun populateExifData(exifBuilder: ExifData.Builder) {
super.populateExifData(exifBuilder)
result.metadata.populateExifData(exifBuilder)
}
override fun getCaptureResult(): CaptureResult =
checkNotNull(unwrapAs(TotalCaptureResult::class)) {
"Failed to unwrap $this as TotalCaptureResult"
}
override fun <T : Any> unwrapAs(type: KClass<T>): T? = result.unwrapAs(type)
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAfMode(): AfMode =
when (val mode = this[CaptureResult.CONTROL_AF_MODE]) {
CaptureResult.CONTROL_AF_MODE_OFF,
CaptureResult.CONTROL_AF_MODE_EDOF -> AfMode.OFF
CaptureResult.CONTROL_AF_MODE_AUTO,
CaptureResult.CONTROL_AF_MODE_MACRO -> AfMode.ON_MANUAL_AUTO
CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE,
CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> AfMode.ON_CONTINUOUS_AUTO
null -> AfMode.UNKNOWN
else -> {
Log.debug { "Unknown AF mode ($mode) for $frameNumber!" }
AfMode.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAfState(): AfState =
when (val state = this[CaptureResult.CONTROL_AF_STATE]) {
CaptureResult.CONTROL_AF_STATE_INACTIVE -> AfState.INACTIVE
CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN,
CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN -> AfState.SCANNING
CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED -> AfState.LOCKED_FOCUSED
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED -> AfState.LOCKED_NOT_FOCUSED
CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED -> AfState.PASSIVE_FOCUSED
CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED -> AfState.PASSIVE_NOT_FOCUSED
null -> AfState.UNKNOWN
else -> {
Log.debug { "Unknown AF state ($state) for $frameNumber!" }
AfState.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAeMode(): AeMode =
when (val mode = this[CaptureResult.CONTROL_AE_MODE]) {
CaptureResult.CONTROL_AE_MODE_OFF -> AeMode.OFF
CaptureResult.CONTROL_AE_MODE_ON -> AeMode.ON
CaptureResult.CONTROL_AE_MODE_ON_AUTO_FLASH ->
AeMode.ON_AUTO_FLASH
CaptureResult.CONTROL_AE_MODE_ON_ALWAYS_FLASH ->
AeMode.ON_ALWAYS_FLASH
CaptureResult.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE ->
AeMode.ON_AUTO_FLASH_REDEYE
null -> AeMode.UNKNOWN
else -> {
Log.debug { "Unknown AE mode ($mode) for $frameNumber!" }
AeMode.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAeState(): AeState =
when (val state = this[CaptureResult.CONTROL_AE_STATE]) {
CaptureResult.CONTROL_AE_STATE_INACTIVE -> AeState.INACTIVE
CaptureResult.CONTROL_AE_STATE_SEARCHING,
CaptureResult.CONTROL_AE_STATE_PRECAPTURE -> AeState.SEARCHING
CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED -> AeState.FLASH_REQUIRED
CaptureResult.CONTROL_AE_STATE_CONVERGED -> AeState.CONVERGED
CaptureResult.CONTROL_AE_STATE_LOCKED -> AeState.LOCKED
null -> AeState.UNKNOWN
else -> {
Log.debug { "Unknown AE state ($state) for $frameNumber!" }
AeState.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAwbMode(): AwbMode =
when (val mode = this[CaptureResult.CONTROL_AWB_MODE]) {
CaptureResult.CONTROL_AWB_MODE_OFF -> AwbMode.OFF
CaptureResult.CONTROL_AWB_MODE_AUTO -> AwbMode.AUTO
CaptureResult.CONTROL_AWB_MODE_INCANDESCENT ->
AwbMode.INCANDESCENT
CaptureResult.CONTROL_AWB_MODE_FLUORESCENT ->
AwbMode.FLUORESCENT
CaptureResult.CONTROL_AWB_MODE_WARM_FLUORESCENT ->
AwbMode.WARM_FLUORESCENT
CaptureResult.CONTROL_AWB_MODE_DAYLIGHT -> AwbMode.DAYLIGHT
CaptureResult.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT ->
AwbMode.CLOUDY_DAYLIGHT
CaptureResult.CONTROL_AWB_MODE_TWILIGHT -> AwbMode.TWILIGHT
CaptureResult.CONTROL_AWB_MODE_SHADE -> AwbMode.SHADE
null -> AwbMode.UNKNOWN
else -> {
Log.debug { "Unknown AWB mode ($mode) for $frameNumber!" }
AwbMode.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getAwbState(): AwbState =
when (val state = this[CaptureResult.CONTROL_AWB_STATE]) {
CaptureResult.CONTROL_AWB_STATE_INACTIVE -> AwbState.INACTIVE
CaptureResult.CONTROL_AWB_STATE_SEARCHING -> AwbState.METERING
CaptureResult.CONTROL_AWB_STATE_CONVERGED -> AwbState.CONVERGED
CaptureResult.CONTROL_AWB_STATE_LOCKED -> AwbState.LOCKED
null -> AwbState.UNKNOWN
else -> {
Log.debug { "Unknown AWB state ($state) for $frameNumber!" }
AwbState.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getFlashState(): FlashState =
when (val state = this[CaptureResult.FLASH_STATE]) {
CaptureResult.FLASH_STATE_UNAVAILABLE,
CaptureResult.FLASH_STATE_CHARGING -> FlashState.NONE
CaptureResult.FLASH_STATE_READY -> FlashState.READY
CaptureResult.FLASH_STATE_FIRED,
CaptureResult.FLASH_STATE_PARTIAL -> FlashState.FIRED
null -> FlashState.UNKNOWN
else -> {
Log.debug { "Unknown flash state ($state) for $frameNumber!" }
FlashState.UNKNOWN
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.getTimestamp(): Long = getOrDefault(CaptureResult.SENSOR_TIMESTAMP, -1L)
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun FrameMetadata.populateExifData(exifData: ExifData.Builder) {
// Set orientation
try {
this[CaptureResult.JPEG_ORIENTATION]?.let { jpegOrientation ->
exifData.setOrientationDegrees(jpegOrientation)
}
} catch (exception: BufferUnderflowException) {
// On certain devices, e.g. Pixel 3 XL API 31, getting JPEG orientation on YUV stream
// throws BufferUnderflowException. The value will be overridden in post-processing
// anyway, so it's safe to ignore. Please reference: b/240998057
// TODO: b/316233308 - Handle the exception inside in CameraPipe.
Log.warn { "Failed to get JPEG orientation." }
}
// Set exposure time
this[CaptureResult.SENSOR_EXPOSURE_TIME]?.let { exposureTimeNs ->
exifData.setExposureTimeNanos(exposureTimeNs)
}
// Set the aperture
this[CaptureResult.LENS_APERTURE]?.let { aperture ->
exifData.setLensFNumber(aperture)
}
// Set the ISO
this[CaptureResult.SENSOR_SENSITIVITY]?.let { iso ->
exifData.setIso(iso)
if (Build.VERSION.SDK_INT >= 24) {
this[CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST]?.let { postRawSensitivityBoost ->
exifData.setIso(iso * (postRawSensitivityBoost / 100f).toInt())
}
}
}
// Set the focal length
this[CaptureResult.LENS_FOCAL_LENGTH]?.let { focalLength ->
exifData.setFocalLength(focalLength)
}
// Set white balance MANUAL/AUTO
this[CaptureResult.CONTROL_AWB_MODE]?.let { whiteBalanceMode ->
var wbMode = ExifData.WhiteBalanceMode.AUTO
if (whiteBalanceMode == CameraMetadata.CONTROL_AWB_MODE_OFF) {
wbMode = ExifData.WhiteBalanceMode.MANUAL
}
exifData.setWhiteBalanceMode(wbMode)
}
}