Система захвата обычно записывает видео- и аудиопотоки, сжимает их, мультиплексирует два потока, а затем записывает полученный поток на диск.

В CameraX решением для захвата видео является вариант использования VideoCapture :

VideoCapture .Как показано на рисунке 2, функция захвата видео CameraX включает в себя несколько архитектурных компонентов высокого уровня:
-
SurfaceProviderдля источника видео. -
AudioSourceдля источника звука. - Два кодировщика для кодирования и сжатия видео/аудио.
- Медиа-мультиплексор для мультиплексирования двух потоков.
- Файловая заставка для записи результата.
API VideoCapture абстрагирует сложный механизм захвата и предоставляет приложениям гораздо более простой и понятный API.
Обзор API видеозахвата
VideoCapture — это вариант использования CameraX, который хорошо работает сам по себе или в сочетании с другими вариантами использования. Конкретные поддерживаемые комбинации зависят от аппаратных возможностей камеры, но Preview и VideoCapture является допустимой комбинацией вариантов использования на всех устройствах.
API VideoCapture состоит из следующих объектов, которые взаимодействуют с приложениями:
-
VideoCapture— это класс вариантов использования верхнего уровня.VideoCaptureпривязывается кLifecycleOwnerс помощьюCameraSelectorи других вариантов использования CameraX. Дополнительные сведения об этих концепциях и их использовании см. в разделе Архитектура CameraX . -
Recorder— это реализация VideoOutput, тесно связанная сVideoCapture.Recorderиспользуется для записи видео и звука. Приложение создает записи сRecorder. -
PendingRecordingнастраивает запись, предоставляя такие параметры, как включение звука и настройку прослушивателя событий. Вы должны использоватьRecorderдля созданияPendingRecording.PendingRecordingничего не записывает. -
Recordingвыполняет фактическую запись. Для созданияRecordingнеобходимо использоватьPendingRecording.
На рисунке 3 показаны отношения между этими объектами:

