O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

API Camera

A biblioteca do Android inclui suporte para diversas câmeras e recursos relacionados disponíveis nos dispositivos. 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 está obsoleta. Recomendamos usar a nova classe camera2, que funciona no Android 5.0 (API de nível 21) ou versões posteriores. Leia mais sobre camera2 no nosso blog e assista a este vídeo.

Considerações

Antes de possibilitar que seu aplicativo use câmeras nos dispositivos Android, considere algumas questões sobre como o aplicativo pretende usar esse recurso de hardware.

  • Exigência de câmera: o uso de uma câmera é tão importante para o aplicativo que você não quer a instalação dele em um dispositivo que não tenha esse recurso? Nesse caso, declare a exigência de câmera no seu manifesto.
  • Imagem rápida ou câmera personalizada: como o aplicativo usará a câmera? Você tem interesse somente em capturar um clipe de vídeo ou imagem rápida ou o aplicativo oferecerá uma nova forma de usar câmeras? Para tirar uma foto ou registrar um clipe rapidamente, considere o Uso de aplicativos de câmera existentes. Para desenvolver um recurso de câmera personalizado, verifique a seção Como criar um aplicativo de câmera.
  • Exigência de serviços em primeiro plano: quando o aplicativo interage com a câmera? No Android 9 (API de nível 28) e versões posteriores, os aplicativos que operam em segundo plano não podem acessar a câmera. Assim, use a câmera quando o aplicativo estiver em primeiro plano ou como parte de um serviço em primeiro plano.
  • Armazenamento: as imagens ou vídeos gerados têm como finalidade ficar visíveis somente para seu aplicativo ou serão compartilhados para que outros aplicativos (como a Galeria e 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.

Conceitos básicos

A biblioteca do Android é compatível com a captura de imagens e vídeos por meio da API android.hardware.camera2 ou do Intent da câmera. Estas são as classes relevantes:

android.hardware.camera2
Esse pacote é a principal API 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 obsoleta 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 de intent de MediaStore.ACTION_IMAGE_CAPTURE ou MediaStore.ACTION_VIDEO_CAPTURE que pode ser usado para capturar imagens ou vídeos sem usar o objeto Camera diretamente.

Declarações do manifesto

Antes de começar o desenvolvimento no seu aplicativo com a API Camera, verifique se o manifesto tem as declarações adequadas para permitir o uso do hardware de câmera e outros recursos relacionados.

  • Permissão da câmera: o aplicativo precisa solicitar permissão para usar a câmera de um dispositivo.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Observação: se você estiver usando a câmera por meio da invocação de um aplicativo de câmera existente, seu aplicativo não precisará solicitar essa permissão.

  • Recursos de câmera: o 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 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 seu aplicativo seja instalado em dispositivos que não tenham uma câmera ou não sejam compatíveis com os recursos que você especificar. 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 recurso relacionado para operar adequadamente, mas isso não seja obrigatório, especifique essa informação no manifesto por meio da inclusão do atributo android:required e o defina como false:

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Permissão de armazenamento: se o aplicativo salvar imagens ou vídeos no armazenamento externo do dispositivo (cartão SD), você também precisará especificar essa informação 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, o aplicativo precisa 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 (API de nível 21) ou versões posteriores, 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 aplicativos de câmera existentes

Uma forma rápida de possibilitar que o aplicativo registre fotos ou vídeos sem muitos códigos extras é usar um Intent para invocar um aplicativo de câmera Android existente. Os detalhes são descritos nas lições de treinamento Como tirar fotos com simplicidade e Como gravar vídeos com simplicidade.

Como criar um aplicativo de câmera

Alguns desenvolvedores podem precisar de uma interface do usuário de câmera personalizada de acordo com o visual do aplicativo ou que ofereça recursos especiais. Escrever seu próprio código para tirar fotos pode fornecer uma experiência mais interessante aos usuários.

Observação: o guia a seguir serve para a antiga e obsoleta API Camera. Para aplicativos de câmera novos ou avançados, é recomendada a API android.hardware.camera2 mais recente.

Estas são as etapas gerais da 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 interface SurfaceHolder. Essa classe exibe as imagens em tempo real da câmera.
  • Criar um layout de visualização: depois de ter 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 e inicie 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 resposta.
  • Liberar a câmera: após utilizá-la, seu aplicativo precisa liberar adequadamente a câmera 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 aplicativos 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 o dispositivo quando o aplicativo deixa de usá-lo.

Atenção: lembre-se de liberar o objeto Camera. Para isso, chame o Camera.release() quando seu aplicativo deixar 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 próprio aplicativo, apresentarão falha. 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 por meio de uma declaração de manifesto, verifique se há uma câmera disponível no tempo 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 fotografias e outra frontal para chamadas de vídeo. No Android 2.3 (API de nível 9) e em versões posteriores, é possível verificar a quantidade de câmeras disponíveis em um dispositivo pelo método Camera.getNumberOfCameras().

Como acessar câmeras

Se você determinou que o dispositivo em que o aplicativo está operando tem uma câmera, será necessário solicitar acesso a ela por meio de uma instância de Camera (a menos que você esteja usando um intent para acessar a câmera).

Para acessar a câmera principal, use o método Camera.open() e certifique-se de registrar qualquer exceção, conforme exibido 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
}

