제품 소식

CameraX 1.5 소개: 강력한 동영상 녹화 및 전문가 수준의 이미지 캡처

전문 길이: 7분
Scott Nien
소프트웨어 엔지니어

CameraX팀은 버전 1.5 출시를 발표하게 되어 기쁩니다. 이번 최신 업데이트는 카메라 세션을 이전보다 더 쉽게 구성할 수 있도록 하면서 전문가 수준의 기능을 손쉽게 사용할 수 있도록 하는 데 중점을 둡니다.

동영상 녹화의 경우 이제 사용자가 멋진 슬로 모션 또는 고속 프레임 속도 동영상을 손쉽게 캡처할 수 있습니다. 더 중요한 점은 새로운 Feature Group API를 사용하면 10비트 HDR 및 60FPS와 같은 복잡한 조합을 자신 있게 사용 설정하여 지원되는 기기에서 일관된 결과를 얻을 수 있다는 것입니다.

이미지 캡처 측면에서는 처리되지 않은 압축되지 않은 DNG (RAW) 파일 캡처를 지원하여 최대한의 유연성을 얻을 수 있습니다. 또한 이제 강력한 카메라 확장 프로그램을 사용하는 경우에도 울트라 HDR 출력을 활용할 수 있습니다.

이러한 기능을 뒷받침하는 것은 카메라 설정 및 재구성을 간소화하는 새로운 SessionConfig API 입니다. 이제 이러한 흥미로운 새 기능의 세부정보를 살펴보겠습니다.

강력한 동영상 녹화: 고속 및 기능 조합

CameraX 1.5는 동영상 기능을 크게 확장하여 더욱 창의적이고 강력한 녹화 환경을 지원합니다.

슬로 모션 및 고속 프레임 속도 동영상

가장 기대되는 기능 중 하나인 슬로 모션 동영상을 이제 사용할 수 있습니다. 이제 고속 동영상 (예: 120 또는 240fps)을 캡처하여 극적인 슬로 모션 동영상으로 직접 인코딩할 수 있습니다. 또는 동일한 고속 프레임 속도로 녹화하여 매우 부드러운 동영상을 제작할 수 있습니다.

VideoCapture API에 익숙하다면 이를 구현하는 것은 간단합니다.

1. 고속 지원 확인:Recorder.getHighSpeedVideoCapabilities() 메서드를 사용하여 기기가 이 기능을 지원하는지 쿼리합니다.

  val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)

if (highSpeedCapabilities == null) {
    // This camera device does not support high-speed video.
    return
}

2. 사용 사례 구성 및 결합: 지원되는 동영상 품질 정보가 포함된 반환된 videoCapabilities를 사용하여 HighSpeedVideoSessionConfig를 빌드합니다. 그런 다음 cameraInfo.getSupportedFrameRateRanges()를 통해 지원되는 프레임 속도 범위를 쿼리하고 원하는 범위를 설정해야 합니다. 슬로 모션 동영상을 녹화하려면 setSlowMotionEnabled(true)를 호출합니다. 그렇지 않으면 고속 프레임 속도 동영상이 녹화됩니다. 마지막 단계는 일반 Recorder.prepareRecording().start()를 사용하여 동영상 녹화를 시작하는 것입니다.

  val preview = Preview.Builder().build()
val quality = highSpeedCapabilities
        .getSupportedQualities(DynamicRange.SDR).first()

val recorder = Recorder.Builder()
      .setQualitySelector(QualitySelector.from(quality)))
      .build()

val videoCapture = VideoCapture.withOutput(recorder)

val frameRateRange = cameraInfo.getSupportedFrameRateRanges(      
       HighSpeedVideoSessionConfig(videoCapture, preview)
).first()

val sessionConfig = HighSpeedVideoSessionConfig(
    videoCapture, 
    preview, 
    frameRateRange = frameRateRange, 
    // Set true for slow-motion playback, or false for high-frame-rate
    isSlowMotionEnabled = true
)

cameraProvider.bindToLifecycle(
     lifecycleOwner, cameraSelector, sessionConfig)

// Start recording slow motion videos. 
val recording = recorder.prepareRecording(context, outputOption)
      .start(executor, {})

