Descobrindo a Camera2

Vamos explorar a API Camera2 do Android com SurfaceView e TextureView?

Jean Dobler
Accenture Digital Product Dev
4 min readJul 8, 2020

--

O que seria dos dias atuais sem a câmera do celular? Acho que podemos considerar este item como um dos mais populares para qualquer usuário. Afinal, quem não gosta de registrar seus momentos favoritos? A popularidade da câmera de celular é intensificada se considerarmos a facilidade dos aplicativos em compartilhar e armazenar vídeos e fotos online.

Entretanto, mesmo com toda essa popularidade é raro ter a oportunidade de pegar alguma task para implementar ou dar manutenção a features para a câmera, como um leitor de QRCode/código de barras, filtros de câmera, realidade aumentada etc. Então, hoje vamos explorar a API Camera2 do Android, usando SurfaceView e TextureView. Vamos aprender juntos.

O que é Camera2? Onde vive? Como se alimenta?

A Camera2 foi adicionada na API 21, ou seja, uma evolução do antiga API de câmera. Ela modela as requests da câmera como uma pipeline, pegando cada frame, capturando a imagem e por fim nos dando o retorno em Metadata. Você pode configurar vários listeners de captura ao mesmo tempo, mas isso impacta diretamente no framerate da câmera, e isso explica o porquê de algumas aplicações de realidade aumentada darem algumas travadinhas na câmera.

Geralmente, as imagens de visualização da câmera são enviadas para o SurfaceView ou TextureView (por meio do SurfaceTexture). A captura de imagens JPEG ou buffers RAW para o DngCreator pode ser feita com o ImageReader nos formatos JPEG e RAW_SENSOR.

No momento que escrevo este texto já temos a versão beta do CameraX, uma evolução do Camera2, que deve facilitar muito a implementação e manutenção de aplicações de câmera.

TextureView ou SurfaceView, qual o melhor?

A imagem de preview da câmera geralmente é enviada para uma dessas duas views. Não existe melhor entre elas, por mais que sejam igualmente herdados de View, cada um deles possui características diferentes para diferentes tipos de implementações.

O TextureView possui maior controle para desenhar, escalar e transformar, e seu callback já retorna a imagem atual que está sendo mostrada na view. Ela é ideal para fazer processamentos como realidade aumentada ou leitor de QRCode, enquanto o SurfaceView possui uma implementação mais simples, custa menos GPU e o seu framerate é um pouco melhor.

Mão na massa

Chegou a hora de aprender na prática! Vou explicar superficialmente como vai funcionar o processo e depois fazemos um passo a passo. Basicamente, vamos instanciar o serviço de câmera para pegar a imagem vinda do hardware, e essa imagem será vinculada a uma view (eu avisei que seria superficial). Agora vamos ao detalhe.

Antes de tudo, precisamos adicionar as permissões de câmera (claro), senão nada vai funcionar.

Agora, vamos instanciar o CameraManager para termos acesso aos serviços de câmera (Hardware).

Com o CameraManager, temos acesso à lista de câmeras disponíveis no dispositivo atual. Com ela, podemos fazer uma busca para pegar o ID da câmera que desejamos, no caso a traseira, e para isso faremos comparações por meio do CameraCharacteristics. São várias as características, que podem ser conferidas neste link.

Caso a solução desenvolvida precise mostrar a imagem em um preview, temos que adicionar um callback na view para que ele verifique se ela já está pronta e iniciada, porque sem isso nosso preview não vai funcionar direito. Como mencionado anteriormente, nosso exemplo vai seguir com TextureView e SurfaceView.

a) Preview com TextureView
Nele, vamos adicionar um setSurfaceListener.

O surfaceReadyCallback será o objeto que ficará com o listener do tipo TextureView.SurfaceTextureListener. Ele possui quatro Overrides:

  • onSurfaceTextureSizeChanged;
  • onSurfaceTextureUpdated;
  • onSurfaceTextureDestroyed;
  • onSurfaceTextureAvailable: essa é a que vamos focar! Nela, vamos fazer uma verificação de permissão e chamar a função que acha o ID da câmera traseira.

b) Preview com SurfaceView
Adicionamos um callback no surfaceView.holder.

Neste caso, o surfaceReadyCallback vai receber um SurfaceHolder.Callback, que por sua vez possui três overrides:

  • SurfaceChange;
  • SurfaceDestroyed;
  • SurfaceCreated: é neste que vamos focar. Aqui faremos basicamente a mesma coisa que no TextureView: a verificação das permissões e chamamos a função para buscar o ID da câmera traseira.

Agora vamos à câmera
Os próximos passos são praticamente idênticos, por isso não precisamos mais separar pelas views. Ao invés disso, faremos comentários nas linhas nas quais seja necessária alguma substituição.

Esse helper vai auxiliar no ajuste da imagem no Preview da tela.

Nos exemplos de implementação nas views vamos utilizar a função cameraManager.openCamera. Ela vai receber o ID da câmera traseira que capturamos na função getBackCamera e um stateCallback que possui os seguintes overrides:

  • onDisconnected;
  • onError;
  • onOpened, que é a qual vamos focar. Inserimos alguns comentários no código para facilitar a explicação.

Dentro de onOpened, chamamos a função cameraDevice.createCaptureSession, na qual passamos a lista de previews que desejamos e o captureCallback, que será um objeto do tipo CameraCaptureSession.StateCallback com apenas duas overrides:

  • onconfigureFailed;
  • onConfigured, que vamos focar. Aqui basicamente criamos um createCaptureRequest.

É importante mencionar que neste request podemos passar parâmetros de CaptureRequest, e com eles conseguimos ligar e desligar o flash, autofoco e etc. No nosso caso, apenas ligamos o foco automático. Para mais informações sobre o CaptureRequest entre neste link.

Caso você tenha alguma dúvida de como ficaria o XML, aqui está:

Prontinho, agora a câmera está funcionando!

Se você estiver disposto ou disposta a estudar um pouquinho mais, pode dar uma olhada neste link, com o “Pack Age Summary”, este aqui sobre Capture Request ou este aqui que faz uma análise entre Surface or Texture.

Ficou alguma dúvida ou tem alguma observação? Deixe um comentário! E se você quiser vir aprender junto com a gente aqui na Concrete é só dar uma olhada aqui e se candidatar a uma de nossas vagas. Vamos aprender juntos! Até a próxima!

--

--

Jean Dobler
Accenture Digital Product Dev

Android and FullStack Web developer, World Of Warcraft Lover, Piranha Plant Player(SSBU) and a father of 2 cats