Camera API

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

Чтобы узнать, как перейти с Camera1 на CameraX, прочитайте статью Migrate Camera1 to CameraX (Переход с Camera1 на CameraX). Вы также можете использовать агентский навык для перехода с Camera1 на CameraX.

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

Ознакомьтесь со следующей информацией по теме:

Что нужно учесть

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

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

Основные сведения

Фреймворк Android поддерживает съемку фото и видео с помощью android.hardware.camera2 API или Intent. Вот соответствующие классы:

android.hardware.camera2
Этот пакет – основной API для управления камерами устройства. Его можно использовать для съемки фотографий или видео при создании приложения камеры.
Camera
Этот класс представляет собой устаревший API для управления камерами устройств.
SurfaceView
Этот класс используется для показа пользователю предварительного просмотра с камеры в реальном времени.
MediaRecorder
Этот класс используется для записи видео с камеры.
Intent
Тип действия 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…

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

    <uses-feature android:name="android.hardware.camera" android:required="false" />
  • Разрешение на доступ к хранилищу. Если приложение предназначено для Android 10 (уровень API 29) или более ранней версии и в его манифесте указано следующее разрешение, оно может сохранять изображения и видео на внешнем накопителе устройства (SD-карте):
    <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(), как показано в примере кода ниже.

Kotlin

/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true
    } else {
        // no camera on this device
        return false
    }
}

Java

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

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

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

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

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

Kotlin

/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
    return try {
        Camera.open() // attempt to get a Camera instance
    } catch (e: Exception) {
        // Camera is not available (in use or does not exist)
        null // returns null if camera is unavailable
    }
}

Java

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

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

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

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

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

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

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

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

Kotlin

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

Java

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

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

Примечание. В Android 7.0 (API уровня 24) и более поздних версиях появилась функция многооконного режима. Из-за этого соотношение сторон в окне предварительного просмотра может не совпадать с соотношением сторон в объекте activity даже после вызова метода 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, показанный в примере выше. Кроме того, в операции камеры должно быть предусмотрено освобождение камеры при приостановке или завершении работы. В примере ниже показано, как изменить действие камеры, чтобы прикрепить класс предварительного просмотра, показанный в разделе Создание класса предварительного просмотра.

Kotlin

class CameraActivity : Activity() {

    private var mCamera: Camera? = null
    private var mPreview: CameraPreview? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Create an instance of Camera
        mCamera = getCameraInstance()

        mPreview = mCamera?.let {
            // Create our Preview view
            CameraPreview(this, it)
        }

        // Set the Preview view as the content of our activity.
        mPreview?.also {
            val preview: FrameLayout = findViewById(R.id.camera_preview)
            preview.addView(it)
        }
    }
}

Java

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }
}

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

Фотосъемка

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

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

Kotlin

private val mPicture = Camera.PictureCallback { data, _ ->
    val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run {
        Log.d(TAG, ("Error creating media file, check storage permissions"))
        return@PictureCallback
    }

    try {
        val fos = FileOutputStream(pictureFile)
        fos.write(data)
        fos.close()
    } catch (e: FileNotFoundException) {
        Log.d(TAG, "File not found: ${e.message}")
    } catch (e: IOException) {
        Log.d(TAG, "Error accessing file: ${e.message}")
    }
}

Java

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

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

Kotlin

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

Java

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, picture);
        }
    }
);

Примечание. Элемент 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 для записи видео необходимо выполнить шаги настройки в определенном порядке, а затем вызвать метод MediaRecorder.prepare(), чтобы проверить и реализовать конфигурацию. В примере кода ниже показано, как правильно настроить и подготовить класс MediaRecorder для записи видео.

Kotlin

private fun prepareVideoRecorder(): Boolean {
    mediaRecorder = MediaRecorder()

    mCamera?.let { camera ->
        // Step 1: Unlock and set camera to MediaRecorder
        camera?.unlock()

        mediaRecorder?.run {
            setCamera(camera)

            // Step 2: Set sources
            setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
            setVideoSource(MediaRecorder.VideoSource.CAMERA)

            // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
            setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))

            // Step 4: Set output file
            setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())

            // Step 5: Set the preview output
            setPreviewDisplay(mPreview?.holder?.surface)

            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
            setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)


            // Step 6: Prepare configured MediaRecorder
            return try {
                prepare()
                true
            } catch (e: IllegalStateException) {
                Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            } catch (e: IOException) {
                Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            }
        }

    }
    return false
}

Java

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}

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

Kotlin

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder?.apply {
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
        setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
    }

Java

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

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

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

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

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

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

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

Kotlin

var isRecording = false
val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    if (isRecording) {
        // stop recording and release camera
        mediaRecorder?.stop() // stop the recording
        releaseMediaRecorder() // release the MediaRecorder object
        mCamera?.lock() // take camera access back from MediaRecorder

        // inform the user that recording has stopped
        setCaptureButtonText("Capture")
        isRecording = false
    } else {
        // initialize video camera
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared,
            // now you can start recording
            mediaRecorder?.start()

            // inform the user that recording has started
            setCaptureButtonText("Stop")
            isRecording = true
        } else {
            // prepare didn't work, release the camera
            releaseMediaRecorder()
            // inform user
        }
    }
}

Java

private boolean isRecording = false;

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isRecording) {
                // stop recording and release camera
                mediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                setCaptureButtonText("Capture");
                isRecording = false;
            } else {
                // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mediaRecorder.start();

                    // inform the user that recording has started
                    setCaptureButtonText("Stop");
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }
            }
        }
    }
);

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

Как отпустить камеру

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

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

Kotlin

