API камеры

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

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

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

Соображения

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

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

Основы

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

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

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

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

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

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

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

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

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

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

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

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />
    

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

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

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

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

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

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

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

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

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

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

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

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

Котлин

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

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

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

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

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

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

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

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

Ява

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

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

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

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

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

Котлин

class CameraActivity : Activity() {

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

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

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

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

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

Ява

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

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

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

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

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

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

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

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

Котлин

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

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

Ява

private PictureCallback mPicture = new PictureCallback() {

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

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

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

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

Котлин

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

Ява

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

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

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

Захват видео

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

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

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

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

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

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

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

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

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

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

Котлин

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

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

        mediaRecorder?.run {
            setCamera(camera)

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

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

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

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

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


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

    }
    return false
}

Ява

private boolean prepareVideoRecorder(){

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

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

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

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

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

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

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

Котлин

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

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

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

Ява

private boolean isRecording = false;

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

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

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

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

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

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

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

Котлин

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

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

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

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

Ява

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

    ...

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

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

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

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

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

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

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

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

Котлин

val MEDIA_TYPE_IMAGE = 1
val MEDIA_TYPE_VIDEO = 2

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

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

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

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

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

Ява

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

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

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

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

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

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

    return mediaFile;
}

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

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

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

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

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

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

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

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

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

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

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

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

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

Котлин

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

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

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

Ява

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

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

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

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

camera.setParameters(params);

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

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

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

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

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

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

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

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

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

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

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

Котлин

internal class MyFaceDetectionListener : Camera.FaceDetectionListener {

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

Ява

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

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

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

Котлин

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Ява

camera.setFaceDetectionListener(new MyFaceDetectionListener());

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

Котлин

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

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

Ява

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

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

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

Котлин

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

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

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

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

Ява

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

        startFaceDetection(); // start face detection feature

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

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

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

    try {
        mCamera.stopPreview();

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

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

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

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

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

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

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

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

Котлин

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

Ява

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

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

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

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

Приложения, управляющие Android 10 (уровень API 29) или выше, должны иметь разрешение CAMERA , чтобы получить доступ к значениям следующих полей, которые возвращает метод getCameraCharacteristics() :

  • LENS_POSE_ROTATION
  • LENS_POSE_TRANSLATION
  • LENS_INTRINSIC_CALIBRATION
  • LENS_RADIAL_DISTORTION
  • LENS_POSE_REFERENCE
  • LENS_DISTORTION
  • LENS_INFO_HYPERFOCAL_DISTANCE
  • LENS_INFO_MINIMUM_FOCUS_DISTANCE
  • SENSOR_REFERENCE_ILLUMINANT1
  • SENSOR_REFERENCE_ILLUMINANT2
  • SENSOR_CALIBRATION_TRANSFORM1
  • SENSOR_CALIBRATION_TRANSFORM2
  • SENSOR_COLOR_TRANSFORM1
  • SENSOR_COLOR_TRANSFORM2
  • SENSOR_FORWARD_MATRIX1
  • SENSOR_FORWARD_MATRIX2

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

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