CameraX 동영상 캡처 아키텍처

일반적으로 캡처 시스템은 동영상 및 오디오 스트림을 녹화하여 압축한 후 두 스트림을 다중화하고 결과로 생성된 스트림을 디스크에 씁니다.

동영상 및 오디오 캡처 시스템의 개념 다이어그램
그림 1. 동영상 및 오디오 캡처 시스템의 개념 다이어그램

CameraX에서 동영상 캡처 솔루션은 VideoCapture 사용 사례입니다.

CameraX가 동영상 캡처 사용 사례를 처리하는 방법을 보여주는 개념 다이어그램
그림 2. CameraX가 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은 이러한 객체 간의 관계를 보여줍니다.

동영상 캡처 사용 사례에서 발생하는 상호작용을 보여주는 다이어그램
그림 3. VideoCapture 사용 사례에서 발생하는 상호작용을 보여주는 다이어그램

범례:

  1. QualitySelector로 Recorder를 만듭니다.
  2. OutputOptions 중 하나로 Recorder를 구성합니다.
  3. 필요한 경우 withAudioEnabled()로 오디오를 사용 설정합니다.
  4. VideoRecordEvent 리스너로 start()를 호출하여 녹화를 시작합니다.
  5. Recording에서 pause()/resume()/stop()을 사용하여 녹화를 제어합니다.
  6. 이벤트 리스너 내에서 VideoRecordEvents에 응답합니다.

자세한 API 목록은 소스 코드 내 current.txt에 있습니다.

VideoCapture API 사용

CameraX VideoCapture 사용 사례를 앱에 통합하려면 다음을 따르세요.

  1. VideoCapture를 바인딩합니다.
  2. 녹화를 준비하고 구성합니다.
  3. 런타임 녹화를 시작하고 제어합니다.

다음 섹션에서는 엔드 투 엔드 녹화 세션을 가져오기 위해 각 단계에서 할 수 있는 작업을 설명합니다.

VideoCapture 바인딩

VideoCapture 사용 사례를 바인딩하려면 다음을 따르세요.

  1. Recorder 객체를 만듭니다.
  2. VideoCapture 객체를 만듭니다.
  3. Lifecycle에 바인딩합니다.

CameraX VideoCapture API는 빌더 디자인 패턴을 따릅니다. 애플리케이션은 Recorder.Builder를 사용하여 Recorder를 만듭니다. QualitySelector 객체를 통해 Recorder의 동영상 해상도를 구성할 수도 있습니다.

CameraX Recorder는 다음과 같은 사전 정의된 동영상 해상도 Qualities를 지원합니다.

  • Quality.UHD - 4K Ultra HD 동영상 크기(2160p)
  • Quality.QHD: CameraX 1.7.0-alpha02에 도입된 QHD 동영상 크기 (1,440p)
  • 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.QHD, 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.QHD, 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.QHD -> "QHD"
            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에서 동영상 및 오디오 캡처를 실행하는 녹화 객체를 만들 수 있습니다. 애플리케이션은 다음을 실행하여 녹화 파일을 만듭니다.

  1. prepareRecording()으로 OutputOptions를 구성합니다.
  2. (선택사항) 오디오 녹음을 사용 설정합니다.
  3. start()를 사용하여 VideoRecordEvent 리스너를 등록하고 동영상 캡처를 시작합니다.

start() 함수를 호출하면 Recorder가 Recording 객체를 반환합니다. 애플리케이션은 이 Recording 객체를 사용하여 캡처를 마치거나 일시중지 또는 다시 시작 등 다른 작업을 실행할 수 있습니다.

Recorder는 Recording 객체를 한 번에 하나씩 지원합니다. 이전 Recording 객체에서 Recording.stop() 또는 Recording.close()를 호출한 후에 새 녹화를 시작할 수 있습니다.

이러한 단계에 관해 더 자세히 살펴보겠습니다. 먼저 애플리케이션은 Recorder.prepareRecording()으로 Recorder의 OutputOptions를 구성합니다. Recorder는 다음 유형의 OutputOptions를 지원합니다.

모든 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);

자바

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);

다이내믹 레인지 (HDR 동영상)

CameraX는 DynamicRange를 사용하여 HLG10, HDR10, HDR10+, Dolby Vision과 같은 10비트 HDR (High Dynamic Range) 동영상 녹화를 지원합니다.

HDR 동영상 녹화를 사용하려면 다음 단계를 완료하세요.

  1. VideoCapabilities.getSupportedDynamicRanges()를 사용하여 카메라의 지원되는 동적 범위를 쿼리합니다.
  2. 선택사항: 커스텀 QualitySelector를 구성하는 경우 getSupportedQualities(DynamicRange)를 사용하여 해당 동적 범위에 지원되는 품질을 확인합니다.
  3. setDynamicRange()를 사용하여 VideoCapture.Builder를 구성합니다.

