O framework do Android inclui compatibilidade com diversas câmeras e recursos relacionados que os dispositivos oferecem. Com isso, é possível capturar imagens e vídeos nos seus aplicativos. Este documento discute uma abordagem simples e rápida para a captura de imagem e vídeo e destaca uma maneira avançada de criar experiências de câmera personalizadas para os usuários.
Observação:
esta página descreve a classe
Camera
,
que teve o uso suspenso. Recomendamos o uso da biblioteca
CameraX do Jetpack ou, para casos de uso específicos, a
classe
camera2
. Tanto a CameraX quanto a Camera2 funcionam no Android 5.0 (nível 21 da API) e
versões mais recentes.
Confira os recursos relacionados abaixo:
Considerações
Antes de permitir que seu aplicativo use câmeras em dispositivos Android, considere algumas questões sobre como ele pretende usar esse recurso de hardware.
- Exigência de câmera: o uso de uma câmera é tão importante para seu aplicativo que você não quer que ele seja instalado em um dispositivo sem esse recurso? Nesse caso, declare a exigência de câmera no seu manifesto.
- Captura rápida ou câmera personalizada: como o aplicativo usará a câmera? Você tem interesse apenas em capturar um trecho de vídeo ou uma imagem rapidamente, ou o aplicativo oferecerá uma nova forma de usar câmeras? Para registrar um clipe ou tirar uma foto rapidamente, consulte Como usar apps de câmera existentes. Para desenvolver um recurso de câmera personalizado, confira a seção Como criar um app de câmera.
- Exigência de serviços em primeiro plano: quando o app interage com a câmera? No Android 9 (nível 28 da API) e versões mais recentes, os apps que operam em segundo plano não podem acessar a câmera. Portanto, use a câmera quando o app estiver em primeiro plano ou como parte de um serviço em primeiro plano.
- Armazenamento: os vídeos ou imagens gerados têm como finalidade ficar visíveis somente para seu aplicativo ou serão compartilhados para que outros apps, como a Galeria e outros aplicativos sociais e de mídia, possam usá-los? Você quer manter as imagens e os vídeos disponíveis mesmo após o aplicativo ser desinstalado? Confira a seção Como salvar arquivos de mídia para ver como implementar essas opções.
Noções básicas
O framework do Android é compatível com a captura de imagens e vídeos pela API
android.hardware.camera2
ou pela Intent
da câmera. Estas são as classes
relevantes:
android.hardware.camera2
- Esse pacote é a API principal para controle de câmeras do dispositivo. Ele pode ser usado para registrar fotos ou vídeos durante a criação de um aplicativo de câmera.
Camera
- Essa classe é a antiga API suspensa para controle de câmeras do dispositivo.
SurfaceView
- Essa classe é usada para apresentar uma visualização da câmera em tempo real ao usuário.
MediaRecorder
- Classe usada para gravar vídeo da câmera.
Intent
- Um tipo de ação da intent de
MediaStore.ACTION_IMAGE_CAPTURE
ouMediaStore.ACTION_VIDEO_CAPTURE
que pode ser usado para capturar imagens ou vídeos sem usar o objetoCamera
diretamente.
Declarações do manifesto
Antes de começar o desenvolvimento no seu aplicativo com a API Camera, confirme se o manifesto tem as declarações adequadas para permitir o uso do hardware da câmera e outros recursos relacionados.
- Permissão da câmera: o app precisa solicitar permissão para usar um dispositivo.
câmera.
<uses-permission android:name="android.permission.CAMERA" />
Observação: se você estiver usando a câmera invocando um app de câmera existente, seu aplicativo não precisará solicitar essa permissão.
- Recursos de câmera: seu aplicativo também precisa declarar o uso dos recursos de câmera.
Por exemplo:
<uses-feature android:name="android.hardware.camera" />
Para uma lista de recursos de câmera, consulte a Referência de recursos do manifesto.
A adição de recursos de câmera ao manifesto faz com que o Google Play impeça que o aplicativo seja instalado em dispositivos que não tenham uma câmera ou não sejam compatíveis com os recursos especificados. Para saber mais sobre como usar o filtro de recursos com o Google Play, consulte Google Play e filtros com base em recurso.
Caso o aplicativo possa usar uma câmera ou um recurso relacionado para operação adequada, mas isso não seja obrigatório, especifique essa informação no manifesto incluindo o atributo
android:required
e o definindo comofalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Permissão de armazenamento: o aplicativo pode salvar imagens ou vídeos no
o armazenamento externo (cartão SD) do dispositivo, caso ele seja destinado ao Android 10 (nível 29 da API) ou
inferior e especifica o seguinte no manifesto.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Permissão para gravação de áudio: para gravar áudio com captura de vídeo, seu
aplicativo deve solicitar a permissão de captura de áudio.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
Permissão de localização: caso o aplicativo marque imagens com informações de localização do GPS, você precisará solicitar a permissão
ACCESS_FINE_LOCATION
. Se o aplicativo for direcionado ao Android 5.0 (nível 21 da API) ou versões mais recentes, também será necessário declarar que ele usa o GPS do dispositivo.<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
Para saber mais sobre o acesso à localização do usuário, consulte Estratégias de localização.
Como usar apps de câmera existentes
Uma forma rápida de permitir que o aplicativo registre fotos ou vídeos sem muitos códigos extras
é usar uma Intent
para invocar um aplicativo de câmera Android já existente.
Os detalhes são descritos nas lições de treinamento
Como tirar fotos de forma simples e
Como gravar vídeos de forma simples.
Como criar um app de câmera
Alguns desenvolvedores podem precisar de uma interface do usuário de câmera que seja personalizada de acordo com o visual do aplicativo deles ou que ofereça recursos especiais. Escrever seu próprio código para tirar fotos pode proporcionar uma experiência mais interessante aos usuários.
Observação: o guia a seguir é destinado à antiga API Camera
de uso suspenso. Para aplicativos de câmera novos ou avançados, é recomendável usar a API android.hardware.camera2
mais recente.
Estas são as etapas gerais para a criação de uma interface de câmera personalizada para seu aplicativo:
- Detectar e acessar a câmera: crie um código para verificar a existência de câmeras e solicitar acesso.
- Criar uma classe de visualização: crie uma classe de visualização da câmera que estenda a
SurfaceView
e implemente a interfaceSurfaceHolder
. Essa classe exibe as imagens em tempo real da câmera. - Criar um layout de visualização: depois de criar a classe de visualização da câmera, crie um layout que incorpore a visualização e os controles da interface do usuário que você quiser.
- Configurar listeners para a captura: conecte listeners aos seus controles de interface para iniciar a captura de imagem ou vídeo em resposta às ações do usuário, como o pressionamento de um botão.
- Capturar e salvar arquivos: configure o código para capturar fotos ou vídeos e salvar a saída.
- Liberar a câmera: depois de usar a câmera, seu aplicativo precisa liberá-la corretamente para uso em outros aplicativos.
O hardware da câmera é um recurso compartilhado que precisa ser gerenciado cuidadosamente para que seu aplicativo não entre em conflito com outros que também possam querer usá-lo. As seções a seguir discutem como detectar o hardware da câmera, como solicitar acesso a uma câmera, como capturar imagens ou vídeos e como liberar a câmera quando o aplicativo terminar de usá-la.
Aviso: lembre-se de liberar o objeto Camera
chamando Camera.release()
quando seu
aplicativo terminar de usá-lo. Se a câmera não for liberada adequadamente, todas
as tentativas subsequentes de acesso a ela, inclusive as feitas pelo seu aplicativo, falharão. Isso pode
fazer com que os aplicativos sejam encerrados.
Detecção do hardware da câmera
Caso seu aplicativo não exija especificamente uma câmera usando uma declaração de manifesto, confirme
se há uma câmera disponível no ambiente de execução. Para fazer essa verificação, use o método PackageManager.hasSystemFeature()
, conforme exibido no código de exemplo abaixo:
Kotlin
/** Check if this device has a camera */ private fun checkCameraHardware(context: Context): Boolean { if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // this device has a camera return true } else { // no camera on this device return false } }
Java
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
Os dispositivos Android podem ter várias câmeras. Por exemplo, uma câmera traseira para fotos e outra
frontal para videochamadas. No Android 2.3 (nível 9 da API) e em versões mais recentes, é possível conferir a
quantidade de câmeras disponíveis em um dispositivo com o método Camera.getNumberOfCameras()
.
Como acessar as câmeras
Se você determinou que o dispositivo em que o aplicativo está operando tem uma câmera, é
necessário solicitar acesso a ela com uma instância de Camera
, a menos que você
esteja usando uma intent para acessar a câmera.
Para acessar a câmera principal, use o método Camera.open()
e registre qualquer exceção, conforme mostrado no código abaixo:
Kotlin
/** A safe way to get an instance of the Camera object. */ fun getCameraInstance(): Camera? { return try { Camera.open() // attempt to get a Camera instance } catch (e: Exception) { // Camera is not available (in use or does not exist) null // returns null if camera is unavailable } }
Java
/** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable }
Aviso: sempre verifique as exceções ao usar Camera.open()
. Se você não fizer isso e a câmera já estiver em
uso ou não existir, seu aplicativo será encerrado pelo sistema.
Nos dispositivos com o Android 2.3 (nível 9 da API) ou versões mais recentes, é possível acessar câmeras específicas usando
Camera.open(int)
. O código de exemplo acima acessará
a primeira câmera traseira em dispositivos com mais de uma câmera.
Como verificar os recursos de câmera
Após conseguir o acesso à câmera, você pode ver mais informações sobre os recursos dela usando
o método Camera.getParameters()
e verificando o
objeto Camera.Parameters
retornado dos recursos compatíveis. A partir do
nível 9 da API, use Camera.getCameraInfo()
para determinar se uma câmera está na parte frontal
ou traseira do dispositivo e a orientação da imagem.
Como criar uma classe de visualização
Para que os usuários registrem fotos ou vídeos de forma eficaz, eles precisam ver o que a câmera do dispositivo está
capturando. Uma classe de visualização da câmera é uma SurfaceView
que pode exibir os dados de imagem
em tempo real de uma câmera para que os usuários possam enquadrar uma foto ou um vídeo.
O código de exemplo a seguir demonstra como criar uma classe básica de visualização da câmera que pode ser
incluída em um layout View
. Essa classe implementa SurfaceHolder.Callback
para capturar os eventos de callback
que criam e destroem a visualização. Eles são necessários para atribuir a entrada de visualização da câmera.
Kotlin
/** A basic Camera preview class */ class CameraPreview( context: Context, private val mCamera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val mHolder: SurfaceHolder = holder.apply { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. addCallback(this@CameraPreview) // deprecated setting, but required on Android versions prior to 3.0 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } override fun surfaceCreated(holder: SurfaceHolder) { // The Surface has been created, now tell the camera where to draw the preview. mCamera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // empty. Take care of releasing the Camera preview in your activity. } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.surface == null) { // preview surface does not exist return } // stop preview before making changes try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings mCamera.apply { try { setPreviewDisplay(mHolder) startPreview() } catch (e: Exception) { Log.d(TAG, "Error starting camera preview: ${e.message}") } } } }
Java
/** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } }
Caso você queira configurar um tamanho específico para a visualização da câmera, defina essa informação no método surfaceChanged()
, conforme observado nos comentários acima. Ao configurar o tamanho da visualização, é
necessário usar valores de getSupportedPreviewSizes()
.
Não defina valores arbitrários no método setPreviewSize()
.
Observação:
com a introdução do recurso
Várias janelas no Android 7.0 (nível 24 da API) e versões mais recentes, não é mais
possível presumir que a proporção da visualização é a mesma que a da sua atividade,
mesmo depois de chamar setDisplayOrientation()
.
Dependendo proporção e do tamanho da janela, pode ser necessário ajustar uma
visualização de câmera ampla em um layout de retrato, ou vice-versa, usando um
layout com efeito letterbox.
Como posicionar a visualização em um layout
Uma classe de visualização da câmera, como o exemplo exibido na seção anterior, precisa ser posicionada no layout de uma atividade com outros controles da interface do usuário para registrar uma foto ou um vídeo. Esta seção demonstra como criar uma atividade e um layout básico para a visualização.
O código de layout a seguir fornece uma exibição muito básica que pode ser usada para mostrar uma visualização
da câmera. Neste exemplo, o elemento FrameLayout
serve como
contêiner para a classe de visualização da câmera. Esse tipo de layout é usado para que os controles ou as informações extras da imagem
possam ser sobrepostos nas imagens de visualização da câmera em tempo real.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
Na maioria dos dispositivos, a orientação padrão da visualização da câmera é paisagem. Esse layout de exemplo especifica uma disposição horizontal (paisagem), e o código abaixo corrige a orientação do aplicativo para paisagem. Para simplificar a renderização do que é exibido em uma câmera, mude a orientação da atividade de visualização do aplicativo para paisagem adicionando as informações a seguir ao manifesto.
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
Observação: uma visualização da câmera não precisa estar no modo paisagem.
A partir do Android 2.2 (nível 8 da API), é possível usar o método setDisplayOrientation()
para definir a
rotação da imagem de visualização. Para mudar a orientação da visualização à medida que o usuário muda o
posicionamento do smartphone, primeiro interrompa a exibição com Camera.stopPreview()
no método surfaceChanged()
da classe de visualização e mude a orientação. Depois, reinicie a visualização com Camera.startPreview()
.
Na atividade da visualização da câmera, adicione sua classe de visualização ao elemento FrameLayout
mostrado no exemplo acima. A atividade, ao ser pausada ou encerrada, também
precisa garantir a liberação da câmera. O exemplo a seguir mostra como
modificar a atividade de uma câmera para adicionar a classe de visualização exibida em Como criar
uma classe de visualização.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? = null private var mPreview: CameraPreview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create an instance of Camera mCamera = getCameraInstance() mPreview = mCamera?.let { // Create our Preview view CameraPreview(this, it) } // Set the Preview view as the content of our activity. mPreview?.also { val preview: FrameLayout = findViewById(R.id.camera_preview) preview.addView(it) } } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
Observação: o método getCameraInstance()
no exemplo acima
se refere ao exemplo mostrado em Como acessar as câmeras.
Como capturar imagens
Após criar uma classe de visualização e um layout para exibi-la, você pode começar a capturar imagens com o aplicativo. No código do aplicativo, é necessário configurar listeners para os controles da interface do usuário para que eles respondam à ação do usuário tirando uma foto.
Para recuperar uma imagem, use o método Camera.takePicture()
. Esse método usa três parâmetros que recebem dados da câmera.
Para receber os dados em formato JPEG, você precisa implementar uma interface Camera.PictureCallback
para receber os dados da imagem e
gravá-los em um arquivo. O código a seguir mostra uma implementação básica da interface Camera.PictureCallback
para salvar uma imagem recebida da câmera.
Kotlin
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Java
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
Para acionar a captura de uma imagem, chame o método Camera.takePicture()
. O código de exemplo a seguir mostra como chamar esse método com um
botão View.OnClickListener
.
Kotlin
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Java
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
Observação: o membro mPicture
no exemplo a seguir se refere
ao código de exemplo acima.
Aviso: lembre-se de liberar o objeto Camera
chamando Camera.release()
quando seu
aplicativo terminar de usá-lo. Para saber mais sobre como liberar a câmera, consulte Como liberar a câmera.
Como capturar vídeos
A captura de vídeos com o framework do Android requer gerenciamento cuidadoso do objeto Camera
e a coordenação com a classe
MediaRecorder
. Ao gravar vídeos com Camera
, é necessário gerenciar as chamadas Camera.lock()
e Camera.unlock()
para permitir o acesso de MediaRecorder
ao hardware da câmera,
além das chamadas Camera.open()
e Camera.release()
.
Observação: a partir do Android 4.0 (nível 14 da API), as chamadas Camera.lock()
e Camera.unlock()
são automaticamente gerenciadas para você.
Diferentemente do que ocorre com a ação de tirar fotos pela câmera de um dispositivo, a captura de vídeos exige um pedido de chamada muito particular. É necessário seguir um pedido de execução específico para o preparo e a captura de vídeos com o aplicativo, conforme detalhado abaixo.
- Abrir a câmera: use
Camera.open()
para acessar uma instância do objeto da câmera. - Conectar a visualização: prepare uma visualização da imagem em tempo real conectando uma
SurfaceView
à câmera usandoCamera.setPreviewDisplay()
. - Iniciar a visualização: chame
Camera.startPreview()
para começar a exibir as imagens da câmera em tempo real. - Iniciar a gravação de vídeos: as etapas a seguir precisam ser concluídas na
ordem para que os vídeos sejam gravados corretamente:
- Desbloquear a câmera: desbloqueie a câmera para que o
MediaRecorder
possa usá-la. Para isso, chameCamera.unlock()
. - Configurar o MediaRecorder: chame os métodos
MediaRecorder
a seguir nesta ordem. Para saber mais, consulte a documentação de referência doMediaRecorder
.setCamera()
: define a câmera que será usada na captura de vídeos. Use a instância deCamera
atual do aplicativo.setAudioSource()
: define a fonte de áudio. UseMediaRecorder.AudioSource.CAMCORDER
.setVideoSource()
: define a fonte de vídeo. UseMediaRecorder.VideoSource.CAMERA
.- Define a codificação e o formato da saída de vídeo. Para o Android 2.2 (nível 8 da API) e
versões mais recentes, use o método
MediaRecorder.setProfile
e acesse uma instância de perfil usandoCamcorderProfile.get()
. Para versões do Android anteriores à 2.2, é necessário definir os parâmetros de codificação e o formato da saída de vídeo:setOutputFormat()
: define o formato de saída. Especifique a configuração padrão ouMediaRecorder.OutputFormat.MPEG_4
.setAudioEncoder()
: define o tipo de codificação do áudio. Especifique a configuração padrão ouMediaRecorder.AudioEncoder.AMR_NB
.setVideoEncoder()
: define o tipo de codificação do vídeo. Especifique a configuração padrão ouMediaRecorder.VideoEncoder.MPEG_4_SP
.
setOutputFile()
: define o arquivo de saída. UsegetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
do método de exemplo na seção Como salvar arquivos de mídia.setPreviewDisplay()
: especifica o elemento de layout da visualizaçãoSurfaceView
para o aplicativo. Use o mesmo objeto especificado em Conectar a visualização.
Cuidado: você precisa chamar esses métodos de configuração
MediaRecorder
nesta ordem. Caso contrário, seu aplicativo apresentará erros e a gravação falhará. - Preparar o MediaRecorder: prepare o
MediaRecorder
com as definições de configuração fornecidas. Para isso, chameMediaRecorder.prepare()
. - Iniciar o MediaRecorder: chame
MediaRecorder.start()
para iniciar a gravação de vídeos.
- Desbloquear a câmera: desbloqueie a câmera para que o
- Interromper a gravação de vídeos: chame os métodos a seguir nesta ordem para
finalizar a gravação de um vídeo corretamente:
- Interromper o MediaRecorder: para interromper a gravação de vídeos, chame
MediaRecorder.stop()
. - Redefinir o MediaRecorder: você tem a opção de remover as definições de configuração do
gravador. Para isso, chame
MediaRecorder.reset()
. - Liberar o MediaRecorder: para liberar o
MediaRecorder
, chameMediaRecorder.release()
. - Bloquear a câmera: bloqueie a câmera para que as sessões futuras do
MediaRecorder
possam usá-las. Para isso, chameCamera.lock()
. A partir do Android 4.0 (nível 14 da API), essa chamada não é obrigatória, a não ser que haja falha na chamada deMediaRecorder.prepare()
.
- Interromper o MediaRecorder: para interromper a gravação de vídeos, chame
- Interromper a visualização: quando a atividade deixar de usar a câmera, use
Camera.stopPreview()
para interromper a visualização. - Liberar a câmera: chame
Camera.release()
para liberar o uso da câmera para outros aplicativos.
Observação: é possível usar o MediaRecorder
sem antes criar uma visualização da câmera e pular as primeiras etapas desse processo. No entanto,
como os usuários geralmente preferem acessar uma visualização antes de começar a gravar, isso não
é discutido aqui.
Dica: se o aplicativo costuma ser usado para gravar vídeos, defina
setRecordingHint(boolean)
como true
antes de iniciar a
visualização. Essa configuração pode ajudar a reduzir o tempo decorrido até o início da gravação
Configuração do MediaRecorder
Ao usar a classe MediaRecorder
para gravar vídeos, é necessário seguir
as etapas de configuração em uma ordem específica e, em seguida, chamar o método MediaRecorder.prepare()
para verificar e implementar a
configuração. O código de exemplo a seguir demonstra como configurar e preparar a classe
MediaRecorder
de forma adequada para a gravação de vídeos.
Kotlin
private fun prepareVideoRecorder(): Boolean { mediaRecorder = MediaRecorder() mCamera?.let { camera -> // Step 1: Unlock and set camera to MediaRecorder camera?.unlock() mediaRecorder?.run { setCamera(camera) // Step 2: Set sources setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Step 4: Set output file setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Step 5: Set the preview output setPreviewDisplay(mPreview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Step 6: Prepare configured MediaRecorder return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } } } return false }
Java
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } return true; }
Antes do Android 2.2 (nível 8 da API), é necessário definir diretamente os parâmetros
de formatos de codificação e saída, em vez de usar CamcorderProfile
. Essa abordagem é
demonstrada no código a seguir:
Kotlin
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder?.apply { setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) }
Java
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
Os parâmetros de gravação de vídeos a seguir para MediaRecorder
são
as configurações padrão fornecidas. No entanto, é recomendável que você ajuste essas configurações de acordo com seu aplicativo:
setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()
Como iniciar e interromper o MediaRecorder
Ao iniciar e interromper a gravação de vídeos com a classe MediaRecorder
,
é necessário seguir uma ordem específica, conforme listado abaixo.
- Desbloqueie a câmera com
Camera.unlock()
. - Configure o
MediaRecorder
conforme demonstrado no exemplo de código acima. - Inicie a gravação com
MediaRecorder.start()
. - Grave o vídeo.
- Interrompa a gravação com
MediaRecorder.stop()
. - Libere o gravador de mídia com
MediaRecorder.release()
. - Bloqueie a câmera com
Camera.lock()
.
O código de exemplo a seguir demonstra como definir um botão para iniciar e interromper
corretamente a gravação de vídeos com a câmera e a classe MediaRecorder
.
Observação: ao concluir a gravação de um vídeo, não libere a câmera. Caso contrário, a visualização será interrompida.
Kotlin
var isRecording = false val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { if (isRecording) { // stop recording and release camera mediaRecorder?.stop() // stop the recording releaseMediaRecorder() // release the MediaRecorder object mCamera?.lock() // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture") isRecording = false } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder?.start() // inform the user that recording has started setCaptureButtonText("Stop") isRecording = true } else { // prepare didn't work, release the camera releaseMediaRecorder() // inform user } } }
Java
private boolean isRecording = false; // Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
Observação: no exemplo acima, o método prepareVideoRecorder()
se refere ao código de exemplo demonstrado em Como configurar o MediaRecorder. Esse método lida com o bloqueio
da câmera, com a configuração e com o preparo da instância MediaRecorder
.
Como liberar a câmera
As câmeras são um recurso compartilhado pelos aplicativos em um dispositivo. O aplicativo pode
usar a câmera depois de receber uma instância de Camera
. É preciso ter
atenção especial ao liberar um objeto de câmera quando o aplicativo para de usá-lo e
assim que o aplicativo é pausado (Activity.onPause()
). Se
o aplicativo não liberar a câmera corretamente, todas as tentativas de acesso a ela,
incluindo as feitas pelo seu próprio aplicativo, falharão. Isso pode fazer com que o seu ou outros aplicativos sejam
encerrados.
Para liberar uma instância do objeto Camera
, use o método Camera.release()
, conforme mostrado no código de exemplo abaixo.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? private var preview: SurfaceView? private var mediaRecorder: MediaRecorder? override fun onPause() { super.onPause() releaseMediaRecorder() // if you are using MediaRecorder, release it first releaseCamera() // release the camera immediately on pause event } private fun releaseMediaRecorder() { mediaRecorder?.reset() // clear recorder configuration mediaRecorder?.release() // release the recorder object mediaRecorder = null mCamera?.lock() // lock camera for later use } private fun releaseCamera() { mCamera?.release() // release the camera for other applications mCamera = null } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView preview; private MediaRecorder mediaRecorder; ... @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
Aviso: se o aplicativo não liberar a câmera corretamente, todas as tentativas de acesso a ela, incluindo as feitas pelo seu próprio aplicativo, falharão. Isso pode fazer com que o seu ou outros aplicativos sejam encerrados.
Como salvar arquivos de mídia
Arquivos de mídia criados pelos usuários, como fotos e vídeos, precisam ser salvos em um diretório de armazenamento externo (cartão SD) do dispositivo. Isso economiza espaço no sistema e permite o acesso a esses arquivos mesmo quando o usuário não está com o aparelho. Em um dispositivo, há diversos locais de diretório onde é possível salvar os arquivos de mídia. No entanto, há somente dois locais padrão a serem considerados pelos desenvolvedores:
Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_PICTURES
): esse método retorna o local padrão, compartilhado e recomendado para salvar imagens e vídeos. Esse diretório é compartilhado (público), então os outros aplicativos podem descobrir, ler, modificar e excluir facilmente os arquivos salvos nesse local. Se o aplicativo for desinstalado pelo usuário, os arquivos de mídia salvos ali não serão removidos. Para evitar interferência com as fotos e os vídeos já existentes do usuário, crie um subdiretório para os arquivos de mídia do seu aplicativo dentro desse diretório, conforme demonstrado no exemplo de código abaixo. Esse método está disponível no Android 2.2 (nível 8 da API). Para chamadas equivalentes em versões da API anteriores, consulte Como salvar arquivos compartilhados.Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
):: esse método retorna um local padrão para salvar fotos e vídeos associados ao seu aplicativo. Caso o aplicativo seja desinstalado, todos os arquivos salvos ali serão removidos. A segurança não aplicada para arquivos nesse local, e outros aplicativos podem ler, modificar e excluir esses dados.
O código de exemplo a seguir demonstra como criar um local File
ou Uri
para um arquivo de mídia que possa ser usado ao invocar a câmera de um dispositivo com
uma Intent
ou como parte de Como criar um app
de câmera.
Kotlin
val MEDIA_TYPE_IMAGE = 1 val MEDIA_TYPE_VIDEO = 2 /** Create a file Uri for saving an image or video */ private fun getOutputMediaFileUri(type: Int): Uri { return Uri.fromFile(getOutputMediaFile(type)) } /** Create a File for saving an image or video */ private fun getOutputMediaFile(type: Int): File? { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. val mediaStorageDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" ) // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist mediaStorageDir.apply { if (!exists()) { if (!mkdirs()) { Log.d("MyCameraApp", "failed to create directory") return null } } } // Create a media file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return when (type) { MEDIA_TYPE_IMAGE -> { File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg") } MEDIA_TYPE_VIDEO -> { File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4") } else -> null } }
Java
public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type){ // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { return null; } return mediaFile; }
Observação: Environment.getExternalStoragePublicDirectory()
está disponível no Android 2.2 (nível 8 da API) ou
versões mais recentes. Caso você esteja destinando o app para dispositivos com versões anteriores do Android, use Environment.getExternalStorageDirectory()
. Para saber mais, consulte Como salvar arquivos compartilhados.
Para tornar o URI compatível com os perfis de trabalho, primeiro
converta o URI do arquivo em um URI de conteúdo. Em seguida, adicione o URI de conteúdo ao
EXTRA_OUTPUT
de uma Intent
.
Para saber mais sobre como salvar arquivos em um dispositivo Android, consulte Armazenamento de dados.
Recursos de câmera
O Android é compatível com uma ampla variedade de recursos de câmera que podem ser controlados com seu aplicativo de câmera,
como o formato da foto, o modo do flash, as configurações de foco e muito mais. Esta seção lista os recursos
comuns de câmera e discute brevemente como usá-los. A maioria dos recursos de câmera podem ser acessados e definidos
usando o objeto Camera.Parameters
. No entanto, há diversos
recursos importantes que exigem mais do que configurações simples em Camera.Parameters
. Esses recursos são abordados nas seções a seguir:
Para informações gerais sobre como usar os recursos controlados por Camera.Parameters
, consulte a seção Como usar os recursos
de câmera. Para ver informações mais detalhadas sobre como usar os recursos controlados pelo
objeto de parâmetros da câmera, acesse a documentação
de referência da API nos links da lista de recursos abaixo.
Recurso | Nível da API | Descrição |
---|---|---|
Detecção facial | 14 | Identifica rostos humanos em uma foto e os usa para foco, medição e balanço de branco |
Áreas de medição | 14 | Especifica uma ou mais áreas na imagem para cálculo do balanço de branco |
Áreas de foco | 14 | Define uma ou mais áreas em uma imagem a serem usadas para foco |
White Balance Lock |
14 | Interrompe ou inicia automaticamente os ajustes de balanço de branco |
Exposure Lock |
14 | Interrompe ou inicia automaticamente os ajustes de exposição |
Video Snapshot |
14 | Tira uma foto enquanto grava vídeos (captação de quadro) |
Vídeo em Time Lapse | 11 | Grava quadros com atrasos definidos para criar um vídeo em Time Lapse |
Multiple Cameras |
9 | Compatibilidade com mais de uma câmera no dispositivo, incluindo frontal e traseira |
Focus Distance |
9 | Informa as distâncias entre a câmera e os objetos que parecem estar em foco |
Zoom |
8 | Define a ampliação da imagem |
Exposure
Compensation |
8 | Aumenta ou diminui o nível de exposição à luz |
GPS Data |
5 | Inclui ou omite os dados de localização geográfica relacionados à imagem |
White Balance |
5 | Define o modo de balanço de branco, que afeta os valores de cor na imagem capturada |
Focus Mode |
5 | Define o foco da câmera em um tema, como automático, fixo, macro ou infinito |
Scene Mode |
5 | Aplica um modo de predefinição para tipos específicos de situações fotográficas, como cenas noturnas, de praia, de neve ou à luz de velas |
JPEG Quality |
5 | Define o nível de compressão para uma imagem JPEG, que aumenta ou diminui a qualidade e o tamanho do arquivo de saída da imagem |
Flash Mode |
5 | Ativa e desativa o flash ou usa a configuração automática |
Color Effects |
5 | Aplica um efeito de cor à imagem capturada, como preto e branco, tom sépia ou negativo |
Anti-Banding |
5 | Reduz o efeito das faixas nos gradientes de cor devido à compressão JPEG |
Picture Format |
1 | Especifica o formato do arquivo para a imagem |
Picture Size |
1 | Especifica as dimensões de pixel da imagem salva |
Observação: esses recursos não são compatíveis com todos os dispositivos devido às diferenças de hardware e à implementação de software. Para informações sobre como conferir a disponibilidade de recursos no dispositivo em que o aplicativo está operando, consulte Como conferir a disponibilidade do recurso.
Como conferir a disponibilidade do recurso
A primeira coisa a se entender durante a definição de uso dos recursos de câmera nos dispositivos Android é que nem todos esses recursos são compatíveis com todos os dispositivos. Além disso, os dispositivos compatíveis com um recurso específico podem oferecer compatibilidade com ele em níveis distintos ou com opções diferentes. Assim, parte do seu processo de decisão durante o desenvolvimento de um aplicativo de câmera é com relação a com quais recursos de câmera você quer oferecer compatibilidade e em qual nível isso ocorrerá. Após decidir, planeje a inclusão do código no seu aplicativo de câmera para conferir se o hardware do dispositivo é compatível com esses recursos e para que ocorra a falha correta se algum deles estiver ausente.
Acesse uma instância do objeto
de parâmetros de uma câmera e confira os métodos relevantes para verificar a disponibilidade dos recursos de câmera. A amostra de código a seguir mostra como acessar um objeto
Camera.Parameters
e verificar se a câmera é compatível com o recurso de foco
automático:
Kotlin
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
A técnica exibida acima pode ser usada para a maioria dos recursos de câmera. O objeto
Camera.Parameters
fornece um método getSupported...()
, is...Supported()
ou getMax...()
para determinar se (e até que ponto) um recurso é
compatível.
Caso o aplicativo exija determinados recursos de câmera para funcionar corretamente, você pode solicitá-los fazendo adições ao manifesto do aplicativo. Ao declarar o uso de recursos de câmera específicos, como flash e foco automático, o Google Play impede que o aplicativo seja instalado em dispositivos não compatíveis com esses recursos. Para acessar uma lista de recursos de câmera que podem ser declarados no manifesto do app, consulte as Referência de recursos do manifesto.
Como usar os recursos de câmera
A maioria dos recursos de câmera são ativados e controlados por um objeto Camera.Parameters
. Para usar esse objeto, primeiro acesse uma instância do
Camera
, chamando o método getParameters()
, modificando o objeto
de parâmetro retornado e o definindo novamente no objeto de câmera, conforme demonstrado no código
de exemplo a seguir:
Kotlin
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
Essa técnica funciona para quase todos os recursos de câmera, e a maioria dos parâmetros podem ser modificados a qualquer
momento depois que você receber uma instância do objeto Camera
. As mudanças
nos parâmetros costumam ficar imediatamente visíveis ao usuário na visualização da câmera do aplicativo.
No lado do software, essas mudanças podem levar vários quadros para serem efetuadas,
à medida que o hardware da câmera processa as novas instruções e, em seguida, envia os dados de imagem atualizados.
Importante: alguns recursos de câmera não podem ser modificados livremente. Em especial, a mudança do tamanho ou da orientação da visualização da câmera requer que você primeiro interrompa a visualização, mude o tamanho dela e a reinicie. A partir do Android 4.0 (nível 14 da API), a orientação da visualização pode ser mudada sem a necessidade de reiniciar a exibição.
Outros recursos de câmera exigem mais códigos para que a implementação ocorra, incluindo estes:
- Áreas de medição e foco
- Detecção facial
- Vídeo em Time Lapse
Nas seções a seguir, é fornecido um rápido resumo de como implementar esses recursos.
Áreas de medição e foco
Em alguns cenários de fotografia, o foco automático e a medição de luz podem não produzir os resultados desejados. A partir do Android 4.0 (nível 14 da API), o aplicativo de câmera pode oferecer outros controles para permitir que seu app ou os usuários especifiquem áreas em uma imagem que serão usadas para determinar as configurações de foco ou de nível de iluminação. Esses valores são transmitidos ao hardware da câmera para serem usados na captura de imagens ou vídeos.
As áreas de medição e foco funcionam de forma muito semelhante a outros recursos de câmera que você controla
com métodos no objeto Camera.Parameters
. O código a seguir
demonstra a configuração de duas áreas de medição da luz para uma instância de
Camera
:
Kotlin
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Java
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
O objeto Camera.Area
contém dois parâmetros de dados: um objeto Rect
para especificar uma área no campo de visão da câmera e um valor
de peso, que informa à câmera qual nível de importância essa área receberá na medição de luz
ou no cálculo de foco.
O campo Rect
em um objeto Camera.Area
descreve uma forma retangular mapeada em uma grade de unidade de 2.000 x 2.000. As coordenadas -1.000, -1.000
representam o canto superior esquerdo da imagem da câmera, enquanto as coordenadas 1000, 1000 representam o
canto inferior direito, conforme mostrado na ilustração abaixo.
Os limites desse sistema de coordenadas sempre correspondem à margem externa da imagem visível na
visualização da câmera e não são reduzidos nem aumentados conforme o nível de zoom. De forma semelhante, a rotação da visualização
da imagem com Camera.setDisplayOrientation()
não remapeia o sistema de coordenadas.
Detecção facial
Em fotos que contêm pessoas, os rostos costumam ser a parte mais importante e precisam ser usados para determinar o foco e o balanço de branco durante a captura de uma imagem. O framework do Android 4.0 (nível 14 da API) oferece APIs para identificar rostos e calcular as configurações da foto usando tecnologia de reconhecimento facial.
Observação: quando o recurso de detecção facial está em uso,
setWhiteBalance(String)
,
setFocusAreas(List<Camera.Area>)
e
setMeteringAreas(List<Camera.Area>)
não têm efeito.
O uso do recurso de detecção facial no aplicativo de câmera requer que alguns passos gerais sejam seguidos:
- Verifique se a detecção facial é compatível com o dispositivo.
- Crie um listener de detecção facial.
- Adicione esse listener ao objeto da câmera.
- Inicie a detecção facial após a visualização (e depois que todas as visualizações tiverem sido reiniciadas).
O recurso de detecção facial não é compatível com todos os dispositivos. Você pode confirmar se há
compatibilidade chamando getMaxNumDetectedFaces()
. Um
exemplo dessa confirmação é mostrado no método de amostra startFaceDetection()
abaixo.
Para ser notificado e responder à detecção de um rosto, o aplicativo de câmera precisa definir
um listener para eventos de detecção facial. Para fazer isso, você precisa criar uma classe de listener que
implemente a interface Camera.FaceDetectionListener
, conforme exibido no
código de exemplo abaixo.
Kotlin
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Java
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
Depois de criar essa classe, defina-a no objeto
Camera
do aplicativo, conforme demonstrado no código de exemplo abaixo:
Kotlin
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
camera.setFaceDetectionListener(new MyFaceDetectionListener());
O aplicativo precisa iniciar a função de detecção facial sempre que você iniciar (ou reiniciar) a visualização da câmera. Crie um método para iniciar a detecção facial e poder chamá-la sempre que for necessário, conforme mostrado no código de exemplo abaixo.
Kotlin
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Java
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
É necessário iniciar a detecção facial todas as vezes que você iniciar (ou reiniciar) a visualização da câmera. Se
você usar a classe de visualização exibida em Como criar uma classe de visualização, adicione o método
startFaceDetection()
aos métodos
surfaceCreated()
e surfaceChanged()
na sua classe de visualização,
conforme demonstrado na amostra de código abaixo.
Kotlin
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Java
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
Observação: lembre-se de chamar esse método depois de chamar startPreview()
. Não tente iniciar a detecção facial no
método onCreate()
da atividade principal do aplicativo de câmera,
uma vez que a visualização ainda não estará disponível na execução do app.
Vídeo em Time Lapse
Os vídeos em Time Lapse permitem que os usuários criem trechos de vídeo que combinam fotos tiradas com alguns segundos ou
minutos de diferença. Esse recurso usa MediaRecorder
para gravar as imagens para uma sequência de Time
Lapse.
Para gravar um vídeo desse tipo com o MediaRecorder
, configure o
objeto gravador como se estivesse gravando um vídeo normal, definindo os quadros por segundo com um
número baixo e usando uma das configurações de qualidade de Time Lapse, conforme mostrado no exemplo de código abaixo.
Kotlin
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Java
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
Essas definições precisam ser feitas como parte de um procedimento de configuração maior para o MediaRecorder
. Para ver um exemplo de código de configuração completo, consulte Como configurar o MediaRecorder. Depois de concluir a configuração,
inicie a gravação do vídeo, como se fosse um trecho de vídeo normal. Para ver mais informações
sobre a configuração e execução do MediaRecorder
, consulte Como capturar vídeos.
As amostras Camera2Video e HdrViewfinder (links em inglês) demonstram melhor o uso das APIs abordadas nesta página.
Campos de câmera que exigem permissão
Os apps executados no Android 10 (nível 29 da API) ou versões mais recentes precisam ter a permissão
CAMERA
para
acessar os valores dos seguintes campos que o
getCameraCharacteristics()
retorna:
LENS_POSE_ROTATION
LENS_POSE_TRANSLATION
LENS_INTRINSIC_CALIBRATION
LENS_RADIAL_DISTORTION
LENS_POSE_REFERENCE
LENS_DISTORTION
LENS_INFO_HYPERFOCAL_DISTANCE
LENS_INFO_MINIMUM_FOCUS_DISTANCE
SENSOR_REFERENCE_ILLUMINANT1
SENSOR_REFERENCE_ILLUMINANT2
SENSOR_CALIBRATION_TRANSFORM1
SENSOR_CALIBRATION_TRANSFORM2
SENSOR_COLOR_TRANSFORM1
SENSOR_COLOR_TRANSFORM2
SENSOR_FORWARD_MATRIX1
SENSOR_FORWARD_MATRIX2
Outra amostra de código
Para fazer o download de apps de amostra, consulte a amostra Camera2Basic e o app de amostra oficial do CameraX (links em inglês).