Фреймворк 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 - Для захвата изображений или видео без прямого использования объекта
Cameraможно использовать тип действия IntentMediaStore.ACTION_IMAGE_CAPTUREилиMediaStore.ACTION_VIDEO_CAPTURE.
Манифест-декларация
Прежде чем начать разработку приложения с использованием Camera API, убедитесь, что ваш манифест содержит соответствующие объявления, разрешающие использование аппаратного обеспечения камеры и других связанных функций.
- Разрешение на использование камеры — ваше приложение должно запросить разрешение на использование камеры устройства.
<uses-permission android:name="android.permission.CAMERA" />
Примечание: Если вы используете камеру , запуская существующее приложение камеры , вашему приложению не нужно запрашивать это разрешение.
- Функции камеры — Ваше приложение также должно объявить об использовании функций камеры, например:
<uses-feature android:name="android.hardware.camera" />
Список функций камеры см. в справочнике функций (Facebook).
Добавление функций камеры в ваш манифест приводит к тому, что 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 } }
Java
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
Устройства Android могут иметь несколько камер, например, заднюю камеру для фотосъемки и фронтальную камеру для видеозвонков. Android 2.3 (API Level 9) и более поздние версии позволяют проверить количество доступных камер на устройстве с помощью метода Camera.getNumberOfCameras() .
Доступ к камерам
Если вы определили, что устройство, на котором работает ваше приложение, имеет камеру, вам необходимо запросить доступ к ней, получив экземпляр объекта Camera (если только вы не используете Intent для доступа к камере ).
Для доступа к основной камере используйте метод 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 } }
Java
/** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable }
Внимание: Всегда проверяйте наличие исключений при использовании Camera.open() . Если вы не проверите наличие исключений, если камера используется или не существует, ваше приложение будет завершено системой.
На устройствах под управлением Android 2.3 (API Level 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}") } } } }
Java
/** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } }
Если вы хотите задать определенный размер для предварительного просмотра камеры, укажите это в методе surfaceChanged() , как указано в комментариях выше. При установке размера предварительного просмотра необходимо использовать значения из getSupportedPreviewSizes() . Не задавайте произвольные значения в методе setPreviewSize() .
Примечание: С появлением функции многооконного режима в Android 7.0 (уровень API 24) и выше, вы больше не можете предполагать, что соотношение сторон предварительного просмотра совпадает с вашей активностью, даже после вызова 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 Level 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) } } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
Примечание: Метод getCameraInstance() в приведенном выше примере ссылается на пример метода, показанный в разделе «Доступ к камерам» .
Фотографирование
После того как вы создали класс предварительного просмотра и макет представления для его отображения, вы готовы начать делать снимки с помощью вашего приложения. В коде вашего приложения необходимо настроить обработчики событий для элементов управления пользовательского интерфейса, чтобы они реагировали на действия пользователя, например, делали снимок.
Для получения изображения используйте метод Camera.takePicture() . Этот метод принимает три параметра, которые получают данные с камеры. Для получения данных в формате JPEG необходимо реализовать интерфейс Camera.PictureCallback , который будет принимать данные изображения и записывать их в файл. Приведенный ниже код демонстрирует базовую реализацию интерфейса Camera.PictureCallback для сохранения изображения, полученного с камеры.
Котлин
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Java
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
Чтобы сделать снимок, вызовите метод Camera.takePicture() . В следующем примере кода показано, как вызвать этот метод из обработчика события View.OnClickListener для кнопки.
Котлин
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Java
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
Примечание: В приведенном ниже примере член mPicture относится к приведенному выше примеру кода.
Внимание: Не забудьте освободить объект Camera , вызвав метод Camera.release() , когда ваше приложение закончит его использовать! Информацию о том, как освободить камеру, см. в разделе «Освобождение камеры» .
Запись видео
Для записи видео с использованием фреймворка Android требуется тщательное управление объектом Camera и координация с классом MediaRecorder . При записи видео с помощью Camera необходимо управлять вызовами Camera.lock() и Camera.unlock() , чтобы предоставить MediaRecorder доступ к аппаратному обеспечению камеры, а также вызовами Camera.open() и Camera.release() .
Примечание: Начиная с Android 4.0 (уровень API 14), вызовы Camera.lock() и Camera.unlock() обрабатываются автоматически.
В отличие от фотосъемки с помощью камеры устройства, для записи видео требуется очень специфическая последовательность вызовов. Для успешной подготовки и записи видео с помощью вашего приложения необходимо следовать определенной последовательности действий, как описано ниже.
- Открыть камеру — используйте метод
Camera.open()для получения экземпляра объекта камеры. - Предварительный просмотр подключения — подготовьте предварительный просмотр изображения с камеры в реальном времени, подключив
SurfaceViewк камере с помощьюCamera.setPreviewDisplay(). - Начать предварительный просмотр — вызовите
Camera.startPreview()чтобы начать отображение изображений с камеры в режиме реального времени. - Начать запись видео — для успешной записи видео необходимо выполнить следующие шаги:
- Разблокировка камеры — разблокируйте камеру для использования программой
MediaRecorder, вызвав методCamera.unlock(). - Настройка MediaRecorder — вызовите следующие методы
MediaRecorderв указанном порядке . Для получения дополнительной информации см. справочную документациюMediaRecorder.-
setCamera()- Устанавливает камеру, которая будет использоваться для захвата видео; используйте текущий экземплярCameraвашего приложения. -
setAudioSource()- Установка источника звука, используйтеMediaRecorder.AudioSource.CAMCORDER. -
setVideoSource()- Задает источник видео, используяMediaRecorder.VideoSource.CAMERA. - Задайте формат и кодировку видеовывода. Для Android 2.2 (API Level 8) и выше используйте метод
MediaRecorder.setProfileи получите экземпляр профиля с помощьюCamcorderProfile.get(). Для версий Android до 2.2 необходимо задать параметры формата и кодировки видеовывода:-
setOutputFormat()- Задает формат вывода, указывая значение по умолчанию илиMediaRecorder.OutputFormat.MPEG_4. -
setAudioEncoder()- Задает тип кодирования звука, указывая значение по умолчанию илиMediaRecorder.AudioEncoder.AMR_NB. -
setVideoEncoder()- Задает тип кодирования видео, указывая значение по умолчанию илиMediaRecorder.VideoEncoder.MPEG_4_SP.
-
-
setOutputFile()- Задает выходной файл; используйтеgetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()из примера метода в разделе «Сохранение медиафайлов» . -
setPreviewDisplay()— Укажите элемент макета предварительного просмотраSurfaceViewдля вашего приложения. Используйте тот же объект, который вы указали для Connect Preview .
Внимание: Вызывать методы конфигурации
MediaRecorderнеобходимо именно в таком порядке , иначе в вашем приложении возникнут ошибки, и запись не удастся. -
- Подготовка MediaRecorder — подготовьте
MediaRecorderс заданными параметрами конфигурации, вызвав методMediaRecorder.prepare(). - Запуск MediaRecorder — начните запись видео, вызвав метод
MediaRecorder.start().
- Разблокировка камеры — разблокируйте камеру для использования программой
- Остановить запись видео — Для успешного завершения записи видео вызовите следующие методы в указанном порядке :
- Остановить MediaRecorder — остановить запись видео, вызвав метод
MediaRecorder.stop(). - Сброс настроек MediaRecorder — При желании можно удалить параметры конфигурации рекордера, вызвав метод
MediaRecorder.reset(). - Освободить MediaRecorder — освободить
MediaRecorder, вызвав методMediaRecorder.release(). - Блокировка камеры — заблокируйте камеру, чтобы будущие сеансы
MediaRecorderмогли ее использовать, вызвав методCamera.lock(). Начиная с Android 4.0 (уровень API 14), этот вызов не требуется, если только вызовMediaRecorder.prepare()не завершится неудачей.
- Остановить MediaRecorder — остановить запись видео, вызвав метод
- Остановить предварительный просмотр — Когда ваша активность завершится с использованием камеры, остановите предварительный просмотр с помощью
Camera.stopPreview(). - Освободить камеру — освободить камеру, чтобы другие приложения могли ею пользоваться, вызвав метод
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 }
Java
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } return true; }
В версиях Android до 2.2 (API Level 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) }
Java
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
В MediaRecorder следующие параметры видеозаписи заданы по умолчанию, однако вы можете изменить эти настройки для своего приложения:
-
setVideoEncodingBitRate() -
setVideoSize() -
setVideoFrameRate() -
setAudioEncodingBitRate() -
setAudioChannels() -
setAudioSamplingRate()
Запуск и остановка MediaRecorder
При запуске и остановке видеозаписи с использованием класса MediaRecorder необходимо соблюдать определенный порядок действий, указанный ниже.
- Разблокируйте камеру с помощью
Camera.unlock() - Настройте
MediaRecorder, как показано в приведенном выше примере кода. - Начните запись с помощью
MediaRecorder.start() - Запишите видео
- Остановите запись с помощью
MediaRecorder.stop() - Освободите медиарекордер с помощью
MediaRecorder.release() - Заблокируйте камеру с помощью
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 } } }
Java
private boolean isRecording = false; // Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
Примечание: В приведенном выше примере метод prepareVideoRecorder() ссылается на пример кода, показанный в разделе «Настройка MediaRecorder» . Этот метод отвечает за блокировку камеры, настройку и подготовку экземпляра MediaRecorder .
Отпускание камеры
Камера — это ресурс, который используется приложениями на устройстве совместно. Ваше приложение может использовать камеру после получения экземпляра объекта Camera , и вам следует быть особенно осторожным, освобождая объект камеры, когда ваше приложение перестает его использовать, и как только ваше приложение приостанавливается ( Activity.onPause() ). Если ваше приложение не освободит камеру должным образом, все последующие попытки доступа к камере, включая попытки вашего собственного приложения, завершатся неудачей и могут привести к завершению работы вашего или других приложений.
Для освобождения экземпляра объекта Camera используйте метод Camera.release() , как показано в приведенном ниже примере кода.
Котлин
class CameraActivity : Activity() { private var mCamera: Camera? private var preview: SurfaceView? private var mediaRecorder: MediaRecorder? override fun onPause() { super.onPause() releaseMediaRecorder() // if you are using MediaRecorder, release it first releaseCamera() // release the camera immediately on pause event } private fun releaseMediaRecorder() { mediaRecorder?.reset() // clear recorder configuration mediaRecorder?.release() // release the recorder object mediaRecorder = null mCamera?.lock() // lock camera for later use } private fun releaseCamera() { mCamera?.release() // release the camera for other applications mCamera = null } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView preview; private MediaRecorder mediaRecorder; ... @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
Внимание: если ваше приложение не сможет корректно освободить камеру, все последующие попытки доступа к камере, включая попытки вашего собственного приложения, завершатся неудачей и могут привести к закрытию вашего или других приложений.
Сохранение медиафайлов
Медиафайлы, созданные пользователями, такие как фотографии и видео, следует сохранять во внешнюю память устройства (SD-карту), чтобы сэкономить место в системе и обеспечить доступ к этим файлам без использования устройства. Существует множество возможных мест для сохранения медиафайлов на устройстве, однако разработчику следует рассмотреть только два стандартных варианта:
-
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) — Этот метод возвращает стандартное, общее и рекомендуемое местоположение для сохранения изображений и видео. Этот каталог является общим (публичным), поэтому другие приложения могут легко обнаруживать, читать, изменять и удалять файлы, сохраненные в этом месте. Если ваше приложение будет удалено пользователем, медиафайлы, сохраненные в этом месте, не будут удалены. Чтобы избежать помех для существующих изображений и видео пользователей, следует создать подкаталог для медиафайлов вашего приложения внутри этого каталога, как показано в приведенном ниже примере кода. Этот метод доступен в Android 2.2 (уровень API 8); аналогичные вызовы в более ранних версиях API см. в разделе «Сохранение общих файлов» . -
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) - Этот метод возвращает стандартное местоположение для сохранения изображений и видео, связанных с вашим приложением. Если ваше приложение удалено, все файлы, сохраненные в этом месте, будут удалены. Безопасность файлов в этом месте не обеспечивается, и другие приложения могут читать, изменять и удалять их.
Приведенный ниже пример кода демонстрирует, как создать путь к File или Uri для медиафайла, который можно использовать при вызове камеры устройства с помощью Intent или в рамках создания приложения для работы с камерой .
Котлин
val MEDIA_TYPE_IMAGE = 1 val MEDIA_TYPE_VIDEO = 2 /** Create a file Uri for saving an image or video */ private fun getOutputMediaFileUri(type: Int): Uri { return Uri.fromFile(getOutputMediaFile(type)) } /** Create a File for saving an image or video */ private fun getOutputMediaFile(type: Int): File? { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. val mediaStorageDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" ) // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist mediaStorageDir.apply { if (!exists()) { if (!mkdirs()) { Log.d("MyCameraApp", "failed to create directory") return null } } } // Create a media file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return when (type) { MEDIA_TYPE_IMAGE -> { File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg") } MEDIA_TYPE_VIDEO -> { File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4") } else -> null } }
Java
public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type){ // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { return null; } return mediaFile; }
Примечание: Environment.getExternalStoragePublicDirectory() доступна в Android 2.2 (уровень API 8) и выше. Если вы ориентируетесь на устройства с более ранними версиями Android, используйте Environment.getExternalStorageDirectory() вместо неё. Дополнительную информацию см. в разделе «Сохранение общих файлов» .
Чтобы обеспечить поддержку URI в профилях, сначала преобразуйте URI файла в URI содержимого . Затем добавьте URI содержимого в EXTRA_OUTPUT объекта Intent .
Для получения дополнительной информации о сохранении файлов на устройстве Android см. раздел «Хранилище данных» .
Характеристики камеры
Android поддерживает широкий спектр функций камеры, которыми можно управлять с помощью приложения камеры, таких как формат изображения, режим вспышки, настройки фокусировки и многое другое. В этом разделе перечислены распространенные функции камеры и кратко описано, как их использовать. Доступ к большинству функций камеры и их настройка осуществляются через объект Camera.Parameters . Однако существует несколько важных функций, для которых требуются не только простые настройки в Camera.Parameters . Эти функции рассматриваются в следующих разделах:
Общую информацию об использовании функций, управляемых через Camera.Parameters , см. в разделе « Использование функций камеры» . Более подробную информацию об использовании функций, управляемых через объект параметров камеры, см. в списке функций ниже, перейдя по ссылкам на справочную документацию по API.
Таблица 1. Общие функции камеры, отсортированные по уровню 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 }
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
Для большинства функций камеры можно использовать описанный выше метод. Объект Camera.Parameters предоставляет методы getSupported...() , is...Supported() или getMax...() для определения того, поддерживается ли функция (и в какой степени).
Если вашему приложению для корректной работы требуются определенные функции камеры, вы можете добавить их в манифест приложения. При указании использования определенных функций камеры, таких как вспышка и автофокус, Google Play ограничивает установку вашего приложения на устройства, не поддерживающие эти функции. Список функций камеры, которые можно указать в манифесте приложения, см. в Справочнике по функциям манифеста.
Использование функций камеры
Большинство функций камеры активируются и управляются с помощью объекта Camera.Parameters . Чтобы получить этот объект, сначала нужно создать экземпляр объекта Camera , вызвать метод getParameters() , изменить возвращаемый объект параметров, а затем снова установить его в объект камеры, как показано в следующем примере кода:
Котлин
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
Этот метод работает практически со всеми функциями камеры, и большинство параметров можно изменить в любое время после получения экземпляра объекта Camera . Изменения параметров обычно сразу же отображаются пользователю в предварительном просмотре камеры в приложении. На программном уровне изменения параметров могут занять несколько кадров, прежде чем они вступят в силу, поскольку аппаратное обеспечение камеры обрабатывает новые инструкции, а затем отправляет обновленные данные изображения.
Важно: Некоторые параметры камеры нельзя изменить по желанию. В частности, для изменения размера или ориентации предварительного просмотра камеры необходимо сначала остановить предварительный просмотр, изменить размер предварительного просмотра, а затем перезапустить его. Начиная с Android 4.0 (API Level 14) ориентацию предварительного просмотра можно изменить без перезапуска.
Для реализации других функций камеры требуется больше кода, в том числе:
- Измерения и приоритетные области
- Обнаружение лиц
- Видео в режиме замедленной съемки
Краткое описание того, как реализовать эти функции, приведено в следующих разделах.
Измерения и приоритетные области
В некоторых сценариях фотосъемки автоматическая фокусировка и замер освещенности могут не давать желаемых результатов. Начиная с Android 4.0 (API Level 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 }
Java
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
Объект Camera.Area содержит два параметра данных: объект Rect для указания области в поле зрения камеры и значение веса, которое указывает камере, какой уровень важности следует придавать этой области при замере освещенности или расчетах фокусировки.
Поле Rect в объекте Camera.Area описывает прямоугольную фигуру, отображаемую на сетке 2000 x 2000 единиц. Координаты -1000, -1000 представляют верхний левый угол изображения с камеры, а координаты 1000, 1000 — нижний правый угол изображения с камеры, как показано на иллюстрации ниже.

