Implementar uma visualização

Ao adicionar uma visualização ao seu app, use a PreviewView, que é uma View que pode ser cortada, redimensionada e girada para que a exibição fique adequada.

A visualização da imagem é transmitida para uma superfície dentro da PreviewView quando a câmera é ativada.

Usar a PreviewView

A implementação de uma visualização para o CameraX usando PreviewView envolve as seguintes etapas, abordadas nas próximas seções:

  1. Configurar um CameraXConfig.Provider (opcional).
  2. Adicionar uma PreviewView ao seu layout.
  3. Solicitar um ProcessCameraProvider.
  4. Verificar se ProcessCameraProvider existe ao criar View.
  5. Selecionar uma câmera e vincular o ciclo de vida e casos de uso.

O uso de PreviewView tem algumas limitações. Ao usar PreviewView, não é possível realizar nenhuma das seguintes ações:

  • Criar uma SurfaceTexture para configurar em TextureView e Preview.SurfaceProvider.
  • Recuperar a SurfaceTexture na TextureView e configurá-la em Preview.SurfaceProvider.
  • Conseguir a Surface da SurfaceView e configurá-la em Preview.SurfaceProvider.

Se qualquer um desses eventos acontecer, a Preview vai interromper o streaming de frames para a PreviewView.

Adicionar uma PreviewView ao layout

O exemplo a seguir mostra uma PreviewView em um layout:

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

Solicitar um CameraProvider

O código a seguir mostra como solicitar um 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);
    }
}

Verificar a disponibilidade do CameraProvider

Depois de solicitar um CameraProvider, verifique se a inicialização foi bem-sucedida quando a visualização for criada. O código a seguir mostra como fazer isso:

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 um exemplo da função bindPreview usada nesta amostra, consulte o código fornecido na próxima seção.

Selecionar uma câmera e vincular o ciclo de vida e os casos de uso

Após criar e confirmar o CameraProvider, faça o seguinte:

  1. Crie uma Preview.
  2. Especifique a opção LensFacing da câmera desejada.
  3. Vincule a câmera selecionada e os casos de uso ao ciclo de vida.
  4. Conecte a Preview à PreviewView.

O código a seguir mostra um exemplo:

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);
}

Observe que bindToLifecycle() retorna um objeto Camera. Para ter mais informações sobre como controlar a saída da câmera, como o zoom e a exposição, consulte Saída da câmera.

Você concluiu a implementação da prévia da câmera. Crie seu app e confirme se a visualização aparece no app e funciona conforme o esperado.

Outros controles para a PreviewView

A PreviewView do CameraX fornece outras APIs para configurar propriedades como:

Modo de implementação

A PreviewView pode usar um dos seguintes modos para renderizar um stream de prévia na View de destino:

  • PERFORMANCE é o modo padrão. A PreviewView usa uma SurfaceView para mostrar o stream de vídeo, mas usa TextureView em determinados casos. A SurfaceView tem uma superfície de desenho dedicada, que tem mais chances de ser implementada com uma sobreposição de hardware do compositor de hardware interno, principalmente quando não há outros elementos da interface (como botões) sobre o vídeo de prévia. Ao renderizar com uma sobreposição de hardware, os frames do vídeo evitam um caminho de GPU, o que pode reduzir a latência e o consumo de energia da plataforma.

  • Modo COMPATIBLE. Nesse modo, a PreviewView usa uma TextureView que, ao contrário da SurfaceView, não tem uma superfície de desenho dedicada. Como resultado, o vídeo é renderizado com mesclagem para que possa ser mostrado. Durante essa etapa extra, o aplicativo pode executar outros processamentos, como fazer o dimensionamento e a rotação dos vídeos sem restrições.

Use PreviewView.setImplementationMode() para selecionar o modo de implementação adequado para seu aplicativo. Caso o modo PERFORMANCE padrão não seja adequado para seu aplicativo, o exemplo de código a seguir mostra como definir o modo COMPATIBLE:

Kotlin

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

Tipo de escala

