Skip to content

Commit

Permalink
fix: Use proper aspect ratio in Preview View on Android (#2964)
Browse files Browse the repository at this point in the history
Uses video's aspect ratio if video is enabled, photo's aspect ratio if photo is enabled, and automatic aspect ratio otherwise.

---------

Co-authored-by: Marc Rousavy <me@mrousavy.com>
  • Loading branch information
j-jonathan and mrousavy committed Jun 12, 2024
1 parent 89a8806 commit 555474d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ data class CameraConfiguration(
data class Audio(val nothing: Unit)
data class Preview(val surfaceProvider: SurfaceProvider)

val targetPreviewAspectRatio: Float?
get() {
val format = format ?: return null
val video = video as? Output.Enabled<Video>
val photo = photo as? Output.Enabled<Photo>
return if (video != null) {
// Video capture is enabled, use video aspect ratio
format.videoWidth.toFloat() / format.videoHeight.toFloat()
} else if (photo != null) {
// Photo capture is enabled, use photo aspect ratio
format.photoWidth.toFloat() / format.photoHeight.toFloat()
} else {
null
}
}

@Suppress("EqualsOrHashCode")
sealed class Output<T> {
val isEnabled: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.Recorder
import androidx.camera.video.VideoCapture
import androidx.lifecycle.Lifecycle
import com.mrousavy.camera.core.extensions.byId
import com.mrousavy.camera.core.extensions.forSize
import com.mrousavy.camera.core.extensions.id
import com.mrousavy.camera.core.extensions.isSDR
import com.mrousavy.camera.core.extensions.setTargetFrameRate
import com.mrousavy.camera.core.extensions.toCameraError
import com.mrousavy.camera.core.extensions.withExtension
import com.mrousavy.camera.core.extensions.*
import com.mrousavy.camera.core.types.CameraDeviceFormat
import com.mrousavy.camera.core.types.Torch
import com.mrousavy.camera.core.types.VideoStabilizationMode
Expand Down Expand Up @@ -67,6 +61,9 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration)

Log.i(CameraSession.TAG, "Using FPS Range: $fpsRange")

val photoConfig = configuration.photo as? CameraConfiguration.Output.Enabled<CameraConfiguration.Photo>
val videoConfig = configuration.video as? CameraConfiguration.Output.Enabled<CameraConfiguration.Video>

// 1. Preview
val previewConfig = configuration.preview as? CameraConfiguration.Output.Enabled<CameraConfiguration.Preview>
if (previewConfig != null) {
Expand All @@ -85,6 +82,16 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration)
}
preview.setTargetFrameRate(fpsRange)
}

val targetPreviewAspectRatio = configuration.targetPreviewAspectRatio
if (targetPreviewAspectRatio != null) {
Log.i(CameraSession.TAG, "Preview aspect ratio: $targetPreviewAspectRatio")
val previewResolutionSelector = ResolutionSelector.Builder()
.forAspectRatio(targetPreviewAspectRatio)
.setAllowedResolutionMode(ResolutionSelector.PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION)
.build()
preview.setResolutionSelector(previewResolutionSelector)
}
}.build()
preview.setSurfaceProvider(previewConfig.config.surfaceProvider)
previewOutput = preview
Expand All @@ -93,7 +100,6 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration)
}

// 2. Image Capture
val photoConfig = configuration.photo as? CameraConfiguration.Output.Enabled<CameraConfiguration.Photo>
if (photoConfig != null) {
Log.i(CameraSession.TAG, "Creating Photo output...")
val photo = ImageCapture.Builder().also { photo ->
Expand All @@ -114,7 +120,6 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration)
}

// 3. Video Capture
val videoConfig = configuration.video as? CameraConfiguration.Output.Enabled<CameraConfiguration.Video>
if (videoConfig != null) {
Log.i(CameraSession.TAG, "Creating Video output...")
val currentRecorder = recorderOutput
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.mrousavy.camera.core.extensions

import androidx.camera.core.resolutionselector.ResolutionSelector
import kotlin.math.abs

/**
* Gets a [ResolutionSelector] that finds a resolution closest to the given target aspect ratio.
*/
fun ResolutionSelector.Builder.forAspectRatio(aspectRatio: Float): ResolutionSelector.Builder {
return this.setResolutionFilter { supportedSizes, _ ->
return@setResolutionFilter supportedSizes.sortedWith(
compareBy(
// Compare difference in aspect ratios first,
{ abs(it.width.toFloat() / it.height - aspectRatio) },
// ..and total resolution afterwards.
{ -(it.width * it.height) }
)
)
}
}

0 comments on commit 555474d

Please sign in to comment.