다음 예에서는 카메라가 지원하는 경우 HLG 10비트 HDR 녹화를 사용 설정합니다.

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val supportedHdrRanges = videoCapabilities.supportedDynamicRanges
    .filter { it != DynamicRange.SDR }

val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.Builder(recorder)
    .apply {
        if (supportedHdrRanges.contains(DynamicRange.HLG_10_BIT)) {
            setDynamicRange(DynamicRange.HLG_10_BIT)
        }
    }
    .build()

자바

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
Set<DynamicRange> supportedRanges = videoCapabilities.getSupportedDynamicRanges();

Recorder recorder = new Recorder.Builder().build();
VideoCapture.Builder<Recorder> builder = new VideoCapture.Builder<>(recorder);
if (supportedRanges.contains(DynamicRange.HLG_10_BIT)) {
    builder.setDynamicRange(DynamicRange.HLG_10_BIT);
}
VideoCapture<Recorder> videoCapture = builder.build();

동영상 흔들림 보정

CameraX는 동영상 녹화 중 핸드헬드 흔들림과 지터를 줄이기 위해 동영상 안정화를 지원합니다.

동영상 안정화를 사용 설정하려면 다음 단계를 완료하세요.

  1. VideoCapabilities.isStabilizationSupported()를 사용하여 카메라 기기가 흔들림 보정을 지원하는지 확인합니다.
  2. setVideoStabilizationEnabled(true)를 사용하여 VideoCapture.Builder에서 사용 설정합니다.

다음 예에서는 카메라가 지원하는 경우 흔들림 보정을 사용 설정합니다.

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val videoCapture = VideoCapture.Builder(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported)
    .build()

Java

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported())
    .build();

활성 상태의 녹화 제어하기

다음 메서드를 사용하여 진행 중인 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에 지정된 위치에서 캡처된 동영상에 액세스할 수 있습니다.

실시간 오디오 진폭 및 상태

녹음 중에 VideoRecordEvent.Status 이벤트는 AudioStats를 통해 실시간 오디오 통계를 제공합니다.

  • AudioStats.getAudioAmplitude()는 0.0에서 1.0 사이의 현재 오디오 피크 진폭을 반환합니다. 이 값을 사용하여 UI 미터 또는 오디오 파형 시각화 도구를 구동할 수 있습니다.
  • AudioStats.getAudioState()는 오디오 스트림의 현재 상태를 나타냅니다(예: AUDIO_STATE_ACTIVE, AUDIO_STATE_MUTED, AUDIO_STATE_SOURCE_SILENCED).

다음 예에서는 상태 이벤트에서 오디오 진폭을 읽습니다.

Kotlin

when (event) {
    is VideoRecordEvent.Status -> {
        val audioStats = event.recordingStats.audioStats
        if (audioStats.hasAudio()) {
            val amplitude = audioStats.audioAmplitude
            updateAudioWaveform(amplitude)
        }
    }
    // ...
}

자바

if (event instanceof VideoRecordEvent.Status) {
    VideoRecordEvent.Status status = (VideoRecordEvent.Status) event;
    AudioStats audioStats = status.getRecordingStats().getAudioStats();
    if (audioStats.hasAudio()) {
        double amplitude = audioStats.getAudioAmplitude();
        updateAudioWaveform(amplitude);
    }
}

고속 및 슬로 모션 동영상

CameraX는 120, 240 또는 480fps와 같은 고속 동영상 녹화를 지원하므로 다음과 같은 두 가지 사용 사례가 가능합니다.

  • 높은 프레임 속도 동영상 (플레이어에서 처리하는 슬로 모션): CameraX는 높은 프레임 속도 (예: 120fps)로 프레임을 캡처하고 저장합니다. 동영상 플레이어는 재생 속도를 제어하여 사용자가 일반 속도와 슬로우 모션 간에 전환하거나 프레임별 분석을 수행할 수 있도록 합니다.
  • 바로 재생할 수 있는 슬로우 모션 동영상: CameraX는 고속 스트림을 처리하고 조정된 프레임 타임스탬프가 있는 표준 30fps 동영상 파일을 출력합니다. 슬로우 모션 효과는 '베이크인'되므로 동영상은 특별한 동영상 플레이어 지원 없이도 표준 플레이어에서 자동으로 슬로우 모션으로 재생됩니다. 예를 들어 120fps로 캡처한 동영상을 30fps로 재생하면 1/4배속 슬로 모션 동영상이 생성됩니다.

