API камеры

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

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

См. следующие сопутствующие ресурсы:

Соображения

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

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

Основы

Фреймворк Android поддерживает захват изображений и видео через API android.hardware.camera2 или функцию Camera 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" />

    Список характеристик камеры см. в Справочнике характеристик .

    Добавление функций камеры в манифест приводит к тому, что 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. Stop 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 для записи видео.

Котлин

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. Распространенные функции камеры, отсортированные по уровню 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...() , чтобы определить, поддерживается ли функция (и в какой степени).

Если вашему приложению требуются определённые функции камеры для корректной работы, вы можете добавить их в манифест приложения. Когда вы объявляете использование определённых функций камеры, таких как вспышка и автофокус, 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 уровня 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 .