API камеры

Платформа Android включает поддержку различных камер и функций камер, доступных на устройствах, что позволяет вам снимать изображения и видео в ваших приложениях. В этом документе обсуждается быстрый и простой подход к захвату изображений и видео, а также описывается расширенный подход к созданию пользовательских возможностей камеры для ваших пользователей.

Примечание. На этой странице описан класс Camera , который устарел. Мы рекомендуем использовать библиотеку CameraX Jetpack или, в особых случаях, класс camera2 . И CameraX, и Camera2 работают на Android 5.0 (уровень API 21) и выше.

Обратитесь к следующим соответствующим ресурсам:

Соображения

Прежде чем разрешить вашему приложению использовать камеры на устройствах Android, вам следует ответить на несколько вопросов о том, как ваше приложение собирается использовать эту аппаратную функцию.

  • Требование к камере . Является ли использование камеры настолько важным для вашего приложения, что вы не хотите, чтобы ваше приложение устанавливалось на устройство, не имеющее камеры? Если да, вам следует объявить требования к камере в своем манифесте .
  • Quick Picture или Customized Camera : как ваше приложение будет использовать камеру? Вас просто интересует возможность быстро сделать снимок или видеоклип, или ваше приложение предоставит новый способ использования камер? Чтобы быстро сделать снимок или клип, рассмотрите возможность использования существующих приложений камеры . Для разработки индивидуальной функции камеры ознакомьтесь с разделом «Создание приложения камеры» .
  • Требование к службам переднего плана . Когда ваше приложение взаимодействует с камерой? В Android 9 (уровень API 28) и более поздних версиях приложения, работающие в фоновом режиме, не могут получить доступ к камере. Поэтому вам следует использовать камеру либо тогда, когда ваше приложение находится на переднем плане, либо как часть службы переднего плана .
  • Хранилище . Предназначены ли изображения или видео, создаваемые вашим приложением, для просмотра только вашему приложению или для совместного использования другими приложениями, такими как Галерея или другими мультимедийными и социальными приложениями? Хотите, чтобы изображения и видео были доступны, даже если ваше приложение удалено? Посетите раздел «Сохранение медиафайлов» , чтобы узнать, как реализовать эти параметры.

Основы

Платформа Android поддерживает захват изображений и видео через API android.hardware.camera2 или камеру Intent . Вот соответствующие классы:

android.hardware.camera2
Этот пакет является основным API для управления камерами устройств. Его можно использовать для съемки фотографий или видео при создании приложения камеры.
Camera
Этот класс представляет собой старый устаревший API для управления камерами устройств.
SurfaceView
Этот класс используется для представления пользователю предварительного просмотра камеры в реальном времени.
MediaRecorder
Этот класс используется для записи видео с камеры.
Intent
Тип действия намерения MediaStore.ACTION_IMAGE_CAPTURE или MediaStore.ACTION_VIDEO_CAPTURE можно использовать для захвата изображений или видео без прямого использования объекта Camera .

Манифестные декларации

Прежде чем начинать разработку приложения с помощью Camera API, вы должны убедиться, что в вашем манифесте есть соответствующие объявления, позволяющие использовать оборудование камеры и другие связанные функции.

  • Разрешение камеры . Ваше приложение должно запросить разрешение на использование камеры устройства.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Примечание. Если вы используете камеру , вызывая существующее приложение камеры , вашему приложению не нужно запрашивать это разрешение.

  • Функции камеры . Ваше приложение также должно заявить об использовании функций камеры, например:
    <uses-feature android:name="android.hardware.camera" />
    

    Список функций камеры см. в справке по функциям манифеста.

    Добавление функций камеры в манифест приведет к тому, что Google Play запретит установку вашего приложения на устройства, которые не оснащены камерой или не поддерживают указанные вами функции камеры. Дополнительную информацию об использовании фильтрации на основе функций в Google Play см. в разделе Google Play и фильтрация на основе функций .

    Если ваше приложение может использовать камеру или функцию камеры для правильной работы, но не требует этого, вам следует указать это в манифесте, включив атрибут android:required и установив для него значение false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Разрешение на хранение . Ваше приложение может сохранять изображения или видео на внешнее хранилище устройства (SD-карту), если оно предназначено для Android 10 (уровень API 29) или более ранней версии и в манифесте указано следующее.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Разрешение на запись звука . Для записи звука с захватом видео ваше приложение должно запросить разрешение на захват звука.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Разрешение на определение местоположения . Если ваше приложение помечает изображения информацией о местоположении GPS, вам необходимо запросить разрешение ACCESS_FINE_LOCATION . Обратите внимание: если ваше приложение предназначено для Android 5.0 (уровень API 21) или выше, вам также необходимо объявить, что ваше приложение использует GPS устройства:

    <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" />
    

    Дополнительные сведения о получении местоположения пользователя см. в разделе Стратегии определения местоположения .

Использование существующих приложений камеры

Быстрый способ включить фото- и видеосъемку в вашем приложении без большого количества дополнительного кода — использовать Intent для вызова существующего приложения камеры Android. Подробности описаны в обучающих уроках «Просто фотографировать» и «Просто записывать видео» .

Создание приложения камеры

Некоторым разработчикам может потребоваться пользовательский интерфейс камеры, адаптированный к внешнему виду их приложения или предоставляющий специальные функции. Написание собственного кода для создания изображений может обеспечить более привлекательный опыт для ваших пользователей.

Примечание. Следующее руководство предназначено для более старого устаревшего API Camera . Для новых или продвинутых приложений камеры рекомендуется использовать новый API android.hardware.camera2 .

Общие шаги по созданию пользовательского интерфейса камеры для вашего приложения следующие:

  • Обнаружение камеры и доступ к ней . Создайте код для проверки наличия камер и запроса доступа.
  • Создайте класс предварительного просмотра . Создайте класс предварительного просмотра камеры, который расширяет SurfaceView и реализует интерфейс SurfaceHolder . Этот класс просматривает живые изображения с камеры.
  • Создайте макет предварительного просмотра . Получив класс предварительного просмотра камеры, создайте макет вида, включающий в себя предварительный просмотр и нужные элементы управления пользовательского интерфейса.
  • Настройка прослушивателей для захвата . Подключите прослушиватели для элементов управления интерфейса, чтобы начать захват изображения или видео в ответ на действия пользователя, например нажатие кнопки.
  • Захват и сохранение файлов — настройте код для захвата изображений или видео и сохранения результатов.
  • Освободите камеру . После использования камеры ваше приложение должно правильно освободить ее для использования другими приложениями.

Аппаратное обеспечение камеры — это общий ресурс, которым необходимо тщательно управлять, чтобы ваше приложение не конфликтовало с другими приложениями, которые также могут захотеть его использовать. В следующих разделах обсуждается, как обнаружить оборудование камеры, как запросить доступ к камере, как захватить изображения или видео и как освободить камеру, когда ваше приложение закончит ее использовать.

Внимание: не забудьте освободить объект Camera , вызвав Camera.release() , когда ваше приложение завершит его использование! Если ваше приложение не освобождает камеру должным образом, все последующие попытки доступа к камере, в том числе со стороны вашего собственного приложения, окажутся неудачными и могут привести к закрытию вашего или других приложений.

Обнаружение оборудования камеры

Если вашему приложению не требуется камера с использованием объявления манифеста, вам следует проверить, доступна ли камера во время выполнения. Чтобы выполнить эту проверку, используйте метод PackageManager.hasSystemFeature() , как показано в примере кода ниже:

Котлин