Atenção: sempre verifique as exceções ao usar Camera.open(). Deixar de verificá-las, caso a câmera esteja sendo usada ou não exista, fará com que seu aplicativo seja encerrado pelo sistema.

Nos dispositivos que operam o Android 2.3 (API de nível 9) ou versões posteriores, é possível acessar câmeras específicas usando Camera.open(int). O código de exemplo acima acessará primeiro a câmera traseira em um dispositivo com mais de uma câmera.

Verificação dos recursos de câmera

Após conseguir o acesso à câmera, você pode ter mais detalhes sobre os recursos usando o método Camera.getParameters() e verificando o objeto Camera.Parameters retornado das funcionalidades compatíveis. Na API de nível 9 ou posterior, use a Camera.getCameraInfo() para determinar se uma câmera está na parte frontal ou traseira do dispositivo e a orientação da imagem.

Criação de uma classe de visualização

Os usuários que efetivamente registram fotos ou vídeos precisam ser capazes de ver a mesma informação visualizada pela câmera do dispositivo. 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 arbitrariamente no método setPreviewSize().

Observação: com a introdução do recurso Várias janelas no Android 7.0 (API de nível 24) e em versões posteriores, não é mais possível presumir que a taxa de proporção da visualização seja a mesma que a da sua atividade, mesmo após chamar setDisplayOrientation(). Dependendo da taxa de 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 de formato letterbox.

Como posicionar a visualização em um layout

Uma classe de visualização da câmera, como os exemplos exibidos na seção anterior, precisa ser posicionada no layout de uma atividade com outros controles da interface do usuário para tirar uma foto ou registrar 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 adicionais 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. Este 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, altere a orientação da atividade de visualização do aplicativo para paisagem. Faça isso 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: a visualização de uma câmera não precisa ser no modo paisagem. A partir do Android 2.2 (API de nível 8), é possível usar o método setDisplayOrientation() para definir a rotação da imagem visualizada. Para alterar a orientação da visualização à medida que o usuário muda o posicionamento do telefone, no método surfaceChanged() da classe de visualização, primeiramente interrompa a exibição com Camera.stopPreview(). Mude a orientação e, em seguida, 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 Criação de 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 abaixo se refere ao exemplo demonstrado em Como acessar 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 aos controles da interface do usuário para responder à ação de quem tirar 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 de 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 demonstrado abaixo se refere ao código de exemplo acima.

Atenção: lembre-se de liberar o objeto Camera. Para isso, chame o Camera.release() quando seu aplicativo deixar de usá-lo. Para saber mais sobre como liberar a câmera, consulte Liberação da câmera.

Captura de vídeos

A captura de vídeos com a biblioteca do Android requer gerenciamento cuidadoso do objeto Camera e coordenação com a classe MediaRecorder. Ao gravar vídeos com Camera, é necessário gerenciar as chamadas Camera.lock() e Camera.unlock() para permitir acesso MediaRecorder ao hardware da câmera, além das chamadas Camera.open() e Camera.release().

Observação: a partir do Android 4.0 (API de nível 14), as chamadas Camera.lock() e Camera.unlock() são automaticamente gerenciadas para você.

