O framework do Android inclui suporte para várias câmeras e recursos de câmera disponíveis em dispositivos diversos, permitindo que você capture imagens e vídeos em suas aplicações. Esse artigo irá mostra de forma rápida e simples como capturar imagens e vídeos e mostrará uma abordagem avançada para criar experiências personalizadas utilizando a câmera aos usuários de seu aplicativo.
Considerações
Antes de permitir que sua aplicação use a câmera do dispositivo Android, você deve considerar algumas poucas questões sobre como seu aplicativo pretende usar esse recurso de hardware.
- Obrigatoriedade da Câmera – O uso da câmera é importante o bastante para sua aplicação de forma que você não queira permitir que ela seja instalada em dispositivos que não possuam câmera? Em caso positivo, você deve declarar a obrigatoriedade da câmera em seu manifesto.
- Imagem rápida ou câmera personalizada – Como a sua aplicação usará a câmera? Você está interessado apenas em obter uma imagem ou vídeo de forma rápida ou sua aplicação fornecerá uma nova forma de usar a câmera? Para obter uma imagem ou vídeo de forma rápida, considere os procedimentos descritos na seção Usando aplicativos existentes de câmera. Para desenvolver um recurso personalizado, cheque a seção Criando um aplicativo de câmera.
- Armazenamento – As imagens e vídeos geradas pela sua aplicação devem estar disponíveis apenas para ela ou devem ser compartilhadas como outros aplicativos, como o Gallery ou outro tipo de aplicativo? Você quer que as imagens e vídeos permaneçam disponíveis mesmo após a remoção do aplicativo? Veja a seção Salvando os arquivos para ver como implementar essas opções.
O básico
O framework do Android suporta a captura de imagens e vídeos através da API Camera
ou do Intent
da câmera. Abaixo seguem as classes relevantes:
Camera
Essa classe é a API primária para controlar a câmera do dispositivo. Essa classe é usada para tirar fotos e vídeos quando se está construindo uma aplicação de câmera.
SurfaceView
Essa classe é usada para apresentar a pré-visualização da câmera ao usuário.
MediaRecorder
Essa classe é usada para gravar vídeo a partir da câmera.
Intent
Um intent do tipo
MediaStore.ACTION_IMAGE_CAPTURE
ou MediaStore.ACTION_VIDEO_CAPTURE
pode ser usado para capturar imagens e vídeos sem usar diretamente o objeto Camera
.
Declarações no Manifesto
Antes de começar o desenvolvimento de sua aplicação com a API da Câmera, você precisa se certificar que o seu arquivo de manifesto possui as declarações necessárias para permitir o uso do hardware da câmera e outros recursos relacionados.
- Permissões da Câmera – Sua aplicação precisa requerer permissão para usar a câmera do dispositivo.
<uses-permission android:name="android.permission.CAMERA" />
Nota: Se você estiver usando a câmera via intent, não precisa dessa permissão.
- Recursos da Câmera – Sua aplicação precisa declarar o uso do recursos da câmera, por exemplo:
<uses-feature android:name="android.hardware.camera" />
Para uma lista de recursos de câmera, veja o manifesto Features Reference.
Adicionar recursos de câmera ao seu manifesto faz com que o Google Play evite que sua aplicação seja instalada em dispositivos que não suportem os recursos de câmera que você especificar. Para mais informações sobre o filtro baseado nos recursos utilizados do Google Play, veja Google Play and Feature-Based Filtering.
Se a sua aplicação puder usar uma câmera ou um recurso da câmera para operar de forma adequada, mas não necessitar desse recurso você deve especificar isso no manifesto pela inclusão do atributoandroid:required
e o ajuste dele para o valorfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Permissões para armazenamento – Se a sua aplicação salva as imagens e vídeos no armazenamento externo (Cartão SD), você deve especificar isso no manifesto.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Permissões para gravação de áudio – Para gravar áudio junto com o vídeo capturado, sua aplicação precisa requerer permissão para captura de áudio.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
- Permissão para Geolocalização – Se sua aplicação anexa a geolocalização da imagem junto com ela, precisa requisitar permissão para geolocalização:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Usando Aplicativos de Câmera existentes
Uma forma rápida para permitir que a sua aplicação tirar fotos ou vídeos sem ter que criar muito código extra é usar um Intent para invocar uma aplicação de câmera existente do Android. Um intent de câmera faz uma requisição para capturar uma imagem ou clip de vídeo através de uma aplicação de câmera existente e em seguida retorna para a aplicação. Essa seção mostra como capturar uma imagem ou vídeo usando essa técnica.
O procedimento para invocar um intent de câmera segue os seguintes passos:
- Criar um Intent de câmera – Crie um
Intent
que represente uma imagem ou vídeo, usando um desses tipos de intent:MediaStore.ACTION_IMAGE_CAPTURE
– tipo para requisitar uma imagem a partir de uma aplicação de câmera existente.MediaStore.ACTION_VIDEO_CAPTURE
– tipo para requisitar um vídeo a partir de uma aplicação de câmera existente.
- Iniciar o Intent da câmera – Use o método
startActivityForResult()
para executar o intent da câmera. Após iniciar o intent, a interface da Câmera aparece na tela do dispositivo e o usuário pode tirar uma foto ou vídeo. - Recepcionar o Resultado da Intent – Configure um método
onActivityResult()
em sua aplicação para receber a resposta e os dados do intent da câmera. Quando o usuário termina de tirar a foto ou vídeo (ou cancela a operação), o sistema chama esse método imediatamente.
Intent de captura de imagem
Capturar imagens usando um intent de câmera é a forma mais rápida de permitir que sua aplicação tire fotos com o mínimo de codificação. Um intent de captura de imagens pode incluir as seguintes informações extras:
MediaStore.EXTRA_OUTPUT
– Esse ajuste necessita de um objetoUri
que especifica um caminho e um nome de arquivo onde você gostaria de salvar a imagem. Essa configuração é opcional mas fortemente recomendada. Se você não precisar especificar esse valor, a aplicação da câmera salva a imagem requisitada no local padrão com um nome padrão, especificado no campoIntent.getData()
dointent.
O exemplo seguinte demonstra como criar um intent de captura de imagem e executá-lo. O método getOutputMediaFileUri()
desse exemplo refere-se ao código fonte exemplo mostrado em Salvando arquivos de mídia.
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private Uri fileUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // create Intent to take a picture and return control to the calling application Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name // start the image capture Intent startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); }
Quando um método startActivityForResult()
é executado, os usuários verão a interface da câmera. Depois que o usuário termina de tirar a foto (ou cancela a operação), a interface retorna para sua aplicação, e você precisa interceptar o método onActivityResult()
para receber o resultado do intent e continuar a execução de sua aplicação. Para informações de como receber o intent completado, veja Receiving camera intent result.
Intent de captura de vídeo
Capturar vídeo usando um intent de câmera é a forma mais rápida de permitir que a sua aplicação tire vídeos com a mínima quantidade de código. Um intent de captura de vídeo pode incluir as seguintes informações extras:
MediaStore.EXTRA_OUTPUT
– Essa configuração necessita de umUri
que especifica um caminho e um nome de arquivo onde você gostaria de salvar o vídeo. Essa configuração é opcional mas fortemente recomendada. Se você não especificar esse valor, a aplicação da Câmera salva o vídeo requisitado no local padrão com um nona padrão especificado no campoIntent.getData()
do intent.MediaStore.EXTRA_VIDEO_QUALITY
– Esse valor pode ser ser 0 para a menor qualidade e arquivos menores ou 1 para para a melhor qualidade e arquivo maiores.MediaStore.EXTRA_DURATION_LIMIT
– Configure esse valor para o limite de tamanho, em segundos, do vídeo a ser capturado.MediaStore.EXTRA_SIZE_LIMIT
– Configure esse valor para o limite, em bytes, do arquivo a ser capturado.
O exemplo a seguir demonstra como criar um intent de captura de vídeo e executa-lo. O método getOutputMediaFileUri()
nesse exemplo refere-se ao código fonte exemplo mostrada em Saving Media Files.
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; private Uri fileUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //create new Intent Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO); // create a file to save the video intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high // start the Video Capture Intent startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE); }
Quando o método startActivityForResult()
é executado, os usuários verão a interface da aplicação de câmera. Depois que o usuário termina de gravar o vídeo (ou cancela a operação), a interface retorna para para sua aplicação, e você precisa interceptar o método onActivityResult()
para receber o resultado do intent e continuar a execução de sua aplicação. Para obter informações de como fazer isso, veja a seção a seguir.
Recebendo o resultado do Intent da câmera
Uma vez que você criou e executou o intent para captura de imagem ou vídeo, sua aplicação precisa estar configurada para receber o resultado do intent. Essa seção descreve como interceptar o resultado de um intent da câmerade forma que sua aplicação possa executar o processamento dessa imagem ou vídeo capturado.
De forma a receber o resultado de um intent, você precisa sobrecarregar o método onActivityResult()
na Activity que iniciou o intent. O exemplo a seguir demonstra como sobrecarregar esse método para capturar o resultado dos exemplos de captura de imagem ou captura de vídeo das seções anteriores.
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // Image captured and saved to fileUri specified in the Intent Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // User cancelled the image capture } else { // Image capture failed, advise user } } if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // Video captured and saved to fileUri specified in the Intent Toast.makeText(this, "Video saved to:\n" + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // User cancelled the video capture } else { // Video capture failed, advise user } } }
Uma vez que a sua Activity receba o resultado com sucesso, a imagem ou vídeo capturado estará disponível no local especificado para acesso pela sua aplicação.
Criando um aplicativo de câmera
Alguns desenvolvedores podem precisar de uma interface de câmera que seja personalizada a aparência de suas aplicações ou forneça recursos especiais. Criar um Activity de câmera personalizada necessita de mais código do que o uso de um intent, mas pode fornecer uma experiência melhor ao usuário.
Os passos gerais para criar uma interface personalizada da câmera para sua aplicação são os seguintes:
- Detectar e acessar a cãmera – Criar o código para verificar a existência de câmeras e solicitar acesso.
- Criar uma classe de pré-visualização – Criar um classe de pré-visualização que estenda
SurfaceView
e implemente a interfaceSurfaceHolder
. Essa classe visualiza imagens ao vivo da cãmera. - Criar o layout da pré-visualização – Uma vez que você tenha a classe de pré-visualização, crie um layout que incorpore a pré-visualização e os controles que você deseja.
- Ajustar os ouvintes para a captura – Conecte os ouvintes para que os controles de sua interface possam iniciar a captura da imagem ou vídeo em resposta a alguma ação, como pressionar um botão.
- Capturar e salvar aqquivos – Configure o código para capturar images e vídeos e salvar a saída.
- Liberar a câmera – Depois de usar a câmera, sua aplicação precisa libera-la adequadamente para que outras aplicações possam usa-la.
O hardware da câmera é um recurso compartilhado que precisa ser gerenciado cuidadosamente de forma que a sua aplicação não colida com outras aplicações que também queiram usa-lo. As seções a seguir discutem como detectar o hardware da câmera, como solicitar acesso a câmera, como capturar imagens e vídeos e como liberar a câmera quando sua aplicação não estiver mais usando ela.
Cuidado: Lembre de liberar o objeto Camera
pela chamada à Camera.release()
quando sua aplicação tiver finalizado o uso da câmera. Se sua aplicação não liberar a câmera adequadamente, todas as tentativas subsequentes de acesso a câmera, incluindo os da sua própria aplicação, irão falhar e podem fazer com que tanto sua aplicação quanto as outras fechem.
Detectando o hardware da câmera
Se a sua aplicação não solicita a câmera usando uma declaração no manifesto, você deve verificar para verificar se existe uma câmera em tempo de execução. Para executar essa checagem, use o método PackageManager.hasSystemFeature()
, como mostrado no código abaixo:
/** 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; } }
Dispositivos Android podem ter múltiplas câmeras, por exemplo, uma câmera na parte de trás para fotografia e uma câmera frontal para videochamadas. O Android 2.3 (API Level 9) e superiores permitem que você verifiquem o número de câmeras disponíveis em um dispositivo usando o método Camera.getNumberOfCameras()
.
Acessando a câmera
Se você determinar que o dispositivo onde sua aplicação está sendo executada possui uma câmera, você precisa solicitar acesso a ela pela obtenção de uma instância de Camera
(a menos que esteja usando um intent de acesso a câmera).
Para acessar a câmera primária, use o método Camera.open()
e certifique-se de capturar qualquer exceção, como mostrado no código abaixo:
/** 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 }
Cuidado: Sempre cheque por exceções quando usar Camera.open()
. Não checar por exceções quando a câmera estiver em uso ou não exista acarretará no encerramento de sua aplicação pelo sistema.
Em dispositivos rodando o Android 2.3 (API Level 9) ou superior, você pode acessar câmeras especificas usando Camera.open(int)
. O exemplo de código acima irá acessar a primeira câmera, na parte de trás, em um dispositivo com mais de uma câmera.
Verificando os recursos da câmera
Uma vez que você tenha obtido a uma câmera, você pode obter informações sobre os seus recursos usando o método Camera.getParameters()
e verificando o retorno do objeto Camera.Parameters
por recursos suportados. Quando estiver usando a API Level 9 ou superior, use Camera.getCameraInfo()
para determinar se a câmera está na parte da frente ou de trás, e a orientação da imagem.
Criando uma classe para pre-visualização
Para que os usuários tirem efetivamente fotos e vídeos, eles precisam serem capazes de ver o que a câmera vê. Uma classe de pré-visualização é um SurfaceView
que pode exibir os dados de imagem vindos da câmera, de forma que os usuários possam enquadrar e capturar um imagem ou vídeo.
O exemplo de código a seguir demonstra como criar uma classe de pré-visualização básica que pode ser incluída em um layout. Essa classe implementa SurfaceHolder.Callback
de forma a poder capturar eventos para a criação e destruição do view, que é necessário para atribuir a entrada da pré-visualização da câmera.
/** 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()); } } }
Se você quiser ajustar um tamanho específico para a pré-visualização da câmera, configure isso no método surfaceChanged()
como observado no comentário acima. Quando ajustar o tamanho da pré-visualização, você precisa usar os valores de getSupportedPreviewSizes()
. Não ajuste o tamanho para valores arbitrários no método setPreviewSize()
.
Colocando a pré-visualização no layout
Uma classe de pré-visualização de câmera, como no exemplo mostrado acima, precisa ser colocada no layout de uma Activity com outros controles para usuário tirar fotos e vídeos. Essa seção mostra como você pode criar um layout básico para a pré-visualização.
O código abaixo fornece um view básico que pode ser usado para exibir a pré-visualização da câmera Nesse exemplo, p elemento FrameLayout
é o contêiner para a classe da pré-visualização da câmera. Esse tipo de layout é usado de forma que imagens adicionais ou controles possam ser sobrepostos sobre a imagem da pré-visualização.
<?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>
Em muitos dispositivos, a orientação padrão da pré-visualização da câmera é a Paisagem. Esse exemplo de layout especifica um layout horizontal e o código abaixo corrige a orientação da aplicação para Paisagem. Para simplificar a renderização da pré-visualização da câmera, você deve alterar a orientação da Activity de sua aplicação pela adicção do seguinte código ao seu 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>
Nota: Uma pré-visualização não tem que estar no modo Paisagem. Desde o Android 2.2 (API Livel 8), você pode usar o método setDisplayOrientation()
para ajustar a rotação da imagem de pré-visualização. De forma a alterar a orientação da pré-visualização quando o usuário re-orienta o telefone, dentro do método surfaceChanged()
de sua classe de pré-visualização, primeiro interrompa a pré-visualização com Camera.stopPreview()
mude a orientação e em seguida inicie a pré-visualização com Camera.startPreview()
.
Na Activity de sua pré-visualização de câmera, adicione sua classe de pré-visualização como o elemento FrameLayout
mostrado no exemplo acima. Sua Activity de câmera precisa também garantir que a câmera seja liberada quando a ela seja pausada ou encerrada. O exemplo seguinte mostra como modificar a Activity da câmera para anexar a classe de pré-visualização mostrada na seção anterior.
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(id.camera_preview); preview.addView(mPreview); } }
Nota: O método getCameraInstance()
do exemplo acima refere-se ao método do exemplo da seção Acessando a câmera.
Capturando imagens
Uma vez que você tenha criado uma classe de pré-visualização e um layout para exibi-la, você está pronto para iniciar a captura de imagens em sua aplicação. No código de sua aplicação, você precisa configurar ouvintes para os controles da interface para responder às ações do usuário ao tirar uma foto.
De modo a recuperar uma imagem, use o método Camera.takePicture()
. Esse método usa três parâmetros qu recebem dados da câmera. Para que os dados sejam recebidos em formato JPEG, você precisa implementar a interface Camera.PictureCallback
para receber os dados da imagem e receber esses dados 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.
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: " + e.getMessage()); 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()); } } };
Dispare a captura de uma imagem pela chamada do método Camera.takePicture()
. O código fonte a seguir mostra como chamar esse método a partir de um botão View.OnClickListener
.
// 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) { // get an image from the camera mCamera.takePicture(null, null, mPicture); } } );
Nota: O membro mPicture
do exemplo refere-se ao código mostrado acima.
Cuidado: Lembre de liberar o objeto Camera
pela chamada a Camera.release()
quando a sua aplicação tiver terminado de usar a cãmera.
Capturando vídeos
Captura de vídeos usando o framework do Android necessita de um gerenciamento cuidadoso do objeto Camera
e coordenação com a classe MediaRecorder
. Quando estiver gravando um vídeo com Camera
, você precisa gerenciar as chamadas a Camera.lock()
e Camera.unlock()
para permitir o acesso a MediaRecorder
ao hardware da câmera, em adição às chamada a Camera.open()
e Camera.release()
.
Nota: A partir do Android 4.0 (API Level 14), as chamadas à Camera.lock()
e Camera.unlock()
são gerenciadas automaticamente.
Ao contrário da captura de fotos com a câmera do dispositivo, a captura de vídeos requer uma ordem de chamada de métodos muito particular. Você precisa seguir uma ordem de execução específica para preparar com sucesso e capturar um vídeo pela sua aplicação, como descrito a seguir.
- Abrir a câmera – Use o método
Camera.open()
para obter uma instância do objeto câmera. - Conectar a Pré-visualização – Preparar uma imagem ao vivo da câmera pela conexão de um
SurfaceView
à câmera usandoCamera.setPreviewDisplay()
. - Iniciar a Pré-visualização – Chamar
Camera.startPreview()
para iniciar a exibição da pré-visualização da câmera. - Iniciar a gravação do vídeo – Os seguintes passos precisam ser executados de forma que o vídeo seja gravado com sucesso:
- Desbloquear a câmera – Desbloqueie a câmera para uso pelo
MediaRecorder
através da chamada àCamera.unlock()
. - Configurar o MediaRecorder – Chame os seguintes métodos de
MediaRecorder
nessa ordem. Para mais informações, veja a documentação deMediaRecorder
.setCamera()
– Configura a câmera a ser usada para a captura de vídeo, use a instância atual deCamera
da sua aplicação.setAudioSource()
– Configure a fonte do áudio, useMediaRecorder.AudioSource.CAMCORDER
.setVideoSource()
– Configure a fonte do vídeo, useMediaRecorder.VideoSource.CAMERA
.- Configure a codificação da saída de vídeo. Para o Android 2.2 (API Level 8) ou superior, use o método
MediaRecorder.setProfile
, e obtenha uma instância do perfil usandoCamcorderProfile.get()
. Para versões do Android anteriores a 2.2, você precisa configurar o formato de saída do vídeo e parâmetros de codificação:setOutputFormat()
– Configura o formato da saída, especificando a configuração padrão ouMediaRecorder.OutputFormat.MPEG_4
.setAudioEncoder()
– Configura o tipo de codificação do áudio, especificando a configuração padrão ouMediaRecorder.AudioEncoder.AMR_NB
.setVideoEncoder()
– Configura o tipo de codificação do vídeo, especificando a configuração padrão ouMediaRecorder.VideoEncoder.MPEG_4_SP
.
setOutputFile()
– Configura o arquivo de saída, use o métodogetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
do exemplo da seção Salvando arquivos de mídia.setPreviewDisplay()
– Especifica o elemento do layout associado aoSurfaceView
para sua aplicação. Use o nome que você especificou para o Connect Preview.
- Preparar o MediaRecorder – Prepara o
MediaRecorder
com as configurações fornecidas através da chamada aMediaRecorder.prepare()
. - Iniciar o MediaRecorder – Inicia a gravação do vídeo através da chamada a
MediaRecorder.start()
.
- Desbloquear a câmera – Desbloqueie a câmera para uso pelo
- Interromper a gravação do vídeo – Chame os seguintes métodos nessa ordem, para completar com sucesso uma gravação de vídeo:
- Interromper o MediaRecorder – Interrompa a gravação do vídeo pela chamada a
MediaRecorder.stop()
. - Reiniciar o MediaRecorder – Opcionalmente, remova as configurações pela chamada a
MediaRecorder.reset()
. - Liberar o MediaRecorder – Libere o
MediaRecorder
através da chamada aMediaRecorder.release()
. - Bloquear a câmera – Trave a câmera de forma que sessões futuras do
MediaRecorder
possam usa-lo através da chamada aCamera.lock()
. A partir do Android 4.0 (API level 14), essa chamada não é necessária a menos queMediaRecorder.prepare()
falhe.
- Interromper o MediaRecorder – Interrompa a gravação do vídeo pela chamada a
- Interromper a pré-visualização – Quando a sua Activity tiver terminado de usar a câmera, interrompa a pré-visualização usando
Camera.stopPreview()
. - Liberar a câmera – Libere a câmera de forma que outras aplicações possam usa-la através da chamada a
Camera.release()
.
Nota: É possível usar o MediaRecorder
sem criar primeiro uma pré-visualização da câmera e pular os primeiros passos desse processo. Porém, como os usuários preferem ver uma prévia antes de começar a gravação, esse processo não é discutido aqui.
Dica: Se sua aplicação for usada tipicamente para gravação, ajuste setRecordingHint(boolean)
para true
antes de iniciar a pré-visualização. Essa ajuste pode reduzir o tempo de início da gravação.
Configurando o MediaRecorder
Quando estiver usando a classe MediaRecorder
para gravar vídeo, você precisa executar os passos da configuração em uma ordem específica e depois chamar o método MediaRecorder.prepare()
para verificar e implementar a configuração. O exemplo de código a seguir demonstra como configurar e preparar de forma adequada a classe MediaRecorder
para gravação de vídeo.
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mMediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mMediaRecorder.setCamera(mCamera); // Step 2: Set sources mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mMediaRecorder.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; }
Os parâmetros de gravação de vídeo a seguir recebem valores padrão, porém, você pode desejar ajusta-los m sua aplicação:
setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()
Iniciando e interrompendo o MediaRecorder
Quando se inicia e interrompe a gravação de vídeo usando a classe MediaRecorder
, você precisa seguir uma ordem especifica, como listada abaixo.
- Desbloquear a câmera com
Camera.unlock()
- Configurar o
MediaRecorder
como mostrado no código acima. - Iniciar a gravação usando
MediaRecorder.start()
- Gravar o vídeo.
- Interromper a gravação pelo uso de
MediaRecorder.stop()
- Libere o MediaRecorder com
MediaRecorder.release()
- Bloqueie a câmera usando
Camera.lock()
O código a seguir demonstra como usar um botão para iniciar e interromper a gravação de vídeo usando a câmera e a classe MediaRecorder
.
Nota: Quando a gravação do vídeo é terminada, não libere a câmera ou a pré-visualização será interrompida.
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 mMediaRecorder.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 mMediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
Nota: No exemplo acima, o método prepareVideoRecorder()
refere-se ao código mostrado na seção Configurando o MediaRecorder. Esse método cuida do bloqueio da câmera, configuração e preparação a instância do MediaRecorder
.
Liberando a câmera
Câmeras são recursos que são compartilhados por várias aplicações instaladas no dispositivo. Sua aplicação pode fazer uso da câmera após obter uma instância de Camera
, e você precisa ser particularmente cuidadoso quando a sua aplicação termina de usa-la, e assim que a aplicação seja pausada (Activity.onPause()
). Se a sua aplicação não liberar de forma adequada a câmera, todas a tentativas de acesso subsequentes a câmera, incluindo aquelas vindas de sua própria aplicação, irão falhar e podem causar o enceramento da aplicação.
Para liberar uma instância do objeto Camera
, use o método Camera.release()
, como mostrado no exemplo a seguir.
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView mPreview; private MediaRecorder mMediaRecorder; ... @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 (mMediaRecorder != null) { mMediaRecorder.reset(); // clear recorder configuration mMediaRecorder.release(); // release the recorder object mMediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
Salvando os arquivos
Arquivos de mídia criados pelos usuários como fotos e vídeos devem ser salvos em um diretório do armazenamento externo do dispositivo (Cartão SD) para preservar o espaço do sistema e permitir que os usuários possam acessar esses arquivos sem o dispositivo. Existem muitos diretórios em que os arquivos podem ser armazenados, porém existem apenas dois locais padrão que você deveria considerar:
Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_PICTURES
) – Esse método retorna o local padrão, compartilhado e recomendado para salvar fotos e vídeos. Esse diretório é público, de forma que outras aplicações podem facilmente descobrir, ler, alterar e apagar os arquivos salvados dentro dele. Se a sua aplicação for desinstalada pelo usuário, os arquivos de mídia salvos nesse local não serão removidos. Para evitar interferência com as imagens e vídeos existentes, você deve criar um sub-diretório para os arquivos de mídia de sua aplicação, como mostrado no código abaixo. Esse método está disponível no Android 2.2 (API Level 8).Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
) – Esse método retorna um local padrão para salvar fotos e vídeos que estejam associados a sua aplicação. Se a sua aplicação for desinstalada, qualquer arquivo salvo nesse local será removido. A segurança não é reforçada para arquivos nesse diretório, de forma que outras aplicações podem ler, alterar e apagar os arquivos.
O exemplo de código a seguir demonstra como criar um File
ou Uri
para um arquivo de mídia que pode ser usado quando se invoca a câmera do dispositivo com um Intent
ou como parte da Criação de uma aplicação de câmera.
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; }
Nota: Environment.getExternalStoragePublicDirectory()
está disponível no Android 2.2 (API Level 8) ou superior. Se seu objetivo for dispositivos com versões mais antigas do Android, use Environment.getExternalStorageDirectory()
ao invés disso.
Recursos de câmera
O Android suporta uma gama ampla de recursos de câmera que você pode controlar com a sua aplicação, como formato da imagem, modo de flash, ajustes de foco, e muito mais. Essa seção lista os recursos de câmera comuns, e discute brevemente como usar cada um. Muitos dos recursos de câmera podem ser acessados e configurados através do objeto Camera.Parameters
. Porém, existem diversos recursos importantes que necessitam do que ajustes simples no Camera.Parameters
. Esses recursos são cobertos nas seguintes seções:
- Medição e foco de certas áreas
- Detecção de rostos
- Timelapse
Tabela 1. Recursos de câmera comuns ordenados pela Nível de API do Android onde eles foram introduzidos.
Recursos | API Level | Descrição |
---|---|---|
Face Detection | 14 | Identify human faces within a picture and use them for focus, metering and white balance |
Metering Areas | 14 | Specify one or more areas within an image for calculating white balance |
Focus Areas | 14 | Set one or more areas within an image to use for focus |
White Balance Lock |
14 | Stop or start automatic white balance adjustments |
Exposure Lock |
14 | Stop or start automatic exposure adjustments |
Video Snapshot |
14 | Take a picture while shooting video (frame grab) |
Time Lapse Video | 11 | Record frames with set delays to record a time lapse video |
Multiple Cameras |
9 | Support for more than one camera on a device, including front-facing and back-facing cameras |
Focus Distance |
9 | Reports distances between the camera and objects that appear to be in focus |
Zoom |
8 | Set image magnification |
Exposure Compensation |
8 | Increase or decrease the light exposure level |
GPS Data |
5 | Include or omit geographic location data with the image |
White Balance |
5 | Set the white balance mode, which affects color values in the captured image |
Focus Mode |
5 | Set how the camera focuses on a subject such as automatic, fixed, macro or infinity |
Scene Mode |
5 | Apply a preset mode for specific types of photography situations such as night, beach, snow or candlelight scenes |
JPEG Quality |
5 | Set the compression level for a JPEG image, which increases or decreases image output file quality and size |
Flash Mode |
5 | Turn flash on, off, or use automatic setting |
Color Effects |
5 | Apply a color effect to the captured image such as black and white, sepia tone or negative. |
Anti-Banding |
5 | Reduces the effect of banding in color gradients due to JPEG compression |
Picture Format |
1 | Specify the file format for the picture |
Picture Size |
1 | Specify the pixel dimensions of the saved picture |
Verificando a disponibilidade do recurso
A primeira coisa a se entender quando estiver configurando o uso de recursos de câmera em dispositivos Android é que nem todos os recursos são suportados em todos os dispositivos. Além disso, os dispositivos que suportem um recurso em particular podem suportar esse recurso em níveis diferentes ou com opções diferentes. Por esse motivo, parte do processo de decisão do desenvolvedor de uma aplicação de câmera é decidir quais recursos de câmera serão suportados e em que nível. Após tomar essas decisões, você deve planejar incluir código em sua aplicação para verificar se o hardware do dispositivo suporta esses recursos e evitar ser executado caso o recurso não esteja disponível.
Você pode verificar a disponibilidade de recursos de câmera pela obtenção de uma instância do objeto de parâmetros da câmera, e checando os métodos relevantes. O código a seguir mostra como obter acesso a um objeto Camera.Parameters
e verificar se a câmera suporta o recurso de auto-foco:
// get Camera parameters Camera.Parameters params = mCamera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
Você pode usar a técnica mostrada acima para outros recursos de câmera. O objeto Camera.Parameters
fornece um método getSupported...()
, is...Supported()
ou getMax...()
para determinar se (e em que nível) um recurso é suportado.
Se a sua aplicação precisar de um determinado recurso de câmera para funcionar corretamente, você pode requerer esses recursos através do manifesto. Quando você declara o uso de recursos específicos da câmera, como flash ou auto-foco, o Google Play restringe a instalação de sua aplicação em dispositivos que não suportem esses recursos. Para obter uma lista de recursos que podem ser declarados no seu manifesto, veja Features Reference.
Usando os recursos da câmera
Muitos recursos de câmera são ativados usando um objeto Camera.Parameters
. Você obtém esses objeto criando uma instância do objeto Camera
, chamando o método getParameters()
, alterando o parâmetro retornado e então configurando de volta para o objeto da câmera, como demonstrado no código a seguir:
// get Camera parameters Camera.Parameters params = mCamera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters mCamera.setParameters(params);
Essa técnica funciona para quase todos os recursos de câmera, e muitos parâmetros podem ser alterado a qualquer tempo após a obtenção de uma instância do objeto Camera
. Alterações nos parâmetros são tipicamente visíveis aos usuários imediatamente pela pré-visualização da câmera. Do lado do software, alterações nos parâmetros podem levar vários quadros da imagem para surtirem efeito e o hardware da câmera processe as novas instruções e atualize os dados da imagem.
Outros recursos de câmera necessitam de mais código para serem implementados, incluindo:
- Medição e foco de certas áreas
- Detecção de rostos
- Timelapse
Medição e focando de certas áreas
In some photographic scenarios, automatic focusing and light metering may not produce the desired results. Starting with Android 4.0 (API Level 14), your camera application can provide additional controls to allow your app or users to specify areas in an image to use for determining focus or light level settings and pass these values to the camera hardware for use in capturing images or video.
Areas for metering and focus work very similarly to other camera features, in that you control them through methods in the Camera.Parameters
object. The following code demonstrates setting two light metering areas for an instance of Camera
:
// Create an instance of Camera mCamera = getCameraInstance(); // set Camera parameters Camera.Parameters params = mCamera.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); } mCamera.setParameters(params);
The Camera.Area
object contains two data parameters: A Rect
object for specifying an area within the camera’s field of view and a weight value, which tells the camera what level of importance this area should be given in light metering or focus calculations.
The Rect
field in a Camera.Area
object describes a rectangular shape mapped on a 2000 x 2000 unit grid. The coordinates -1000, -1000 represent the top, left corner of the camera image, and coordinates 1000, 1000 represent the bottom, right corner of the camera image, as shown in the illustration below.

The bounds of this coordinate system always correspond to the outer edge of the image visible in the camera preview and do not shrink or expand with the zoom level. Similarly, rotation of the image preview usingCamera.setDisplayOrientation()
does not remap the coordinate system.
Detecção de rostos
For pictures that include people, faces are usually the most important part of the picture, and should be used for determining both focus and white balance when capturing an image. The Android 4.0 (API Level 14) framework provides APIs for identifying faces and calculating picture settings using face recognition technology.
Nota: While the face detection feature is running, setWhiteBalance(String)
, setFocusAreas(List)
and setMeteringAreas(List)
have no effect.
Using the face detection feature in your camera application requires a few general steps:
- Check that face detection is supported on the device
- Create a face detection listener
- Add the face detection listener to your camera object
- Start face detection after preview (and after every preview restart)
The face detection feature is not supported on all devices. You can check that this feature is supported by calling getMaxNumDetectedFaces()
. An example of this check is shown in the startFaceDetection()
sample method below.
In order to be notified and respond to the detection of a face, your camera application must set a listener for face detection events. In order to do this, you must create a listener class that implements theCamera.FaceDetectionListener
interface as shown in the example code below.
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() ); } } }
After creating this class, you then set it into your application’s Camera
object, as shown in the example code below:
mCamera.setFaceDetectionListener(new MyFaceDetectionListener());
Your application must start the face detection function each time you start (or restart) the camera preview. Create a method for starting face detection so you can call it as needed, as shown in the example code below.
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(); } }
You must start face detection each time you start (or restart) the camera preview. If you use the preview class shown in Creating a preview class, add your startFaceDetection()
method to both thesurfaceCreated()
and surfaceChanged()
methods in your preview class, as shown in the sample code below.
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 (mHolder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "mHolder.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(mHolder); 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()); } }
Nota: Remember to call this method after calling startPreview()
. Do not attempt to start face detection in the onCreate()
method of your camera app’s main activity, as the preview is not available by this point in your application’s the execution.
Timelapse
Time lapse video allows users to create video clips that combine pictures taken a few seconds or minutes apart. This feature uses MediaRecorder
to record the images for a time lapse sequence.
To record a time lapse video with MediaRecorder
, you must configure the recorder object as if you are recording a normal video, setting the captured frames per second to a low number and using one of the time lapse quality settings, as shown in the code example below.
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mMediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
These settings must be done as part of a larger configuration procedure for MediaRecorder
. For a full configuration code example, see Configuring MediaRecorder. Once the configuration is complete, you start the video recording as if you were recording a normal video clip. For more information about configuring and running MediaRecorder
, see Capturing videos.