제품 소식

단일 기능 그 이상: CameraX 1.5로 기능 조합 보장

6분 읽기
2025년 10월 15일
Tahsin Masrur
소프트웨어 엔지니어

최신 카메라 앱은 강력하고 중복되는 기능으로 정의됩니다. 사용자는 멋진 HDR로 동영상을 녹화하고, 60FPS로 부드러운 동작을 캡처하고, 미리보기 손떨림 보정으로 부드러운 영상을 얻을 수 있기를 기대합니다. 종종 이 모든 작업을 동시에 수행할 수 있기를 기대합니다.

개발자로서 우리는 현실이 더 복잡하다는 것을 알고 있습니다. 특정 기기가 실제로 특정 조합을 지원하는지 어떻게 보장할 수 있을까요? 지금까지 여러 기능을 사용 설정하는 것은 종종 도박과 같았습니다. 개별 기능 지원을 확인할 수 있지만 이를 결합하면 정의되지 않은 동작이 발생하거나 더 나쁜 경우 카메라 세션이 실패할 수 있습니다. 이러한 불확실성으로 인해 개발자는 보수적으로 대처하게 되며, 이로 인해 성능이 우수한 기기의 사용자가 최상의 환경에 액세스할 수 없게 됩니다.

예를 들어 HDR과 60FPS 동영상을 동시에 안정적으로 지원하는 프리미엄 기기는 거의 없습니다. 따라서 대부분의 앱은 대부분의 휴대전화에서 좋지 않은 사용자 환경을 방지하기 위해 두 가지를 동시에 사용 설정하지 않습니다.

이 문제를 해결하기 위해 Google에서는 이러한 추측을 없애도록 설계된 새로운 API인 CameraX의 기능 그룹을 도입합니다. 이제 카메라를 구성하기 전에 특정 기능 조합이 지원되는지 쿼리하거나 CameraX에 우선순위를 알려주고 CameraX에서 가장 잘 지원되는 조합을 사용 설정하도록 할 수 있습니다.

CameraX를 처음 사용하는 경우

새로운 기능 그룹 API를 살펴보기 전에 CameraX가 무엇인지 간단히 살펴보겠습니다. CameraX는 카메라 앱 개발을 돕는 Jetpack 지원 라이브러리입니다. 대부분의 Android 기기에서 작동하는 일관성 있고 사용하기 쉬운 API 노출 영역을 제공하며 Android 6.0 (API 수준 23)까지 호환됩니다. CameraX를 처음 사용하는 경우 공식 문서를 확인하고 Codelab을 사용해 보는 것이 좋습니다.

기능 그룹 API로 빌드할 수 있는 항목

더 이상 기능 조합에 의존할 필요가 없으며, 조합을 지원할 수 없는 기기에서 오류를 우아하게 방지하면서 성능이 우수한 하드웨어 (예: Pixel 10 Pro)에서 HDR과 60FPS 동영상을 동시에 사용하는 것과 같은 최상의 카메라 환경을 자신 있게 제공할 수 있습니다.

unnamed.png

HDR과 60FPS를 동시에 사용 설정하는 Pixel 10 Pro

unnamed (1).png

HDR과 60FPS를 동시에 실행할 수 없는 이전 기기에서는 60FPS 옵션이 사용 중지된 상태에서 HDR만 사용 설정됩니다.

기능 그룹 API를 사용하면 다음 작업을 할 수 있습니다.

  • 더 스마트하고 동적인 UI 빌드: 실시간 하드웨어 지원을 기반으로 UI에서 설정을 지능적으로 사용 설정하거나 사용 중지합니다. 예를 들어 사용자가 HDR을 사용 설정하면 해당 기기에서 조합이 지원되지 않는 경우 60FPS 옵션을 즉시 회색으로 표시하고 사용 중지할 수 있습니다. 