고속 기능 확인

고속 동영상 캡처에는 하드웨어 지원과 기기 제조업체의 해당 CamcorderProfile 정의(예: CamcorderProfile.QUALITY_HIGH_SPEED_1080P 또는 QUALITY_HIGH_SPEED_720P)가 필요합니다.

고속 녹화를 구성하기 전에 Recorder.getHighSpeedVideoCapabilities(CameraInfo)를 사용하여 고속 기능을 쿼리합니다.

Kotlin

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return
}
val supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR)

자바

VideoCapabilities highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo);
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return;
}
List<Quality> supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR);

HighSpeedVideoSessionConfig 구성

고속 캡처를 사용하려면 HighSpeedVideoSessionConfig에서 VideoCapture 및 Preview 사용 사례를 결합합니다. 세션을 구성하려면 다음 단계를 완료하세요.

  1. VideoCapture 사용 사례와 Preview 사용 사례를 만듭니다.
  2. VideoCapture 사용 사례로 HighSpeedVideoSessionConfig.Builder를 초기화하고 Preview를 연결합니다.
  3. CameraInfo.getSupportedFrameRateRanges(SessionConfig)를 사용하여 지원되는 프레임 속도 범위를 쿼리하고 선택한 범위를 설정합니다.
  4. 고프레임 속도 동영상 또는 바로 재생 가능한 슬로우 모션 동영상 중에서 선택합니다.
    • 높은 프레임 속도 동영상을 만들려면 setSlowMotionEnabled(false)(기본값)를 그대로 둡니다.
    • 바로 재생할 수 있는 슬로 모션 동영상을 만들려면 setSlowMotionEnabled(true)를 호출합니다.
  5. cameraProvider.bindToLifecycle()를 사용하여 세션 구성을 바인딩합니다.

다음 예에서는 재생 준비가 완료된 슬로우 모션 세션을 구성하고 결합합니다.

Kotlin

val preview = Preview.Builder().build()
val recorder = Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.first()))
    .build()
val videoCapture = VideoCapture.withOutput(recorder)

// Build HighSpeedVideoSessionConfig
val sessionConfigBuilder = HighSpeedVideoSessionConfig.Builder(videoCapture)
    .setPreview(preview)
    // Enable automatic slow-motion playback at 30 fps
    .setSlowMotionEnabled(true)

// Query and set a supported high-speed frame rate range (such as 120 or 240 fps).
// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
val supportedFpsRanges = cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build())
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.first())

val sessionConfig = sessionConfigBuilder.build()

// Bind session config to lifecycle
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

자바

Preview preview = new Preview.Builder().build();
Recorder recorder = new Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.get(0)))
    .build();
VideoCapture<Recorder> videoCapture = VideoCapture.withOutput(recorder);

HighSpeedVideoSessionConfig.Builder sessionConfigBuilder =
    new HighSpeedVideoSessionConfig.Builder(videoCapture)
        .setPreview(preview)
        .setSlowMotionEnabled(true);

// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
Set<Range<Integer>> supportedFpsRanges =
    cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build());
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.iterator().next());

HighSpeedVideoSessionConfig sessionConfig = sessionConfigBuilder.build();

cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
);

CameraX 1.7.0-alpha02에 도입된 Kotlin DSL을 사용하여 고속 세션을 간결하게 구성할 수도 있습니다.

val sessionConfig = highSpeedVideoSessionConfig(videoCapture) {
    this.preview = preview
    isSlowMotionEnabled = true
    frameRateRange = supportedFpsRanges.first()
}
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

고속 또는 슬로 모션 동영상 녹화하기

HighSpeedVideoSessionConfig를 바인딩한 후 표준 동영상 녹화와 동일한 방식으로 VideoCapture를 사용하여 녹화를 시작합니다.

Kotlin

val recording = videoCapture.output
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context)) { event ->
        when (event) {
            is VideoRecordEvent.Start -> Log.d(TAG, "Recording started")
            is VideoRecordEvent.Finalize -> {
                if (!event.hasError()) {
                    Log.d(TAG, "Video saved: ${event.outputResults.outputUri}")
                }
            }
        }
    }

Java

Recording recording = videoCapture.getOutput()
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context), event -> {
        if (event instanceof VideoRecordEvent.Start) {
            Log.d(TAG, "Recording started");
        } else if (event instanceof VideoRecordEvent.Finalize) {
            VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) event;
            if (!finalize.hasError()) {
                Log.d(TAG, "Video saved: " + finalize.getOutputResults().getOutputUri());
            }
        }
    });

추가 리소스

CameraX에 관해 자세히 알아보려면 다음 추가 리소스를 참고하세요.