일반적으로 캡처 시스템은 동영상 및 오디오 스트림을 녹화하여 압축한 후 두 스트림을 다중화하고 결과로 생성된 스트림을 디스크에 씁니다.
![동영상 및 오디오 캡처 시스템의 개념 다이어그램](https://developer.android.google.cn/static/images/training/camera/camerax/conceptual-capturing-system.png?authuser=3&hl=ko)
CameraX에서 동영상 캡처 솔루션은 VideoCapture
사용 사례입니다.
![CameraX가 동영상 캡처 사용 사례를 처리하는 방법을 보여주는 개념 다이어그램](https://developer.android.google.cn/static/images/training/camera/camerax/videocapture-use-case.png?authuser=3&hl=ko)
VideoCapture
사용 사례를 처리하는 방법을 보여주는 개념 다이어그램그림 2와 같이 CameraX 동영상 캡처에는 상위 수준의 몇 가지 아키텍처 구성요소가 포함됩니다.
- 동영상 소스용
SurfaceProvider
- 오디오 소스용
AudioSource
- 동영상/오디오를 인코딩하고 압축하는 2개의 인코더
- 2개의 스트림을 결합하는 미디어 Muxer
- 결과를 기록할 수 있는 File Saver
VideoCapture API는 복잡한 캡처 엔진을 추상화하고 애플리케이션에 훨씬 단순하고 간단한 API를 제공합니다.
VideoCapture API 개요
VideoCapture
는 그 자체로도 잘 작동하고 다른 사용 사례와 결합할 수도 있는 CameraX 사용 사례입니다. 지원되는 조합은 카메라 하드웨어 기능에 따라 다르지만, Preview
및 VideoCapture
는 모든 기기에서 유효한 사용 사례 조합입니다.
VideoCapture API는 애플리케이션과 통신하는 다음 객체로 구성됩니다.
VideoCapture
는 최상위 사용 사례 클래스입니다.VideoCapture
는CameraSelector
및 다른 CameraX UseCases와 함께LifecycleOwner
에 바인딩됩니다. 이러한 개념 및 사용법에 관한 자세한 내용은 CameraX 아키텍처를 참고하세요.Recorder
는VideoCapture
와 긴밀하게 결합된 VideoOutput의 구현입니다.Recorder
는 동영상 및 오디오 캡처를 실행하는 데 사용됩니다. 애플리케이션은Recorder
로부터 녹화 파일을 만듭니다.PendingRecording
은 오디오를 사용 설정하고 이벤트 리스너를 설정하는 등의 옵션을 제공하여 녹화를 구성합니다.PendingRecording
을 만들려면Recorder
를 사용해야 합니다.PendingRecording
은 아무것도 녹화하지 않습니다.Recording
은 실제 녹화를 실행합니다.Recording
을 만들려면PendingRecording
을 사용해야 합니다.
그림 3은 이러한 객체 간의 관계를 보여줍니다.
![동영상 캡처 사용 사례에서 발생하는 상호작용을 보여주는 다이어그램](https://developer.android.google.cn/static/images/training/camera/camerax/videocapture-roles-interaction.png?authuser=3&hl=ko)
범례:
QualitySelector
로Recorder
를 만듭니다.OutputOptions
중 하나로Recorder
를 구성합니다.- 필요한 경우
withAudioEnabled()
로 오디오를 사용 설정합니다. VideoRecordEvent
리스너로start()
를 호출하여 녹화를 시작합니다.Recording
에서pause()
/resume()
/stop()
을 사용하여 녹화를 제어합니다.- 이벤트 리스너 내에서
VideoRecordEvents
에 응답합니다.
자세한 API 목록은 소스 코드 내 current.txt에 있습니다.
VideoCapture API 사용
CameraX VideoCapture
사용 사례를 앱에 통합하려면 다음을 따르세요.
VideoCapture
를 바인딩합니다.- 녹화를 준비하고 구성합니다.
- 런타임 녹화를 시작하고 제어합니다.
다음 섹션에서는 엔드 투 엔드 녹화 세션을 가져오기 위해 각 단계에서 할 수 있는 작업을 설명합니다.
VideoCapture 바인딩
VideoCapure
사용 사례를 바인딩하려면 다음을 따르세요.
Recorder
객체를 만듭니다.VideoCapture
객체를 만듭니다.Lifecycle
에 바인딩합니다.
CameraX VideoCapture API는 빌더 디자인 패턴을 따릅니다. 애플리케이션은 Recorder.Builder
를 사용하여 Recorder
를 만듭니다. QualitySelector
객체를 통해 Recorder
의 동영상 해상도를 구성할 수도 있습니다.
CameraX Recorder
는 다음과 같은 사전 정의된 동영상 해상도 Qualities
를 지원합니다.
Quality.UHD
: 4K Ultra HD 동영상 크기(2,160p)Quality.FHD
- 풀 HD 동영상 크기(1080p)Quality.HD
- HD 동영상 크기(720p)Quality.SD
- SD 동영상 크기(480p)
참고로 CameraX는 앱에서 승인한 경우 다른 해상도를 선택할 수도 있습니다.
각 선택 항목의 정확한 동영상 크기는 카메라와 인코더 기능에 따라 다릅니다. 자세한 내용은 CamcorderProfile
문서를 참고하세요.
애플리케이션은 QualitySelector
를 만들어 해상도를 구성할 수 있습니다.
다음 메서드 중 하나를 사용하여 QualitySelector
를 만들 수 있습니다.
fromOrderedList()
를 사용하여 선호하는 해상도를 제공하고, 선호하는 해상도가 지원되지 않는 경우 사용할 대체 전략을 포함합니다.CameraX는 선택된 카메라의 기능에 따라 최적의 대체 전략을 결정할 수 있습니다. 자세한 내용은
QualitySelector
의FallbackStrategy specification
을 참고하세요. 예를 들어 다음 코드는 지원되는 가장 높은 녹화 해상도를 요청하고, 요청한 해상도가 지원되지 않으면 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
는 시스템에 가장 적합한 형식을 선택합니다. 가장 일반적인 동영상 코덱은 컨테이너 형식 MPEG-4를 사용하는 H.264 AVC입니다.
녹화 구성 및 만들기
애플리케이션은 Recorder
에서 동영상 및 오디오 캡처를 실행하는 녹화 객체를 만들 수 있습니다. 애플리케이션은 다음을 실행하여 녹화 파일을 만듭니다.
prepareRecording()
으로OutputOptions
를 구성합니다.- (선택사항) 오디오 녹음을 사용 설정합니다.
start()
를 사용하여VideoRecordEvent
리스너를 등록하고 동영상 캡처를 시작합니다.
start()
함수를 호출하면 Recorder
가 Recording
객체를 반환합니다.
애플리케이션은 이 Recording
객체를 사용하여 캡처를 마치거나 일시중지 또는 다시 시작 등 다른 작업을 실행할 수 있습니다.
Recorder
는 Recording
객체를 한 번에 하나씩 지원합니다. 이전 Recording
객체에서 Recording.stop()
또는 Recording.close()
를 호출한 후에 새 녹화를 시작할 수 있습니다.
이러한 단계에 관해 더 자세히 살펴보겠습니다. 먼저 애플리케이션은 Recorder.prepareRecording()
으로 Recorder의 OutputOptions
를 구성합니다.
Recorder
는 다음 유형의 OutputOptions
를 지원합니다.
FileDescriptorOutputOptions
-FileDescriptor
에 캡처FileOutputOptions
-File
에 캡처MediaStoreOutputOptions
-MediaStore
에 캡처
모든 OutputOptions
유형을 사용하면 setFileSizeLimit()
으로 최대 파일 크기를 설정할 수 있습니다. 다른 옵션은 개별 출력 유형에 따라 다릅니다(예: FileDescriptorOutputOptions
의 경우 ParcelFileDescriptor
).
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입니다. 카메라 미리보기와 일치하려면 MIROR_MODE_ON_FRONT_ONLY를 사용하는 것이 좋습니다. 즉, 미러링이 후면 카메라에는 사용 설정되지 않지만 전면 카메라에는 사용 설정됩니다. MirrorMode에 관한 자세한 내용은 MirrorMode constants
를 참고하세요.
다음 코드 스니펫은 MIRROR_MODE_ON_FRONT_ONLY
를 사용하여 VideoCapture.Builder.setMirrorMode()
를 호출하는 방법을 보여줍니다. 자세한 내용은 setMirrorMode()
를 참고하세요.
Kotlin
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Java
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
을 종료할 수 있습니다.
PendingRecording.start()
에 EventListener
를 등록했다면 Recording
은 VideoRecordEvent
를 사용하여 통신합니다.
VideoRecordEvent.EVENT_TYPE_STATUS
는 현재 파일 크기 및 녹화된 기간과 같은 통계를 기록하는 데 사용됩니다.VideoRecordEvent.EVENT_TYPE_FINALIZE
는 결과를 기록하는 데 사용되며 관련 오류와 함께 최종 파일의 URI와 같은 정보를 포함합니다.
앱에서 녹화 세션이 성공했음을 나타내는 EVENT_TYPE_FINALIZE
를 수신하면 OutputOptions
에 지정된 위치에서 캡처된 동영상에 액세스할 수 있습니다.
추가 리소스
CameraX에 관해 자세히 알아보려면 다음 추가 리소스를 참고하세요.