unsupported-features-disabled.gif
  • 안정적인 '고품질' 모드 제공: 우선순위가 지정된 원하는 기능 목록으로 카메라를 구성합니다. CameraX는 복잡한 기기별 로직 없이도 최상의 결과를 보장하면서 모든 기기에서 가장 잘 지원되는 조합을 자동으로 찾아 사용 설정합니다.
  • 카메라 세션 실패 방지: 미리 지원을 확인하면 카메라가 지원되지 않는 조합을 구성하려고 시도하지 않도록 하여 일반적인 비정상 종료 원인을 없애고 원활한 사용자 환경을 제공합니다.

작동 방식: 코어 구성요소

새로운 API는 SessionConfigCameraInfo에 대한 주요 추가사항을 중심으로 합니다.

  1. GroupableFeature: 이 API는 HDR_HLG10, FPS_60, PREVIEW_STABILIZATION, IMAGE_ULTRA_HDR과 같은 사전 정의된 그룹화 가능한 기능 집합을 도입합니다. 계산상의 제한으로 인해 이 API가 제공하는 높은 안정성으로 특정 기능 집합만 그룹화할 수 있습니다. Google은 이 목록을 확장하기 위해 적극적으로 노력하고 있으며 향후 출시에서 더 많은 기능을 지원할 예정입니다.
     
  2. 새로운 SessionConfig 매개변수: 카메라 세션을 시작하는 데 사용되는 이 클래스는 이제 두 가지 새로운 매개변수를 허용합니다.
    • requiredFeatureGroup: 구성이 성공하려면 지원되어야 하는 기능에 사용합니다. 'HDR' 스위치 전환과 같이 사용자가 명시적으로 사용 설정하는 기능에 적합합니다. 결정적이고 일관된 환경을 보장하기 위해 요청된 조합이 지원되지 않는 경우 bindToLifecycle 호출은 기능 요청을 자동으로 무시하는 대신 IllegalArgumentException을 발생시킵니다. 이 결과를 미리 쿼리하려면 CameraInfo#isFeatureGroupSupported API (아래 세부정보)를 사용해야 합니다.
    • preferredFeatureGroup: 원하는 기능이지만 선택사항인 기능에 사용합니다. 예를 들어 기본 '고품질' 모드를 구현하려는 경우에 사용합니다. 원하는 기능 목록을 우선순위에 따라 정렬된 제공하면 CameraX는 기기에서 지원하는 가장 높은 우선순위의 조합을 자동으로 사용 설정합니다.
  3. CameraInfo#isFeatureGroupSupported(): 기능 그룹이 지원되는지 명시적으로 확인하는 핵심 쿼리 메서드입니다. 앱 UI에서 지원되는 기능 옵션만 사용자에게 제공하는 데 적합합니다. SessionConfig를 전달하면 조합이 지원되는지 나타내는 불리언이 반환됩니다. 필수 기능이 있는 SessionConfig를 바인딩하려면 먼저 이 API를 사용하여 지원되는지 확인해야 합니다. 

실무에서의 구현

이러한 구성요소를 사용하여 더 나은 카메라 환경을 빌드하는 방법을 살펴보겠습니다.

시나리오 1: '최선의 노력' 고품질 모드

최상의 기능을 기본적으로 사용 설정하려면 우선순위가 지정된 목록을 preferredFeatureGroup에 제공하면 됩니다. 이 예에서는 CameraX에 HDR, 60FPS, 미리보기 손떨림 보정 순으로 우선순위를 지정하도록 지시합니다. CameraX는 가능한 모든 조합을 확인하고 기기에서 지원하는 최상의 조합을 선택하는 복잡성을 처리합니다.

예를 들어 기기가 HDR과 60FPS를 함께 처리할 수 있지만 미리보기 손떨림 보정은 처리할 수 없는 경우 CameraX는 처음 두 가지를 사용 설정하고 세 번째는 삭제합니다. 이렇게 하면 복잡한 기기별 검사를 작성하지 않고도 최상의 환경을 얻을 수 있습니다.

cameraProvider.bindToLifecycle(

    lifecycleOwner,

    cameraSelector,

    SessionConfig(

        useCases = listOf(preview, videoCapture),

        // The order of features in this list determines their priority. 

        // CameraX will enable the best-supported combination based on these

        // priorities: HDR_HLG10 > FPS_60 > Preview Stabilization.  

        preferredFeatureGroup =

           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),

    ).apply {

        // (Optional) Get a callback with the enabled features

        // to update your UI. 

        setFeatureSelectionListener { selectedFeatures ->

            updateUiIndicators(selectedFeatures)

        }

    }

)