호환성 및 제한사항

고속 녹화에는 특정 CameraConstrainedHighSpeedCaptureSessionCamcorderProfile 지원이 필요합니다. 항상 기능 검사를 실행하고 지원되는 기기에서만 고속 녹화를 사용 설정하여 사용자 환경을 저해하지 않도록 하세요. 현재 이 기능은 거의 모든 Pixel 기기의 후면 카메라와 다른 제조업체의 일부 모델에서 지원됩니다.

자세한 내용은 블로그 게시물을 참고하세요.

자신 있게 기능 결합: Feature Group API

CameraX 1.5에는 기능 호환성을 추측할 필요가 없는 Feature Group API가 도입되었습니다. 이제 Android 15의 기능 조합 쿼리 API를 기반으로 여러 기능을 함께 사용 설정하여 안정적인 카메라 세션을 보장할 수 있습니다. 현재 Feature Group은 HDR (HLG), 60fps, 미리보기 손떨림 보정, 울트라 HDR 을 지원합니다. 예를 들어 Pixel 10 및 갤럭시 S25 시리즈에서 HDR, 60fps, 미리보기 손떨림 보정을 동시에 사용 설정할 수 있습니다. 향후 4K 녹화 및 초광각 줌을 포함하도록 개선할 계획입니다. 

Feature Group API는 두 가지 필수 사용 사례를 지원합니다.

사용 사례 1: 최상의 품질 우선순위 지정

가능한 최상의 기능 조합을 사용하여 캡처하려면 우선순위가 지정된 목록을 제공하면 됩니다. CameraX는 기기에서 완전히 지원하는 첫 번째 조합을 선택하여 순서대로 사용 설정하려고 시도합니다.

  val sessionConfig = SessionConfig(
    useCases = listOf(preview, videoCapture),
    preferredFeatureGroup = listOf(
        GroupableFeature.HDR_HLG10,
        GroupableFeature.FPS_60,
        GroupableFeature.PREVIEW_STABILIZATION
    )
).apply {
    // (Optional) Get a callback with the enabled features to update your UI.
    setFeatureSelectionListener { selectedFeatures ->
        updateUiIndicators(selectedFeatures)
    }
}
processCameraProvider.bindToLifecycle(activity, cameraSelector, sessionConfig)

이 예에서 CameraX는 다음과 같은 순서로 기능을 사용 설정하려고 시도합니다.

  1. HDR + 60FPS + 미리보기 손떨림 보정
  2. HDR + 60 FPS
  3. HDR + 미리보기 손떨림 보정
  4. HDR
  5. 60FPS + 미리보기 손떨림 보정
  6. 60 FPS
  7. 미리보기 손떨림 보정
  8. 없음

사용 사례 2: 사용자 대상 설정 UI 빌드

이제 앱의 설정 UI에서 지원되는 기능 조합을 정확하게 반영하여 아래 그림과 같이 지원되지 않는 옵션의 전환 버튼을 사용 중지할 수 있습니다. 

unsupported-features-disabled.gif

전환 버튼을 회색으로 표시할지 결정하려면 다음 코드를 사용하여 기능 조합 지원을 확인하세요. 먼저 각 개별 기능의 상태를 쿼리합니다. 기능이 사용 설정되면 호환성 제약 조건으로 인해 전환 버튼을 회색으로 표시해야 하는지 확인하기 위해 사용 설정된 기능으로 나머지 기능을 다시 쿼리합니다.

  fun disableFeatureIfNotSuported(
   enabledFeatures: Set<GroupableFeature>,     
   featureToCheck:GroupableFeature
) {
 val sessionConfig = SessionConfig(
     useCases = useCases,
     requiredFeatureGroup = enabledFeatures + featureToCheck
 )
 val isSupported = cameraInfo.isFeatureGroupSupported(sessionConfig)

 if (!isSupported) {
     // disable the toggle for featureToCheck
 }
}

자세한 내용은 Feature Group 블로그 게시물 을 참고하세요. 