Quando a resolução do vídeo de prévia é diferente das dimensões da sua PreviewView de destino, o conteúdo do vídeo precisa ser ajustado à prévia, sendo cortado ou usando o efeito letterbox, sem mudar a proporção original. A PreviewView fornece os seguintes ScaleTypes para essa finalidade:

  • FIT_CENTER, FIT_START e FIT_END para o efeito letterbox. O conteúdo completo do vídeo é dimensionado (para cima ou para baixo) no tamanho máximo que pode ser mostrado na PreviewView de destino. No entanto, embora o frame completo do vídeo esteja visível, algumas partes da tela podem ficar em branco. Dependendo de qual dos três tipos de escala você escolher, o frame do vídeo será alinhado ao centro, início ou fim da prévia de destino.

  • Use FILL_CENTER, FILL_START e FILL_END para cortar. Se um vídeo não corresponder à proporção da PreviewView, apenas uma parte do conteúdo ficará visível, mas vai preencher toda a PreviewView.

O tipo de escala padrão que o CameraX usa é FILL_CENTER. Use PreviewView.setScaleType() para definir o tipo de escala mais adequado para seu aplicativo. O exemplo de código a seguir define o tipo de escala FIT_CENTER.

Kotlin

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

O processo para reproduzir um vídeo consiste nas seguintes etapas:

  1. Dimensione o vídeo:
    • Para tipos de escala FIT_*, dimensione o vídeo com min(dst.width/src.width, dst.height/src.height).
    • Para tipos de escala FILL_*, dimensione o vídeo com max(dst.width/src.width, dst.height/src.height).
  2. Alinhe o vídeo dimensionado com a PreviewView de destino:
    • Para FIT_CENTER/FILL_CENTER, centralize o vídeo dimensionado e a PreviewView de destino.
    • Para FIT_START/FILL_START, alinhe o vídeo dimensionado e a PreviewView de destino ao canto superior esquerdo de cada um.
    • Para FIT_END/FILL_END, alinhe o vídeo dimensionado e a PreviewView de destino em relação ao canto inferior direito de cada um.

Por exemplo, aqui temos um vídeo de origem de 640 x 480 e uma PreviewView de destino de 1920 x 1080:

Imagem mostrando um vídeo de 640 x 480 em comparação com uma prévia de 1920 x 1080

A imagem a seguir mostra o processo de dimensionamento FIT_START / FIT_CENTER / FIT_END:

Imagem mostrando o processo de dimensionamento FIT_START, FIT_CENTER e FIT_END

O processo funciona assim:

  1. Ajuste o frame do vídeo (mantendo a proporção original) com min(1920/640, 1080/480) = 2.25 para conseguir um frame de vídeo intermediário de 1440 x 1080.
  2. Alinhe o frame do vídeo de 1440 x 1080 à PreviewView de 1920 x 1080.
    • Para FIT_CENTER, alinhe o frame do vídeo ao centro da janela de PreviewView. As colunas inicial e final de 240 pixels da PreviewView estão em branco.
    • Para FIT_START, alinhe o frame do vídeo ao início (canto superior esquerdo) da janela de PreviewView. As colunas finais de 480 pixels da PreviewView estão em branco.
    • Para FIT_END, alinhe o frame do vídeo ao final (canto inferior direito) da janela PreviewView. As colunas iniciais de 480 pixels da PreviewView estão em branco.

A imagem a seguir mostra o processo de dimensionamento FILL_START / FILL_CENTER / FILL_END:

Imagem mostrando o processo de dimensionamento FILL_START, FILL_CENTER e FILL_END

O processo funciona assim:

  1. Dimensione o frame do vídeo com max(1920/640, 1080/480) = 3 para conseguir um frame intermediário de 1920 x 1440, que é maior que o tamanho da janela de PreviewView.
  2. Corte o frame do vídeo de 1920 x 1440 para que ele se ajuste à janela de PreviewView de 1920 x 1080.
    • Para FILL_CENTER, corte de 1920 x 1440 para 1920 x 1080 do centro do vídeo dimensionado. As 180 linhas de vídeo nas partes de cima e de baixo não ficam visíveis.
    • Para FILL_START, corte de 1920 x 1440 para 1920 x 1080 do início do vídeo dimensionado. As últimas 360 linhas de vídeo não ficam visíveis.
    • Para FILL_END, corte de 1920 x 1440 para 1920 x 1080 do fim do vídeo dimensionado. As primeiras 360 linhas de vídeo não ficam visíveis.

Outros recursos

Para saber mais sobre o CameraX, consulte os seguintes recursos.

Codelab

  • Introdução ao CameraX
  • Exemplo de código

  • Apps de exemplo do CameraX (link em inglês)