Система захвата обычно записывает видео- и аудиопотоки, сжимает их, мультиплексирует два потока, а затем записывает полученный поток на диск.
В CameraX решением для захвата видео является вариант использования 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 specification
QualitySelector
. Например, следующий код запрашивает самое высокое поддерживаемое разрешение для записи, и если ни одно из разрешений запроса не может быть поддержано, разрешите 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
илиImageAnalysis
CameraX может по-прежнему не выполнить привязку, если требуемая комбинация не поддерживается на запрошенной камере.
Если у вас есть 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