추가 동영상 자동 개선 기능

  • 동시 카메라 개선사항: CameraX 1.5.1을 사용하면 이제 비구성 모드 에서 각 SingleCameraConfig에 대해 미리보기 + ImageCapture + VideoCapture 사용 사례를 동시에 결합할 수 있습니다. 또한 구성 모드 (CompositionSettings가 있는 동일한 사용 사례)에서 이제 최종 구성 결과에 적용되는 CameraEffect를 설정할 수 있습니다.
  • 동적 음소거: 이제 PendingRecording.withAudioEnabled(boolean initialMuted)를 사용하여 음소거된 상태로 녹화를 시작하고 Recording.mute(boolean muted)를 사용하여 사용자가 나중에 음소거를 해제하도록 허용할 수 있습니다.
  • 저장용량 부족 처리 개선: 이제 CameraX가 VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE 오류를 안정적으로 디스패치하므로 앱에서 저장용량이 부족한 상황을 정상적으로 처리하고 사용자에게 알릴 수 있습니다.
  • 저조도 부스트: 지원되는 기기 (예: Pixel 10 시리즈)에서는 CameraControl.enableLowLightBoostAsync를 사용 설정하여 어두운 환경에서 미리보기 및 동영상 스트림을 자동으로 밝게 할 수 있습니다.

전문가 수준의 이미지 캡처

CameraX 1.5는 최대한의 품질과 유연성을 요구하는 개발자를 위해 ImageCapture를 크게 업그레이드합니다.

DNG (RAW) 캡처로 창의적인 제어 기능 활용

후처리를 완전히 제어하기 위해 CameraX는 이제 DNG (RAW) 캡처를 지원합니다. 이렇게 하면 카메라 센서에서 직접 처리되지 않은 압축되지 않은 이미지 데이터에 액세스하여 전문가 수준의 편집 및 색상 그레이딩을 할 수 있습니다. API는 DNG 파일만 캡처하거나 JPEG 및 DNG 출력을 동시에 캡처하는 것을 지원합니다. JPEG 및 DNG 파일을 동시에 캡처하는 방법은 아래 샘플 코드를 참고하세요.

  val capabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
val imageCapture = ImageCapture.Builder().apply {
    if (capabilities.supportedOutputFormats
             .contains(OUTPUT_FORMAT_RAW_JPEG)) {
        // Capture both RAW and JPEG formats.
        setOutputFormat(OUTPUT_FORMAT_RAW_JPEG)
    }
}.build()
// ... bind imageCapture to lifecycle ...


// Provide separate output options for each format.
val outputOptionRaw = /* ... configure for image/x-adobe-dng ... */
val outputOptionJpeg = /* ... configure for image/jpeg ... */
imageCapture.takePicture(
    outputOptionRaw,
    outputOptionJpeg,
    executor,
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(results: OutputFileResults) {
            // This callback is invoked twice: once for the RAW file
            // and once for the JPEG file.
        }

        override fun onError(exception: ImageCaptureException) {}
    }
)

카메라 확장 프로그램용 울트라 HDR

야간 모드와 같은 카메라 확장 프로그램의 멋진 계산 사진과 울트라 HDR의 뛰어난 색상 및 다이내믹 레인지라는 두 가지 장점을 모두 활용하세요. 이 기능은 이제 Pixel 9/10 시리즈 및 삼성 S24/S25 시리즈와 같은 많은 최신 프리미엄 Android 휴대전화에서 지원됩니다.

  // Support UltraHDR when Extension is enabled. 

val extensionsEnabledCameraSelector = extensionsManager
     .getExtensionEnabledCameraSelector(
        CameraSelector.DEFAULT_BACK_CAMERA, ExtensionMode.NIGHT)

val imageCapabilities = ImageCapture.getImageCaptureCapabilities(
               cameraProvider.getCameraInfo(extensionsEnabledCameraSelector)

val imageCapture = ImageCapture.Builder()
     .apply {
       if (imageCapabilities.supportedOutputFormats
                .contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR) {
           setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)

       }

     }.build()

핵심 API 및 사용성 개선사항

새로운 구성 방법: SessionConfig

