Merge "[FPS Range Settings] Improve the power and latency by setting the fps range before creating capture session" into androidx-main
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
index 6bd2e52..6fe08bc 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
@@ -18,6 +18,7 @@
import android.hardware.camera2.CameraDevice
import android.media.MediaCodec
+import android.util.Range
import androidx.annotation.VisibleForTesting
import androidx.camera.camera2.pipe.OutputStream
import androidx.camera.camera2.pipe.core.Log
@@ -32,6 +33,7 @@
import androidx.camera.core.UseCase
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.StreamSpec
import androidx.camera.core.impl.UseCaseConfig
import androidx.camera.core.streamsharing.StreamSharing
import kotlinx.coroutines.CoroutineScope
@@ -118,6 +120,15 @@
}
}
+ fun getExpectedFrameRateRange(): Range<Int>? {
+ return if (
+ isSessionConfigValid() &&
+ sessionConfig.expectedFrameRateRange != StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED
+ )
+ sessionConfig.expectedFrameRateRange
+ else null
+ }
+
/**
* Populates the mapping between surfaces of a capture session and the Stream Use Case of their
* associated stream.
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index b832f7b..0b760d2 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -874,6 +874,8 @@
}
}
+ // Set fps range to capture request
+ val targetFpsRange = sessionConfigAdapter.getExpectedFrameRateRange()
val defaultParameters =
buildMap<Any, Any?> {
if (isExtensions) {
@@ -884,7 +886,13 @@
CameraPipeKeys.camera2CaptureRequestTag,
"android.hardware.camera2.CaptureRequest.setTag.CX"
)
+ targetFpsRange?.let {
+ set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFpsRange)
+ }
}
+ targetFpsRange?.let {
+ sessionParameters[CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE] = targetFpsRange
+ }
// TODO: b/327517884 - Add a quirk to not abort captures on stop for certain OEMs during
// extension sessions.
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
index a11268a..7bce113 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
@@ -18,7 +18,9 @@
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
import android.os.Build
+import android.util.Range
import android.view.Surface
import androidx.camera.core.impl.DeferrableSurface
import androidx.camera.core.impl.SessionConfig
@@ -121,6 +123,34 @@
}
@Test
+ fun getExpectedFrameRateRange() {
+ // Arrange
+ val testDeferrableSurface = createTestDeferrableSurface()
+
+ // Create an invalid SessionConfig which doesn't set the template
+ val fakeTestUseCase = createFakeTestUseCase {
+ it.setupSessionConfig(
+ SessionConfig.Builder().also { sessionConfigBuilder ->
+ sessionConfigBuilder.addSurface(testDeferrableSurface)
+ sessionConfigBuilder.setTemplateType(TEMPLATE_PREVIEW)
+ sessionConfigBuilder.setExpectedFrameRateRange(Range(15, 24))
+ }
+ )
+ }
+
+ // Act
+ val sessionConfigAdapter = SessionConfigAdapter(useCases = listOf(fakeTestUseCase))
+
+ // Assert
+ assertThat(sessionConfigAdapter.isSessionConfigValid()).isTrue()
+ assertThat(sessionConfigAdapter.getValidSessionConfigOrNull()).isNotNull()
+ assertThat(sessionConfigAdapter.getExpectedFrameRateRange()).isEqualTo(Range(15, 24))
+
+ // Clean up
+ testDeferrableSurface.close()
+ }
+
+ @Test
fun populateSurfaceToStreamUseCaseMappingEmptyUseCase() {
val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(listOf(), listOf())
TestCase.assertTrue(mapping.isEmpty())
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
index 89ed085..0e24668 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
@@ -19,11 +19,14 @@
import android.content.Context
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
import android.hardware.camera2.CameraDevice.TEMPLATE_RECORD
import android.hardware.camera2.CameraMetadata.CONTROL_CAPTURE_INTENT_PREVIEW
+import android.hardware.camera2.CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE
import android.hardware.camera2.CaptureRequest.CONTROL_CAPTURE_INTENT
import android.hardware.camera2.params.SessionConfiguration.SESSION_HIGH_SPEED
import android.os.Build
+import android.util.Range
import android.util.Size
import androidx.camera.camera2.pipe.CameraGraph
import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.HIGH_SPEED
@@ -523,6 +526,40 @@
}
@Test
+ fun createCameraGraphConfig_setTargetFpsRange() = runTest {
+ // Arrange
+ initializeUseCaseThreads(this)
+ val useCaseManager = createUseCaseManager()
+ val fakeUseCase =
+ FakeUseCase().apply {
+ updateSessionConfigForTesting(
+ SessionConfig.Builder()
+ .setTemplateType(TEMPLATE_PREVIEW)
+ .setExpectedFrameRateRange(Range(15, 24))
+ .build()
+ )
+ }
+ val sessionConfigAdapter = SessionConfigAdapter(setOf(fakeUseCase))
+ val streamConfigMap = mutableMapOf<CameraStream.Config, DeferrableSurface>()
+
+ // Act
+ val graphConfig =
+ useCaseManager.createCameraGraphConfig(
+ sessionConfigAdapter,
+ streamConfigMap,
+ )
+
+ // Assert
+ assertThat(graphConfig.sessionTemplate).isEqualTo(RequestTemplate(TEMPLATE_PREVIEW))
+ assertThat(graphConfig.sessionParameters).containsKey(CONTROL_AE_TARGET_FPS_RANGE)
+ assertThat(graphConfig.sessionParameters[CONTROL_AE_TARGET_FPS_RANGE])
+ .isEqualTo(Range(15, 24))
+ assertThat(graphConfig.defaultParameters).containsKey(CONTROL_AE_TARGET_FPS_RANGE)
+ assertThat(graphConfig.defaultParameters[CONTROL_AE_TARGET_FPS_RANGE])
+ .isEqualTo(Range(15, 24))
+ }
+
+ @Test
fun overrideTemplateParams() = runTest {
// Arrange
initializeUseCaseThreads(this)
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CaptureRequestBuilder.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CaptureRequestBuilder.java
index 70decc2..08ccc13 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CaptureRequestBuilder.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CaptureRequestBuilder.java
@@ -237,6 +237,8 @@
applyTemplateParamsOverrideWorkaround(builder, captureConfig.getTemplateType(),
templateParamsOverride);
+ applyAeFpsRange(captureConfig, builder);
+
applyImplementationOptionToCaptureBuilder(builder,
captureConfig.getImplementationOptions());
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CaptureOptionSubmissionTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CaptureOptionSubmissionTest.kt
index f45d709..73dfc42 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CaptureOptionSubmissionTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CaptureOptionSubmissionTest.kt
@@ -141,11 +141,6 @@
@Test
fun canSubmitSupportedAeTargetFpsRanges_whenTargetFrameRateSetToPreviewOnly() = runBlocking {
assumeTrue(
- "TODO(b/331900702): Enable when the bug is fixed at camera-pipe",
- implName != CameraPipeConfig::class.simpleName
- )
-
- assumeTrue(
"TODO(b/332235883): Enable for legacy when the bug is resolved",
!isHwLevelLegacy()
)
@@ -184,11 +179,6 @@
fun canSubmitSupportedAeTargetFpsRanges_whenTargetFrameRateSetToVideoCaptureOnly() =
runBlocking {
assumeTrue(
- "TODO(b/331900702): Enable when the bug is fixed at camera-pipe",
- implName != CameraPipeConfig::class.simpleName
- )
-
- assumeTrue(
"TODO(b/332235883): Enable for legacy when the bug is resolved",
!isHwLevelLegacy()
)
@@ -233,11 +223,6 @@
@Test
fun canSetAeTargetFpsRangeWithCamera2Interop() = runBlocking {
assumeTrue(
- "TODO(b/331900702): Enable when the bug is fixed at camera-pipe",
- implName != CameraPipeConfig::class.simpleName
- )
-
- assumeTrue(
"TODO(b/332235883): Enable for legacy when the bug is resolved",
!isHwLevelLegacy()
)
@@ -292,11 +277,6 @@
@Test
fun canOverwriteFpsRangeWithCamera2Interop_whenAnotherSetViaSetTargetFrameRate() = runBlocking {
assumeTrue(
- "TODO(b/331900702): Enable when the bug is fixed at camera-pipe",
- implName != CameraPipeConfig::class.simpleName
- )
-
- assumeTrue(
"TODO(b/332235883): Enable for legacy when the bug is resolved",
!isHwLevelLegacy()
)