/** 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
    }
}

Ява

/** 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;
    }
}

Устройства Android могут иметь несколько камер, например заднюю камеру для фотосъемки и фронтальную камеру для видеозвонков. Android 2.3 (уровень API 9) и более поздних версий позволяет проверять количество камер, доступных на устройстве, с помощью метода Camera.getNumberOfCameras() .

Доступ к камерам

Если вы определили, что устройство, на котором работает ваше приложение, имеет камеру, вы должны запросить доступ к ней, получив экземпляр Camera (если вы не используете намерение для доступа к камере ).

Чтобы получить доступ к основной камере, используйте метод Camera.open() и обязательно перехватите все исключения, как показано в коде ниже:

Котлин

/** 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
    }
}

Ява

/** 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
}

Внимание: всегда проверяйте наличие исключений при использовании Camera.open() . Если не выполнить проверку исключений, если камера используется или не существует, ваше приложение будет закрыто системой.

На устройствах под управлением Android 2.3 (уровень API 9) или выше вы можете получить доступ к определенным камерам с помощью Camera.open(int) . В приведенном выше примере кода будет осуществляться доступ к первой задней камере на устройстве с более чем одной камерой.

Проверка функций камеры

Получив доступ к камере, вы можете получить дополнительную информацию о ее возможностях, используя метод Camera.getParameters() и проверив возвращаемый объект Camera.Parameters на наличие поддерживаемых возможностей. При использовании API уровня 9 или выше используйте Camera.getCameraInfo() , чтобы определить, находится ли камера на передней или задней части устройства, а также ориентацию изображения.

Создание класса предварительного просмотра

Чтобы пользователи могли эффективно снимать фотографии или видео, они должны иметь возможность видеть то, что видит камера устройства. Класс предварительного просмотра камеры — это SurfaceView , который может отображать данные живого изображения, поступающие с камеры, чтобы пользователи могли кадрировать и снимать изображения или видео.

В следующем примере кода показано, как создать базовый класс предварительного просмотра камеры, который можно включить в макет View . Этот класс реализует SurfaceHolder.Callback для захвата событий обратного вызова для создания и уничтожения представления, которые необходимы для назначения входных данных предварительного просмотра камеры.

Котлин

/** 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}")
            }
        }
    }
}

Ява

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

Если вы хотите установить определенный размер для предварительного просмотра камеры, установите его в методе surfaceChanged() , как указано в комментариях выше. При настройке размера предварительного просмотра вы должны использовать значения из getSupportedPreviewSizes() . Не устанавливайте произвольные значения в методе setPreviewSize() .

Примечание. С появлением функции многооконности в Android 7.0 (уровень API 24) и более поздних версиях вы больше не можете предполагать, что соотношение сторон предварительного просмотра такое же, как и ваша активность, даже после вызова setDisplayOrientation() . В зависимости от размера окна и соотношения сторон вам, возможно, придется встроить предварительный просмотр широкой камеры в макет с портретной ориентацией или наоборот, используя макет почтового ящика.

Размещение предварительного просмотра в макете

Класс предварительного просмотра камеры, такой как пример, показанный в предыдущем разделе, должен быть размещен в макете действия вместе с другими элементами управления пользовательского интерфейса для съемки изображений или видео. В этом разделе показано, как создать базовый макет и действия для предварительного просмотра.

Следующий код макета предоставляет очень простой вид, который можно использовать для предварительного просмотра камеры. В этом примере элемент FrameLayout является контейнером для класса предварительного просмотра камеры. Этот тип макета используется для наложения дополнительной информации об изображении или элементов управления на изображения предварительного просмотра с камеры в реальном времени.

<?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>

На большинстве устройств ориентация предварительного просмотра камеры по умолчанию — альбомная. В этом примере макета указан горизонтальный (альбомный) макет, а приведенный ниже код фиксирует альбомную ориентацию приложения. Для упрощения отрисовки предварительного просмотра камеры вам следует изменить ориентацию действия предварительного просмотра вашего приложения на альбомную, добавив в манифест следующее.

<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>

Примечание. Предварительный просмотр камеры не обязательно должен быть в ландшафтном режиме. Начиная с Android 2.2 (уровень API 8), вы можете использовать метод setDisplayOrientation() чтобы задать поворот изображения предварительного просмотра. Чтобы изменить ориентацию предварительного просмотра, когда пользователь переориентирует телефон, в методе surfaceChanged() вашего класса предварительного просмотра сначала остановите предварительный просмотр с помощью Camera.stopPreview() измените ориентацию, а затем снова запустите предварительный просмотр с помощью Camera.startPreview() .

В действии для просмотра с камеры добавьте класс предварительного просмотра к элементу FrameLayout , показанному в примере выше. Действия вашей камеры также должны гарантировать, что она освобождает камеру, когда она приостанавливается или выключается. В следующем примере показано, как изменить действие камеры, чтобы прикрепить класс предварительного просмотра, показанный в разделе Создание класса предварительного просмотра .

Котлин

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

Ява

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

Примечание. Метод getCameraInstance() в приведенном выше примере относится к примеру метода, показанному в разделе Доступ к камерам .

Захват изображений

После того как вы создали класс предварительного просмотра и макет представления для его отображения, вы готовы начать захват изображений с помощью своего приложения. В коде вашего приложения вы должны настроить прослушиватели для элементов управления пользовательского интерфейса, чтобы они реагировали на действия пользователя, делая снимки.

Чтобы получить изображение, используйте метод Camera.takePicture() . Этот метод принимает три параметра, которые получают данные с камеры. Чтобы получать данные в формате JPEG, необходимо реализовать интерфейс Camera.PictureCallback для получения данных изображения и записи их в файл. В следующем коде показана базовая реализация интерфейса Camera.PictureCallback для сохранения изображения, полученного с камеры.

Котлин

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

Ява

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

Запустите захват изображения, вызвав метод Camera.takePicture() . В следующем примере кода показано, как вызвать этот метод из кнопки View.OnClickListener .

Котлин

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Ява

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

Примечание. Член mPicture в следующем примере относится к приведенному выше примеру кода.

Внимание: не забудьте освободить объект Camera , вызвав Camera.release() , когда ваше приложение завершит его использование! Информацию о том, как освободить камеру, см. в разделе «Освобождение камеры» .

Захват видео

Захват видео с помощью платформы Android требует тщательного управления объектом Camera и координации с классом MediaRecorder . При записи видео с помощью Camera вы должны управлять вызовами Camera.lock() и Camera.unlock() , чтобы разрешить MediaRecorder доступ к оборудованию камеры, в дополнение к вызовам Camera.open() и Camera.release() .

Примечание. Начиная с Android 4.0 (уровень API 14), вызовы Camera.lock() и Camera.unlock() управляются автоматически.

В отличие от съемки с помощью камеры устройства, съемка видео требует особого порядка вызовов. Вы должны следовать определенному порядку выполнения, чтобы успешно подготовиться и записать видео с помощью вашего приложения, как подробно описано ниже.

  1. Открыть камеру . Используйте Camera.open() чтобы получить экземпляр объекта камеры.
  2. Предварительный просмотр подключения . Подготовьте предварительный просмотр изображения с камеры в реальном времени, подключив SurfaceView к камере с помощью Camera.setPreviewDisplay() .
  3. Начать предварительный просмотр . Вызовите Camera.startPreview() , чтобы начать отображение изображений с камеры в реальном времени.
  4. Начать запись видео . Для успешной записи видео необходимо выполнить следующие шаги:
    1. Разблокировать камеру — разблокируйте камеру для использования MediaRecorder вызвав Camera.unlock() .
    2. Настройте MediaRecorder — вызовите следующие методы MediaRecorder в указанном порядке . Дополнительные сведения см. в справочной документации MediaRecorder .
      1. setCamera() — установите камеру, которая будет использоваться для захвата видео, используйте текущий экземпляр Camera вашего приложения.
      2. setAudioSource() — установите источник звука, используйте MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() — установите источник видео, используйте MediaRecorder.VideoSource.CAMERA .
      4. Установите формат и кодировку вывода видео. Для Android 2.2 (уровень API 8) и более поздних версий используйте метод MediaRecorder.setProfile и получите экземпляр профиля с помощью CamcorderProfile.get() . Для версий Android до 2.2 необходимо установить формат вывода видео и параметры кодирования:
        1. setOutputFormat() — установите формат вывода, укажите настройку по умолчанию или MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() — установите тип кодирования звука, укажите настройку по умолчанию или MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() — установите тип кодирования видео, укажите настройку по умолчанию или MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() — установите выходной файл, используйте getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() из примера метода в разделе «Сохранение медиафайлов» .
      6. setPreviewDisplay() — укажите элемент макета предварительного просмотра SurfaceView для вашего приложения. Используйте тот же объект, который вы указали для Connect Preview .

      Внимание: Вы должны вызывать эти методы конфигурации MediaRecorder в указанном порядке , иначе ваше приложение столкнется с ошибками и запись не удастся.

    3. Подготовьте MediaRecorder — подготовьте MediaRecorder с предоставленными настройками конфигурации, вызвав MediaRecorder.prepare() .
    4. Запустить MediaRecorder — начать запись видео, вызвав MediaRecorder.start() .
  5. Остановить запись видео . Чтобы успешно завершить запись видео, вызовите следующие методы:
    1. Остановить MediaRecorder — остановить запись видео, вызвав MediaRecorder.stop() .
    2. Сбросить MediaRecorder — при необходимости удалите настройки конфигурации из рекордера, вызвав MediaRecorder.reset() .
    3. Освободить MediaRecorder — Освободите MediaRecorder вызвав MediaRecorder.release() .
    4. Заблокировать камеру — заблокируйте камеру, чтобы будущие сеансы MediaRecorder могли использовать ее, вызвав Camera.lock() . Начиная с Android 4.0 (уровень API 14), этот вызов не требуется, если вызов MediaRecorder.prepare() не завершится сбоем.
  6. Остановить предварительный просмотр . Когда ваша деятельность с использованием камеры завершится, остановите предварительный просмотр с помощью Camera.stopPreview() .
  7. Освободить камеру . Отпустите камеру, чтобы другие приложения могли использовать ее, вызвав Camera.release() .

Примечание. MediaRecorder можно использовать без предварительного просмотра камеры и пропустить первые несколько шагов этого процесса. Однако, поскольку пользователи обычно предпочитают просматривать предварительный просмотр перед началом записи, этот процесс здесь не обсуждается.

Совет: Если ваше приложение обычно используется для записи видео, установите для setRecordingHint(boolean) значение true перед запуском предварительного просмотра. Эта настройка может помочь сократить время, необходимое для начала записи.

Настройка МедиаРекордера

При использовании класса MediaRecorder для записи видео необходимо выполнить шаги настройки в определенном порядке , а затем вызвать метод MediaRecorder.prepare() для проверки и реализации конфигурации. В следующем примере кода показано, как правильно настроить и подготовить класс MediaRecorder для записи видео.

Котлин

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
}

Ява

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

До Android 2.2 (уровень API 8) необходимо устанавливать параметры выходного формата и форматов кодирования напрямую, а не использовать CamcorderProfile . Этот подход продемонстрирован в следующем коде:

Котлин

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

Ява

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

Следующие параметры записи видео для MediaRecorder имеют настройки по умолчанию, однако вы можете настроить эти параметры для своего приложения:

Запуск и остановка MediaRecorder

При запуске и остановке записи видео с использованием класса MediaRecorder необходимо следовать определенному порядку, как указано ниже.

  1. Разблокируйте камеру с помощью Camera.unlock()
  2. Настройте MediaRecorder , как показано в примере кода выше.
  3. Начните запись с помощью MediaRecorder.start()
  4. Запишите видео
  5. Остановите запись с помощью MediaRecorder.stop()
  6. Освободите медиа-рекордер с помощью MediaRecorder.release()
  7. Заблокируйте камеру с помощью Camera.lock()

В следующем примере кода показано, как подключить кнопку для правильного запуска и остановки записи видео с помощью камеры и класса MediaRecorder .

Примечание. При завершении видеозаписи не отпускайте камеру, иначе предварительный просмотр будет остановлен.

Котлин

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

Ява

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

Примечание. В приведенном выше примере метод prepareVideoRecorder() относится к примеру кода, показанному в разделе «Настройка MediaRecorder» . Этот метод обеспечивает блокировку камеры, настройку и подготовку экземпляра MediaRecorder .

Отпускаем камеру

Камеры — это ресурс, который используется приложениями на устройстве совместно. Ваше приложение может использовать камеру после получения экземпляра Camera , и вы должны быть особенно осторожны, чтобы освободить объект камеры, когда ваше приложение перестанет его использовать и как только ваше приложение будет приостановлено ( Activity.onPause() ). Если ваше приложение не освобождает камеру должным образом, все последующие попытки доступа к камере, в том числе со стороны вашего собственного приложения, окажутся неудачными и могут привести к закрытию вашего или других приложений.

Чтобы освободить экземпляр объекта Camera , используйте метод Camera.release() , как показано в примере кода ниже.

Котлин

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

Ява

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

Внимание: Если ваше приложение не освобождает камеру должным образом, все последующие попытки доступа к камере, в том числе со стороны вашего собственного приложения, окажутся неудачными и могут привести к закрытию вашего или других приложений.

Сохранение медиафайлов

Мультимедийные файлы, созданные пользователями, такие как изображения и видео, следует сохранять в каталоге внешнего хранилища устройства (SD-карта), чтобы сэкономить системное пространство и предоставить пользователям доступ к этим файлам без устройства. Существует много возможных мест для сохранения медиафайлов на устройстве, однако есть только два стандартных места, которые вы должны учитывать как разработчик:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) — этот метод возвращает стандартное, общее и рекомендуемое расположение для сохранения изображений и видео. Этот каталог является общим (общедоступным), поэтому другие приложения могут легко находить, читать, изменять и удалять файлы, сохраненные в этом месте. Если ваше приложение будет удалено пользователем, медиафайлы, сохраненные в этом месте, не будут удалены. Чтобы не мешать существующим изображениям и видео пользователей, вам следует создать в этом каталоге подкаталог для медиафайлов вашего приложения, как показано в примере кода ниже. Этот метод доступен в Android 2.2 (уровень API 8). Эквивалентные вызовы в более ранних версиях API см. в разделе «Сохранение общих файлов» .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) — этот метод возвращает стандартное местоположение для сохранения изображений и видео, связанных с вашим приложением. Если ваше приложение удалено, все файлы, сохраненные в этом месте, будут удалены. Безопасность файлов в этом месте не обеспечивается, и другие приложения могут читать, изменять и удалять их.

В следующем примере кода показано, как создать расположение File или Uri для медиафайла, который можно использовать при вызове камеры устройства с Intent или как часть создания приложения камеры .

Котлин

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

Ява

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

Примечание. Environment.getExternalStoragePublicDirectory() доступен в Android 2.2 (уровень API 8) или более поздних версиях. Если вы ориентируетесь на устройства с более ранними версиями Android, используйте вместо этого Environment.getExternalStorageDirectory() . Дополнительную информацию см. в разделе Сохранение общих файлов .

Чтобы URI поддерживал рабочие профили, сначала преобразуйте URI файла в URI контента . Затем добавьте URI контента в EXTRA_OUTPUT Intent .

Дополнительную информацию о сохранении файлов на устройстве Android см. в разделе Хранение данных .

Возможности камеры

Android поддерживает широкий спектр функций камеры, которыми вы можете управлять с помощью приложения камеры, например формат изображения, режим вспышки, настройки фокусировки и многое другое. В этом разделе перечислены общие функции камеры и кратко описано, как их использовать. Доступ к большинству функций камеры и их настройку можно получить с помощью объекта Camera.Parameters . Однако есть несколько важных функций, которые требуют большего, чем простая настройка в Camera.Parameters . Эти функции описаны в следующих разделах:

Общие сведения об использовании функций, управляемых через Camera.Parameters , см. в разделе «Использование функций камеры» . Для получения более подробной информации о том, как использовать функции, управляемые через объект параметров камеры, перейдите по ссылкам в списке функций ниже на справочную документацию API.

Таблица 1. Общие функции камеры, отсортированные по уровню Android API, на котором они были представлены.

Особенность Уровень API Описание
Распознавание лиц 14 Распознавайте человеческие лица на изображении и используйте их для фокусировки, замера экспозиции и баланса белого.
Зоны измерения 14 Укажите одну или несколько областей изображения для расчета баланса белого.
Направления деятельности 14 Установите одну или несколько областей изображения, которые будут использоваться для фокусировки.
White Balance Lock 14 Остановите или запустите автоматическую регулировку баланса белого.
Exposure Lock 14 Остановите или запустите автоматическую регулировку экспозиции
Video Snapshot 14 Сделать снимок во время съемки видео (захват кадра)
Таймлапс-видео 11 Записывайте кадры с установленными задержками для записи замедленного видео.
Multiple Cameras 9 Поддержка более чем одной камеры на устройстве, включая фронтальную и заднюю камеры.
Focus Distance 9 Сообщает расстояния между камерой и объектами, которые кажутся в фокусе.
Zoom 8 Установить увеличение изображения
Exposure Compensation 8 Увеличьте или уменьшите уровень освещенности.
GPS Data 5 Включите или опустите данные о географическом местоположении в изображении.
White Balance 5 Установите режим баланса белого, который влияет на значения цветов в захваченном изображении.
Focus Mode 5 Установите способ фокусировки камеры на объекте, например автоматический, фиксированный, макро или бесконечность.
Scene Mode 5 Применение предустановленного режима для определенных типов фотосъемки, например, ночью, на пляже, в снегу или при свечах.
JPEG Quality 5 Установите уровень сжатия для изображения JPEG, который увеличивает или уменьшает качество и размер выходного файла изображения.
Flash Mode 5 Включите, выключите вспышку или используйте автоматическую настройку.
Color Effects 5 Примените к захваченному изображению цветовой эффект, например черно-белый, тон сепии или негатив.
Anti-Banding 5 Уменьшает эффект полос в цветовых градиентах за счет сжатия JPEG.
Picture Format 1 Укажите формат файла для изображения
Picture Size 1 Укажите размеры сохраненного изображения в пикселях.

Примечание. Эти функции поддерживаются не на всех устройствах из-за различий в аппаратном обеспечении и программной реализации. Информацию о проверке доступности функций на устройстве, на котором работает ваше приложение, см. в разделе Проверка доступности функций .

Проверка доступности функции

Первое, что нужно понимать, собираясь использовать функции камеры на устройствах Android, — это то, что не все функции камеры поддерживаются на всех устройствах. Кроме того, устройства, поддерживающие определенную функцию, могут поддерживать ее на разных уровнях или с разными опциями. Таким образом, частью процесса принятия решения при разработке приложения для камеры является определение того, какие функции камеры вы хотите поддерживать и на каком уровне. После принятия этого решения вам следует запланировать включение в приложение камеры кода, который проверяет, поддерживает ли аппаратное обеспечение устройства эти функции, и корректно завершает работу, если функция недоступна.

Вы можете проверить доступность функций камеры, получив экземпляр объекта параметров камеры и проверив соответствующие методы. В следующем примере кода показано, как получить объект Camera.Parameters и проверить, поддерживает ли камера функцию автофокусировки:

Котлин

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
}

Ява

// 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
}

Вы можете использовать технику, показанную выше, для большинства функций камеры. Объект Camera.Parameters предоставляет метод getSupported...() , is...Supported() или getMax...() для определения того, поддерживается ли (и в какой степени) функция.

Если вашему приложению для правильной работы требуются определенные функции камеры, вы можете потребовать их, добавив дополнения в манифест вашего приложения. Когда вы заявляете об использовании определенных функций камеры, таких как вспышка и автофокус, Google Play запрещает установку вашего приложения на устройства, которые не поддерживают эти функции. Список функций камеры, которые можно объявить в манифесте вашего приложения, см. в справочнике по функциям манифеста.

Использование функций камеры

Большинство функций камеры активируются и управляются с помощью объекта Camera.Parameters . Вы получаете этот объект, сначала получив экземпляр объекта Camera , вызвав метод getParameters() , изменив возвращаемый объект параметра и затем установив его обратно в объект камеры, как показано в следующем примере кода:

Котлин

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Ява

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

Этот метод работает практически для всех функций камеры, и большинство параметров можно изменить в любое время после получения экземпляра объекта Camera . Изменения параметров обычно видны пользователю сразу при предварительном просмотре камеры приложения. Что касается программного обеспечения, изменения параметров могут занять несколько кадров, прежде чем они действительно вступят в силу, поскольку аппаратное обеспечение камеры обрабатывает новые инструкции, а затем отправляет обновленные данные изображения.

Важно: некоторые функции камеры нельзя изменить по своему желанию. В частности, для изменения размера или ориентации предварительного просмотра камеры необходимо сначала остановить предварительный просмотр, изменить его размер, а затем перезапустить предварительный просмотр. Начиная с Android 4.0 (уровень API 14), ориентацию предварительного просмотра можно изменить без перезапуска предварительного просмотра.

Для реализации других функций камеры требуется больше кода, в том числе:

  • Зоны замера экспозиции и фокусировки
  • Распознавание лиц
  • Таймлапс видео

Краткое описание того, как реализовать эти функции, представлено в следующих разделах.

Зоны замера экспозиции и фокусировки

В некоторых сценариях фотосъемки автоматическая фокусировка и экспозамер могут не дать желаемых результатов. Начиная с Android 4.0 (уровень API 14), ваше приложение камеры может предоставлять дополнительные элементы управления, позволяющие вашему приложению или пользователям указывать области изображения, которые будут использоваться для определения настроек фокусировки или уровня освещенности, и передавать эти значения оборудованию камеры для использования при съемке. изображения или видео.

Области измерения и фокусировки работают очень похоже на другие функции камеры, поскольку вы управляете ими с помощью методов объекта Camera.Parameters . Следующий код демонстрирует настройку двух областей замера освещенности для экземпляра Camera :

Котлин

// 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
}

Ява

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

Объект Camera.Area содержит два параметра данных: объект Rect для указания области в поле зрения камеры и значение веса, которое сообщает камере, какой уровень важности этой области следует придавать при измерении освещенности или расчетах фокусировки.

Поле Rect в объекте Camera.Area описывает прямоугольную форму, отображаемую на сетке размером 2000 x 2000. Координаты -1000, -1000 представляют верхний левый угол изображения камеры, а координаты 1000, 1000 представляют нижний правый угол изображения камеры, как показано на рисунке ниже.

Рисунок 1. Красные линии иллюстрируют систему координат для указания Camera.Area в предварительном просмотре камеры. Синий прямоугольник показывает расположение и форму области камеры со значениями Rect 333,333,667,667.

Границы этой системы координат всегда соответствуют внешнему краю изображения, видимого при предварительном просмотре камеры, и не сжимаются и не расширяются с увеличением уровня масштабирования. Аналогично, вращение предварительного просмотра изображения с помощью Camera.setDisplayOrientation() не переназначает систему координат.

Распознавание лиц

Для изображений, на которых изображены люди, лица обычно являются наиболее важной частью изображения и должны использоваться для определения фокусировки и баланса белого при съемке изображения. Платформа Android 4.0 (API Level 14) предоставляет API для идентификации лиц и расчета настроек изображения с использованием технологии распознавания лиц.

Примечание. Пока функция обнаружения лиц работает, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) и setMeteringAreas(List<Camera.Area>) не действуют.

Для использования функции распознавания лиц в приложении камеры необходимо выполнить несколько общих шагов:

  • Убедитесь, что распознавание лиц поддерживается на устройстве.
  • Создание прослушивателя обнаружения лиц
  • Добавьте прослушиватель обнаружения лиц к объекту камеры.
  • Запуск распознавания лиц после предварительного просмотра (и после каждого перезапуска предварительного просмотра)

Функция распознавания лиц поддерживается не на всех устройствах. Вы можете проверить, поддерживается ли эта функция, вызвав getMaxNumDetectedFaces() . Пример этой проверки показан в примере метода startFaceDetection() ниже.

Чтобы получать уведомления и реагировать на обнаружение лица, приложение камеры должно настроить прослушиватель событий обнаружения лица. Для этого необходимо создать класс прослушивателя, реализующий интерфейс Camera.FaceDetectionListener , как показано в примере кода ниже.

Котлин

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

Ява

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

После создания этого класса вы затем устанавливаете его в объект Camera вашего приложения, как показано в примере кода ниже:

Котлин

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Ява

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Ваше приложение должно запускать функцию обнаружения лиц каждый раз, когда вы запускаете (или перезапускаете) предварительный просмотр камеры. Создайте метод для запуска распознавания лиц, чтобы вы могли вызывать его по мере необходимости, как показано в примере кода ниже.

Котлин

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

Ява

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

Вы должны запускать распознавание лиц каждый раз, когда запускаете (или перезапускаете) предварительный просмотр камеры. Если вы используете класс предварительного просмотра, показанный при создании класса предварительного просмотра , добавьте свой метод startFaceDetection() как в методы surfaceCreated() , так и surfaceChanged() в вашем классе предварительного просмотра, как показано в примере кода ниже.

Котлин

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

Ява

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

Примечание. Не забудьте позвонить в этот метод после вызова startPreview() . Не пытайтесь начать обнаружение лица в методе onCreate() основной деятельности приложения вашей камеры, так как предварительный просмотр недоступен к этому моменту в вашем приложении.

Время промежуточного видео

Видео Time Lappe позволяет пользователям создавать видеоклипы, которые объединяют фотографии, затрачиваемые на несколько секунд или минут друг от друга. Эта функция использует MediaRecorder для записи изображений для последовательности промежутка времени.

Чтобы записать видео о промежутке времени с помощью MediaRecorder , необходимо настроить объект Recorder, как если бы вы записывали обычное видео, устанавливая захваченные кадры в секунду на низкое число и используя одну из настройки качества промежутка времени, как показано в примере кода ниже.

Котлин

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Ява

// 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

Эти настройки должны быть выполнены как часть более крупной процедуры конфигурации для MediaRecorder . Для полного примера кода конфигурации см. Настройку MedieareCorder . После завершения конфигурации вы запускаете видеозапись видео, как будто вы записывали обычный видеоклип. Для получения дополнительной информации о настройке и запуске MediaRecorder см. В захвате видео .

Образцы Camera2Video и HDRViewFinder дополнительно демонстрируют использование API, охватываемых на этой странице.

Поля камеры, которые требуют разрешения

Приложения, управляющие Android 10 (уровень API 29) или выше, должны иметь разрешение CAMERA , чтобы получить доступ к значениям следующих полей, которые возвращает метод 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

Дополнительный пример кода

Чтобы загрузить приложения, см. Пример Camera2basic и официальное приложение Camerax Sample .

,

Android Framework включает в себя поддержку различных камер и функций камеры, доступных на устройствах, что позволяет собирать изображения и видео в ваших приложениях. В этом документе обсуждается быстрый, простой подход к захвату изображений и видео и описывает расширенный подход к созданию пользовательских камерных опытов для ваших пользователей.

Примечание. На этой странице описывается класс Camera , который устарел. Мы рекомендуем использовать библиотеку JetPack Camerax или, для конкретных вариантов использования, camera2 , класс. Как камер, так и камера 2 работают на Android 5.0 (API -уровне 21) и выше.

См. Следующие связанные ресурсы:

Соображения

Прежде чем позволить вашему приложению использовать камеры на устройствах Android, вам следует рассмотреть несколько вопросов о том, как ваше приложение намеревается использовать эту аппаратную функцию.

  • Требование камеры - Является ли использование камеры настолько важным для вашего приложения, что вы не хотите, чтобы ваше приложение было установлено на устройстве, у которого нет камеры? Если это так, вы должны объявить требования камеры в своем манифесте .
  • Краткое изображение или индивидуальная камера - как ваше приложение будет использовать камеру? Вы просто заинтересованы в том, чтобы сделать быстрый картинки или видеоклип, или ваше приложение предоставит новый способ использования камер? Чтобы получить быстрый снимок или клип, рассмотрите возможность использования существующих приложений камеры . Для разработки индивидуальной функции камеры, ознакомьтесь с разделом приложения «Построение камеры» .
  • Требование услуг переднего плана - Когда ваше приложение взаимодействует с камерой? На Android 9 (API -уровне 28), а затем приложения, работающие на фоне, не могут получить доступ к камере. Поэтому вам следует использовать камеру, когда ваше приложение находится на переднем плане, либо в рамках службы переднего плана .
  • Хранение - предназначены ли изображения или видео, предназначенные для вашего приложения, чтобы быть видимыми только для вашего приложения или обмен, чтобы их использовали другие приложения, такие как галерея или другие медиа и социальные приложения? Вы хотите, чтобы фотографии и видео были доступны, даже если ваше приложение удалено? Проверьте раздел «Сохранение медиа -файлов» , чтобы увидеть, как реализовать эти параметры.

Основы

Framework Android поддерживает съемку изображений и видео через API android.hardware.camera2 или Intent камеры. Вот соответствующие классы:

android.hardware.camera2
Этот пакет является основным API для управления камерами устройства. Его можно использовать для съемки или видео при создании приложения камеры.
Camera
Этот класс является более старым устаревшим API для управления камерами устройства.
SurfaceView
Этот класс используется для представления предварительного просмотра камеры для пользователя.
MediaRecorder
Этот класс используется для записи видео с камеры.
Intent
Тип действия намерения MediaStore.ACTION_IMAGE_CAPTURE или MediaStore.ACTION_VIDEO_CAPTURE можно использовать для захвата изображений или видео без непосредственного использования объекта Camera .

Манифестные заявления

Перед началом разработки вашего приложения с помощью API камеры вы должны убедиться, что у вашего манифеста есть соответствующие объявления, позволяющие использовать аппаратное обеспечение камеры и другие связанные функции.

  • Разрешение камеры - ваше приложение должно запросить разрешение на использование камеры устройства.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Примечание. Если вы используете камеру , вызывая существующее приложение камеры , вашему приложению не нужно запросить это разрешение.

  • Функции камеры - Например, ваше приложение также должно объявить о функциях камеры:
    <uses-feature android:name="android.hardware.camera" />
    

    Список функций камеры см. Справочник Manifest Features .

    Добавление функций камеры в ваш манифест заставляет Google Play, чтобы предотвратить установку вашего приложения на устройства, которые не включают камеру или не поддерживают указанные вами функции камеры. Для получения дополнительной информации об использовании фильтрации на основе функций с помощью Google Play см . В Google Play и Filtering Filtering .

    Если ваше приложение может использовать функцию камеры или камеры для правильной работы, но не требует этого, вы должны указать это в манифесте, включив атрибут android:required и установив его на false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Разрешение на хранение - ваше приложение может сохранять изображения или видео на внешнее хранилище устройства (SD -карта), если оно нацелено на Android 10 (уровень 29 API 29) или ниже и указывает следующее в манифесте.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Разрешение на запись аудио - Для записи аудио с захватом видео ваше приложение должно запросить разрешение на захват аудио.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Разрешение на местоположение - если ваше приложение течет изображений с информацией о местоположении GPS, необходимо запросить разрешение ACCESS_FINE_LOCATION . Обратите внимание, что, если ваше приложение нацелено на Android 5.0 (API -уровень 21) или выше, вам также необходимо заявить, что ваше приложение использует GPS устройства:

    <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" />
    

    Для получения дополнительной информации о получении местоположения пользователя см. Стратегии местоположения .

Использование существующих приложений камеры

Быстрый способ включить снимки или видео в вашем приложении без большого дополнительного кода - использовать Intent вызвать существующее приложение для камеры Android. Детали описаны в уроках обучения , которые просто делают фотографии просто и просто записывают видео .

Создание приложения камеры

Некоторым разработчикам может потребоваться пользовательский интерфейс камеры, который настроен на внешний вид их приложения или предоставляет специальные функции. Написание своего собственного кода с рисунком может обеспечить более убедительный опыт для ваших пользователей.

ПРИМЕЧАНИЕ. Следующее руководство предназначено для старых устаревших API Camera . Для новых или расширенных приложений камеры рекомендуется более новый API android.hardware.camera2 .

Общие шаги по созданию пользовательского интерфейса камеры для вашего приложения следующие:

  • Обнаружение и доступ к камере - Создайте код для проверки наличия камер и запроса доступа.
  • Создайте класс предварительного просмотра - создайте класс предварительного просмотра камеры, который расширяет SurfaceView и реализует интерфейс SurfaceHolder . Этот класс предварительно просмотрит живые изображения с камеры.
  • Создайте макет предварительного просмотра - как только у вас будет класс предварительного просмотра камеры, создайте макет представления, который включает в себя предварительный просмотр и элемент управления пользовательским интерфейсом, который вы хотите.
  • Настройка слушателей для захвата - подключите слушатели для управления вашим интерфейсом, чтобы запустить изображение или видео в ответ на действия пользователя, такие как нажатие кнопки.
  • Захват и сохранение файлов - Настройка кода для сбора изображений или видео и сохранения вывода.
  • Отпустите камеру - после использования камеры ваше приложение должно правильно отпустить ее для использования другими приложениями.

Аппаратное обеспечение камеры - это общий ресурс, который должен быть тщательно управляться, поэтому ваше приложение не сталкивается с другими приложениями, которые также могут его использовать. В следующих разделах обсуждается, как обнаружить аппаратное обеспечение камеры, как запросить доступ к камере, как снимать изображения или видео и как выпустить камеру, когда ваше приложение выполняется с помощью ее.

Осторожно: не забудьте выпустить объект Camera , позвонив в Camera.release() Если ваше приложение не отпускает камеру должным образом, все последующие попытки получить доступ к камере, в том числе с помощью вашего собственного приложения, потерпят неудачу и могут привести к выключению ваших или других приложений.

Обнаружение аппаратного обеспечения камеры

Если ваше приложение конкретно не требует камеры с использованием манифестного объявления, вы должны проверить, доступна ли камера во время выполнения. Чтобы выполнить эту проверку, используйте метод PackageManager.hasSystemFeature() , как показано в примере кода ниже:

Котлин

/** 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
    }
}

Ява

/** 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;
    }
}

Устройства Android могут иметь несколько камер, например, камеру с обратной задачей для фотографии и фронтальную камеру для видеозвонок. Android 2.3 (API -уровень 9), а затем позволяет проверить количество камер, доступных на устройстве с использованием метода Camera.getNumberOfCameras() .

Доступ к камерам

Если вы определили, что устройство, на котором работает ваше приложение, имеет камеру, вы должны попросить получить к нему доступ, получив экземпляр Camera (если вы не используете намерение получить доступ к камере ).

Чтобы получить доступ к основной камере, используйте метод Camera.open() и обязательно поймайте любые исключения, как показано в коде ниже:

Котлин

/** 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
    }
}

Ява

/** 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
}

Осторожно: всегда проверяйте исключения при использовании Camera.open() . Неспособность проверить на наличие исключений, если камера используется или не существует, приведет к выключению вашего приложения системой.

На устройствах под управлением Android 2.3 (API -уровень 9) или выше вы можете получить доступ к конкретным камерам с использованием Camera.open(int) . Пример приведенного выше будет получить доступ к первой обратной камере на устройстве с более чем одной камерой.

Проверка функций камеры

Как только вы получите доступ к камере, вы можете получить дополнительную информацию о ее возможностях, используя метод Camera.getParameters() и проверить возвращенную Camera.Parameters . При использовании уровня API 9 или выше, используйте Camera.getCameraInfo() чтобы определить, находится ли камера на передней или задней части устройства, а также ориентацию изображения.

Создание класса предварительного просмотра

Чтобы пользователи могли эффективно снимать снимки или видео, они должны быть в состоянии увидеть, что видит камера устройства. Класс предварительного просмотра камеры - это SurfaceView , которая может отображать данные живого изображения, поступающие с камеры, поэтому пользователи могут создавать и снимать изображение или видео.

В следующем примере код демонстрируется, как создать базовый класс предварительного просмотра камеры, который может быть включен в макет View . Этот класс реализует SurfaceHolder.Callback , чтобы захватить события обратного вызова для создания и уничтожения представления, которые необходимы для назначения ввода предварительного просмотра камеры.

Котлин

/** 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}")
            }
        }
    }
}

Ява

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

Если вы хотите установить определенный размер для предварительного просмотра камеры, установите его в методе surfaceChanged() , как указано в комментариях выше. При настройке размера предварительного просмотра вы должны использовать значения из getSupportedPreviewSizes() . Не устанавливайте произвольные значения в методе setPreviewSize() .

ПРИМЕЧАНИЕ. С введением функции с несколькими Window в Android 7.0 (API-уровне 24) и выше, вы больше не можете предполагать, что соотношение сторон предварительного просмотра совпадает с вашей деятельностью даже после вызова setDisplayOrientation() . В зависимости от размера окна и соотношения сторон, вам, возможно, придется поместить широкий предварительный просмотр камеры в ориентированную на портретную макет, или наоборот, используя макет букв.

Расположение предварительного просмотра в макете

Класс предварительного просмотра камеры, такой как пример, показанный в предыдущем разделе, должен быть размещен в макете действия вместе с другими элементами управления пользовательским интерфейсом для съемки или видео. В этом разделе показано, как создать базовый макет и активность для предварительного просмотра.

Следующий код макета предоставляет очень простой представление, которое можно использовать для отображения предварительного просмотра камеры. В этом примере элемент FrameLayout должен быть контейнером для класса предварительного просмотра камеры. Этот тип макета используется таким образом, чтобы дополнительная информация или управления изображениями можно было наложить на изображения предварительного просмотра в прямом эфире.

<?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>

На большинстве устройств ориентация по умолчанию предварительного просмотра камеры заключается в ландшафте. Этот пример макета указывает горизонтальную (ландшафтную) макет, а приведенный ниже код фиксирует ориентацию применения на ландшафт. Для простоты при подаче предварительного просмотра камеры вы должны изменить ориентацию предварительного просмотра приложения на ландшафт, добавив следующее к вашему манифесту.

<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>

Примечание. Предварительный просмотр камеры не должен быть в режиме ландшафта. Начиная с Android 2.2 (API -уровень 8), вы можете использовать метод setDisplayOrientation() для установления вращения изображения предварительного просмотра. Чтобы изменить ориентацию предварительного просмотра, когда пользователь переорирует телефон, в рамках метода surfaceChanged() вашего класса предварительного просмотра сначала остановите предварительный просмотр с помощью Camera.stopPreview() изменить ориентацию, а затем снова запустите предварительный просмотр с Camera.startPreview() .

В действии для представления вашей камеры добавьте свой класс предварительного просмотра в элемент FrameLayout , показанный в примере выше. Ваша активность камеры также должна гарантировать, что она выпускает камеру при приостановке или выключении. В следующем примере показано, как изменить активность камеры, чтобы подключить класс предварительного просмотра, показанный при создании класса предварительного просмотра .

Котлин

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

Ява

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

ПРИМЕЧАНИЕ. Метод getCameraInstance() в приведенном выше примере относится к примеру метода, показанного в доступе к камерам .

Захватывает картинки

После того, как вы создали класс предварительного просмотра и макет представления, в котором можно отобразить его, вы готовы начать снимать изображения с помощью вашего приложения. В вашем коде приложения вы должны настроить слушателей для управления пользовательским интерфейсом, чтобы ответить на действие пользователя, сделав снижение.

Чтобы получить изображение, используйте метод Camera.takePicture() . Этот метод принимает три параметра, которые получают данные от камеры. Чтобы получить данные в формате JPEG, вы должны реализовать интерфейс Camera.PictureCallback . В следующем коде показана базовая реализация интерфейса Camera.PictureCallback для сохранения изображения, полученного с камеры.

Котлин

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

Ява

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

Запуск захвата изображения, вызывая метод Camera.takePicture() . В следующем примере кода показано, как вызвать этот метод из кнопки View.OnClickListener .

Котлин

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Ява

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

Примечание. Член mPicture в следующем примере относится к примеру кода выше.

Осторожно: не забудьте выпустить объект Camera , позвонив в Camera.release() Для получения информации о том, как выпустить камеру, см. Выпуск камеры .

Захват видео

Захват видео с использованием Android Framework требует тщательного управления объектом Camera и координации с классом MediaRecorder . При записи видео с помощью Camera вы должны управлять вызовы Camera.lock() и Camera.unlock() , чтобы позволить MediaRecorder доступ к аппаратному обеспечению камеры, в дополнение к Camera.open() и Camera.release() .

ПРИМЕЧАНИЕ. Начиная с Android 4.0 (API -уровень 14), Camera.lock() и Camera.unlock() вызовы автоматически управляются для вас.

В отличие от фотографирования с помощью камеры устройства, для захвата видео требуется очень конкретный заказ вызовов. Вы должны следовать конкретному порядку выполнения, чтобы успешно подготовиться и снять видео с вашим приложением, как подробно описано ниже.

  1. Открыть камеру - используйте Camera.open() чтобы получить экземпляр объекта камеры.
  2. Подключите предварительный просмотр - подготовьте предварительный просмотр изображения камеры, подключив SurfaceView к камере с помощью Camera.setPreviewDisplay() .
  3. Start Preview - Call Camera.startPreview() , чтобы начать отображение изображений живой камеры.
  4. Начните записывать видео - должны быть выполнены следующие шаги , чтобы успешно записать видео:
    1. Разблокируйте камеру - разблокируйте камеру для использования MediaRecorder вызывая Camera.unlock() .
    2. Настройте MediareCorder - вызовите следующие методы MediaRecorder в этом порядке . Для получения дополнительной информации см. Справочную документацию MediaRecorder .
      1. setCamera() - Установите камеру для использования для захвата видео, используйте текущий экземпляр Camera вашего приложения.
      2. setAudioSource() - Установите источник аудио, используйте MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() - Установите источник видео, используйте MediaRecorder.VideoSource.CAMERA .
      4. Установите формат вывода видео и кодирование. Для Android 2.2 (API -уровне 8) и выше, используйте метод MediaRecorder.setProfile и получите экземпляр профиля с использованием CamcorderProfile.get() . Для версий Android до 2.2, вы должны установить формат вывода видео и параметры кодирования:
        1. setOutputFormat() - Установите выходной формат, укажите настройку по умолчанию или MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() - установите тип кодирования звука, укажите настройку по умолчанию или MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() - Установите тип кодирования видео, укажите настройку по умолчанию или MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() - Установите выходной файл, используйте getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() из метода примера в разделе «Сохранение медиа -файлов» .
      6. setPreviewDisplay() - укажите элемент макета предварительного просмотра SurfaceView для вашего приложения. Используйте тот же объект, который вы указали для предварительного просмотра Connect .

      Внимание: вы должны вызвать эти методы конфигурации MediaRecorder в этом порядке , в противном случае ваше приложение столкнется с ошибками, а запись потерпит неудачу.

    3. Подготовьте MediareCorder - подготовьте MediaRecorder с предоставленными настройками конфигурации, позвонив в MediaRecorder.prepare() .
    4. Start MedieareCorder - Начните записывать видео, позвонив MediaRecorder.start() .
  5. Прекратить запись видео - вызовите следующие методы, чтобы успешно завершить видеозапись:
    1. Stop MedieareCorder - Stop Winding Video, позвонив MediaRecorder.stop() .
    2. Сбросить MediareCorder - необязательно удалить настройки конфигурации с рекордера, вызывая MediaRecorder.reset() .
    3. Выпустить MedieareCorder - Выпустите MediaRecorder , назвав MediaRecorder.release() .
    4. Заблокируйте камеру - заблокируйте камеру так, чтобы будущие сеансы MediaRecorder могли использовать ее, вызывая Camera.lock() . Начиная с Android 4.0 (уровень API 14), этот вызов не требуется, если вызов MediaRecorder.prepare() не выполняется.
  6. Остановите предварительный просмотр - когда ваша деятельность закончила с помощью камеры, остановите предварительный просмотр с помощью Camera.stopPreview() .
  7. Отпустите камеру - отпустите камеру, чтобы другие приложения могли использовать ее, вызывая Camera.release() .

ПРИМЕЧАНИЕ. Можно использовать MediaRecorder , не создавая предварительный просмотр камеры и пропустить первые несколько этапов этого процесса. Однако, поскольку пользователи обычно предпочитают видеть предварительный просмотр перед началом записи, этот процесс здесь не обсуждается.

Совет: если ваше приложение обычно используется для записи видео, установите setRecordingHint(boolean) true до начала вашего предварительного просмотра. Этот параметр может помочь сократить время, необходимое для начала записи.

Настройка MedieareCorder

При использовании класса MediaRecorder для записи видео вы должны выполнить шаги конфигурации в определенном порядке , а затем позвонить в метод MediaRecorder.prepare() для проверки и реализации конфигурации. В следующем примере код демонстрируется, как правильно настроить и подготовить класс MediaRecorder для записи видео.

Котлин

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
}

Ява

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

Перед Android 2.2 (API -уровнем 8) необходимо напрямую установить параметры выходного формата и форматы кодирования, а не использование CamcorderProfile . Этот подход демонстрируется в следующем коде:

Котлин

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

Ява

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

Следующие параметры записи видео для MediaRecorder даются настройки по умолчанию, однако вы можете настроить эти настройки для вашего приложения:

Запуск и остановка медиа -

При запуске и остановке записи видео с использованием класса MediaRecorder вы должны следовать конкретному порядку, как указано ниже.

  1. Разблокировать камеру с помощью Camera.unlock()
  2. Настройка MediaRecorder , как показано в примере кода выше
  3. Начните записывать с помощью MediaRecorder.start()
  4. Запишите видео
  5. Прекратите запись с использованием MediaRecorder.stop()
  6. Выпустить регистратор в медиа -рекордере с MediaRecorder.release()
  7. Заблокируйте камеру с помощью Camera.lock()

В следующем примере код демонстрируется, как подключить кнопку для правильного запуска и остановки записи видео с помощью камеры и класса MediaRecorder .

ПРИМЕЧАНИЕ. При завершении записи видео не выпускайте камеру, иначе ваш предварительный просмотр будет остановлен.

Котлин

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

Ява

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

ПРИМЕЧАНИЕ. В приведенном выше примере метод prepareVideoRecorder() относится к примеру кода, показанного при настройке MediareCorder . Этот метод заботится о блокировке камеры, настройке и подготовке экземпляра MediaRecorder .

Выпуск камеры

Камеры - это ресурс, который разделяется приложениями на устройстве. Ваше приложение может использовать камеру после получения экземпляра Camera , и вы должны быть особенно осторожны, чтобы освободить объект камеры, когда ваше приложение перестает его использовать, и как только ваше приложение будет приостановлено ( Activity.onPause() ). Если ваше приложение не отпускает камеру должным образом, все последующие попытки получить доступ к камере, в том числе с помощью вашего собственного приложения, потерпят неудачу и могут привести к выключению ваших или других приложений.

Чтобы выпустить экземпляр объекта Camera , используйте метод Camera.release() , как показано в примере кода ниже.

Котлин

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

Ява

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

Внимание: если ваше приложение не отпускает камеру, все последующие попытки получить доступ к камере, в том числе с помощью вашего собственного приложения, потерпят неудачу и могут привести к выключению ваших или других приложений.

Сохранение медиа -файлов

СМИ файлы, созданные пользователями, такими как изображения и видео, должны быть сохранены в каталоге внешнего хранилища (SD -карта) устройства для сохранения системного пространства и для того, чтобы пользователи могли получить доступ к этим файлам без своего устройства. Существует много возможных местоположений каталогов для сохранения медиа -файлов на устройстве, однако существует только два стандартных местоположения, которые вы должны рассматривать как разработчик:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - Этот метод возвращает стандартное, общее и рекомендуемое место для сохранения изображений и видео. Этот каталог обменивается (общедоступным), поэтому другие приложения могут легко обнаружить, читать, изменять и удалять файлы, сохраненные в этом месте. Если ваше приложение удаляется пользователем, медиа -файлы, сохраненные в это место, не будут удалены. Чтобы не вмешиваться в пользователи существующих изображений и видео, вы должны создать подканальную режиссера для медиа-файлов вашего приложения в этом каталоге, как показано в примере кода ниже. Этот метод доступен в Android 2.2 (API -уровне 8) для эквивалентных вызовов в более ранних версиях API, см. Сохранение общих файлов .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - Этот метод возвращает стандартное местоположение для сохранения изображений и видео, которые связаны с вашим приложением. Если ваше приложение удаляется, любые файлы, сохраненные в этом месте, удалены. Безопасность не применяется для файлов в этом месте, и другие приложения могут читать, изменять и удалять их.

В следующем примере код демонстрируется, как создать File или местоположение Uri для медиа -файла, который можно использовать при вызове камеры устройства с Intent или как часть приложения для построения камеры .

Котлин

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

Ява

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

Примечание. Environment.getExternalStoragePublicDirectory() доступен в Android 2.2 (API -уровне 8) или выше. Если вы нацелены на устройства с более ранними версиями Android, используйте Environment.getExternalStorageDirectory() . Для получения дополнительной информации см. Сохранение общих файлов .

Чтобы сделать профили работы поддержки URI, сначала преобразуйте файл URI в URI контента . Затем добавьте URI контента в EXTRA_OUTPUT о Intent .

Для получения дополнительной информации о сохранении файлов на устройстве Android см. Хранение данных .

Функции камеры

Android поддерживает широкий спектр функций камеры, которые вы можете управлять с помощью приложения камеры, например, формат изображений, режим Flash, настройки фокусировки и многое другое. В этом разделе перечислены общие функции камеры и кратко обсуждаются, как их использовать. Большинство функций камеры можно получить доступ и установить с помощью объекта через Camera.Parameters . Pparameters. Тем не менее, есть несколько важных функций, которые требуют более чем простых настройки в Camera.Parameters . Эти функции рассматриваются в следующих разделах:

Для общей информации о том, как использовать функции, которые контролируются через Camera.Parameters , просмотрите раздел «Использование функций камеры» . Для получения более подробной информации о том, как использовать функции, управляемые через объект параметров камеры, перейдите по ссылкам в списке функций, ниже, с эталонной документацией API.

Таблица 1. Обычные функции камеры, отсортированные по уровню API Android, на котором они были представлены.

Особенность API Уровень Описание
Распознавание лиц 14 Определите человеческие лица на картинке и используйте их для фокуса, измерения и баланса белого
Учитывающие зоны 14 Укажите одну или несколько областей в изображении для расчета баланса белого
Направления деятельности 14 Установите одну или несколько областей в изображении для использования для фокуса
White Balance Lock 14 Остановите или запустите автоматические корректировки баланса белого
Exposure Lock 14 Остановить или запустить автоматические корректировки экспозиции
Video Snapshot 14 Сфотографируйте во время съемки видео (захват кадров)
Время промежуточного видео 11 Записи рам
Multiple Cameras 9 Поддержка для более чем одной камеры на устройстве, включая фронтальные и обратные камеры
Focus Distance 9 Сообщает расстояния между камерой и объектами, которые, кажется, находятся в фокусе
Zoom 8 Установить увеличение изображения
Exposure Compensation 8 Увеличить или уменьшить уровень воздействия света
GPS Data 5 Включите или опустите данные географического местоположения с изображением
White Balance 5 Установите режим баланса белого, который влияет на значения цвета в захваченном изображении
Focus Mode 5 Установите, как камера фокусируется на предмете, такой как автоматический, фиксированный, макрос или бесконечность
Scene Mode 5 Примените заданный режим для конкретных типов фотографий, таких как ночь, пляж, снег или сцены при свечах
JPEG Quality 5 Установите уровень сжатия для изображения JPEG, которое увеличивает или уменьшает качество выходного файла изображения и размер
Flash Mode 5 Включите вспышку или используйте автоматическую настройку
Color Effects 5 Примените эффект цвета к захваченному изображению, такому как черно -белый, сепийский тон или отрицательный.
Anti-Banding 5 Уменьшает эффект полос цветовых градиентов из -за сжатия JPEG
Picture Format 1 Укажите формат файла для изображения
Picture Size 1 Укажите размеры пикселей сохраненной картинки

Примечание. Эти функции не поддерживаются на всех устройствах из -за различий в оборудовании и реализации программного обеспечения. Для получения информации о проверке доступности функций на устройстве, где работает ваше приложение, см. Проверка доступности функций .

Проверка доступности функции

Первое, что нужно понять при использовании функций камеры на устройствах Android, это то, что не все функции камеры поддерживаются на всех устройствах. Кроме того, устройства, которые поддерживают определенную функцию, могут поддерживать их на разных уровнях или с разными параметрами. Таким образом, часть вашего процесса принятия решения при разработке приложения камеры заключается в том, чтобы решить, какие функции камеры вы хотите поддержать и на каком уровне. После принятия этого решения вы должны планировать включение кода в приложение вашей камеры, которое проверяет, поддерживает ли аппаратное обеспечение устройства эти функции и изящно сбои, если функция недоступна.

Вы можете проверить наличие функций камеры, получив экземпляр объекта параметров камеры и проверив соответствующие методы. Следующий образец кода показывает, как получить объект Camera.Parameters и проверить, поддерживает ли камера функцию автофокуса:

Котлин

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
}

Ява

// 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
}

Вы можете использовать технику, показанную выше для большинства функций камеры. Объект Camera.Parameters обеспечивает getSupported...() , is...Supported() или getMax...() чтобы определить (и в какой степени) поддерживается функция.

Если ваше приложение требует определенных функций камеры, чтобы правильно функционировать, вы можете потребовать их посредством дополнений к манифесту вашего приложения. Когда вы заявляете об использовании определенных функций камеры, таких как Flash и Auto-Focus, Google Play ограничивает ваше приложение установлено на устройствах, которые не поддерживают эти функции. Список функций камеры, которые можно объявить в манифесте вашего приложения, см. Справочник Manifest Features .

Использование функций камеры

Большинство функций камеры активируются и контролируются с использованием объекта Camera.Parameters . Parameters. Вы получаете этот объект, сначала получив экземпляр объекта Camera , вызывая метод getParameters() , изменяя возвращаемый объект параметра, а затем установив его обратно в объект камеры, как показано в следующем примере кода:

Котлин

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Ява

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

Этот метод работает почти для всех функций камеры, и большинство параметров можно изменить в любое время после того, как вы получили экземпляр объекта Camera . Изменения в параметрах обычно видны пользователю немедленно в предварительном просмотре камеры приложения. На стороне программного обеспечения изменения параметров могут потребоваться несколько кадров, чтобы фактически вступить в силу, поскольку аппаратное обеспечение камеры обрабатывает новые инструкции, а затем отправляет обновленные данные изображения.

Важно: некоторые функции камеры не могут быть изменены по желанию. В частности, изменение размера или ориентации предварительного просмотра камеры требует, чтобы вы сначала остановили предварительный просмотр, изменили размер предварительного просмотра, а затем перезапустили предварительный просмотр. Начиная с Android 4.0 (API уровня 14) Предварительной ориентации может быть изменена без перезапуска предварительного просмотра.

Другие функции камеры требуют большего кода для реализации, включая:

  • Области и фокусировки
  • Распознавание лиц
  • Время промежуточного видео

Быстрый план того, как реализовать эти функции, представлен в следующих разделах.

Области и фокусировки

В некоторых фотографических сценариях автоматическая фокусировка и измерение света могут не дать желаемых результатов. Начиная с Android 4.0 (уровень API -уровня 14), ваше приложение камеры может предоставить дополнительные элементы управления, чтобы позволить вашему приложению или пользователям указать области в изображении для определения настройки фокуса или уровня освещения и передавать эти значения аппаратному обеспечению камеры для использования при захвате изображения или видео.

Области для измерения и фокусировки работают очень аналогично другим функциям камеры, так как вы контролируете их с помощью методов в Camera.Parameters Object. Следующий код демонстрирует установление двух областей измерения света для экземпляра Camera :

Котлин

// 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
}

Ява

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

Объект Camera.Area содержит два параметра данных: Rect объект для указания области в поле зрения камеры и значение веса, которое сообщает камере, какой уровень важности должен быть указан в расчетах света или фокусировки.

Rect поле в Camera.Area Объект OREA описывает прямоугольную форму, отображаемую на единичной сетке 2000 x 2000. Координаты -1000, -1000 представляют верхний, левый угол изображения камеры и координат 1000, 1000 представляют нижний, правый угол изображения камеры, как показано на рисунке ниже.

Рисунок 1. Красные линии иллюстрируют систему координат для указания Camera.Area В рамках предварительного просмотра камеры. Синяя коробка показывает местоположение и форму области камеры с Rect значения 333,333,667 667.

Границы этой системы координат всегда соответствуют внешнему краю изображения, видимого в предварительном просмотре камеры, и не сжимаются и не расширяются с уровнем масштабирования. Аналогичным образом, вращение предварительного просмотра изображения с использованием Camera.setDisplayOrientation() не удаляет систему координат.

Распознавание лиц

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.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) 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 the Camera.FaceDetectionListener interface as shown in the example code below.

Котлин

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

Ява

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:

Котлин

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Ява

camera.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.

Котлин

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

Ява

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 the surfaceCreated() and surfaceChanged() methods in your preview class, as shown in the sample code below.

Котлин

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

Ява

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

Note: 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.

Time lapse video

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 ниже.

Котлин

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Ява

// 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

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 .

The Camera2Video and HdrViewfinder samples further demonstrate the use of the APIs covered on this page.

Camera fields that require permission

Apps running Android 10 (API level 29) or higher must have the CAMERA permission in order to access the values of the following fields that the getCameraCharacteristics() method returns:

  • 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

Additional sample code

To download sample apps, see the Camera2Basic sample and Official CameraX sample app .

,

The Android framework includes support for various cameras and camera features available on devices, allowing you to capture pictures and videos in your applications. This document discusses a quick, simple approach to image and video capture and outlines an advanced approach for creating custom camera experiences for your users.

Note: This page describes the Camera class, which has been deprecated. We recommend using the CameraX Jetpack library or, for specific use cases, the camera2 , class. Both CameraX and Camera2 work on Android 5.0 (API level 21) and higher.

Refer to the following related resources:

Considerations

Before enabling your application to use cameras on Android devices, you should consider a few questions about how your app intends to use this hardware feature.

  • Camera Requirement - Is the use of a camera so important to your application that you do not want your application installed on a device that does not have a camera? If so, you should declare the camera requirement in your manifest .
  • Quick Picture or Customized Camera - How will your application use the camera? Are you just interested in snapping a quick picture or video clip, or will your application provide a new way to use cameras? For getting a quick snap or clip, consider Using Existing Camera Apps . For developing a customized camera feature, check out the Building a Camera App section.
  • Foreground Services Requirement - When does your app interact with the camera? On Android 9 (API level 28) and later, apps running in the background cannot access the camera. Therefore, you should use the camera either when your app is in the foreground or as part of a foreground service .
  • Storage - Are the images or videos your application generates intended to be only visible to your application or shared so that other applications such as Gallery or other media and social apps can use them? Do you want the pictures and videos to be available even if your application is uninstalled? Check out the Saving Media Files section to see how to implement these options.

Основы

The Android framework supports capturing images and video through the android.hardware.camera2 API or camera Intent . Here are the relevant classes:

android.hardware.camera2
This package is the primary API for controlling device cameras. It can be used to take pictures or videos when you are building a camera application.
Camera
This class is the older deprecated API for controlling device cameras.
SurfaceView
This class is used to present a live camera preview to the user.
MediaRecorder
This class is used to record video from the camera.
Intent
An intent action type of MediaStore.ACTION_IMAGE_CAPTURE or MediaStore.ACTION_VIDEO_CAPTURE can be used to capture images or videos without directly using the Camera object.

Manifest declarations

Before starting development on your application with the Camera API, you should make sure your manifest has the appropriate declarations to allow use of camera hardware and other related features.

  • Camera Permission - Your application must request permission to use a device camera.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Note: If you are using the camera by invoking an existing camera app , your application does not need to request this permission.

  • Camera Features - Your application must also declare use of camera features, for example:
    <uses-feature android:name="android.hardware.camera" />
    

    For a list of camera features, see the manifest Features Reference .

    Adding camera features to your manifest causes Google Play to prevent your application from being installed to devices that do not include a camera or do not support the camera features you specify. For more information about using feature-based filtering with Google Play, see Google Play and Feature-Based Filtering .

    If your application can use a camera or camera feature for proper operation, but does not require it, you should specify this in the manifest by including the android:required attribute, and setting it to false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Storage Permission - Your application can save images or videos to the device's external storage (SD Card) if it targets Android 10 (API level 29) or lower and specifies the following in the manifest.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Audio Recording Permission - For recording audio with video capture, your application must request the audio capture permission.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Location Permission - If your application tags images with GPS location information, you must request the ACCESS_FINE_LOCATION permission. Note that, if your app targets Android 5.0 (API level 21) or higher, you also need to declare that your app uses the device's GPS:

    <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" />
    

    For more information about getting user location, see Location Strategies .

Using existing camera apps

A quick way to enable taking pictures or videos in your application without a lot of extra code is to use an Intent to invoke an existing Android camera application. The details are described in the training lessons Taking Photos Simply and Recording Videos Simply .

Building a camera app

Some developers may require a camera user interface that is customized to the look of their application or provides special features. Writing your own picture-taking code can provide a more compelling experience for your users.

Note: The following guide is for the older, deprecated Camera API. For new or advanced camera applications, the newer android.hardware.camera2 API is recommended.

The general steps for creating a custom camera interface for your application are as follows:

  • Detect and Access Camera - Create code to check for the existence of cameras and request access.
  • Create a Preview Class - Create a camera preview class that extends SurfaceView and implements the SurfaceHolder interface. This class previews the live images from the camera.
  • Build a Preview Layout - Once you have the camera preview class, create a view layout that incorporates the preview and the user interface controls you want.
  • Setup Listeners for Capture - Connect listeners for your interface controls to start image or video capture in response to user actions, such as pressing a button.
  • Capture and Save Files - Setup the code for capturing pictures or videos and saving the output.
  • Release the Camera - After using the camera, your application must properly release it for use by other applications.

Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses how to detect camera hardware, how to request access to a camera, how to capture pictures or video and how to release the camera when your application is done using it.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Detecting camera hardware

If your application does not specifically require a camera using a manifest declaration, you should check to see if a camera is available at runtime. To perform this check, use the PackageManager.hasSystemFeature() method, as shown in the example code below:

Котлин

/** 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
    }
}

Ява

/** 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;
    }
}

Android devices can have multiple cameras, for example a back-facing camera for photography and a front-facing camera for video calls. Android 2.3 (API Level 9) and later allows you to check the number of cameras available on a device using the Camera.getNumberOfCameras() method.

Accessing cameras

If you have determined that the device on which your application is running has a camera, you must request to access it by getting an instance of Camera (unless you are using an intent to access the camera ).

To access the primary camera, use the Camera.open() method and be sure to catch any exceptions, as shown in the code below:

Котлин

/** 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
    }
}

Ява

/** 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
}

Caution: Always check for exceptions when using Camera.open() . Failing to check for exceptions if the camera is in use or does not exist will cause your application to be shut down by the system.

On devices running Android 2.3 (API Level 9) or higher, you can access specific cameras using Camera.open(int) . The example code above will access the first, back-facing camera on a device with more than one camera.

Checking camera features

Once you obtain access to a camera, you can get further information about its capabilities using the Camera.getParameters() method and checking the returned Camera.Parameters object for supported capabilities. When using API Level 9 or higher, use the Camera.getCameraInfo() to determine if a camera is on the front or back of the device, and the orientation of the image.

Creating a preview class

For users to effectively take pictures or video, they must be able to see what the device camera sees. A camera preview class is a SurfaceView that can display the live image data coming from a camera, so users can frame and capture a picture or video.

The following example code demonstrates how to create a basic camera preview class that can be included in a View layout. This class implements SurfaceHolder.Callback in order to capture the callback events for creating and destroying the view, which are needed for assigning the camera preview input.

Котлин

/** 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}")
            }
        }
    }
}

Ява

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

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes() . Do not set arbitrary values in the setPreviewSize() method.

Note: With the introduction of the Multi-Window feature in Android 7.0 (API level 24) and higher, you can no longer assume the aspect ratio of the preview is the same as your activity even after calling setDisplayOrientation() . Depending on the window size and aspect ratio, you may may have to fit a wide camera preview into a portrait-orientated layout, or vice versa, using a letterbox layout.

Placing preview in a layout

A camera preview class, such as the example shown in the previous section, must be placed in the layout of an activity along with other user interface controls for taking a picture or video. This section shows you how to build a basic layout and activity for the preview.

The following layout code provides a very basic view that can be used to display a camera preview. In this example, the FrameLayout element is meant to be the container for the camera preview class. This layout type is used so that additional picture information or controls can be overlaid on the live camera preview images.

<?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>

On most devices, the default orientation of the camera preview is landscape. This example layout specifies a horizontal (landscape) layout and the code below fixes the orientation of the application to landscape. For simplicity in rendering a camera preview, you should change your application's preview activity orientation to landscape by adding the following to your manifest.

<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>

Note: A camera preview does not have to be in landscape mode. Starting in Android 2.2 (API Level 8), you can use the setDisplayOrientation() method to set the rotation of the preview image. In order to change preview orientation as the user re-orients the phone, within the surfaceChanged() method of your preview class, first stop the preview with Camera.stopPreview() change the orientation and then start the preview again with Camera.startPreview() .

In the activity for your camera view, add your preview class to the FrameLayout element shown in the example above. Your camera activity must also ensure that it releases the camera when it is paused or shut down. The following example shows how to modify a camera activity to attach the preview class shown in Creating a preview class .

Котлин

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

Ява

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

Note: The getCameraInstance() method in the example above refers to the example method shown in Accessing cameras .

Capturing pictures

Once you have built a preview class and a view layout in which to display it, you are ready to start capturing images with your application. In your application code, you must set up listeners for your user interface controls to respond to a user action by taking a picture.

In order to retrieve a picture, use the Camera.takePicture() method. This method takes three parameters which receive data from the camera. In order to receive data in a JPEG format, you must implement an Camera.PictureCallback interface to receive the image data and write it to a file. The following code shows a basic implementation of the Camera.PictureCallback interface to save an image received from the camera.

Котлин

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

Ява

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

Trigger capturing an image by calling the Camera.takePicture() method. The following example code shows how to call this method from a button View.OnClickListener .

Котлин

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Ява

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

Note: The mPicture member in the following example refers to the example code above.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! For information about how to release the camera, see Releasing the camera .

Capturing videos

Video capture using the Android framework requires careful management of the Camera object and coordination with the MediaRecorder class. When recording video with Camera , you must manage the Camera.lock() and Camera.unlock() calls to allow MediaRecorder access to the camera hardware, in addition to the Camera.open() and Camera.release() calls.

Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

Unlike taking pictures with a device camera, capturing video requires a very particular call order. You must follow a specific order of execution to successfully prepare for and capture video with your application, as detailed below.

  1. Open Camera - Use the Camera.open() to get an instance of the camera object.
  2. Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera using Camera.setPreviewDisplay() .
  3. Start Preview - Call Camera.startPreview() to begin displaying the live camera images.
  4. Start Recording Video - The following steps must be completed in order to successfully record video:
    1. Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock() .
    2. Configure MediaRecorder - Call in the following MediaRecorder methods in this order . For more information, see the MediaRecorder reference documentation.
      1. setCamera() - Set the camera to be used for video capture, use your application's current instance of Camera .
      2. setAudioSource() - Set the audio source, use MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() - Set the video source, use MediaRecorder.VideoSource.CAMERA .
      4. Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get() . For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
        1. setOutputFormat() - Set the output format, specify the default setting or MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() - Set the sound encoding type, specify the default setting or MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() - Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() - Set the output file, use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() from the example method in the Saving Media Files section.
      6. setPreviewDisplay() - Specify the SurfaceView preview layout element for your application. Use the same object you specified for Connect Preview .

      Caution: You must call these MediaRecorder configuration methods in this order , otherwise your application will encounter errors and the recording will fail.

    3. Prepare MediaRecorder - Prepare the MediaRecorder with provided configuration settings by calling MediaRecorder.prepare() .
    4. Start MediaRecorder - Start recording video by calling MediaRecorder.start() .
  5. Stop Recording Video - Call the following methods in order , to successfully complete a video recording:
    1. Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop() .
    2. Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by calling MediaRecorder.reset() .
    3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release() .
    4. Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by calling Camera.lock() . Starting with Android 4.0 (API level 14), this call is not required unless the MediaRecorder.prepare() call fails.
  6. Stop the Preview - When your activity has finished using the camera, stop the preview using Camera.stopPreview() .
  7. Release Camera - Release the camera so that other applications can use it by calling Camera.release() .

Note: It is possible to use MediaRecorder without creating a camera preview first and skip the first few steps of this process. However, since users typically prefer to see a preview before starting a recording, that process is not discussed here.

Tip: If your application is typically used for recording video, set setRecordingHint(boolean) to true prior to starting your preview. This setting can help reduce the time it takes to start recording.

Configuring MediaRecorder

When using the MediaRecorder class to record video, you must perform configuration steps in a specific order and then call the MediaRecorder.prepare() method to check and implement the configuration. The following example code demonstrates how to properly configure and prepare the MediaRecorder class for video recording.

Котлин

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
}

Ява

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

Prior to Android 2.2 (API Level 8), you must set the output format and encoding formats parameters directly, instead of using CamcorderProfile . This approach is demonstrated in the following code:

Котлин

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

Ява

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

The following video recording parameters for MediaRecorder are given default settings, however, you may want to adjust these settings for your application:

Starting and stopping MediaRecorder

When starting and stopping video recording using the MediaRecorder class, you must follow a specific order, as listed below.

  1. Unlock the camera with Camera.unlock()
  2. Configure MediaRecorder as shown in the code example above
  3. Start recording using MediaRecorder.start()
  4. Record the video
  5. Stop recording using MediaRecorder.stop()
  6. Release the media recorder with MediaRecorder.release()
  7. Lock the camera using Camera.lock()

The following example code demonstrates how to wire up a button to properly start and stop video recording using the camera and the MediaRecorder class.

Note: When completing a video recording, do not release the camera or else your preview will be stopped.

Котлин

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

Ява

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

Note: In the above example, the prepareVideoRecorder() method refers to the example code shown in Configuring MediaRecorder . This method takes care of locking the camera, configuring and preparing the MediaRecorder instance.

Releasing the camera

Cameras are a resource that is shared by applications on a device. Your application can make use of the camera after getting an instance of Camera , and you must be particularly careful to release the camera object when your application stops using it, and as soon as your application is paused ( Activity.onPause() ). If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

To release an instance of the Camera object, use the Camera.release() method, as shown in the example code below.

Котлин

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

Ява

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

Caution: If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Saving media files

Media files created by users such as pictures and videos should be saved to a device's external storage directory (SD Card) to conserve system space and to allow users to access these files without their device. There are many possible directory locations to save media files on a device, however there are only two standard locations you should consider as a developer:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - This method returns the standard, shared and recommended location for saving pictures and videos. This directory is shared (public), so other applications can easily discover, read, change and delete files saved in this location. If your application is uninstalled by the user, media files saved to this location will not be removed. To avoid interfering with users existing pictures and videos, you should create a sub-directory for your application's media files within this directory, as shown in the code sample below. This method is available in Android 2.2 (API Level 8), for equivalent calls in earlier API versions, see Saving Shared Files .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - This method returns a standard location for saving pictures and videos which are associated with your application. If your application is uninstalled, any files saved in this location are removed. Security is not enforced for files in this location and other applications may read, change and delete them.

The following example code demonstrates how to create a File or Uri location for a media file that can be used when invoking a device's camera with an Intent or as part of a Building a Camera App .

Котлин

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

Ява

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

Note: Environment.getExternalStoragePublicDirectory() is available in Android 2.2 (API Level 8) or higher. If you are targeting devices with earlier versions of Android, use Environment.getExternalStorageDirectory() instead. For more information, see Saving Shared Files .

To make the URI support work profiles, first convert the file URI to a content URI . Then, add the content URI to EXTRA_OUTPUT of an Intent .

For more information about saving files on an Android device, see Data Storage .

Camera features

Android supports a wide array of camera features you can control with your camera application, such as picture format, flash mode, focus settings, and many more. This section lists the common camera features, and briefly discusses how to use them. Most camera features can be accessed and set using the through Camera.Parameters object. However, there are several important features that require more than simple settings in Camera.Parameters . These features are covered in the following sections:

For general information about how to use features that are controlled through Camera.Parameters , review the Using camera features section. For more detailed information about how to use features controlled through the camera parameters object, follow the links in the feature list below to the API reference documentation.

Table 1. Common camera features sorted by the Android API Level in which they were introduced.

Особенность API Level Описание
Распознавание лиц 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
Направления деятельности 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

Note: These features are not supported on all devices due to hardware differences and software implementation. For information on checking the availability of features on the device where your application is running, see Checking feature availability .

Checking feature availability

The first thing to understand when setting out to use camera features on Android devices is that not all camera features are supported on all devices. In addition, devices that support a particular feature may support them to different levels or with different options. Therefore, part of your decision process as you develop a camera application is to decide what camera features you want to support and to what level. After making that decision, you should plan on including code in your camera application that checks to see if device hardware supports those features and fails gracefully if a feature is not available.

You can check the availability of camera features by getting an instance of a camera's parameters object, and checking the relevant methods. The following code sample shows you how to obtain a Camera.Parameters object and check if the camera supports the autofocus feature:

Котлин

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
}

Ява

// 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
}

You can use the technique shown above for most camera features. The Camera.Parameters object provides a getSupported...() , is...Supported() or getMax...() method to determine if (and to what extent) a feature is supported.

If your application requires certain camera features in order to function properly, you can require them through additions to your application manifest. When you declare the use of specific camera features, such as flash and auto-focus, Google Play restricts your application from being installed on devices which do not support these features. For a list of camera features that can be declared in your app manifest, see the manifest Features Reference .

Using camera features

Most camera features are activated and controlled using a Camera.Parameters object. You obtain this object by first getting an instance of the Camera object, calling the getParameters() method, changing the returned parameter object and then setting it back into the camera object, as demonstrated in the following example code:

Котлин

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Ява

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

This technique works for nearly all camera features, and most parameters can be changed at any time after you have obtained an instance of the Camera object. Changes to parameters are typically visible to the user immediately in the application's camera preview. On the software side, parameter changes may take several frames to actually take effect as the camera hardware processes the new instructions and then sends updated image data.

Important: Some camera features cannot be changed at will. In particular, changing the size or orientation of the camera preview requires that you first stop the preview, change the preview size, and then restart the preview. Starting with Android 4.0 (API Level 14) preview orientation can be changed without restarting the preview.

Other camera features require more code in order to implement, including:

  • Metering and focus areas
  • Распознавание лиц
  • Time lapse video

A quick outline of how to implement these features is provided in the following sections.

Metering and focus areas

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

Ява

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

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.

Figure 1. The red lines illustrate the coordinate system for specifying a Camera.Area within a camera preview. The blue box shows the location and shape of an camera area with the Rect values 333,333,667,667.

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 using Camera.setDisplayOrientation() does not remap the coordinate system.

Распознавание лиц

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.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) 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 the Camera.FaceDetectionListener interface as shown in the example code below.

Котлин

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

Ява

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:

Котлин

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Ява

camera.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.

Котлин

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

Ява

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 the surfaceCreated() and surfaceChanged() methods in your preview class, as shown in the sample code below.

Котлин

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

Ява

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

Note: 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.

Time lapse video

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 ниже.

Котлин

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Ява

// 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

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 .

The Camera2Video and HdrViewfinder samples further demonstrate the use of the APIs covered on this page.

Camera fields that require permission

Apps running Android 10 (API level 29) or higher must have the CAMERA permission in order to access the values of the following fields that the getCameraCharacteristics() method returns:

  • 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

Additional sample code

To download sample apps, see the Camera2Basic sample and Official CameraX sample app .

,

The Android framework includes support for various cameras and camera features available on devices, allowing you to capture pictures and videos in your applications. This document discusses a quick, simple approach to image and video capture and outlines an advanced approach for creating custom camera experiences for your users.

Note: This page describes the Camera class, which has been deprecated. We recommend using the CameraX Jetpack library or, for specific use cases, the camera2 , class. Both CameraX and Camera2 work on Android 5.0 (API level 21) and higher.

Refer to the following related resources:

Considerations

Before enabling your application to use cameras on Android devices, you should consider a few questions about how your app intends to use this hardware feature.

  • Camera Requirement - Is the use of a camera so important to your application that you do not want your application installed on a device that does not have a camera? If so, you should declare the camera requirement in your manifest .
  • Quick Picture or Customized Camera - How will your application use the camera? Are you just interested in snapping a quick picture or video clip, or will your application provide a new way to use cameras? For getting a quick snap or clip, consider Using Existing Camera Apps . For developing a customized camera feature, check out the Building a Camera App section.
  • Foreground Services Requirement - When does your app interact with the camera? On Android 9 (API level 28) and later, apps running in the background cannot access the camera. Therefore, you should use the camera either when your app is in the foreground or as part of a foreground service .
  • Storage - Are the images or videos your application generates intended to be only visible to your application or shared so that other applications such as Gallery or other media and social apps can use them? Do you want the pictures and videos to be available even if your application is uninstalled? Check out the Saving Media Files section to see how to implement these options.

Основы

The Android framework supports capturing images and video through the android.hardware.camera2 API or camera Intent . Here are the relevant classes:

android.hardware.camera2
This package is the primary API for controlling device cameras. It can be used to take pictures or videos when you are building a camera application.
Camera
This class is the older deprecated API for controlling device cameras.
SurfaceView
This class is used to present a live camera preview to the user.
MediaRecorder
This class is used to record video from the camera.
Intent
An intent action type of MediaStore.ACTION_IMAGE_CAPTURE or MediaStore.ACTION_VIDEO_CAPTURE can be used to capture images or videos without directly using the Camera object.

Manifest declarations

Before starting development on your application with the Camera API, you should make sure your manifest has the appropriate declarations to allow use of camera hardware and other related features.

  • Camera Permission - Your application must request permission to use a device camera.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Note: If you are using the camera by invoking an existing camera app , your application does not need to request this permission.

  • Camera Features - Your application must also declare use of camera features, for example:
    <uses-feature android:name="android.hardware.camera" />
    

    For a list of camera features, see the manifest Features Reference .

    Adding camera features to your manifest causes Google Play to prevent your application from being installed to devices that do not include a camera or do not support the camera features you specify. For more information about using feature-based filtering with Google Play, see Google Play and Feature-Based Filtering .

    If your application can use a camera or camera feature for proper operation, but does not require it, you should specify this in the manifest by including the android:required attribute, and setting it to false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Storage Permission - Your application can save images or videos to the device's external storage (SD Card) if it targets Android 10 (API level 29) or lower and specifies the following in the manifest.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Audio Recording Permission - For recording audio with video capture, your application must request the audio capture permission.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Location Permission - If your application tags images with GPS location information, you must request the ACCESS_FINE_LOCATION permission. Note that, if your app targets Android 5.0 (API level 21) or higher, you also need to declare that your app uses the device's GPS:

    <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" />
    

    For more information about getting user location, see Location Strategies .

Using existing camera apps

A quick way to enable taking pictures or videos in your application without a lot of extra code is to use an Intent to invoke an existing Android camera application. The details are described in the training lessons Taking Photos Simply and Recording Videos Simply .

Building a camera app

Some developers may require a camera user interface that is customized to the look of their application or provides special features. Writing your own picture-taking code can provide a more compelling experience for your users.

Note: The following guide is for the older, deprecated Camera API. For new or advanced camera applications, the newer android.hardware.camera2 API is recommended.

The general steps for creating a custom camera interface for your application are as follows:

  • Detect and Access Camera - Create code to check for the existence of cameras and request access.
  • Create a Preview Class - Create a camera preview class that extends SurfaceView and implements the SurfaceHolder interface. This class previews the live images from the camera.
  • Build a Preview Layout - Once you have the camera preview class, create a view layout that incorporates the preview and the user interface controls you want.
  • Setup Listeners for Capture - Connect listeners for your interface controls to start image or video capture in response to user actions, such as pressing a button.
  • Capture and Save Files - Setup the code for capturing pictures or videos and saving the output.
  • Release the Camera - After using the camera, your application must properly release it for use by other applications.

Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses how to detect camera hardware, how to request access to a camera, how to capture pictures or video and how to release the camera when your application is done using it.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Detecting camera hardware

If your application does not specifically require a camera using a manifest declaration, you should check to see if a camera is available at runtime. To perform this check, use the PackageManager.hasSystemFeature() method, as shown in the example code below:

Котлин

/** 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
    }
}

Ява

/** 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;
    }
}

Android devices can have multiple cameras, for example a back-facing camera for photography and a front-facing camera for video calls. Android 2.3 (API Level 9) and later allows you to check the number of cameras available on a device using the Camera.getNumberOfCameras() method.

Accessing cameras

If you have determined that the device on which your application is running has a camera, you must request to access it by getting an instance of Camera (unless you are using an intent to access the camera ).

To access the primary camera, use the Camera.open() method and be sure to catch any exceptions, as shown in the code below:

Котлин

/** 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
    }
}

Ява

/** 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
}

Caution: Always check for exceptions when using Camera.open() . Failing to check for exceptions if the camera is in use or does not exist will cause your application to be shut down by the system.

On devices running Android 2.3 (API Level 9) or higher, you can access specific cameras using Camera.open(int) . The example code above will access the first, back-facing camera on a device with more than one camera.

Checking camera features

Once you obtain access to a camera, you can get further information about its capabilities using the Camera.getParameters() method and checking the returned Camera.Parameters object for supported capabilities. When using API Level 9 or higher, use the Camera.getCameraInfo() to determine if a camera is on the front or back of the device, and the orientation of the image.

Creating a preview class

For users to effectively take pictures or video, they must be able to see what the device camera sees. A camera preview class is a SurfaceView that can display the live image data coming from a camera, so users can frame and capture a picture or video.

The following example code demonstrates how to create a basic camera preview class that can be included in a View layout. This class implements SurfaceHolder.Callback in order to capture the callback events for creating and destroying the view, which are needed for assigning the camera preview input.

Котлин

/** 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}")
            }
        }
    }
}

Ява

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

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes() . Do not set arbitrary values in the setPreviewSize() method.

Note: With the introduction of the Multi-Window feature in Android 7.0 (API level 24) and higher, you can no longer assume the aspect ratio of the preview is the same as your activity even after calling setDisplayOrientation() . Depending on the window size and aspect ratio, you may may have to fit a wide camera preview into a portrait-orientated layout, or vice versa, using a letterbox layout.

Placing preview in a layout

A camera preview class, such as the example shown in the previous section, must be placed in the layout of an activity along with other user interface controls for taking a picture or video. This section shows you how to build a basic layout and activity for the preview.

The following layout code provides a very basic view that can be used to display a camera preview. In this example, the FrameLayout element is meant to be the container for the camera preview class. This layout type is used so that additional picture information or controls can be overlaid on the live camera preview images.

<?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>

On most devices, the default orientation of the camera preview is landscape. This example layout specifies a horizontal (landscape) layout and the code below fixes the orientation of the application to landscape. For simplicity in rendering a camera preview, you should change your application's preview activity orientation to landscape by adding the following to your manifest.

<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>

Note: A camera preview does not have to be in landscape mode. Starting in Android 2.2 (API Level 8), you can use the setDisplayOrientation() method to set the rotation of the preview image. In order to change preview orientation as the user re-orients the phone, within the surfaceChanged() method of your preview class, first stop the preview with Camera.stopPreview() change the orientation and then start the preview again with Camera.startPreview() .

In the activity for your camera view, add your preview class to the FrameLayout element shown in the example above. Your camera activity must also ensure that it releases the camera when it is paused or shut down. The following example shows how to modify a camera activity to attach the preview class shown in Creating a preview class .

Котлин

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

Ява

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

Note: The getCameraInstance() method in the example above refers to the example method shown in Accessing cameras .

Capturing pictures

Once you have built a preview class and a view layout in which to display it, you are ready to start capturing images with your application. In your application code, you must set up listeners for your user interface controls to respond to a user action by taking a picture.

In order to retrieve a picture, use the Camera.takePicture() method. This method takes three parameters which receive data from the camera. In order to receive data in a JPEG format, you must implement an Camera.PictureCallback interface to receive the image data and write it to a file. The following code shows a basic implementation of the Camera.PictureCallback interface to save an image received from the camera.

Котлин

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

Ява

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

Trigger capturing an image by calling the Camera.takePicture() method. The following example code shows how to call this method from a button View.OnClickListener .

Котлин

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Ява

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

Note: The mPicture member in the following example refers to the example code above.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! For information about how to release the camera, see Releasing the camera .

Capturing videos

Video capture using the Android framework requires careful management of the Camera object and coordination with the MediaRecorder class. When recording video with Camera , you must manage the Camera.lock() and Camera.unlock() calls to allow MediaRecorder access to the camera hardware, in addition to the Camera.open() and Camera.release() calls.

Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

Unlike taking pictures with a device camera, capturing video requires a very particular call order. You must follow a specific order of execution to successfully prepare for and capture video with your application, as detailed below.

  1. Open Camera - Use the Camera.open() to get an instance of the camera object.
  2. Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera using Camera.setPreviewDisplay() .
  3. Start Preview - Call Camera.startPreview() to begin displaying the live camera images.
  4. Start Recording Video - The following steps must be completed in order to successfully record video:
    1. Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock() .
    2. Configure MediaRecorder - Call in the following MediaRecorder methods in this order . For more information, see the MediaRecorder reference documentation.
      1. setCamera() - Set the camera to be used for video capture, use your application's current instance of Camera .
      2. setAudioSource() - Set the audio source, use MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() - Set the video source, use MediaRecorder.VideoSource.CAMERA .
      4. Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get() . For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
        1. setOutputFormat() - Set the output format, specify the default setting or MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() - Set the sound encoding type, specify the default setting or MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() - Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() - Set the output file, use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() from the example method in the Saving Media Files section.
      6. setPreviewDisplay() - Specify the SurfaceView preview layout element for your application. Use the same object you specified for Connect Preview .

      Caution: You must call these MediaRecorder configuration methods in this order , otherwise your application will encounter errors and the recording will fail.

    3. Prepare MediaRecorder - Prepare the MediaRecorder with provided configuration settings by calling MediaRecorder.prepare() .
    4. Start MediaRecorder - Start recording video by calling MediaRecorder.start() .
  5. Stop Recording Video - Call the following methods in order , to successfully complete a video recording:
    1. Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop() .
    2. Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by calling MediaRecorder.reset() .
    3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release() .
    4. Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by calling Camera.lock() . Starting with Android 4.0 (API level 14), this call is not required unless the MediaRecorder.prepare() call fails.
  6. Stop the Preview - When your activity has finished using the camera, stop the preview using Camera.stopPreview() .
  7. Release Camera - Release the camera so that other applications can use it by calling Camera.release() .

Note: It is possible to use MediaRecorder without creating a camera preview first and skip the first few steps of this process. However, since users typically prefer to see a preview before starting a recording, that process is not discussed here.

Tip: If your application is typically used for recording video, set setRecordingHint(boolean) to true prior to starting your preview. This setting can help reduce the time it takes to start recording.

Configuring MediaRecorder

When using the MediaRecorder class to record video, you must perform configuration steps in a specific order and then call the MediaRecorder.prepare() method to check and implement the configuration. The following example code demonstrates how to properly configure and prepare the MediaRecorder class for video recording.

Котлин

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
}

Ява

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

Prior to Android 2.2 (API Level 8), you must set the output format and encoding formats parameters directly, instead of using CamcorderProfile . This approach is demonstrated in the following code:

Котлин

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

Ява

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

The following video recording parameters for MediaRecorder are given default settings, however, you may want to adjust these settings for your application:

Starting and stopping MediaRecorder

When starting and stopping video recording using the MediaRecorder class, you must follow a specific order, as listed below.

  1. Unlock the camera with Camera.unlock()
  2. Configure MediaRecorder as shown in the code example above
  3. Start recording using MediaRecorder.start()
  4. Record the video
  5. Stop recording using MediaRecorder.stop()
  6. Release the media recorder with MediaRecorder.release()
  7. Lock the camera using Camera.lock()

The following example code demonstrates how to wire up a button to properly start and stop video recording using the camera and the MediaRecorder class.

Note: When completing a video recording, do not release the camera or else your preview will be stopped.

Котлин

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

Ява

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

Note: In the above example, the prepareVideoRecorder() method refers to the example code shown in Configuring MediaRecorder . This method takes care of locking the camera, configuring and preparing the MediaRecorder instance.

Releasing the camera

Cameras are a resource that is shared by applications on a device. Your application can make use of the camera after getting an instance of Camera , and you must be particularly careful to release the camera object when your application stops using it, and as soon as your application is paused ( Activity.onPause() ). If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

To release an instance of the Camera object, use the Camera.release() method, as shown in the example code below.

Котлин

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

Ява

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

Caution: If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Saving media files

Media files created by users such as pictures and videos should be saved to a device's external storage directory (SD Card) to conserve system space and to allow users to access these files without their device. There are many possible directory locations to save media files on a device, however there are only two standard locations you should consider as a developer:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - This method returns the standard, shared and recommended location for saving pictures and videos. This directory is shared (public), so other applications can easily discover, read, change and delete files saved in this location. If your application is uninstalled by the user, media files saved to this location will not be removed. To avoid interfering with users existing pictures and videos, you should create a sub-directory for your application's media files within this directory, as shown in the code sample below. This method is available in Android 2.2 (API Level 8), for equivalent calls in earlier API versions, see Saving Shared Files .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - This method returns a standard location for saving pictures and videos which are associated with your application. If your application is uninstalled, any files saved in this location are removed. Security is not enforced for files in this location and other applications may read, change and delete them.

The following example code demonstrates how to create a File or Uri location for a media file that can be used when invoking a device's camera with an Intent or as part of a Building a Camera App .

Котлин

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

Ява

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

Note: Environment.getExternalStoragePublicDirectory() is available in Android 2.2 (API Level 8) or higher. If you are targeting devices with earlier versions of Android, use Environment.getExternalStorageDirectory() instead. For more information, see Saving Shared Files .

To make the URI support work profiles, first convert the file URI to a content URI . Then, add the content URI to EXTRA_OUTPUT of an Intent .

For more information about saving files on an Android device, see Data Storage .

Camera features

Android supports a wide array of camera features you can control with your camera application, such as picture format, flash mode, focus settings, and many more. This section lists the common camera features, and briefly discusses how to use them. Most camera features can be accessed and set using the through Camera.Parameters object. However, there are several important features that require more than simple settings in Camera.Parameters . These features are covered in the following sections:

For general information about how to use features that are controlled through Camera.Parameters , review the Using camera features section. For more detailed information about how to use features controlled through the camera parameters object, follow the links in the feature list below to the API reference documentation.

Table 1. Common camera features sorted by the Android API Level in which they were introduced.

Особенность API Level Описание
Распознавание лиц 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
Направления деятельности 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

Note: These features are not supported on all devices due to hardware differences and software implementation. For information on checking the availability of features on the device where your application is running, see Checking feature availability .

Checking feature availability

The first thing to understand when setting out to use camera features on Android devices is that not all camera features are supported on all devices. In addition, devices that support a particular feature may support them to different levels or with different options. Therefore, part of your decision process as you develop a camera application is to decide what camera features you want to support and to what level. After making that decision, you should plan on including code in your camera application that checks to see if device hardware supports those features and fails gracefully if a feature is not available.

You can check the availability of camera features by getting an instance of a camera's parameters object, and checking the relevant methods. The following code sample shows you how to obtain a Camera.Parameters object and check if the camera supports the autofocus feature:

Котлин

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
}

Ява

// 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
}

You can use the technique shown above for most camera features. The Camera.Parameters object provides a getSupported...() , is...Supported() or getMax...() method to determine if (and to what extent) a feature is supported.

If your application requires certain camera features in order to function properly, you can require them through additions to your application manifest. When you declare the use of specific camera features, such as flash and auto-focus, Google Play restricts your application from being installed on devices which do not support these features. For a list of camera features that can be declared in your app manifest, see the manifest Features Reference .

Using camera features

Most camera features are activated and controlled using a Camera.Parameters object. You obtain this object by first getting an instance of the Camera object, calling the getParameters() method, changing the returned parameter object and then setting it back into the camera object, as demonstrated in the following example code:

Котлин

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Ява

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

This technique works for nearly all camera features, and most parameters can be changed at any time after you have obtained an instance of the Camera object. Changes to parameters are typically visible to the user immediately in the application's camera preview. On the software side, parameter changes may take several frames to actually take effect as the camera hardware processes the new instructions and then sends updated image data.

Important: Some camera features cannot be changed at will. In particular, changing the size or orientation of the camera preview requires that you first stop the preview, change the preview size, and then restart the preview. Starting with Android 4.0 (API Level 14) preview orientation can be changed without restarting the preview.

Other camera features require more code in order to implement, including:

  • Metering and focus areas
  • Распознавание лиц
  • Time lapse video

A quick outline of how to implement these features is provided in the following sections.

Metering and focus areas

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

Ява

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

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.

Figure 1. The red lines illustrate the coordinate system for specifying a Camera.Area within a camera preview. The blue box shows the location and shape of an camera area with the Rect values 333,333,667,667.

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 using Camera.setDisplayOrientation() does not remap the coordinate system.

Распознавание лиц

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.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) 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 the Camera.FaceDetectionListener interface as shown in the example code below.

Котлин

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

Ява

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:

Котлин

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Ява

camera.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.

Котлин

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

Ява

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 the surfaceCreated() and surfaceChanged() methods in your preview class, as shown in the sample code below.

Котлин

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

Ява

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

Note: 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.

Time lapse video

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 ниже.

Котлин

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Ява

// 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

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 .

The Camera2Video and HdrViewfinder samples further demonstrate the use of the APIs covered on this page.

Camera fields that require permission

Apps running Android 10 (API level 29) or higher must have the CAMERA permission in order to access the values of the following fields that the getCameraCharacteristics() method returns:

  • 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

Additional sample code

To download sample apps, see the Camera2Basic sample and Official CameraX sample app .