위의 예에서 볼 수 있듯이 SessionConfig는 CameraX 1.5의 새로운 개념입니다. 구성의 중앙 집중화 및 API 간소화를 다음과 같은 두 가지 주요 방법으로 지원합니다.

  1. 더 이상 수동 unbind() 호출이 필요하지 않음: CameraX API는 수명 주기를 인식합니다. 활동 또는 기타 LifecycleOwner가 소멸되면 사용 사례를 암시적으로 '결합 해제'합니다. 하지만 사용 사례를 업데이트하거나 카메라를 전환하려면 다시 결합하기 전에 unbind() 또는 unbindAll()을 호출해야 합니다. 이제 CameraX 1.5를 사용하면 새 SessionConfig를 결합할 때 CameraX가 세션을 원활하게 업데이트하므로 결합 해제 호출이 필요하지 않습니다.
  2. 결정적 프레임 속도 제어:SessionConfig API는 프레임 속도를 관리하는 결정적 방법을 도입합니다. 힌트일 뿐이었던 이전 setTargetFrameRate와 달리 이 새 메서드는 구성이 완료되면 지정된 프레임 속도 범위가 적용되도록 보장 합니다. 정확성을 보장하려면 CameraInfo.getSupportedFrameRateRanges(SessionConfig)를 사용하여 지원되는 프레임 속도를 쿼리해야 합니다. 전체 SessionConfig를 전달하면 CameraX는 스트림 구성을 기반으로 지원되는 범위를 정확하게 결정할 수 있습니다.

Camera-Compose가 이제 안정화됨

Jetpack Compose를 얼마나 즐겨 사용하는지 잘 알고 있으며 camera-compose 라이브러리가 이제 1.5.1 버전에서 안정화되었음을 발표하게 되어 기쁩니다! 이 출시에는 CameraXViewfinder 사용과 관련된 중요한 버그 수정과 moveableContentOfPager와 같은 Compose 기능, 미리보기 스트레칭 문제 해결이 포함되어 있습니다. 향후 출시에서 camera-compose에 더 많은 기능을 추가할 예정입니다.

ImageAnalysis 및 CameraControl 개선사항

  • 토치 강도 조정: 새 API를 사용하여 기기의 토치를 세밀하게 제어할 수 있습니다. CameraInfo.getMaxTorchStrengthLevel()을 사용하여 지원되는 최대 강도를 쿼리한 다음 CameraControl.setTorchStrengthLevel()을 사용하여 원하는 수준을 설정할 수 있습니다.
  • ImageAnalysisNV21 지원: 이제 ImageAnalysis에서 직접 NV21 이미지 형식을 요청하여 다른 라이브러리 및 API와의 통합을 간소화할 수 있습니다. 이는 ImageAnalysis.Builder.setOutputImageFormat(OUTPUT_IMAGE_FORMAT_NV21)을 호출하여 사용 설정됩니다.

지금 시작하기

지금 종속 항목을 CameraX 1.5로 업데이트 하고 흥미로운 새 기능을 살펴보세요. 앞으로 제작하실 멋진 프로토타입을 기대하겠습니다.

CameraX 1.5를 사용하려면 libs.versions.toml에 다음 종속 항목을 추가하세요. (많은 중요한 버그 수정과 동시 카메라 개선사항이 포함된 1.5.1을 사용하는 것이 좋습니다.)

  [versions]

camerax = "1.5.1"


[libraries]

..

androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "camerax" }

androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "camerax" }

androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }

androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }

androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }

androidx-camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "camerax" }

그런 다음 이러한 종속 항목을 모듈 build.gradle.kts에 추가합니다.

  dependencies {

  ..

  implementation(libs.androidx.camera.core)
  implementation(libs.androidx.camera.lifecycle)

  implementation(libs.androidx.camera.camera2)

  implementation(libs.androidx.camera.view) // for PreviewView 
  implementation(libs.androidx.camera.compose) // for compose UI

  implementation(libs.androidx.camera.extensions) // For Extensions 

}

궁금한 점이 있거나 CameraX팀과 소통하고 싶으신가요? CameraX 개발자 토론방에 참여하거나 버그 신고 양식을 작성하세요.

작성자:

계속 읽기