camera: Android preview rotation stays at 0 (texture transform applies)
Flutter's `Texture` widget on Android samples the underlying `SurfaceTexture` with its transform matrix applied (the GL `GL_TEXTURE_EXTERNAL_OES` sampler reads `SurfaceTexture.getTransformMatrix()` each frame), and CameraX populates that matrix with the rotation needed for upright display. A `RotatedBox` on top of that double-applies — manifested as the preview being 90° CW from where it should be. So `CameraInstance.previewRotationQuarterTurns` is hard-coded to 0 on Android. The wire field stays (iOS always emits 0 too because AVCaptureConnection.videoOrientation pre-rotates the sample buffers); future preview pipelines that bypass the SurfaceTexture transform would set it to a non-zero value.
This commit is contained in:
@@ -46,18 +46,17 @@ class CameraInstance(
|
|||||||
val currentLens: String get() = lens
|
val currentLens: String get() = lens
|
||||||
val audioClaimed: Boolean get() = enableAudio
|
val audioClaimed: Boolean get() = enableAudio
|
||||||
|
|
||||||
/// Number of 90° CW rotations the Flutter Texture needs so the
|
/// Always 0 on Android: Flutter's `Texture` widget samples the
|
||||||
/// sensor frames display upright on a portrait screen. Derived
|
/// underlying `SurfaceTexture` with its transform matrix applied
|
||||||
/// from the active camera's `sensorRotationDegrees`.
|
/// (`GL_TEXTURE_EXTERNAL_OES` sampling reads
|
||||||
val previewRotationQuarterTurns: Int get() {
|
/// `SurfaceTexture.getTransformMatrix()`), and CameraX populates
|
||||||
val degrees = cameraProvider?.let {
|
/// that matrix with the rotation needed for upright display. Any
|
||||||
val selector = if (lens == "front") CameraSelector.DEFAULT_FRONT_CAMERA
|
/// `RotatedBox` on top of that would double-apply the rotation.
|
||||||
else CameraSelector.DEFAULT_BACK_CAMERA
|
/// The field stays in the wire protocol for iOS' sake (always 0
|
||||||
selector.filter(it.availableCameraInfos).firstOrNull()
|
/// there too, since AVCaptureConnection pre-rotates the sample
|
||||||
?.sensorRotationDegrees ?: 0
|
/// buffers) and as a future hook if a non-CameraX preview path
|
||||||
} ?: 0
|
/// ever lands.
|
||||||
return ((degrees % 360 + 360) % 360) / 90
|
val previewRotationQuarterTurns: Int get() = 0
|
||||||
}
|
|
||||||
|
|
||||||
/// Bind the provider against [lens]. Resolves the
|
/// Bind the provider against [lens]. Resolves the
|
||||||
/// [ProcessCameraProvider.getInstance] future on the main executor
|
/// [ProcessCameraProvider.getInstance] future on the main executor
|
||||||
|
|||||||
Reference in New Issue
Block a user