Aperture: Rework framerate handling
* Assume a specific framerate will always be available, per AOSP docs:
For devices at the LEGACY level or above: (...) a camera device must
either not support any CamcorderProfile, or support at least one
normal CamcorderProfile that has videoFrameRate x >= 24.
* Always set a framerate, the default is 30fps and the app will try to
find a lower or higher framerate
* If the camera has less than two framerates available, disable the
framerate button
* In case the camera supports no known framerate, let CameraX handle it
Change-Id: I1826328d0399469a95b03f0676a7a960fc0a0317
diff --git a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
index 3a2a4d9..4292d97 100644
--- a/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/CameraActivity.kt
@@ -175,9 +175,9 @@
get() = camera.supportedVideoQualities.keys.toList()
private val supportedVideoFramerates: List<Framerate>
get() = camera.supportedVideoQualities.getOrDefault(
- sharedPreferences.videoQuality, listOf(Framerate.FPS_AUTO)
+ sharedPreferences.videoQuality, listOf()
)
- private var videoFramerate = Framerate.FPS_AUTO
+ private var videoFramerate: Framerate? = null
private lateinit var audioConfig: AudioConfig
private var recording: Recording? = null
@@ -888,10 +888,10 @@
}
cameraController.videoCaptureTargetQuality = sharedPreferences.videoQuality
- // Fallback to Framerate.FPS_AUTO if necessary
- if (!supportedVideoFramerates.contains(videoFramerate)) {
- videoFramerate = Framerate.FPS_AUTO
- }
+ // Set proper video framerate
+ videoFramerate = (Framerate::getLowerOrHigher)(
+ videoFramerate ?: Framerate.FPS_30, supportedVideoFramerates
+ )
CameraController.VIDEO_CAPTURE
}
@@ -945,7 +945,7 @@
if (cameraMode == CameraMode.VIDEO) {
videoFramerate
} else {
- Framerate.FPS_AUTO
+ null
}
)
setStabilizationMode(
@@ -1148,12 +1148,12 @@
}
private fun updateVideoFramerateIcon() {
+ videoFramerateButton.isEnabled = supportedVideoFramerates.size > 1
videoFramerateButton.isVisible = cameraMode == CameraMode.VIDEO
- videoFramerateButton.text = when (videoFramerate) {
- Framerate.FPS_AUTO -> resources.getString(R.string.video_framerate_auto)
- else -> resources.getString(R.string.video_framerate_value, videoFramerate.value)
- }
+ videoFramerateButton.text = videoFramerate?.let {
+ resources.getString(R.string.video_framerate_value, it.value)
+ } ?: resources.getString(R.string.video_framerate_auto)
}
private fun cycleVideoFramerate() {
diff --git a/app/src/main/java/org/lineageos/aperture/CaptureRequestOptionsBuilderExt.kt b/app/src/main/java/org/lineageos/aperture/CaptureRequestOptionsBuilderExt.kt
index 9bc8d21..68faad5 100644
--- a/app/src/main/java/org/lineageos/aperture/CaptureRequestOptionsBuilderExt.kt
+++ b/app/src/main/java/org/lineageos/aperture/CaptureRequestOptionsBuilderExt.kt
@@ -13,10 +13,10 @@
import org.lineageos.aperture.utils.StabilizationMode
@androidx.camera.camera2.interop.ExperimentalCamera2Interop
-fun CaptureRequestOptions.Builder.setFramerate(framerate: Framerate) {
- framerate.range?.let {
+fun CaptureRequestOptions.Builder.setFramerate(framerate: Framerate?) {
+ framerate?.let {
setCaptureRequestOption(
- CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, it
+ CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, it.range
)
} ?: run {
clearCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE)
diff --git a/app/src/main/java/org/lineageos/aperture/utils/Camera.kt b/app/src/main/java/org/lineageos/aperture/utils/Camera.kt
index 1a3093d..1b5fa70 100644
--- a/app/src/main/java/org/lineageos/aperture/utils/Camera.kt
+++ b/app/src/main/java/org/lineageos/aperture/utils/Camera.kt
@@ -75,15 +75,12 @@
var intrinsicZoomRatio = 1f
- private val supportedVideoFramerates = mutableListOf(Framerate.FPS_AUTO).apply {
+ private val supportedVideoFramerates =
camera2CameraInfo.getCameraCharacteristic(
CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
)?.mapNotNull { range ->
Framerate.fromRange(range)
- }?.let {
- addAll(it)
- }
- }.distinct().sorted().toList()
+ }?.distinct()?.sorted() ?: listOf()
val supportedVideoQualities = QualitySelector.getSupportedQualities(cameraInfo).associateWith {
supportedVideoFramerates + cameraManager.getAdditionalVideoFramerates(cameraId, it)
}.toSortedMap { a, b ->
diff --git a/app/src/main/java/org/lineageos/aperture/utils/Framerate.kt b/app/src/main/java/org/lineageos/aperture/utils/Framerate.kt
index edea0d9..598771c 100644
--- a/app/src/main/java/org/lineageos/aperture/utils/Framerate.kt
+++ b/app/src/main/java/org/lineageos/aperture/utils/Framerate.kt
@@ -8,13 +8,23 @@
import android.util.Range
enum class Framerate(val value: Int) {
- FPS_AUTO(-1),
FPS_24(24),
FPS_30(30),
FPS_60(60),
FPS_120(120);
- val range = if (value == -1) null else Range(value, value)
+ val range = Range(value, value)
+
+ /**
+ * Get the closer framerate to the requested one, first finding a lower one
+ * then checking for a higher one if no one exists.
+ */
+ fun getLowerOrHigher(framerates: List<Framerate>): Framerate? {
+ val smaller = framerates.filter { it <= this }.sortedDescending()
+ val bigger = framerates.filter { it > this }.sorted()
+
+ return (smaller + bigger).firstOrNull()
+ }
companion object {
fun fromValue(value: Int) = values().firstOrNull { it.value == value }