class CameraActivity : Activity() {
    private var mCamera: Camera?
    private var preview: SurfaceView?
    private var mediaRecorder: MediaRecorder?

    override fun onPause() {
        super.onPause()
        releaseMediaRecorder() // if you are using MediaRecorder, release it first
        releaseCamera() // release the camera immediately on pause event
    }

    private fun releaseMediaRecorder() {
        mediaRecorder?.reset() // clear recorder configuration
        mediaRecorder?.release() // release the recorder object
        mediaRecorder = null
        mCamera?.lock() // lock camera for later use
    }

    private fun releaseCamera() {
        mCamera?.release() // release the camera for other applications
        mCamera = null
    }
}

Java

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView preview;
    private MediaRecorder mediaRecorder;

    ...

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseMediaRecorder(){
        if (mediaRecorder != null) {
            mediaRecorder.reset();   // clear recorder configuration
            mediaRecorder.release(); // release the recorder object
            mediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

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

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

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

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

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

Kotlin

val MEDIA_TYPE_IMAGE = 1
val MEDIA_TYPE_VIDEO = 2

/** Create a file Uri for saving an image or video */
private fun getOutputMediaFileUri(type: Int): Uri {
    return Uri.fromFile(getOutputMediaFile(type))
}

/** Create a File for saving an image or video */
private fun getOutputMediaFile(type: Int): File? {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    val mediaStorageDir = File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp"
    )
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    mediaStorageDir.apply {
        if (!exists()) {
            if (!mkdirs()) {
                Log.d("MyCameraApp", "failed to create directory")
                return null
            }
        }
    }

    // Create a media file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    return when (type) {
        MEDIA_TYPE_IMAGE -> {
            File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg")
        }
        MEDIA_TYPE_VIDEO -> {
            File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4")
        }
        else -> null
    }
}

Java

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}

Примечание. Класс 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 и проверить, поддерживает ли камера функцию автофокусировки.

Kotlin

val params: Camera.Parameters? = camera?.parameters
val focusModes: List<String>? = params?.supportedFocusModes
if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) {
    // Autofocus mode is supported
}

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();

List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  // Autofocus mode is supported
}

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

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

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

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

Kotlin

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

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
camera.setParameters(params);

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

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

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

  • Области замера и фокусировки
  • Распознавание лица
  • Ускоренное видео

Ниже приведены краткие инструкции по реализации этих функций.

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

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

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

Kotlin

// Create an instance of Camera
camera = getCameraInstance()

// set Camera parameters
val params: Camera.Parameters? = camera?.parameters

params?.apply {
    if (maxNumMeteringAreas > 0) { // check that metering areas are supported
        meteringAreas = ArrayList<Camera.Area>().apply {
            val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image
            add(Camera.Area(areaRect1, 600)) // set weight to 60%
            val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image
            add(Camera.Area(areaRect2, 400)) // set weight to 40%
        }
    }
    camera?.parameters = this
}

Java

// Create an instance of Camera
camera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = camera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

camera.setParameters(params);

Объект 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 14) есть API для распознавания лиц и расчета настроек изображения с помощью технологии распознавания лиц.

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

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

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

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

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

Kotlin

internal class MyFaceDetectionListener : Camera.FaceDetectionListener {

    override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) {
        if (faces.isNotEmpty()) {
            Log.d("FaceDetection", ("face detected: ${faces.size}" +
                    " Face 1 Location X: ${faces[0].rect.centerX()}" +
                    "Y: ${faces[0].rect.centerY()}"))
        }
    }
}

Java

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

    @Override
    public void onFaceDetection(Face[] faces, Camera camera) {
        if (faces.length > 0){
            Log.d("FaceDetection", "face detected: "+ faces.length +
                    " Face 1 Location X: " + faces[0].rect.centerX() +
                    "Y: " + faces[0].rect.centerY() );
        }
    }
}

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

Kotlin

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Java

camera.setFaceDetectionListener(new MyFaceDetectionListener());

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

Kotlin

fun startFaceDetection() {
    // Try starting Face Detection
    val params = mCamera?.parameters
    // start face detection only *after* preview has started

    params?.apply {
        if (maxNumDetectedFaces > 0) {
            // camera supports face detection, so can start it:
            mCamera?.startFaceDetection()
        }
    }
}

Java

public void startFaceDetection(){
    // Try starting Face Detection
    Camera.Parameters params = mCamera.getParameters();

    // start face detection only *after* preview has started
    if (params.getMaxNumDetectedFaces() > 0){
        // camera supports face detection, so can start it:
        mCamera.startFaceDetection();
    }
}

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

Kotlin

override fun surfaceCreated(holder: SurfaceHolder) {
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // start face detection feature
    } catch (e: IOException) {
        Log.d(TAG, "Error setting camera preview: ${e.message}")
    }
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
    if (holder.surface == null) {
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null")
        return
    }
    try {
        mCamera.stopPreview()
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: ${e.message}")
    }
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // re-start face detection feature
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: ${e.message}")
    }
}

Java

public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // start face detection feature

    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    if (holder.getSurface() == null){
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null");
        return;
    }

    try {
        mCamera.stopPreview();

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
    }

    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // re-start face detection feature

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

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

Ускоренное видео

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

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

Kotlin

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

Java

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds

Эти настройки необходимо задать в рамках общей процедуры настройки MediaRecorder. Полный пример кода конфигурации приведен в разделе Настройка MediaRecorder. После завершения настройки вы начинаете видеозапись, как если бы вы записывали обычный видеоклип. Подробную информацию о настройке и запуске 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 sample и Official CameraX sample app.