Implementa una vista previa

Cuando agregues una vista previa a tu app, usa PreviewView, que es una View que se puede recortar, escalar y rotar para mostrarse correctamente.

La vista previa de la imagen se transmite a una superficie dentro de PreviewView cuando se activa la cámara.

Cómo usar PreviewView

La implementación de una vista previa de CameraX con PreviewView implica los siguientes pasos, que se explican en secciones posteriores:

  1. De manera opcional, configura un CameraXConfig.Provider.
  2. Agrega un elemento PreviewView a tu diseño.
  3. Solicita un elemento ProcessCameraProvider.
  4. Durante la creación de View, comprueba la presencia de ProcessCameraProvider.
  5. Selecciona una cámara y vincula el ciclo de vida y los casos de uso.

El uso de PreviewView tiene algunas limitaciones. Cuando usas PreviewView, no puedes hacer nada de lo siguiente:

  • Crear un elemento SurfaceTexture para configurar en TextureView y Preview.SurfaceProvider
  • Recuperar el elemento SurfaceTexture de TextureView y configurarlo en Preview.SurfaceProvider
  • Obtener el elemento Surface de SurfaceView y configurarlo en Preview.SurfaceProvider

Si se produce alguno de estos problemas, Preview detendrá la transmisión de marcos a PreviewView.

Cómo agregar un elemento PreviewView a tu diseño

En el siguiente ejemplo, se muestra un elemento PreviewView en un diseño:

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

Solicita un elemento CameraProvider

En el siguiente código, se muestra cómo solicitar un elemento CameraProvider:

Kotlin

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

class MainActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
    override fun onCreate(savedInstanceState: Bundle?) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    }
}

Java

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

public class MainActivity extends AppCompatActivity {
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    }
}

Comprueba la disponibilidad de CameraProvider

Después de solicitar un elemento CameraProvider, verifica que se realice correctamente la inicialización cuando se cree la vista. El siguiente código muestra cómo hacer esto:

Kotlin

cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

Java

cameraProviderFuture.addListener(() -> {
    try {
        ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
        bindPreview(cameraProvider);
    } catch (ExecutionException | InterruptedException e) {
        // No errors need to be handled for this Future.
        // This should never be reached.
    }
}, ContextCompat.getMainExecutor(this));

Para ver un ejemplo de la función bindPreview que se usa en esta muestra, consulta el código proporcionado en la próxima sección.

Selecciona una cámara y vincula el ciclo de vida y los casos de uso

Una vez que hayas creado y confirmado el elemento CameraProvider, haz lo siguiente:

  1. Crea un elemento Preview.
  2. Especifica la opción de cámara LensFacing deseada.
  3. Vincula la cámara seleccionada y los casos de uso al ciclo de vida.
  4. Conecta el elemento Preview a PreviewView.

En el siguiente código, se muestra un ejemplo:

Kotlin

fun bindPreview(cameraProvider : ProcessCameraProvider) {
    var preview : Preview = Preview.Builder()
            .build()

    var cameraSelector : CameraSelector = CameraSelector.Builder()
          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
          .build()

    preview.setSurfaceProvider(previewView.getSurfaceProvider())

    var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

Java

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder()
            .build();

    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}

Ten en cuenta que bindToLifecycle() muestra un objeto Camera. Consulta esta guía a fin de obtener más información para controlar la salida de la cámara, como el zoom y la exposición.

Ya terminaste de implementar la vista previa de la cámara. Compila tu app y confirma que la vista previa aparezca en ella y funcione como lo deseas.

Controles adicionales para PreviewView

El elemento PreviewView de CameraX proporciona algunas API adicionales para configurar propiedades, como las siguientes:

Modo de implementación

PreviewView puede usar uno de los siguientes modos a fin de renderizar una transmisión de vista previa en la View de destino:

  • PERFORMANCE es el modo predeterminado. PreviewView usa una SurfaceView para mostrar la transmisión de video por Internet, pero recurre a una TextureView en algunos casos. SurfaceView tiene una superficie de dibujo dedicada, que tiene más probabilidades de implementarse con una superposición de hardware por parte del compositor de hardware interno, en especial cuando no hay otros elementos de la IU (como botones) sobre el video de vista previa. Cuando se renderiza con una superposición de hardware, los marcos de video evitan una ruta de GPU, lo que puede reducir el consumo de energía y la latencia de la plataforma.

  • Modo COMPATIBLE: En este modo, PreviewView usa una TextureView que, a diferencia de SurfaceView, no tiene una superficie de dibujo dedicada. Por lo tanto, el video se renderiza mediante fusiones de modo que se pueda mostrar. Durante este paso adicional, la aplicación puede realizar un procesamiento adicional, como ajustar y rotar videos sin restricción.

Usa PreviewView.setImplementationMode() a fin de seleccionar el modo de implementación adecuado para tu aplicación. Si el modo PERFORMANCE predeterminado no resulta útil para tu aplicación, la siguiente muestra de código indica cómo configurar el modo COMPATIBLE:

Kotlin

// viewFinder is a PreviewView instance
viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE

Tipo de escala

Cuando la resolución del video de vista previa difiera de las dimensiones de tu PreviewView objetivo, el contenido de video deberá ajustarse a la vista, ya sea mediante recortes o formato letterbox (lo que mantiene la relación de aspecto original). A tal fin, PreviewView proporciona los siguientes ScaleTypes:

  • FIT_CENTER, FIT_START y FIT_END para el formato letterbox. Se ajusta el contenido completo del video (ya sea un aumento o una disminución) al tamaño máximo posible que se puede mostrar en la PreviewView objetivo. Sin embargo, mientras se vea todo el marco de video, es posible que algunas partes de la pantalla queden en blanco. Según cuál de estos tres tipos de escala elijas, el marco de video se alineará con el centro, el inicio o el final de la Vista objetivo.

  • FILL_CENTER, FILL_START y FILL_END para los recortes. Si un video no coincide con la relación de aspecto de la PreviewView, solo una parte del contenido es visible, pero el video abarca toda la PreviewView.

El tipo de escala predeterminado que usa CameraX es FILL_CENTER. Usa PreviewView.setScaleType() a fin de establecer el tipo de escala más adecuado para tu aplicación. En la siguiente muestra de código, se establece el tipo de escala FIT_CENTER:

Kotlin

// viewFinder is a PreviewView instance
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER

El proceso para mostrar un video consta de los siguientes pasos:

  1. Ajusta el video:
    • Para los tipos de escala FIT_*, ajusta el video con min(dst.width/src.width, dst.height/src.height).
    • Para los tipos de escala FILL_*, ajusta el video con max(dst.width/src.width, dst.height/src.height).
  2. Alinea el video ajustado con la PreviewView objetivo:
    • Para FIT_CENTER/FILL_CENTER, centra el video ajustado y la PreviewView objetivo.
    • Para FIT_START/FILL_START, alinea el video ajustado y la PreviewView objetivo respecto de la esquina superior izquierda de cada uno.
    • Para FIT_END/FILL_END, alinea el video ajustado y la PreviewView objetivo respecto de la esquina inferior derecha de cada uno.

Por ejemplo, este es un video fuente de 640 x 480 y una PreviewView objetivo de 1920 x 1080:

Imagen que muestra un video de 640 x 480 en comparación con una vista previa de 1920 x 1080

En la siguiente imagen, se muestra el proceso de ajuste de FIT_START, FIT_CENTER y FIT_END:

Imagen que muestra el proceso de ajuste de FIT_START, FIT_CENTER y FIT_END

El proceso funciona de la siguiente manera:

  1. Ajusta el marco de video (manteniendo la relación de aspecto original) con min(1920/640, 1080/480) = 2.25 para obtener un marco de video intermedio de 1440 x 1080.
  2. Alinea el marco de video de 1440 x 1080 con la PreviewView de 1920 x 1080.
    • Para FIT_CENTER, alinea el marco de video con el centro de la ventana de la PreviewView. Las columnas de los 240 píxeles iniciales y finales de la PreviewView están en blanco.
    • Para FIT_START, alinea el marco de video con el inicio (esquina superior izquierda) de la ventana de la PreviewView. Las columnas de los 480 píxeles finales de la PreviewView están en blanco.
    • Para FIT_END, alinea el marco de video con el final (esquina inferior derecha) de la ventana de la PreviewView. Las columnas de los 480 píxeles iniciales del PreviewView están en blanco.

En la siguiente imagen, se muestra el proceso de ajuste de FILL_START, FILL_CENTER y FILL_END:

Imagen que muestra el proceso de ajuste de FILL_START, FILL_CENTER y FILL_END

El proceso funciona de la siguiente manera:

  1. Ajusta el marco de video con max(1920/640, 1080/480) = 3 para obtener un marco de video intermedio de 1920 x 1440 (que es más grande que el tamaño de la PreviewView).
  2. Recorta el marco de video de 1920 x 1440 de modo que se ajuste a la ventana de la PreviewView de 1920 x 1080.
    • Para FILL_CENTER, recorta 1920 x 1080 desde el centro del video ajustado de 1920 x 1440. Las 180 líneas superiores e inferiores del video no se verán.
    • Para FILL_START, recorta 1920 x 1080 desde el inicio del video ajustado de 1920 x 1440. Las 360 líneas inferiores del video no se verán.
    • Para FILL_END, recorta 1920 x 1080 desde el final del video ajustado de 1920 x 1440. Las 360 líneas superiores del video no se verán.

Recursos adicionales

Para obtener más información sobre CameraX, consulta los siguientes recursos adicionales:

Codelab

  • Cómo comenzar a usar CameraX
  • Muestra de código

  • Apps de ejemplo de CameraX