제품 소식

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

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

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

동영상 녹화의 경우 이제 사용자가 멋진 슬로우 모션 또는 높은 프레임 속도 동영상을 손쉽게 촬영할 수 있습니다. 무엇보다 새로운 기능 그룹 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에서는 기능 호환성을 추측할 필요가 없는 기능 그룹 API가 도입되었습니다. 이제 Android 15의 기능 조합 쿼리 API를 기반으로 안정적인 카메라 세션을 보장하면서 여러 기능을 함께 사용 설정할 수 있습니다. 현재 기능 그룹은 HDR (HLG), 60fps, 미리보기 안정화, 울트라 HDR을 지원합니다. 예를 들어 Pixel 10 및 갤럭시 S25 시리즈에서 HDR, 60fps, 미리보기 손떨림 보정을 동시에 사용 설정할 수 있습니다. 향후 개선사항에는 4K 녹화 및 초광각 줌이 포함될 예정입니다. 

기능 그룹 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. 60FPS
  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
 }
}

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

더 많은 동영상 자동 개선 기능

  • 동시 카메라 개선사항: 이제 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 버전으로 안정화되었음을 알려드립니다. 이 출시에는 moveableContentOf, Pager과 같은 Compose 기능과 함께 CameraXViewfinder 사용과 관련된 중요한 버그 수정사항이 포함되어 있으며 미리보기 스트레칭 문제도 해결되었습니다. 향후 출시에서 camera-compose에 더 많은 기능이 추가될 예정입니다.

ImageAnalysis 및 CameraControl 개선사항

  • 손전등 강도 조정: 새로운 API를 사용하여 기기의 손전등을 세밀하게 제어할 수 있습니다. CameraInfo.getMaxTorchStrengthLevel()을 사용하여 지원되는 최대 강도를 쿼리한 다음 CameraControl.setTorchStrengthLevel()을 사용하여 원하는 수준을 설정할 수 있습니다.
  • ImageAnalysis의 NV21 지원: 이제 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 개발자 토론 그룹에 참여하거나 버그 신고를 제출하세요.

작성자:

계속 읽기