Nota: Esta página hace referencia al paquete Camera2. A menos que la app requiera funciones específicas y de bajo nivel de Camera2, te recomendamos que uses CameraX. CameraX y Camera2 admiten Android 5.0 (nivel de API 21) y versiones posteriores.
En Android, las cámaras y las vistas previas no siempre están en la misma orientación. dispositivos.
Una cámara se encuentra en una posición fija en un dispositivo, sin importar si este es un teléfono, una tablet o una computadora. Cuando cambia la orientación del dispositivo, el que cambie la orientación de la cámara.
Como resultado, las apps de cámara generalmente suponen una relación fija entre la orientación del dispositivo y la relación de aspecto de la vista previa de la cámara. Cuando un elemento el teléfono está en orientación vertical, se supone que la vista previa de la cámara es más alta que su ancho. Cuando el teléfono (y la cámara) se rotan a la posición horizontal, el Se espera que la vista previa de la cámara sea más ancha que alta.
Pero estas suposiciones se enfrentan a nuevos factores de forma, como dispositivos plegables dispositivos y modos de visualización. como, por ejemplo, multiventana y pantallas múltiples. Los dispositivos plegables cambian el tamaño de la pantalla y la relación de aspecto sin cambiar orientación. El modo multiventana restringe las apps de cámara a una parte de la y ajustar la vista previa de la cámara, independientemente de la orientación del dispositivo. El modo de varias pantallas permite el uso de pantallas secundarias que podrían no tener estar en la misma orientación que la pantalla principal.
Orientación de la cámara
El Definición de compatibilidad de Android especifica que un sensor de imagen de la cámara "SE DEBE orientar para que la longitud de la cámara se alinee con la dimensión larga de la pantalla. Es decir, cuando el dispositivo se mantiene en orientación horizontal, las cámaras DEBEN capturar imágenes en la orientación horizontal. Esto se aplica independientemente de la naturaleza orientación; es decir, se aplica a los dispositivos principales horizontales y a los principales dispositivos principales verticales".
La disposición de cámara a pantalla maximiza el área de visualización de la cámara visor en una app de cámara. Además, los sensores de imagen suelen generar sus datos relaciones de aspecto horizontales, 4:3 es la más común.
La orientación natural del sensor de la cámara es horizontal. En la figura 1, el sensor de la cámara frontal (la cámara apunta en la misma dirección que el pantalla) se rote 270 grados con relación al teléfono para cumplir con la Definición de compatibilidad de Android.
Para exponer la rotación del sensor a las apps, el
La API de camera2 incluye una
SENSOR_ORIENTATION
constante. En la mayoría de los teléfonos y tablets, el dispositivo informa la orientación de un sensor.
de 270 grados para las cámaras frontales y de 90 grados (punto de vista desde la
parte posterior del dispositivo) para las cámaras traseras, que alinea el borde largo de la
con el borde largo del dispositivo. Las cámaras de las laptops suelen informar
orientación del sensor de 0 o 180 grados.
Debido a que los sensores de imagen de la cámara
generan datos (un búfer de imagen) en la
en la orientación natural del sensor (horizontal), el búfer de imagen se debe rotar
la cantidad de grados especificados por SENSOR_ORIENTATION
para la vista previa de la cámara en
aparezcan en posición vertical en la orientación natural del dispositivo. En el caso de las cámaras frontales,
la rotación es en el sentido contrario a las manecillas del reloj; para las cámaras posteriores, en el sentido de las manecillas del reloj.
Por ejemplo, para la cámara frontal de la figura 1, el búfer de imagen que produce el sensor de la cámara se ve de la siguiente manera:
La imagen se debe girar 270 grados a la izquierda para que la vista previa la orientación coincide con la del dispositivo:
Una cámara posterior produciría un búfer de imagen con la misma orientación.
que el búfer anterior, pero SENSOR_ORIENTATION
es de 90 grados. Como resultado, el
se rota 90 grados en el sentido de las manecillas del reloj.
Rotación del dispositivo
La rotación del dispositivo es la cantidad de grados en los que se rota un dispositivo respecto de su rotación natural orientación. Por ejemplo, un teléfono en orientación horizontal tiene un dispositivo de 90 o 270 grados, según la dirección de rotación.
Un búfer de imagen del sensor de la cámara se debe rotar la misma cantidad de grados que el de rotación del dispositivo (además de los grados de orientación del sensor) para la que la vista previa de la cámara se vea en posición vertical.
Cálculo de orientación
La orientación correcta de la vista previa de la cámara tiene en cuenta el sensor. y la rotación del dispositivo.
La rotación general del búfer de imagen del sensor se puede calcular con el siguiente fórmula:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
donde sign
es 1
para las cámaras frontales y -1
para las cámaras posteriores.
Para las cámaras frontales, el búfer de imagen se rota en sentido contrario a las manecillas del reloj (desde la orientación natural del sensor). Para las cámaras posteriores, el sensor el búfer de imagen se rota en el sentido de las manecillas del reloj.
La expresión deviceOrientationDegrees * sign + 360
convierte la rotación del dispositivo.
de las manecillas del reloj a las agujas del reloj para las cámaras traseras (por ejemplo,
convirtiendo 270 grados en sentido antihorario a 90 grados en el sentido de las manecillas del reloj). El módulo
escala el resultado a menos de 360 grados (por ejemplo, escala 540)
grados de rotación a 180).
Las diferentes APIs informan la rotación de dispositivos de manera diferente:
Display#getRotation()
Proporciona la rotación del dispositivo en el sentido contrario a las manecillas del reloj (desde el punto del usuario visual). Este valor se agrega a la fórmula anterior tal como está.OrientationEventListener#onOrientationChanged()
muestra la rotación en el sentido de las manecillas del reloj del dispositivo (desde el punto de vista del usuario). Negar el valor que se usará en la fórmula anterior
Cámaras frontales
En la figura 2, se muestra el búfer de imagen producido por el sensor de la cámara:
El búfer se debe girar 270 grados en sentido antihorario para ajustarse al sensor. orientación (consulta Orientación de la cámara más arriba):
Luego, el búfer se rota 90 grados adicionales en sentido antihorario para tienen en cuenta la rotación del dispositivo, lo que da como resultado la orientación correcta de la vista previa de la cámara en la figura 2:
Aquí está la cámara girada hacia la derecha en orientación horizontal:
Este es el búfer de imagen:
El búfer se debe rotar 270 grados en sentido antihorario para ajustarse al sensor orientación:
Luego, el búfer se rota otros 270 grados en sentido antihorario para tener en cuenta la rotación del dispositivo:
Cámaras posteriores
Las cámaras traseras generalmente tienen una orientación de sensor de 90 grados (como se ve desde la parte posterior del dispositivo). Cuando se orienta la vista previa de la cámara, el el búfer de imagen del sensor se rota en el sentido de las manecillas del reloj según la rotación del sensor (en lugar de en el sentido contrario a las manecillas del reloj, como las cámaras frontales) y, luego, la imagen el búfer se rota en sentido contrario a las manecillas del reloj según la rotación del dispositivo.
En la figura 4, se muestra el búfer de imagen del sensor de la cámara:
El búfer se debe rotar 90 grados en el sentido de las manecillas del reloj para ajustarse al sensor orientación:
Luego, el búfer se rota 270 grados en sentido contrario a las manecillas del reloj para tener en cuenta el dispositivo. rotación:
Relación de aspecto
La relación de aspecto de la pantalla cambia cuando cambia la orientación del dispositivo, pero también cuando Los dispositivos plegables se pliegan y se despliegan cuando se cambia el tamaño de las ventanas en el modo multiventana y cuando las apps se abren en pantallas secundarias.
El búfer de imagen del sensor de la cámara se debe orientar y ajustar para que coincida con la orientación y relación de aspecto del elemento de la IU del visor como la IU Cambia la orientación de forma dinámica, con o sin que el dispositivo cambie. orientación.
En factores de forma nuevos o en entornos multiventana o de varias pantallas, si tu app asume que la vista previa de la cámara tiene la misma orientación que la del dispositivo (horizontal o vertical), es posible que la vista previa esté orientada o ajustada de forma incorrecta incorrectamente o ambas.
En la figura 5, la aplicación supone erróneamente que el dispositivo se rotó 90 grados en el sentido contrario a las manecillas del reloj; Por lo tanto, la app giró la vista previa del mismo modo.
En la figura 6, la app no ajustó la relación de aspecto del búfer de imagen a permitir que se ajuste correctamente a las nuevas dimensiones de la IU de vista previa de la cámara .
Las apps de cámaras con orientación fija suelen experimentar problemas en dispositivos plegables y otros dispositivos con pantalla grande, como laptops,
En la figura 7, la IU de la app de cámara es lateral porque la orientación de la app está restringido al modo vertical. La imagen del visor está orientada correctamente en relación con el sensor de la cámara.
Modo vertical insertado
Apps de cámara que no admiten el modo multiventana
(resizeableActivity="false"
)
y restringir su orientación
(screenOrientation="portrait"
)
o screenOrientation="landscape"
)
se puede colocar en modo vertical insertado en dispositivos con pantalla grande para orientar correctamente
la vista previa de la cámara.
Inserciones en formato letterbox (inserciones) en modo vertical para apps solo con orientación vertical en orientación vertical orientación, aunque la relación de aspecto de la pantalla sea horizontal. Las apps que solo funcionan con formato horizontal tienen formato letterbox en orientación horizontal aunque la relación de aspecto de la pantalla sea vertical. Se rota la imagen de la cámara para alinearla con la IU de la app, recortada para que coincida con la relación de aspecto de la vista previa de la cámara y, luego, ajustarlo para llenar la vista previa.
El modo Retrato insertado se activa cuando la relación de aspecto de la imagen de la cámara y la relación de aspecto de la actividad principal de la aplicación no coinciden.
En la figura 8, se rotó la app de cámara solo con orientación vertical para mostrar la IU. en posición vertical en la pantalla de la laptop. La app tiene formato letterbox debido a la diferencia en la relación de aspecto entre la app vertical y la pantalla horizontal. La cámara se rotó la imagen de vista previa para compensar la rotación de la IU de la app (debido a modo vertical de inserción), y la imagen se recortó y se ajustó para adaptarla al con orientación vertical, lo que reduce el campo visual.
Rotar, recortar, ajustar
Se invoca el modo vertical de inserción para una app de cámara solo con modo vertical en una pantalla. que tiene una relación de aspecto horizontal:
La app tiene formato letterbox en orientación vertical:
La imagen de la cámara se rota 90 grados para ajustarse a la reorientación de la app:
La imagen se recorta según la relación de aspecto de la vista previa de la cámara y, luego, se ajusta a rellenar la vista previa (se reduce el campo visual):
En dispositivos plegables, la orientación del sensor de la cámara puede ser vertical. mientras que la relación de aspecto de la pantalla es horizontal:
Debido a que la vista previa de la cámara se rota para ajustarse a la orientación del sensor, la imagen esté orientada correctamente en el visor, pero la app está de lado.
El modo vertical para inserción solo necesita aplicar formato letterbox a la app en orientación vertical. para orientar correctamente la app y la vista previa de la cámara:
API
A partir de Android 12 (nivel de API 31), las apps también pueden controlar de forma explícita la inserción vertical
mediante el
SCALER_ROTATE_AND_CROP
propiedad de CaptureRequest
clase.
El valor predeterminado es
SCALER_ROTATE_AND_CROP_AUTO
:
que le permite al sistema invocar el modo vertical con inserción.
SCALER_ROTATE_AND_CROP_90
es el comportamiento del modo vertical insertado como se describió anteriormente.
No todos los dispositivos admiten todos los valores SCALER_ROTATE_AND_CROP
. Cómo obtener una lista
de valores admitidos, los valores de referencia
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
CameraX
La biblioteca de Jetpack CameraX permite crear un visor de cámara que se adapta a la orientación de los sensores y rotación del dispositivo es una tarea sencilla.
El elemento de diseño PreviewView
crea una vista previa de la cámara y se ajusta automáticamente según la orientación del sensor.
la rotación y el escalamiento
del dispositivo. PreviewView
mantiene la relación de aspecto de la
imagen de la cámara aplicando el
FILL_CENTER
tipo de escala, que centra la imagen, pero podría recortarla para que coincida con las dimensiones
de la PreviewView
. Para aplicar formato letterbox a la imagen de la cámara, establece el tipo de escala en
FIT_CENTER
Para aprender los conceptos básicos de la creación de una vista previa de la cámara con PreviewView
, consulta
Implementa una vista previa.
Para ver una implementación de muestra completa, consulta la
CameraXBasic
en un repositorio de GitHub.
Visor de la cámara
Al igual que en el caso de uso de Preview, el CameraViewfinder proporciona un conjunto de herramientas para simplificar la creación de una vista previa de la cámara. No depende de CameraX Core, por lo que puedes integrarlo sin problemas en tu base de código de Camera2 existente.
En lugar de usar
Surface
directamente, puedes usar el
CameraViewfinder
para mostrar el feed de la cámara de Camera2.
CameraViewfinder
usa de forma interna un TextureView
o un SurfaceView
.
para mostrar el feed de la cámara y aplica las transformaciones requeridas a ellas
mostrar correctamente el visor.
Esto implica corregir su relación de aspecto, escala y rotación.
Para solicitar la superficie del objeto CameraViewfinder
, debes hacer lo siguiente:
crea un ViewfinderSurfaceRequest
.
Esta solicitud contiene requisitos para la resolución de superficie y el dispositivo de cámara
información de CameraCharacteristics
.
Llamando a requestSurfaceAsync()
envía la solicitud al proveedor de superficie, que es un TextureView
o
SurfaceView
y obtiene un ListenableFuture
de Surface
.
Llamando a markSurfaceSafeToRelease()
notifica al proveedor de superficies que la superficie no es necesaria y está relacionada
se pueden liberar recursos.
Kotlin
fun startCamera(){ val previewResolution = Size(width, height) val viewfinderSurfaceRequest = ViewfinderSurfaceRequest(previewResolution, characteristics) val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest) Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> { override fun onSuccess(surface: Surface) { /* create a CaptureSession using this surface as usual */ } override fun onFailure(t: Throwable) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)) }
Java
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFuture<Surface> surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)); }
SurfaceView
SurfaceView
es un
enfoque directo para crear una vista previa de la cámara si esta no
requieren procesamiento y no están animadas.
SurfaceView
rota automáticamente el búfer de imagen del sensor de la cámara para que coincida.
la orientación de la pantalla, teniendo en cuenta tanto la orientación del sensor como la
y la rotación de claves. Sin embargo, el búfer de imagen se ajusta para adaptarse a SurfaceView
dimensiones sin considerar la relación de aspecto.
Debes asegurarte de que la relación de aspecto del búfer de imagen coincida con el
proporción de SurfaceView
, que puedes lograr escalando el contenido
de SurfaceView
en el archivo
onMeasure()
método:
(El código fuente computeRelativeRotation()
está en
Rotación relativa a continuación).
Kotlin
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
Java
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
Para obtener más detalles sobre cómo implementar SurfaceView
como vista previa de la cámara, consulta
Orientaciones de la cámara:
Vista de textura
TextureView
tiene un rendimiento menor que
SurfaceView
, y más trabajo, pero TextureView
le brinda el máximo
control de la vista previa de la cámara.
TextureView
rota el búfer de imagen del sensor según la orientación del sensor, pero
No controla la rotación del dispositivo ni el escalamiento de la vista previa.
El escalamiento y la rotación se pueden codificar
Transformación de Matrix. Para aprender a hacer lo siguiente:
escalar y rotar correctamente un TextureView
, consulta
Cómo brindar compatibilidad con superficies redimensionables en tu app de cámara
Rotación relativa
La rotación relativa del sensor de la cámara es la cantidad de rotación necesaria para alinea la salida del sensor de la cámara con la orientación del dispositivo.
Componentes como SurfaceView
y TextureView
usan la rotación relativa
para determinar los factores de escala x e y para la imagen de vista previa. También se usa para
especifica la rotación del búfer de imagen del sensor.
El
CameraCharacteristics
y
Las clases Surface
permiten el cálculo de la
rotación relativa del sensor de la cámara:
Kotlin
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!! // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
Java
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1; // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360; }
Métricas de la ventana
No debe usarse el tamaño de la pantalla para determinar las dimensiones de la cámara visor; es posible que la app de cámara se esté ejecutando en una parte de la pantalla, ya sea en el modo multiventana en dispositivos móviles o en el modo gratuito en ChromeOS.
WindowManager#getCurrentWindowMetrics()
(agregado en el nivel de API 30) muestra el tamaño de la ventana de la aplicación en lugar de
el tamaño de la pantalla. Los métodos de la biblioteca de WindowManager de Jetpack
WindowMetricsCalculator#computeCurrentWindowMetrics()
y
WindowInfoTracker#currentWindowMetrics()
proporcionan una compatibilidad similar con retrocompatibilidad con el nivel de API 14.
Rotación de 180 grados
Rotación de 180 grados de un dispositivo (por ejemplo, de la orientación natural a
orientación natural al revés) no activa el
onConfigurationChanged()
devolución de llamada. Como resultado, la vista previa de la cámara puede estar al revés.
Para detectar una rotación de 180 grados, implementa una
DisplayListener
y comprueba la rotación del dispositivo con una llamada a
Display#getRotation()
en la
onDisplayChanged()
devolución de llamada.
Recursos exclusivos
Antes de Android 10, solo la actividad visible superior en un modo multiventana
estaba en el estado RESUMED
. Esto era confuso para los usuarios porque
el sistema no proporcionó ninguna indicación de qué actividad se reanudó.
Android 10 (nivel de API 29) introdujo la reanudación múltiple, en la que todas las actividades visibles
están en el estado RESUMED
. Las actividades visibles aún pueden ingresar a la PAUSED
estado si, por ejemplo, una actividad transparente está sobre la actividad o
la actividad no se puede enfocar, como en el modo de pantalla en pantalla (consulta
Compatibilidad con pantalla en pantalla).
Una aplicación que utiliza la cámara, el micrófono o cualquier función exclusiva o
El recurso singleton en el nivel de API 29 o versiones posteriores debe admitir la reanudación múltiple. Para
ejemplo, si tres actividades reanudadas quieren usar la cámara, solo una puede
para acceder a este recurso exclusivo. Cada actividad debe implementar un
onDisconnected()
para mantenerse al tanto del acceso preventivo a la cámara mediante una prioridad más alta
actividad.
Para obtener más información, consulta Reanudación múltiple:
Recursos adicionales
- Para ver una muestra de Camera2, consulta la app de Camera2Basic en GitHub.
- Para obtener información sobre el caso de uso de la vista previa de CameraX, consulta CameraX. Implementa una vista previa.
- Para ver un ejemplo de implementación de vista previa de la cámara de CameraX, consulta el CameraXBasic en un repositorio de GitHub.
- Para obtener información sobre la vista previa de la cámara en ChromeOS, consulta lo siguiente: Orientaciones de la cámara:
- Para obtener información sobre el desarrollo para dispositivos plegables, consulta Obtén más información sobre dispositivos plegables.