Diferentemente do que ocorre com 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 os detalhes abaixo.

  1. Abrir a câmera: use o Camera.open() para acessar uma instância do objeto da câmera.
  2. Conectar a visualização: prepare uma visualização da imagem em tempo real conectando uma SurfaceView à câmera por meio de Camera.setPreviewDisplay().
  3. Iniciar a visualização: chame Camera.startPreview() para começar a exibir as imagens da câmera em tempo real.
  4. 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:
    1. Desbloquear a câmera: desbloqueie a câmera para que o MediaRecorder possa usá-la. Para isso, chame Camera.unlock().
    2. Configurar o MediaRecorder: chame os métodos MediaRecorder a seguir nesta ordem. Para saber mais, consulte a documentação de referência do MediaRecorder.
      1. setCamera(): define a câmera que será usada na captura de vídeos. Use a instância de Camera atual do aplicativo.
      2. setAudioSource(): define a fonte de áudio. Use MediaRecorder.AudioSource.CAMCORDER.
      3. setVideoSource(): define a fonte de vídeo. Use MediaRecorder.VideoSource.CAMERA.
      4. Define a codificação e o formato da saída de vídeo. Para o Android 2.2 (API de nível 8) e versões posteriores, use o método MediaRecorder.setProfile e acesse uma instância de perfil usando CamcorderProfile.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:
        1. setOutputFormat(): define o formato de saída. Especifique a configuração padrão ou MediaRecorder.OutputFormat.MPEG_4.
        2. setAudioEncoder(): define o tipo de codificação do áudio. Especifique a configuração padrão ou MediaRecorder.AudioEncoder.AMR_NB.
        3. setVideoEncoder(): define o tipo de codificação do vídeo. Especifique a configuração padrão ou MediaRecorder.VideoEncoder.MPEG_4_SP.
      5. setOutputFile(): define o arquivo de saída. Use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() do método de exemplo na seção Como salvar arquivos de mídia.
      6. setPreviewDisplay(): especifica o elemento de layout da visualização SurfaceView para o aplicativo. Use o mesmo objeto especificado em Conectar a visualização.

      Atenção: é necessário chamar esses métodos de configuração MediaRecorder nesta ordem, caso contrário, o aplicativo apresentará erros e ocorrerá falha na gravação.

    3. Preparar o MediaRecorder: prepare o MediaRecorder com as definições de configuração fornecidas. Para isso, chame MediaRecorder.prepare().
    4. Iniciar o MediaRecorder: chame MediaRecorder.start() para iniciar a gravação de vídeos.
  5. Interromper a gravação de vídeos: chame os métodos a seguir na ordem para finalizar a gravação de um vídeo corretamente.
    1. Interromper o MediaRecorder: para interromper a gravação de vídeos, chame MediaRecorder.stop().
    2. Redefinir o MediaRecorder: você tem a opção de remover as definições de configuração do gravador. Para isso, chame MediaRecorder.reset().
    3. Liberar o MediaRecorder: para liberar o MediaRecorder, chame MediaRecorder.release().
    4. Bloquear a câmera: bloqueie a câmera para que as sessões MediaRecorder futuras possam usá-las. Para isso, chame Camera.lock(). A partir do Android 4.0 (API de nível 14), essa chamada não é obrigatória, a não ser que haja falha na chamada MediaRecorder.prepare().
  6. Interromper a visualização: quando a atividade deixar de usar a câmera, use Camera.stopPreview() para interromper a visualização.
  7. 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: caso seu aplicativo costume ser usado para gravar vídeos, defina setRecordingHint(boolean) como true antes de iniciar a visualização. Essa configuração ajuda a fazer com que a gravação inicie mais rapidamente.

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 (API de nível 8), é necessário definir diretamente os parâmetros de formatos de codificação e saída, em vez de usar CamcorderProfile. Essa abordagem é demostrada 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, convém que você ajuste essas configurações de acordo com seu aplicativo:

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.

  1. Desbloqueie a câmera com Camera.unlock().
  2. Configure MediaRecorder conforme demonstrado no exemplo de código acima.
  3. Inicie a gravação com MediaRecorder.start().
  4. Grave o vídeo.
  5. Interrompa a gravação com MediaRecorder.stop().
  6. Libere o gravador de mídia com MediaRecorder.release().
  7. 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 Configuração do MediaRecorder. Esse método trata do bloqueio da câmera, da configuração e da preparação da instância MediaRecorder.

Liberação da câmera