Легенда:
- Создайте
Recorderс помощьюQualitySelector. - Настройте
Recorderс помощью одного изOutputOptions. - При необходимости включите звук с помощью
withAudioEnabled(). - Вызовите
start()с прослушивателемVideoRecordEvent, чтобы начать запись. - Используйте
pause()/resume()/stop()вRecordingдля управления записью. - Отвечайте на
VideoRecordEventsвнутри прослушивателя событий.
Подробный список API находится в файле current.txt внутри исходного кода .
Использование API VideoCapture
Чтобы интегрировать вариант использования CameraX VideoCapture в ваше приложение, выполните следующие действия:
- Привязать
VideoCapture. - Подготовьте и настройте запись.
- Запускайте и управляйте записью во время выполнения.
В следующих разделах описывается, что вы можете сделать на каждом этапе, чтобы получить сеанс сквозной записи.
Привязать видеозахват
Чтобы связать вариант использования VideoCapure , выполните следующие действия:
- Создайте объект
Recorder. - Создайте объект
VideoCapture. - Привязка к
Lifecycle.
API CameraX VideoCapture соответствует шаблону проектирования построителя. Приложения используют Recorder.Builder для создания Recorder . Вы также можете настроить разрешение видео для Recorder с помощью объекта QualitySelector .
CameraX Recorder поддерживает следующие предопределенные Qualities разрешения видео:
-
Quality.UHDдля видео формата 4K Ultra HD (2160p) -
Quality.FHDдля видео формата Full HD (1080p) -
Quality.HDдля видео формата HD (720p) -
Quality.SDдля размера видео SD (480p)
Обратите внимание, что CameraX также может выбирать другие разрешения, если это разрешено приложением.
Точный размер видео каждого выбора зависит от возможностей камеры и кодера. Для получения дополнительной информации см. документацию по CamcorderProfile .
Приложения могут настраивать разрешение, создавая QualitySelector . Вы можете создать QualitySelector используя один из следующих методов:
Предоставьте несколько предпочтительных разрешений с помощью
fromOrderedList()и включите запасную стратегию, которая будет использоваться в случае, если ни одно из предпочтительных разрешений не поддерживается.CameraX может выбрать лучший резервный вариант на основе возможностей выбранной камеры. Более подробную информацию можно найти в
FallbackStrategy specificationQualitySelector. Например, следующий код запрашивает самое высокое поддерживаемое разрешение для записи, и если ни одно из разрешений запроса не может быть поддержано, разрешите CameraX выбрать то, которое наиболее близко к разрешению Quality.SD:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))Сначала запросите возможности камеры и выберите поддерживаемое разрешение с помощью
QualitySelector::from():val cameraInfo = cameraProvider.availableCameraInfos.filter { Camera2CameraInfo .from(it) .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK } val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0]) val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD) .filter { supportedQualities.contains(it) } // Use a simple ListView with the id of simple_quality_list_view viewBinding.simpleQualityListView.apply { adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, filteredQualities.map { it.qualityToString() }) // Set up the user interaction to manually show or hide the system UI. setOnItemClickListener { _, _, position, _ -> // Inside View.OnClickListener, // convert Quality.* constant to QualitySelector val qualitySelector = QualitySelector.from(filteredQualities[position]) // Create a new Recorder/VideoCapture for the new quality // and bind to lifecycle val recorder = Recorder.Builder() .setQualitySelector(qualitySelector).build() // ... } } // A helper function to translate Quality to a string fun Quality.qualityToString() : String { return when (this) { Quality.UHD -> "UHD" Quality.FHD -> "FHD" Quality.HD -> "HD" Quality.SD -> "SD" else -> throw IllegalArgumentException() } }Обратите внимание, что возвращаемая возможность из
QualitySelector.getSupportedQualities()гарантированно будет работать либо для варианта использованияVideoCapture, либо для комбинации вариантов использованияVideoCaptureиPreview. При связывании вместе с вариантом использованияImageCaptureилиImageAnalysisCameraX может по-прежнему не выполнить привязку, если требуемая комбинация не поддерживается на запрошенной камере.
Если у вас есть QualitySelector , приложение может создать объект VideoCapture и выполнить привязку. Обратите внимание, что эта привязка такая же, как и в других случаях использования:
val recorder = Recorder.Builder()
.setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
try {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
Обратите внимание, что bindToLifecycle() возвращает объект Camera . См. это руководство для получения дополнительной информации об управлении выходными данными камеры, такими как масштабирование и экспозиция.
Recorder выбирает наиболее подходящий для системы формат. Самый распространенный видеокодек — H.264 AVC ) с контейнерным форматом MPEG-4 .
Настроить и создать запись
Из Recorder приложение может создавать объекты записи для захвата видео и звука. Приложения создают записи, выполняя следующие действия:
- Настройте
OutputOptionsс помощьюprepareRecording(). - (Необязательно) Включите запись звука.
- Используйте
start(), чтобы зарегистрировать прослушивательVideoRecordEventи начать захват видео.
Recorder возвращает объект Recording при вызове функции start() . Ваше приложение может использовать этот объект Recording для завершения записи или выполнения других действий, таких как приостановка или возобновление.
Recorder одновременно поддерживает один объект Recording . Вы можете начать новую запись после вызова Recording.stop() или Recording.close() для предыдущего объекта Recording .
Давайте рассмотрим эти шаги более подробно. Сначала приложение настраивает OutputOptions для устройства записи с помощью Recorder.prepareRecording() . Recorder поддерживает следующие типы OutputOptions :
-
FileDescriptorOutputOptionsдля захвата вFileDescriptor. -
FileOutputOptionsдля захвата вFile. -
MediaStoreOutputOptionsдля захвата вMediaStore.
Все типы OutputOptions позволяют вам установить максимальный размер файла с помощью setFileSizeLimit() . Другие параметры зависят от отдельного типа вывода, например ParcelFileDescriptor для FileDescriptorOutputOptions .
prepareRecording() возвращает объект PendingRecording , который является промежуточным объектом, используемым для создания соответствующего объекта Recording . PendingRecording — это временный класс, который в большинстве случаев должен быть невидимым и редко кэшируется приложением.
Приложения могут дополнительно настроить запись, например:
- Включите звук с помощью
withAudioEnabled(). - Зарегистрируйте прослушиватель для получения событий видеозаписи с помощью
start(Executor, Consumer<VideoRecordEvent>). - Разрешите непрерывную запись записи, пока VideoCapture, к которому она подключена, повторно привязана к другой камере, с помощью
PendingRecording.asPersistentRecording().
Чтобы начать запись, вызовите PendingRecording.start() . CameraX превращает PendingRecording в Recording , ставит запрос на запись в очередь и возвращает приложению вновь созданный объект Recording . Как только запись начинается на соответствующем устройстве камеры, CameraX отправляет событие VideoRecordEvent.EVENT_TYPE_START .
В следующем примере показано, как записывать видео и аудио в файл MediaStore :
// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), captureListener)
Хотя предварительный просмотр камеры по умолчанию зеркально отображается на передней камере, видео, записанные с помощью VideoCapture, по умолчанию не зеркалируются. С помощью CameraX 1.3 теперь можно зеркально отображать видеозаписи, чтобы предварительный просмотр передней камеры и записанное видео совпадали.
Существует три параметра MirrorMode: MIRROR_MODE_OFF, MIRROR_MODE_ON и MIRROR_MODE_ON_FRONT_ONLY. Для согласования с предварительным просмотром камеры Google рекомендует использовать MIROR_MODE_ON_FRONT_ONLY, что означает, что зеркальное отображение не включено для задней камеры, но включено для передней камеры. Дополнительные сведения о MirrorMode см. в MirrorMode constants .
В этом фрагменте кода показано, как вызвать VideoCapture.Builder.setMirrorMode() с использованием MIRROR_MODE_ON_FRONT_ONLY . Для получения дополнительной информации см. setMirrorMode() .
Котлин
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Ява
Recorder.Builder builder = new Recorder.Builder(); if (mVideoQuality != QUALITY_AUTO) { builder.setQualitySelector( QualitySelector.from(mVideoQuality)); } VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build()) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build(); useCases.add(videoCapture);
Управление активной записью
Вы можете приостановить, возобновить и остановить текущую Recording , используя следующие методы:
-
pause, чтобы приостановить текущую активную запись. -
resume(), чтобы возобновить приостановленную активную запись. -
stop()чтобы завершить запись и очистить все связанные объекты записи. -
mute()чтобы отключить или включить звук текущей записи.
Обратите внимание, что вы можете вызвать функцию stop() для прекращения Recording независимо от того, находится ли запись в состоянии паузы или в активном состоянии.
Если вы зарегистрировали EventListener с помощью PendingRecording.start() , Recording осуществляется с помощью VideoRecordEvent .
-
VideoRecordEvent.EVENT_TYPE_STATUSиспользуется для записи статистики, такой как текущий размер файла и записанный промежуток времени. -
VideoRecordEvent.EVENT_TYPE_FINALIZEиспользуется для результата записи и включает такую информацию, как URI конечного файла, а также любые связанные ошибки.
Как только ваше приложение получит EVENT_TYPE_FINALIZE , указывающее на успешный сеанс записи, вы сможете получить доступ к захваченному видео из местоположения, указанного в OutputOptions .
Дополнительные ресурсы
Чтобы узнать больше о CameraX, посетите следующие дополнительные ресурсы:
- Начало работы с CameraX Codelab
- Официальное приложение CameraX
- Последний список API захвата видео CameraX
- Примечания к выпуску CameraX
- Исходный код CameraX