Платформа Android включает поддержку различных камер и функций камер, доступных на устройствах, что позволяет вам захватывать изображения и видео в ваших приложениях. В этом документе обсуждается быстрый и простой подход к захвату изображений и видео, а также описывается расширенный подход к созданию пользовательских камер для ваших пользователей.
Примечание: На этой странице описывается класс Camera
, который устарел. Мы рекомендуем использовать библиотеку CameraX Jetpack или, для особых случаев использования, класс camera2
. И CameraX, и Camera2 работают на Android 5.0 (уровень API 21) и выше.
См. следующие сопутствующие ресурсы:
Соображения
Прежде чем разрешить приложению использовать камеры на устройствах Android, следует рассмотреть несколько вопросов о том, как ваше приложение будет использовать эту аппаратную функцию.
- Требование к камере — использование камеры настолько важно для вашего приложения, что вы не хотите, чтобы приложение устанавливалось на устройстве, на котором нет камеры? Если да, то вам следует указать требование к камере в вашем манифесте .
- Быстрый снимок или настраиваемая камера — как ваше приложение будет использовать камеру? Вас просто интересует возможность быстрой съемки фото или видеоклипа или ваше приложение предоставит новый способ использования камер? Для получения быстрого снимка или клипа рассмотрите использование существующих приложений для камер . Для разработки настраиваемой функции камеры ознакомьтесь с разделом Создание приложения для камер .
- Требование к службам переднего плана — когда ваше приложение взаимодействует с камерой? На Android 9 (уровень API 28) и более поздних версиях приложения, работающие в фоновом режиме, не могут получить доступ к камере. Поэтому вам следует использовать камеру либо когда ваше приложение находится на переднем плане, либо как часть службы переднего плана .
- Хранилище — предназначены ли изображения или видео, которые генерирует ваше приложение, для просмотра только вашим приложением или для общего доступа, чтобы другие приложения, такие как Галерея или другие медиа и социальные приложения, могли их использовать? Хотите ли вы, чтобы изображения и видео были доступны, даже если ваше приложение удалено? Ознакомьтесь с разделом Сохранение файлов мультимедиа, чтобы узнать, как реализовать эти параметры.
Основы
Фреймворк Android поддерживает захват изображений и видео через API android.hardware.camera2
или camera Intent
. Вот соответствующие классы:
-
android.hardware.camera2
- Этот пакет является основным API для управления камерами устройств. Его можно использовать для съемки фотографий или видео при создании приложения камеры.
-
Camera
- Этот класс представляет собой устаревший API для управления камерами устройств.
-
SurfaceView
- Этот класс используется для предоставления пользователю предварительного просмотра изображения с камеры в реальном времени.
-
MediaRecorder
- Этот класс используется для записи видео с камеры.
-
Intent
- Тип действия намерения
MediaStore.ACTION_IMAGE_CAPTURE
илиMediaStore.ACTION_VIDEO_CAPTURE
можно использовать для захвата изображений или видео без прямого использования объектаCamera
.
Явные заявления
Прежде чем приступить к разработке приложения с использованием API камеры, следует убедиться, что в вашем манифесте есть соответствующие декларации, разрешающие использование аппаратного обеспечения камеры и других связанных функций.
- Разрешение на использование камеры . Ваше приложение должно запросить разрешение на использование камеры устройства.
<uses-permission android:name="android.permission.CAMERA" />
Примечание: если вы используете камеру , вызывая существующее приложение камеры , вашему приложению не нужно запрашивать это разрешение.
- Функции камеры . Ваше приложение также должно декларировать использование функций камеры, например:
<uses-feature android:name="android.hardware.camera" />
Список характеристик камеры см. в Справочнике характеристик камеры.
Добавление функций камеры в ваш манифест заставляет Google Play не допускать установку вашего приложения на устройства, которые не включают камеру или не поддерживают указанные вами функции камеры. Для получения дополнительной информации об использовании фильтрации на основе функций с Google Play см. Google Play и фильтрация на основе функций .
Если ваше приложение может использовать камеру или функцию камеры для правильной работы, но не требует этого, вам следует указать это в манифесте, включив атрибут
android:required
и установив его вfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Разрешение на хранение . Ваше приложение может сохранять изображения или видео на внешнем хранилище устройства (SD-карте), если оно предназначено для Android 10 (уровень API 29) или ниже и в манифесте указано следующее.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Разрешение на запись звука . Для записи звука с захватом видео ваше приложение должно запросить разрешение на запись звука.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Разрешение на местоположение - Если ваше приложение помечает изображения информацией о местоположении GPS, вы должны запросить разрешение
ACCESS_FINE_LOCATION
. Обратите внимание, что если ваше приложение предназначено для Android 5.0 (уровень API 21) или выше, вам также необходимо объявить, что ваше приложение использует GPS устройства:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
Дополнительную информацию о получении местоположения пользователя см. в разделе Стратегии определения местоположения .
Использование существующих приложений камеры
Быстрый способ включить фото- или видеосъемку в вашем приложении без большого количества дополнительного кода — использовать Intent
для вызова существующего приложения камеры Android. Подробности описаны в обучающих уроках Taking Photos Simply и Recording Videos Simply .
Создание приложения для камеры
Некоторым разработчикам может потребоваться пользовательский интерфейс камеры, который настроен под внешний вид их приложения или предоставляет специальные функции. Написание собственного кода для съемки может обеспечить более захватывающий опыт для ваших пользователей.
Примечание: Следующее руководство предназначено для старого, устаревшего 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 Level 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 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}") } } } }
Ява
/** 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()
.
Примечание: С появлением функции Multi-Window в Android 7.0 (уровень API 24) и выше вы больше не можете предполагать, что соотношение сторон предварительного просмотра совпадает с вашей активностью даже после вызова setDisplayOrientation()
. В зависимости от размера окна и соотношения сторон вам, возможно, придется вписать широкоэкранный предварительный просмотр камеры в портретно-ориентированный макет или наоборот, используя макет Letterbox.
Размещение предварительного просмотра в макете
Класс предварительного просмотра камеры, такой как пример, показанный в предыдущем разделе, должен быть помещен в макет действия вместе с другими элементами управления пользовательского интерфейса для съемки фото или видео. В этом разделе показано, как создать базовый макет и действие для предварительного просмотра.
Следующий код макета обеспечивает очень простое представление, которое можно использовать для отображения предварительного просмотра камеры. В этом примере элемент 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) } } }
Ява
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()
управляются автоматически.
В отличие от съемки фотографий камерой устройства, захват видео требует очень специфического порядка вызовов. Вы должны следовать определенному порядку выполнения, чтобы успешно подготовиться и захватить видео с помощью вашего приложения, как подробно описано ниже.
- Открыть камеру — используйте
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 }
Ява
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) }
Ява
// 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 } } }
Ява
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 Level 8) или выше. Если вы ориентируетесь на устройства с более ранними версиями Android, используйте вместо этого Environment.getExternalStorageDirectory()
. Для получения дополнительной информации см. Сохранение общих файлов .
Чтобы URI поддерживал рабочие профили, сначала преобразуйте файловый URI в контентный URI . Затем добавьте контентный URI в EXTRA_OUTPUT
Intent
.
Дополнительную информацию о сохранении файлов на устройстве Android см. в разделе Хранение данных .
Характеристики камеры
Android поддерживает широкий спектр функций камеры, которыми вы можете управлять с помощью приложения камеры, например, формат изображения, режим вспышки, настройки фокуса и многое другое. В этом разделе перечислены общие функции камеры и кратко обсуждается, как их использовать. Доступ к большинству функций камеры и их настройка могут осуществляться с помощью объекта Camera.Parameters
. Однако есть несколько важных функций, для которых требуются более простые настройки в Camera.Parameters
. Эти функции рассматриваются в следующих разделах:
Для получения общей информации о том, как использовать функции, которые управляются через Camera.Parameters
, ознакомьтесь с разделом Использование функций камеры . Для получения более подробной информации о том, как использовать функции, управляемые через объект параметров камеры, перейдите по ссылкам в списке функций ниже на справочную документацию API.
Таблица 1. Общие функции камеры, отсортированные по уровню API Android, на котором они были представлены.
Особенность | Уровень API | Описание |
---|---|---|
Распознавание лиц | 14 | Распознавать человеческие лица на снимке и использовать их для фокусировки, замера экспозиции и баланса белого |
Зоны измерения | 14 | Укажите одну или несколько областей на изображении для расчета баланса белого |
Области фокусировки | 14 | Установите одну или несколько областей на изображении для фокусировки |
White Balance Lock | 14 | Остановка или запуск автоматической регулировки баланса белого |
Exposure Lock | 14 | Остановка или запуск автоматической регулировки экспозиции |
Video Snapshot | 14 | Сделать снимок во время видеосъемки (захват кадра) |
Видео с покадровой съемкой | 11 | Запись кадров с заданными задержками для записи покадрового видео |
Multiple Cameras | 9 | Поддержка более одной камеры на устройстве, включая фронтальную и тыльную камеры |
Focus Distance | 9 | Сообщает расстояния между камерой и объектами, которые кажутся в фокусе |
Zoom | 8 | Установить увеличение изображения |
Exposure Compensation | 8 | Увеличьте или уменьшите уровень освещенности |
GPS Data | 5 | Включите или исключите данные о географическом местоположении вместе с изображением |
White Balance | 5 | Установите режим баланса белого, который влияет на цветовые значения на захваченном изображении. |
Focus Mode | 5 | Установите способ фокусировки камеры на объекте: автоматический, фиксированный, макро или бесконечность. |
Scene Mode | 5 | Применяйте предустановленный режим для определенных типов ситуаций фотосъемки, таких как ночная съемка, съемка на пляже, при снеге или при свете свечей. |
JPEG Quality | 5 | Установите уровень сжатия для изображения JPEG, что увеличит или уменьшит качество и размер выходного файла изображения. |
Flash Mode | 5 | Включите, выключите вспышку или используйте автоматическую настройку |
Color Effects | 5 | Примените цветовой эффект к отснятому изображению, например, черно-белый, сепия или негатив. |
Anti-Banding | 5 | Уменьшает эффект полосатости в цветовых градиентах из-за сжатия JPEG |
Picture Format | 1 | Укажите формат файла для изображения |
Picture Size | 1 | Укажите размеры сохраняемого изображения в пикселях. |
Примечание: Эти функции поддерживаются не на всех устройствах из-за различий в оборудовании и программной реализации. Информацию о проверке доступности функций на устройстве, на котором запущено ваше приложение, см. в разделе Проверка доступности функций .
Проверка доступности функции
Первое, что нужно понять при использовании функций камеры на устройствах Android, это то, что не все функции камеры поддерживаются на всех устройствах. Кроме того, устройства, которые поддерживают определенную функцию, могут поддерживать ее на разных уровнях или с разными опциями. Поэтому часть вашего процесса принятия решения при разработке приложения камеры — решить, какие функции камеры вы хотите поддерживать и на каком уровне. После принятия этого решения вы должны запланировать включение кода в приложение камеры, который проверяет, поддерживает ли оборудование устройства эти функции, и корректно завершает работу, если функция недоступна.
Вы можете проверить доступность функций камеры, получив экземпляр объекта параметров камеры и проверив соответствующие методы. Следующий пример кода показывает, как получить объект Camera.Parameters
и проверить, поддерживает ли камера функцию автофокуса:
Котлин
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Ява
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
Вы можете использовать технику, показанную выше, для большинства функций камеры. Объект Camera.Parameters
предоставляет метод getSupported...()
, is...Supported()
или getMax...()
для определения того, поддерживается ли (и в какой степени) функция.
Если для правильной работы вашего приложения требуются определенные функции камеры, вы можете потребовать их с помощью дополнений к манифесту вашего приложения. Когда вы объявляете использование определенных функций камеры, таких как вспышка и автофокус, Google Play ограничивает установку вашего приложения на устройствах, которые не поддерживают эти функции. Список функций камеры, которые могут быть объявлены в манифесте вашего приложения, см. в Справочнике по функциям манифеста.
Использование функций камеры
Большинство функций камеры активируются и контролируются с помощью объекта Camera.Parameters
. Вы получаете этот объект, сначала получая экземпляр объекта Camera
, вызывая метод getParameters()
, изменяя возвращаемый объект параметра, а затем устанавливая его обратно в объект камеры, как показано в следующем примере кода:
Котлин
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Ява
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
Этот метод работает почти для всех функций камеры, и большинство параметров можно изменить в любое время после получения экземпляра объекта Camera
. Изменения параметров обычно видны пользователю немедленно в предварительном просмотре камеры приложения. Со стороны программного обеспечения изменения параметров могут занять несколько кадров, чтобы фактически вступить в силу, поскольку аппаратное обеспечение камеры обрабатывает новые инструкции, а затем отправляет обновленные данные изображения.
Важно: некоторые функции камеры нельзя изменить по желанию. В частности, изменение размера или ориентации предварительного просмотра камеры требует сначала остановки предварительного просмотра, изменения размера предварительного просмотра, а затем его перезапуска. Начиная с Android 4.0 (API Level 14) ориентацию предварительного просмотра можно изменить без перезапуска предварительного просмотра.
Для реализации других функций камеры требуется больше кода, в том числе:
- Зоны измерения и фокусировки
- Распознавание лиц
- Покадровая видеосъемка
Краткое описание того, как реализовать эти функции, приведено в следующих разделах.
Зоны измерения и фокусировки
В некоторых фотографических сценариях автоматическая фокусировка и измерение освещенности могут не давать желаемых результатов. Начиная с Android 4.0 (API уровня 14) ваше приложение камеры может предоставлять дополнительные элементы управления, позволяющие вашему приложению или пользователям указывать области на изображении, которые будут использоваться для определения настроек фокусировки или уровня освещенности, и передавать эти значения оборудованию камеры для использования при съемке изображений или видео.
Зоны для измерения и фокусировки работают очень похоже на другие функции камеры, в том смысле, что вы управляете ими с помощью методов в объекте Camera.Parameters
. Следующий код демонстрирует установку двух зон измерения освещенности для экземпляра Camera
:
Котлин
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Ява
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
Объект Camera.Area
содержит два параметра данных: объект Rect
для указания области в поле зрения камеры и значение веса, которое сообщает камере, какой уровень важности следует придать этой области при замере освещенности или расчетах фокусировки.
Поле Rect
в объекте Camera.Area
описывает прямоугольную форму, отображенную на сетке единиц 2000 x 2000. Координаты -1000, -1000 представляют верхний левый угол изображения с камеры, а координаты 1000, 1000 представляют нижний правый угол изображения с камеры, как показано на иллюстрации ниже.
Рисунок 1. Красные линии иллюстрируют систему координат для указания Camera.Area
в предварительном просмотре камеры. Синее поле показывает местоположение и форму области камеры со значениями Rect
333,333,667,667.
Границы этой системы координат всегда соответствуют внешнему краю изображения, видимого в предварительном просмотре камеры, и не сжимаются и не расширяются с уровнем масштабирования. Аналогично, поворот предварительного просмотра изображения с помощью Camera.setDisplayOrientation()
не переназначает систему координат.
Распознавание лиц
Для фотографий, на которых есть люди, лица обычно являются самой важной частью изображения и должны использоваться для определения как фокуса, так и баланса белого при съемке изображения. Платформа Android 4.0 (API уровня 14) предоставляет API для идентификации лиц и расчета настроек изображения с использованием технологии распознавания лиц.
Примечание: пока работает функция обнаружения лиц, setWhiteBalance(String)
, setFocusAreas(List<Camera.Area>)
и setMeteringAreas(List<Camera.Area>)
не действуют.
Для использования функции распознавания лиц в приложении камеры необходимо выполнить несколько общих шагов:
- Проверьте, поддерживается ли на устройстве функция распознавания лиц.
- Создать прослушиватель обнаружения лиц
- Добавьте прослушиватель обнаружения лиц к объекту камеры
- Запустить распознавание лиц после предварительного просмотра (и после каждого перезапуска предварительного просмотра)
Функция обнаружения лиц поддерживается не на всех устройствах. Вы можете проверить, поддерживается ли эта функция, вызвав getMaxNumDetectedFaces()
. Пример этой проверки показан в примере метода startFaceDetection()
ниже.
Чтобы получать уведомления и реагировать на обнаружение лица, ваше приложение камеры должно установить прослушиватель для событий обнаружения лица. Для этого необходимо создать класс прослушивателя, реализующий интерфейс Camera.FaceDetectionListener
, как показано в примере кода ниже.
Котлин
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Ява
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
После создания этого класса вы устанавливаете его в объект Camera
вашего приложения, как показано в примере кода ниже:
Котлин
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Ява
camera.setFaceDetectionListener(new MyFaceDetectionListener());
Ваше приложение должно запускать функцию обнаружения лиц каждый раз, когда вы запускаете (или перезапускаете) предварительный просмотр камеры. Создайте метод для запуска обнаружения лиц, чтобы вы могли вызывать его по мере необходимости, как показано в примере кода ниже.
Котлин
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Ява
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
Вы должны начать обнаружение лица каждый раз, когда вы начинаете (или перезапустите) предварительный просмотр камеры. Если вы используете класс предварительного просмотра, показанный при создании класса предварительного просмотра , добавьте свой метод startFaceDetection()
как в методы surfaceCreated()
, так и surfaceChanged()
в вашем классе предварительного просмотра, как показано в примере кода ниже.
Котлин
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Ява
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
Примечание. Не забудьте позвонить в этот метод после вызова startPreview()
. Не пытайтесь начать обнаружение лица в методе onCreate()
основной деятельности приложения вашей камеры, так как предварительный просмотр недоступен к этому моменту в вашем приложении.
Время промежуточного видео
Видео Time Lappe позволяет пользователям создавать видеоклипы, которые объединяют фотографии, затрачиваемые на несколько секунд или минут друг от друга. Эта функция использует MediaRecorder
для записи изображений для последовательности промежутка времени.
Чтобы записать видео с MediaRecorder
, вы должны настроить объект Recorder, как если бы вы записывали обычное видео, устанавливая захваченные кадры в секунду на низкое число и используя одну из настройки качества промаха времени, как показано в примере кода ниже.
Котлин
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Ява
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
Эти настройки должны быть выполнены как часть более крупной процедуры конфигурации для MediaRecorder
. Для полного примера кода конфигурации см. Настройку MedieareCorder . После завершения конфигурации вы запускаете видеозапись видео, как будто вы записывали обычный видеоклип. Для получения дополнительной информации о настройке и запуске MediaRecorder
см. В захвате видео .
Образцы Camera2Video и HDRViewFinder дополнительно демонстрируют использование API, охватываемых на этой странице.
Поля камеры, которые требуют разрешения
Приложения, управляющие Android 10 (уровень API 29) или выше, должны иметь разрешение CAMERA
, чтобы получить доступ к значениям следующих полей, которые возвращает метод getCameraCharacteristics()
:
-
LENS_POSE_ROTATION
-
LENS_POSE_TRANSLATION
-
LENS_INTRINSIC_CALIBRATION
-
LENS_RADIAL_DISTORTION
-
LENS_POSE_REFERENCE
-
LENS_DISTORTION
-
LENS_INFO_HYPERFOCAL_DISTANCE
-
LENS_INFO_MINIMUM_FOCUS_DISTANCE
-
SENSOR_REFERENCE_ILLUMINANT1
-
SENSOR_REFERENCE_ILLUMINANT2
-
SENSOR_CALIBRATION_TRANSFORM1
-
SENSOR_CALIBRATION_TRANSFORM2
-
SENSOR_COLOR_TRANSFORM1
-
SENSOR_COLOR_TRANSFORM2
-
SENSOR_FORWARD_MATRIX1
-
SENSOR_FORWARD_MATRIX2
Дополнительный пример кода
Чтобы загрузить приложения, см. Пример Camera2basic и официальное приложение Camerax Sample .