As câmeras são um recurso compartilhado pelos aplicativos em um dispositivo. Após acessar uma instância de Camera, seu aplicativo poderá usar a câmera. Você precisa estar especialmente atento ao fato de liberar o objeto câmera quando seu aplicativo deixar de usá-lo e também sempre que ele estiver pausado. (Activity.onPause()). Se a câmera não for liberada adequadamente, todas as tentativas subsequentes de acesso a ela, inclusive as feitas pelo seu próprio aplicativo, apresentarão falha. Isso pode fazer com que os aplicativos sejam encerrados.

Para liberar uma instância do objeto Camera, use o método Camera.release(), conforme exibido 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;
        }
    }
}

Atenção: se a câmera não for liberada adequadamente, todas as tentativas subsequentes de acesso a ela, inclusive as feitas pelo seu próprio aplicativo, apresentarão falha. Isso pode fazer com que os 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 (cartão SD) externo do dispositivo. Isso economiza espaço no sistema e permite o acesso a esses dados mesmo quando o usuário não estiver 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), portanto, outros aplicativos podem descobrir, ler 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 (API de nível 8). Para chamadas equivalentes em versões de 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 é reforçada para arquivos nesse local, e outros aplicativos podem ler, alterar e excluir esses dados.

O código de exemplo a seguir demonstra como criar um File ou local Uri para um arquivo de mídia que possa ser usado ao invocar a câmera de um dispositivo com um Intent ou como parte da Criação de um aplicativo 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 (API de nível 8) ou versões posteriores. Caso seu direcionamento seja 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 um 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 pode ser acessada e definida por meio do 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 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 por meio dos links na lista de recursos abaixo.

Tabela 1. Recursos de câmera comuns, classificados pelo nível de API do Android em que foram introduzidos.

Recurso Nível de API Descrição
Reconhecimento facial 14 Identifica rostos humanos em uma foto e os usa para foco, métrica 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 equilíbrio de branco
Exposure Lock 14 Interrompe ou inicia automaticamente os ajustes de exposição
Video Snapshot 14 Tira uma foto enquanto grava vídeos (registro de frame)
Vídeo de tempo transcorrido 11 Grava frames com atrasos definidos para criar um vídeo de tempo transcorrido
Multiple Cameras 9 É compatível com mais de uma câmera no dispositivo, inclusive as frontais e traseiras.
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 equilíbrio de branco, que afeta os valores de cor na imagem capturada
Focus Mode 5 Define como a câmera foca 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 verificar a disponibilidade de recursos no dispositivo em que o aplicativo está operando, consulte Verificação de disponibilidade do recurso.

Verificação de 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 em particular podem oferecer suporte a 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 para quais recursos de câmera você quer oferecer suporte e em qual nível isso ocorrerá. Após decidir, planeje a inclusão do código no seu aplicativo de câmera para verificar se o hardware do dispositivo é compatível com essas funcionalidades e para que ocorra a devida falha se faltar algum recurso.

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. O exemplo 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 em qual extensão) 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 seu 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 incompatíveis com essas funcionalidades. Para acessar uma lista de recursos de câmera que podem ser declarados no manifesto do aplicativo, consulte Referência de recursos do manifesto.

Como usar os recursos de câmera

A maioria dos recursos de câmera é ativada e controlada por meio de um objeto Camera.Parameters. Para ter esse objeto, primeiro acesse uma instância do objeto Camera, chamando o método getParameters(), alterando o objeto de parâmetro retornado e o definindo novamente no objeto 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 pode ser alterada a qualquer momento após você ter uma instância do objeto Camera. As mudanças nos parâmetros costumam ficar imediatamente visíveis ao usuário na visualização de câmera do aplicativo. No lado do software, essas alterações podem levar vários frames 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: não é possível alterar livremente alguns recursos de câmera. Em especial, a alteração do tamanho ou da orientação da exibição da câmera requer que você primeiramente interrompa a visualização, mude a dimensão dela e a reinicie. A partir do Android 4.0 (API de nível 14), a orientação da visualização pode ser alterada sem a necessidade de reiniciar a exibição.

