Платформа Android включает поддержку различных камер и функций камер, доступных на устройствах, что позволяет вам снимать изображения и видео в ваших приложениях. В этом документе обсуждается быстрый и простой подход к захвату изображений и видео, а также описывается расширенный подход к созданию пользовательских возможностей камеры для ваших пользователей.
Примечание. На этой странице описан класс Camera
, который устарел. Мы рекомендуем использовать библиотеку CameraX Jetpack или, в особых случаях, класс camera2
. И CameraX, и Camera2 работают на Android 5.0 (уровень API 21) и выше.
Обратитесь к следующим соответствующим ресурсам:
Соображения
Прежде чем разрешить вашему приложению использовать камеры на устройствах Android, вам следует ответить на несколько вопросов о том, как ваше приложение собирается использовать эту аппаратную функцию.
- Требование к камере . Является ли использование камеры настолько важным для вашего приложения, что вы не хотите, чтобы ваше приложение устанавливалось на устройство, не имеющее камеры? Если да, вам следует объявить требования к камере в своем манифесте .
- Quick Picture или Customized Camera : как ваше приложение будет использовать камеру? Вас просто интересует возможность быстро сделать снимок или видеоклип, или ваше приложение предоставит новый способ использования камер? Чтобы быстро сделать снимок или клип, рассмотрите возможность использования существующих приложений камеры . Для разработки индивидуальной функции камеры ознакомьтесь с разделом «Создание приложения камеры» .
- Требование к службам переднего плана . Когда ваше приложение взаимодействует с камерой? В Android 9 (уровень API 28) и более поздних версиях приложения, работающие в фоновом режиме, не могут получить доступ к камере. Поэтому вам следует использовать камеру либо тогда, когда ваше приложение находится на переднем плане, либо как часть службы переднего плана .
- Хранилище . Предназначены ли изображения или видео, создаваемые вашим приложением, для просмотра только в вашем приложении или для совместного использования другими приложениями, такими как Галерея или другими мультимедийными и социальными приложениями? Хотите, чтобы изображения и видео были доступны, даже если ваше приложение удалено? Посетите раздел «Сохранение медиафайлов» , чтобы узнать, как реализовать эти параметры.
Основы
Платформа Android поддерживает захват изображений и видео через API android.hardware.camera2
или камеру Intent
. Вот соответствующие классы:
-
android.hardware.camera2
- Этот пакет является основным API для управления камерами устройств. Его можно использовать для съемки фотографий или видео при создании приложения камеры.
-
Camera
- Этот класс представляет собой старый устаревший API для управления камерами устройств.
-
SurfaceView
- Этот класс используется для представления пользователю предварительного просмотра камеры в реальном времени.
-
MediaRecorder
- Этот класс используется для записи видео с камеры.
-
Intent
- Тип действия намерения
MediaStore.ACTION_IMAGE_CAPTURE
илиMediaStore.ACTION_VIDEO_CAPTURE
можно использовать для захвата изображений или видео без прямого использования объектаCamera
.
Манифестные декларации
Прежде чем начинать разработку приложения с помощью API камеры, вы должны убедиться, что в вашем манифесте есть соответствующие объявления, позволяющие использовать оборудование камеры и другие связанные функции.
- Разрешение камеры . Ваше приложение должно запросить разрешение на использование камеры устройства.
<uses-permission android:name="android.permission.CAMERA" />
Примечание. Если вы используете камеру , вызывая существующее приложение камеры , вашему приложению не нужно запрашивать это разрешение.
- Функции камеры . Ваше приложение также должно заявить об использовании функций камеры, например:
<uses-feature android:name="android.hardware.camera" />
Список функций камеры см. в справке по функциям манифеста.
Добавление функций камеры в манифест приведет к тому, что Google Play запретит установку вашего приложения на устройства, которые не оснащены камерой или не поддерживают указанные вами функции камеры. Дополнительную информацию об использовании фильтрации на основе функций в Google Play см. в разделе Google Play и фильтрация на основе функций .
Если ваше приложение может использовать камеру или функцию камеры для правильной работы, но не требует этого, вам следует указать это в манифесте, включив атрибут
android:required
и установив для него значениеfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Разрешение на хранение . Ваше приложение может сохранять изображения или видео на внешнее хранилище устройства (SD-карту), если оно предназначено для Android 10 (уровень API 29) или более ранней версии и в манифесте указано следующее.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Разрешение на запись звука . Для записи звука с захватом видео ваше приложение должно запросить разрешение на захват звука.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Разрешение на определение местоположения . Если ваше приложение помечает изображения информацией о местоположении GPS, вам необходимо запросить разрешение
ACCESS_FINE_LOCATION
. Обратите внимание: если ваше приложение предназначено для Android 5.0 (уровень API 21) или выше, вам также необходимо объявить, что ваше приложение использует GPS устройства:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
Дополнительные сведения о получении местоположения пользователя см. в разделе Стратегии определения местоположения .
Использование существующих приложений камеры
Быстрый способ включить фото- или видеосъемку в вашем приложении без большого количества дополнительного кода — использовать Intent
для вызова существующего приложения камеры Android. Подробности описаны в обучающих уроках «Просто фотографировать» и «Просто записывать видео» .
Создание приложения камеры
Некоторым разработчикам может потребоваться пользовательский интерфейс камеры, адаптированный к внешнему виду их приложения или предоставляющий специальные функции. Написание собственного кода для создания изображений может обеспечить более привлекательный опыт для ваших пользователей.
Примечание. Следующее руководство предназначено для более старого устаревшего API Camera
. Для новых или продвинутых приложений камеры рекомендуется использовать новый API android.hardware.camera2
.
Общие шаги по созданию пользовательского интерфейса камеры для вашего приложения следующие:
- Обнаружение камеры и доступ к ней . Создайте код для проверки наличия камер и запроса доступа.
- Создайте класс предварительного просмотра . Создайте класс предварительного просмотра камеры, который расширяет
SurfaceView
и реализует интерфейсSurfaceHolder
. Этот класс просматривает живые изображения с камеры. - Создайте макет предварительного просмотра . Получив класс предварительного просмотра камеры, создайте макет вида, включающий в себя предварительный просмотр и нужные элементы управления пользовательского интерфейса.
- Настройка прослушивателей для захвата . Подключите прослушиватели для элементов управления интерфейса, чтобы начать захват изображений или видео в ответ на действия пользователя, например нажатие кнопки.
- Захват и сохранение файлов — настройте код для захвата изображений или видео и сохранения результатов.
- Освободите камеру . После использования камеры ваше приложение должно правильно освободить ее для использования другими приложениями.
Аппаратное обеспечение камеры — это общий ресурс, которым необходимо тщательно управлять, чтобы ваше приложение не конфликтовало с другими приложениями, которые также могут захотеть его использовать. В следующих разделах обсуждается, как обнаружить оборудование камеры, как запросить доступ к камере, как захватить изображения или видео и как освободить камеру, когда ваше приложение закончит ее использовать.
Внимание: не забудьте освободить объект Camera
, вызвав Camera.release()
, когда ваше приложение завершит его использование! Если ваше приложение не освобождает камеру должным образом, все последующие попытки доступа к камере, в том числе со стороны вашего собственного приложения, окажутся неудачными и могут привести к закрытию вашего или других приложений.
Обнаружение оборудования камеры
Если вашему приложению не требуется камера с использованием объявления манифеста, вам следует проверить, доступна ли камера во время выполнения. Чтобы выполнить эту проверку, используйте метод PackageManager.hasSystemFeature()
, как показано в примере кода ниже:
Котлин
/** Check if this device has a camera */ private fun checkCameraHardware(context: Context): Boolean { if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // this device has a camera return true } else { // no camera on this device return false } }
Ява
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
Устройства Android могут иметь несколько камер, например заднюю камеру для фотосъемки и фронтальную камеру для видеозвонков. Android 2.3 (уровень API 9) и более поздних версий позволяет проверять количество камер, доступных на устройстве, с помощью метода Camera.getNumberOfCameras()
.
Доступ к камерам
Если вы определили, что устройство, на котором работает ваше приложение, имеет камеру, вы должны запросить доступ к ней, получив экземпляр Camera
(если вы не используете намерение для доступа к камере ).
Чтобы получить доступ к основной камере, используйте метод Camera.open()
и обязательно перехватите все исключения, как показано в коде ниже:
Котлин
/** A safe way to get an instance of the Camera object. */ fun getCameraInstance(): Camera? { return try { Camera.open() // attempt to get a Camera instance } catch (e: Exception) { // Camera is not available (in use or does not exist) null // returns null if camera is unavailable } }
Ява
/** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable }
Внимание: всегда проверяйте наличие исключений при использовании Camera.open()
. Если не выполнить проверку исключений, если камера используется или не существует, ваше приложение будет закрыто системой.
На устройствах под управлением Android 2.3 (уровень API 9) или выше вы можете получить доступ к определенным камерам с помощью Camera.open(int)
. В приведенном выше примере кода будет осуществляться доступ к первой задней камере на устройстве с более чем одной камерой.
Проверка функций камеры
Получив доступ к камере, вы можете получить дополнительную информацию о ее возможностях, используя метод Camera.getParameters()
и проверив возвращаемый объект Camera.Parameters
на наличие поддерживаемых возможностей. При использовании API уровня 9 или выше используйте Camera.getCameraInfo()
, чтобы определить, находится ли камера на передней или задней части устройства, а также ориентацию изображения.
Создание класса предварительного просмотра
Чтобы пользователи могли эффективно снимать фотографии или видео, они должны иметь возможность видеть то, что видит камера устройства. Класс предварительного просмотра камеры — это SurfaceView
, который может отображать данные живого изображения, поступающие с камеры, чтобы пользователи могли кадрировать и снимать изображения или видео.
В следующем примере кода показано, как создать базовый класс предварительного просмотра камеры, который можно включить в макет View
. Этот класс реализует SurfaceHolder.Callback
для захвата событий обратного вызова для создания и уничтожения представления, которые необходимы для назначения входных данных предварительного просмотра камеры.
Котлин
/** A basic Camera preview class */ class CameraPreview( context: Context, private val mCamera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val mHolder: SurfaceHolder = holder.apply { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. addCallback(this@CameraPreview) // deprecated setting, but required on Android versions prior to 3.0 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } override fun surfaceCreated(holder: SurfaceHolder) { // The Surface has been created, now tell the camera where to draw the preview. mCamera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // empty. Take care of releasing the Camera preview in your activity. } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.surface == null) { // preview surface does not exist return } // stop preview before making changes try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings mCamera.apply { try { setPreviewDisplay(mHolder) startPreview() } catch (e: Exception) { Log.d(TAG, "Error starting camera preview: ${e.message}") } } } }
Ява
/** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } }
Если вы хотите установить определенный размер для предварительного просмотра камеры, установите его в методе surfaceChanged()
, как указано в комментариях выше. При настройке размера предварительного просмотра вы должны использовать значения из getSupportedPreviewSizes()
. Не устанавливайте произвольные значения в методе setPreviewSize()
.
Примечание. С появлением функции многооконности в Android 7.0 (уровень API 24) и более поздних версиях вы больше не можете предполагать, что соотношение сторон предварительного просмотра такое же, как и ваша активность, даже после вызова setDisplayOrientation()
. В зависимости от размера окна и соотношения сторон вам, возможно, придется встроить предварительный просмотр широкой камеры в макет с портретной ориентацией или наоборот, используя макет почтового ящика.
Размещение предварительного просмотра в макете
Класс предварительного просмотра камеры, такой как пример, показанный в предыдущем разделе, должен быть размещен в макете действия вместе с другими элементами управления пользовательского интерфейса для съемки изображений или видео. В этом разделе показано, как создать базовый макет и действие для предварительного просмотра.
Следующий код макета предоставляет очень простой вид, который можно использовать для предварительного просмотра камеры. В этом примере элемент FrameLayout
является контейнером для класса предварительного просмотра камеры. Этот тип макета используется для наложения дополнительной информации об изображении или элементов управления на изображения предварительного просмотра с камеры в реальном времени.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
На большинстве устройств ориентация предварительного просмотра камеры по умолчанию — альбомная. В этом примере макета указан горизонтальный (альбомный) макет, а приведенный ниже код фиксирует альбомную ориентацию приложения. Для упрощения отрисовки предварительного просмотра камеры вам следует изменить ориентацию действия предварительного просмотра вашего приложения на альбомную, добавив в манифест следующее.
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
Примечание. Предварительный просмотр камеры не обязательно должен быть в ландшафтном режиме. Начиная с Android 2.2 (уровень API 8), вы можете использовать метод setDisplayOrientation()
чтобы задать поворот изображения предварительного просмотра. Чтобы изменить ориентацию предварительного просмотра, когда пользователь переориентирует телефон, в методе surfaceChanged()
вашего класса предварительного просмотра сначала остановите предварительный просмотр с помощью Camera.stopPreview()
измените ориентацию, а затем снова запустите предварительный просмотр с помощью Camera.startPreview()
.
В действии для просмотра с камеры добавьте класс предварительного просмотра к элементу FrameLayout
, показанному в примере выше. Действия вашей камеры также должны гарантировать, что она освобождает камеру, когда она приостанавливается или выключается. В следующем примере показано, как изменить действие камеры, чтобы прикрепить класс предварительного просмотра, показанный в разделе «Создание класса предварительного просмотра» .
Котлин
class CameraActivity : Activity() { private var mCamera: Camera? = null private var mPreview: CameraPreview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create an instance of Camera mCamera = getCameraInstance() mPreview = mCamera?.let { // Create our Preview view CameraPreview(this, it) } // Set the Preview view as the content of our activity. mPreview?.also { val preview: FrameLayout = findViewById(R.id.camera_preview) preview.addView(it) } } }
Ява
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
Примечание. Метод getCameraInstance()
в приведенном выше примере относится к примеру метода, показанному в разделе Доступ к камерам .
Захват изображений
После того как вы создали класс предварительного просмотра и макет представления для его отображения, вы готовы начать захват изображений с помощью своего приложения. В коде вашего приложения вы должны настроить прослушиватели для элементов управления пользовательского интерфейса, чтобы они реагировали на действия пользователя, делая снимки.
Чтобы получить изображение, используйте метод Camera.takePicture()
. Этот метод принимает три параметра, которые получают данные с камеры. Чтобы получать данные в формате JPEG, необходимо реализовать интерфейс Camera.PictureCallback
для получения данных изображения и записи их в файл. В следующем коде показана базовая реализация интерфейса Camera.PictureCallback
для сохранения изображения, полученного с камеры.
Котлин
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Ява
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
Запустите захват изображения, вызвав метод Camera.takePicture()
. В следующем примере кода показано, как вызвать этот метод из кнопки View.OnClickListener
.
Котлин
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Ява
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
Примечание. Член mPicture
в следующем примере относится к приведенному выше примеру кода.
Внимание: не забудьте освободить объект Camera
, вызвав Camera.release()
, когда ваше приложение завершит его использование! Информацию о том, как освободить камеру, см. в разделе «Освобождение камеры» .
Захват видео
Захват видео с помощью платформы Android требует тщательного управления объектом Camera
и координации с классом MediaRecorder
. При записи видео с помощью Camera
вы должны управлять вызовами Camera.lock()
и Camera.unlock()
, чтобы разрешить MediaRecorder
доступ к оборудованию камеры, в дополнение к вызовам Camera.open()
и Camera.release()
.
Примечание. Начиная с Android 4.0 (уровень API 14), вызовы Camera.lock()
и Camera.unlock()
управляются автоматически.
В отличие от съемки с помощью камеры устройства, съемка видео требует особого порядка вызовов. Вы должны следовать определенному порядку выполнения, чтобы успешно подготовиться и записать видео с помощью вашего приложения, как подробно описано ниже.
- Открыть камеру . Используйте
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 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.prepare()
для проверки и реализации конфигурации. В следующем примере кода показано, как правильно настроить и подготовить класс MediaRecorder
для записи видео.
Котлин
private fun prepareVideoRecorder(): Boolean { mediaRecorder = MediaRecorder() mCamera?.let { camera -> // Step 1: Unlock and set camera to MediaRecorder camera?.unlock() mediaRecorder?.run { setCamera(camera) // Step 2: Set sources setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Step 4: Set output file setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Step 5: Set the preview output setPreviewDisplay(mPreview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Step 6: Prepare configured MediaRecorder return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } } } return false }
Ява
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } return true; }
До Android 2.2 (уровень API 8) необходимо устанавливать параметры выходного формата и форматов кодирования напрямую, а не использовать CamcorderProfile
. Этот подход продемонстрирован в следующем коде:
Котлин
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder?.apply { setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) }
Ява
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
Следующие параметры записи видео для MediaRecorder
имеют настройки по умолчанию, однако вы можете настроить эти параметры для своего приложения:
-
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 8) или более поздних версиях. Если вы ориентируетесь на устройства с более ранними версиями Android, используйте вместо этого Environment.getExternalStorageDirectory()
. Дополнительную информацию см. в разделе Сохранение общих файлов .
Чтобы URI поддерживал рабочие профили, сначала преобразуйте URI файла в URI контента . Затем добавьте URI контента в EXTRA_OUTPUT
Intent
.
Дополнительную информацию о сохранении файлов на устройстве Android см. в разделе Хранение данных .
Возможности камеры
Android поддерживает широкий спектр функций камеры, которыми вы можете управлять с помощью приложения камеры, например формат изображения, режим вспышки, настройки фокусировки и многое другое. В этом разделе перечислены общие функции камеры и кратко описано, как их использовать. Доступ к большинству функций камеры и их настройку можно получить с помощью объекта Camera.Parameters
. Однако есть несколько важных функций, которые требуют большего, чем простая настройка в Camera.Parameters
. Эти функции описаны в следующих разделах:
Общие сведения об использовании функций, управляемых через Camera.Parameters
, см. в разделе «Использование функций камеры» . Для получения более подробной информации о том, как использовать функции, управляемые через объект параметров камеры, перейдите по ссылкам в списке функций ниже на справочную документацию по API.
Особенность | Уровень API | Описание |
---|---|---|
Распознавание лиц | 14 | Распознавайте человеческие лица на изображении и используйте их для фокусировки, замера экспозиции и баланса белого. |
Зоны измерения | 14 | Укажите одну или несколько областей изображения для расчета баланса белого. |
Направления деятельности | 14 | Установите одну или несколько областей изображения, которые будут использоваться для фокусировки. |
White Balance Lock | 14 | Остановите или запустите автоматическую регулировку баланса белого. |
Exposure Lock | 14 | Остановите или запустите автоматическую регулировку экспозиции |
Video Snapshot | 14 | Сделать снимок во время съемки видео (захват кадра) |
Таймлапс-видео | 11 | Записывайте кадры с установленными задержками для записи замедленного видео. |
Multiple Cameras | 9 | Поддержка более чем одной камеры на устройстве, включая фронтальную и заднюю камеры. |
Focus Distance | 9 | Сообщает расстояния между камерой и объектами, которые кажутся в фокусе. |
Zoom | 8 | Установить увеличение изображения |
Exposure Compensation | 8 | Увеличьте или уменьшите уровень освещенности. |
GPS Data | 5 | Включите или опустите данные о географическом местоположении в изображении. |
White Balance | 5 | Установите режим баланса белого, который влияет на значения цветов в захваченном изображении. |
Focus Mode | 5 | Установите способ фокусировки камеры на объекте, например автоматический, фиксированный, макро или бесконечность. |
Scene Mode | 5 | Применение предустановленного режима для определенных типов фотосъемки, например, ночью, на пляже, в снегу или при свечах. |
JPEG Quality | 5 | Установите уровень сжатия для изображения JPEG, который увеличивает или уменьшает качество и размер выходного файла изображения. |
Flash Mode | 5 | Включите, выключите вспышку или используйте автоматическую настройку. |
Color Effects | 5 | Примените к захваченному изображению цветовой эффект, например черно-белый, оттенок сепии или негатив. |
Anti-Banding | 5 | Уменьшает эффект полос в цветовых градиентах за счет сжатия JPEG. |
Picture Format | 1 | Укажите формат файла для изображения |
Picture Size | 1 | Укажите размеры сохраненного изображения в пикселях. |
Примечание. Эти функции поддерживаются не на всех устройствах из-за различий в аппаратном обеспечении и программной реализации. Информацию о проверке доступности функций на устройстве, на котором работает ваше приложение, см. в разделе Проверка доступности функций .
Проверка доступности функции
Первое, что нужно понимать, собираясь использовать функции камеры на устройствах Android, — это то, что не все функции камеры поддерживаются на всех устройствах. Кроме того, устройства, поддерживающие определенную функцию, могут поддерживать ее на разных уровнях или с разными опциями. Таким образом, частью процесса принятия решения при разработке приложения для камеры является определение того, какие функции камеры вы хотите поддерживать и на каком уровне. После принятия этого решения вам следует запланировать включение в приложение камеры кода, который проверяет, поддерживает ли аппаратное обеспечение устройства эти функции, и корректно завершает работу, если функция недоступна.
Вы можете проверить доступность функций камеры, получив экземпляр объекта параметров камеры и проверив соответствующие методы. В следующем примере кода показано, как получить объект Camera.Parameters
и проверить, поддерживает ли камера функцию автофокусировки:
Котлин
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Ява
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
Вы можете использовать технику, показанную выше, для большинства функций камеры. Объект Camera.Parameters
предоставляет метод getSupported...()
, is...Supported()
или getMax...()
для определения того, поддерживается ли (и в какой степени) функция.
Если вашему приложению для правильной работы требуются определенные функции камеры, вы можете потребовать их, добавив дополнения в манифест вашего приложения. Когда вы заявляете об использовании определенных функций камеры, таких как вспышка и автофокус, Google Play запрещает установку вашего приложения на устройства, которые не поддерживают эти функции. Список функций камеры, которые можно объявить в манифесте приложения, см. в справочнике по функциям манифеста.
Использование функций камеры
Большинство функций камеры активируются и управляются с помощью объекта Camera.Parameters
. Вы получаете этот объект, сначала получив экземпляр объекта Camera
, вызвав метод getParameters()
, изменив возвращаемый объект параметра и затем установив его обратно в объект камеры, как показано в следующем примере кода:
Котлин
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Ява
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
Этот метод работает практически для всех функций камеры, и большинство параметров можно изменить в любое время после получения экземпляра объекта Camera
. Изменения параметров обычно видны пользователю сразу при предварительном просмотре камеры приложения. Что касается программного обеспечения, изменения параметров могут занять несколько кадров, прежде чем они действительно вступят в силу, поскольку аппаратное обеспечение камеры обрабатывает новые инструкции, а затем отправляет обновленные данные изображения.
Важно: некоторые функции камеры нельзя изменить по своему желанию. В частности, для изменения размера или ориентации предварительного просмотра камеры необходимо сначала остановить предварительный просмотр, изменить его размер, а затем перезапустить предварительный просмотр. Начиная с Android 4.0 (уровень API 14), ориентацию предварительного просмотра можно изменить без перезапуска предварительного просмотра.
Для реализации других функций камеры требуется больше кода, в том числе:
- Зоны замера экспозиции и фокусировки
- Распознавание лиц
- Таймлапс-видео
Краткое описание того, как реализовать эти функции, представлено в следующих разделах.
Зоны замера экспозиции и фокусировки
В некоторых фотографических сценариях автоматическая фокусировка и экспозамер могут не дать желаемых результатов. Начиная с Android 4.0 (уровень API 14), ваше приложение камеры может предоставлять дополнительные элементы управления, позволяющие вашему приложению или пользователям указывать области изображения, которые будут использоваться для определения настроек фокусировки или уровня освещенности, и передавать эти значения оборудованию камеры для использования при съемке. изображения или видео.
Области измерения и фокусировки работают очень похоже на другие функции камеры, поскольку вы управляете ими с помощью методов объекта Camera.Parameters
. Следующий код демонстрирует настройку двух областей замера освещенности для экземпляра Camera
:
Котлин
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Ява
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
Объект Camera.Area
содержит два параметра данных: объект Rect
для указания области в поле зрения камеры и значение веса, которое сообщает камере, какой уровень важности этой области следует придавать при измерении освещенности или расчетах фокусировки.
Поле Rect
в объекте Camera.Area
описывает прямоугольную форму, отображаемую на сетке размером 2000 x 2000. Координаты -1000, -1000 представляют верхний левый угол изображения камеры, а координаты 1000, 1000 представляют нижний правый угол изображения камеры, как показано на рисунке ниже.
Границы этой системы координат всегда соответствуют внешнему краю изображения, видимого при предварительном просмотре камеры, и не сжимаются и не расширяются с увеличением уровня масштабирования. Аналогично, вращение предварительного просмотра изображения с помощью Camera.setDisplayOrientation()
не переназначает систему координат.
Распознавание лиц
Для изображений, на которых изображены люди, лица обычно являются наиболее важной частью изображения и должны использоваться для определения фокусировки и баланса белого при съемке изображения. Платформа Android 4.0 (API Level 14) предоставляет API для идентификации лиц и расчета настроек изображения с использованием технологии распознавания лиц.
Примечание. Пока функция обнаружения лиц работает, setWhiteBalance(String)
, setFocusAreas(List<Camera.Area>)
и setMeteringAreas(List<Camera.Area>)
не действуют.
Для использования функции распознавания лиц в приложении камеры необходимо выполнить несколько общих шагов:
- Убедитесь, что распознавание лиц поддерживается на устройстве.
- Создание прослушивателя обнаружения лиц
- Добавьте прослушиватель обнаружения лиц к объекту камеры.
- Запуск распознавания лиц после предварительного просмотра (и после каждого перезапуска предварительного просмотра)
Функция распознавания лиц поддерживается не на всех устройствах. Вы можете проверить, поддерживается ли эта функция, вызвав getMaxNumDetectedFaces()
. Пример этой проверки показан в примере метода startFaceDetection()
ниже.
Чтобы получать уведомления и реагировать на обнаружение лица, приложение камеры должно настроить прослушиватель событий обнаружения лица. Для этого необходимо создать класс прослушивателя, реализующий интерфейс Camera.FaceDetectionListener
, как показано в примере кода ниже.
Котлин
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Ява
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
После создания этого класса вы затем устанавливаете его в объект Camera
вашего приложения, как показано в примере кода ниже:
Котлин
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Ява
camera.setFaceDetectionListener(new MyFaceDetectionListener());
Ваше приложение должно запускать функцию обнаружения лиц каждый раз, когда вы запускаете (или перезапускаете) предварительный просмотр камеры. Создайте метод для запуска распознавания лиц, чтобы вы могли вызывать его по мере необходимости, как показано в примере кода ниже.
Котлин
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Ява
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
Вы должны запускать распознавание лиц каждый раз, когда запускаете (или перезапускаете) предварительный просмотр камеры. Если вы используете класс предварительного просмотра, показанный при создании класса предварительного просмотра , добавьте свой метод startFaceDetection()
как в методы surfaceCreated()
, так и surfaceChanged()
в вашем классе предварительного просмотра, как показано в примере кода ниже.
Котлин
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Ява
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
Примечание. Не забудьте позвонить в этот метод после вызова startPreview()
. Не пытайтесь начать обнаружение лица в методе onCreate()
основной деятельности приложения вашей камеры, так как предварительный просмотр недоступен к этому моменту в вашем приложении.
Время промежуточного видео
Видео Time Lappe позволяет пользователям создавать видеоклипы, которые объединяют фотографии, затрачиваемые на несколько секунд или минут друг от друга. Эта функция использует MediaRecorder
для записи изображений для последовательности промежутка времени.
Чтобы записать видео о промежутке времени с помощью MediaRecorder
, необходимо настроить объект Recorder, как если бы вы записывали обычное видео, устанавливая захваченные кадры в секунду на низкое число и используя одну из настройки качества промежутка времени, как показано в примере кода ниже.
Котлин
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Ява
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
Эти настройки должны быть выполнены как часть более крупной процедуры конфигурации для MediaRecorder
. Для полного примера кода конфигурации см. Настройку MedieareCorder . После завершения конфигурации вы запускаете видеозапись видео, как будто вы записывали обычный видеоклип. Для получения дополнительной информации о настройке и запуске MediaRecorder
см. В захвате видео .
Образцы Camera2Video и HDRViewFinder дополнительно демонстрируют использование API, охватываемых на этой странице.
Поля камеры, которые требуют разрешения
Приложения, управляющие Android 10 (уровень API 29) или выше, должны иметь разрешение CAMERA
, чтобы получить доступ к значениям следующих полей, которые возвращает метод getCameraCharacteristics()
:
-
LENS_POSE_ROTATION
-
LENS_POSE_TRANSLATION
-
LENS_INTRINSIC_CALIBRATION
-
LENS_RADIAL_DISTORTION
-
LENS_POSE_REFERENCE
-
LENS_DISTORTION
-
LENS_INFO_HYPERFOCAL_DISTANCE
-
LENS_INFO_MINIMUM_FOCUS_DISTANCE
-
SENSOR_REFERENCE_ILLUMINANT1
-
SENSOR_REFERENCE_ILLUMINANT2
-
SENSOR_CALIBRATION_TRANSFORM1
-
SENSOR_CALIBRATION_TRANSFORM2
-
SENSOR_COLOR_TRANSFORM1
-
SENSOR_COLOR_TRANSFORM2
-
SENSOR_FORWARD_MATRIX1
-
SENSOR_FORWARD_MATRIX2
Дополнительный пример кода
Чтобы загрузить приложения, см. Пример Camera2basic и официальное приложение Camerax Sample .