이 코드 스니펫의 경우 CameraX는 다음 우선순위 순서로 기능 조합을 사용 설정하려고 시도하며 기기에서 완전히 지원하는 첫 번째 조합을 선택합니다.

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

시나리오 2: 반응형 UI 빌드

사용자 선택에 응답하고 사용자가 지원되지 않는 기능 조합을 선택하지 못하도록 하는 UI를 만들려면 지원을 직접 쿼리하면 됩니다. 아래 함수는 사용자의 현재 선택과 호환되지 않는 기능을 확인하여 상응하는 UI 요소를 사용 중지할 수 있도록 합니다.

/**

 * Returns a list of features that are NOT supported in combination

 * with the currently selected features.

 */

fun getUnsupportedFeatures(

    currentFeatures: Set<GroupableFeature>

): Set<GroupableFeature> {

    val unsupportedFeatures = mutableSetOf<GroupableFeature>()

    val appFeatureOptions = setOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION)


    // Iterate over every available feature option in your app. 

    appFeatureOptions.forEach { featureOption ->

        // Skip features the user has already selected. 

        if (currentFeatures.contains(featureOption)) return@forEach


        // Check if adding this new feature is supported. 

        val isSupported = cameraInfo.isFeatureGroupSupported(

            SessionConfig(

                useCases = useCases,

                // Check the new feature on top of existing ones.

                requiredFeatureGroup = currentFeatures + featureOption

            )

        )


        if (!isSupported) {

            unsupportedFeatures.add(featureOption)

        }

    }


    return unsupportedFeatures

}

그런 다음 이 로직을 ViewModel 또는 UI 컨트롤러에 연결하여 사용자 입력에 반응하고 작동이 보장된 구성으로 카메라를 다시 바인딩할 수 있습니다.

// Invoked when user turns some feature on/off.

fun onFeatureChange(currentFeatures: Set<GroupableFeature>) {

    // Identify features that are unsupported with the current selection.

    val unsupportedFeatures = getUnsupportedFeatures(currentFeatures)



    // Update app UI so that users can't enable them.

    updateDisabledFeatures(unsupportedFeatures)



    // Since the UI now only allows selecting supported feature combinations, 

    // `currentFeatures` is always valid. This allows setting

    // `requiredFeatureGroup` directly, without needing to re-check for

    // support or set a feature selection listener.  

    cameraProvider.bindToLifecycle(

        lifecycleOwner,

        cameraSelector,

        SessionConfig(

            useCases = listOf(preview, videoCapture),

            requiredFeatureGroup = currentFeatures,

        )

    )

}

작동하는 애플리케이션에서 이러한 개념을 확인하려면 내부 테스트 앱을 살펴보세요. 위에서 설명한 "최선의 노력" 및 "반응형 UI" 시나리오를 모두 완전히 구현합니다.

참고: 이는 테스트 애플리케이션이며 공식적으로 지원되는 샘플이 아닙니다. 기능 그룹 API에 대한 훌륭한 참고 자료이지만 프로덕션용으로 개선되지는 않았습니다.

지금 시작하기

기능 그룹 API는 고급 카메라 기능 작업의 모호성을 없애줍니다. 기능 지원을 쿼리하는 결정적인 방법을 제공하므로 자신 있게 더 강력하고 안정적인 카메라 앱을 빌드할 수 있습니다.

이 API는 CameraX 1.5에서 실험용으로 제공되며 1.6 출시에서 완전히 안정화될 예정이며 더 많은 지원과 개선사항이 제공될 예정입니다.

자세한 내용은 공식 문서를 참고하세요. Google은 여러분이 무엇을 만들지 기대하고 있으며 의견을 기다리고 있습니다. 다음 채널을 통해 의견을 공유하고 문제를 신고해 주세요.

작성자:

계속 읽기