Outros recursos de câmera exigem mais códigos para que a implementação ocorra, inclusive estes:

  • Áreas de medição e foco
  • Reconhecimento facial
  • Vídeo de tempo transcorrido

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 métrica de luz podem não produzir os resultados desejados. A partir do Android 4.0 (API de nível 14), o aplicativo de câmera pode oferecer controles adicionais para permitir que o aplicativo ou os usuários especifiquem áreas em uma imagem que serão usadas para determinar as configurações de foco ou de nível da luz. Esses valores são transmitidos ao hardware da câmera para a 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 por 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 visualização da câmera e um valor de peso, que informa à câmera qual nível de importância essa área receberá nos cálculos de foco ou medição da luz.

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 “-1000, -1000” representam a parte superior do canto esquerdo da imagem da câmera. As coordenadas “1000, 1000” representam a parte inferior do canto direito da imagem da câmera, conforme mostrado na ilustração abaixo.

Imagem 1. As linhas vermelhas ilustram o sistema de coordenadas para especificar uma Camera.Area na visualização da câmera. A caixa azul mostra o local e o formato da área de uma câmera com os valores Rect 333,333,667,667.

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 expandidos com 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.

Reconhecimento facial

Para fotos que contêm pessoas, os rostos costumam ser a parte mais importante e precisam ser usados para determinar o foco e o equilíbrio de branco durante a captura de uma imagem. A biblioteca do Android 4.0 (API de nível 14) oferece APIs para identificar rostos e calcular as configurações da foto por meio da tecnologia de reconhecimento facial.

Observação: durante a execução do recurso de reconhecimento facial, setWhiteBalance(String), setFocusAreas(List<Camera.Area>) e setMeteringAreas(List<Camera.Area>) não têm efeito.

O uso do recurso de reconhecimento facial no aplicativo de câmera requer que alguns passos gerais sejam seguidos:

  • Verifique se o reconhecimento facial é compatível com o dispositivo.
  • Crie um listener de reconhecimento facial.
  • Adicione esse listener ao objeto da câmera.
  • Inicie o reconhecimento facial após a visualização (e depois que todas as visualizações forem reiniciadas).

O recurso de reconhecimento facial não é compatível com todos os dispositivos. Você pode verificar se há compatibilidade chamando getMaxNumDetectedFaces(). Um exemplo dessa verificação é mostrado no método de exemplo startFaceDetection() abaixo.

Para ser notificado e responder à detecção de um rosto, o aplicativo de câmera precisa definir um listener para eventos de reconhecimento facial. Para fazer isso, você precisa criar uma classe de listener que implemente a interface Camera.FaceDetectionListener, conforme exibido no código de exemplo a seguir.

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

Após 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 reconhecimento facial sempre que você iniciar (ou reiniciar) a visualização da câmera. Crie um método para iniciar o reconhecimento facial e poder chamá-lo sempre que for necessário, conforme exibido no código de exemplo a seguir.

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 o reconhecimento 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 Criação de uma classe de visualização, adicione o método startFaceDetection() aos métodos surfaceCreated() e surfaceChanged() na sua classe de visualização, conforme demonstrado no código de exemplo 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 chamar esse método após chamar startPreview(). Não tente iniciar o reconhecimento 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 aplicativo.

Vídeo de tempo transcorrido

Os vídeos de tempo transcorrido permitem que os usuários criem clipes de vídeo que combinem fotos tiradas com alguns segundos ou minutos de diferença. Esse recurso usa MediaRecorder para gravar as imagens de uma sequência de tempo transcorrido.

Para gravar um vídeo desse tipo com MediaRecorder, configure o objeto gravador como se estivesse gravando um vídeo normal, definindo os frames capturados por segundo com um número baixo e usando uma das configurações de qualidade de tempo transcorrido, conforme exibido no exemplo de código a seguir.

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 MediaRecorder. Para ver um exemplo de código de configuração completo, consulte Configuração do MediaRecorder. Após concluir a configuração, inicie a gravação do vídeo, como se fosse um clipe de vídeo normal. Para saber mais sobre a configuração e execução do MediaRecorder, consulte Captura de vídeos.

Os exemplos Android Camera2Video e Android HcrViewfinder demonstram mais detalhadamente o uso das APIs abordadas nesta página.

Campos de câmera que exigem permissão

Os aplicativos que executam Android 10 (nível de API 29) ou versão posterior precisam ter a permissão CAMERA para acessar os valores dos campos a seguir retornados pelo método getCameraCharacteristics():

  • 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

Exemplo de código adicional

Para fazer o download de um aplicativo de amostra do Camera2 básico, consulte Exemplo do Android Camera2Basic. Para fazer o download de um aplicativo de amostra do Camera2 bruto, consulte Exemplo do Android Camera2Raw.