Рисунок 1. Красные линии иллюстрируют систему координат для задания области Camera.Area в предварительном просмотре камеры. Синий прямоугольник показывает расположение и форму области камеры со значениями Rect 333, 333, 667, 667.
Границы этой системы координат всегда соответствуют внешнему краю изображения, видимого в предварительном просмотре камеры, и не сжимаются и не расширяются с увеличением масштаба. Аналогично, поворот предварительного просмотра изображения с помощью Camera.setDisplayOrientation() не изменяет систему координат.
Обнаружение лиц
На фотографиях с людьми лица обычно являются наиболее важной частью изображения и должны использоваться для определения фокуса и баланса белого при съемке. Платформа Android 4.0 (API 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()}")) } } }
Java
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
После создания этого класса необходимо присвоить его объекту Camera вашего приложения, как показано в приведенном ниже примере кода:
Котлин
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
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() } } }
Java
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
You must start face detection each time you start (or restart) the camera preview. If you use the preview class shown in Creating a preview class , add your startFaceDetection() method to both the surfaceCreated() and surfaceChanged() methods in your preview class, as shown in the sample code below.
Котлин
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Java
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
Note: Remember to call this method after calling startPreview() . Do not attempt to start face detection in the onCreate() method of your camera app's main activity, as the preview is not available by this point in your application's the execution.
Time lapse video
Time lapse video allows users to create video clips that combine pictures taken a few seconds or minutes apart. This feature uses MediaRecorder to record the images for a time lapse sequence.
To record a time lapse video with MediaRecorder , you must configure the recorder object as if you are recording a normal video, setting the captured frames per second to a low number and using one of the time lapse quality settings, as shown in the code example below.
Котлин
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Java
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
These settings must be done as part of a larger configuration procedure for MediaRecorder . For a full configuration code example, see Configuring MediaRecorder . Once the configuration is complete, you start the video recording as if you were recording a normal video clip. For more information about configuring and running MediaRecorder , see Capturing videos .
The Camera2Video and HdrViewfinder samples further demonstrate the use of the APIs covered on this page.
Camera fields that require permission
Apps running Android 10 (API level 29) or higher must have the CAMERA permission in order to access the values of the following fields that the getCameraCharacteristics() method returns:
-
LENS_POSE_ROTATION -
LENS_POSE_TRANSLATION -
LENS_INTRINSIC_CALIBRATION -
LENS_RADIAL_DISTORTION -
LENS_POSE_REFERENCE -
LENS_DISTORTION -
LENS_INFO_HYPERFOCAL_DISTANCE -
LENS_INFO_MINIMUM_FOCUS_DISTANCE -
SENSOR_REFERENCE_ILLUMINANT1 -
SENSOR_REFERENCE_ILLUMINANT2 -
SENSOR_CALIBRATION_TRANSFORM1 -
SENSOR_CALIBRATION_TRANSFORM2 -
SENSOR_COLOR_TRANSFORM1 -
SENSOR_COLOR_TRANSFORM2 -
SENSOR_FORWARD_MATRIX1 -
SENSOR_FORWARD_MATRIX2
Additional sample code
To download sample apps, see the Camera2Basic sample and Official CameraX sample app .