Android/Camera

[Android] 카메라 미리보기 - CameraX · PreviewView

O_Gyong 2022. 11. 9.

앱에 카메라 기능을 추가하려는 경우 CameraX와 Camera2를 사용할 수 있다.

CameraX는 Camera2 패키지를 기반으로 만들어진 Jetpack 라이브러리로, API가 Camera2보다 훨씬 단순하고 기기 호환성 문제가 없어서 안드로이드에서 권장하고 있다.

(Camera2는 복잡한 작업을 할 때 사용한다고 한다.)

참고

 

CameraX를 사용하여 카메라 화면을 보기 위해서 PreviewView를 사용해야 한다.

PreviewView는 화면을 유연하게(자르기, 크기 조정, 회전 등) 표시할 수 있는 View이다.


카메라 미리보기 예제

CamreaX와 PrevieView를 사용하여 화면에 미리보기를 띄우려고 한다.

1. gradle에 CameraX 의존성 추가
2. 카메라 권한 Manifest에 등록
3. 카메라 권한 체크
4. CameraProvider 요청
5. Preview 생성 및 PreviewView에 연결

CamreaX 의존성 추가

//CameraX
implementation 'androidx.camera:camera-view:1.1.0'
implementation "androidx.camera:camera-camera2:1.2.0-rc01"
implementation 'androidx.camera:camera-lifecycle:1.1.0'

의존성 추가 이후 implementation "androidx.camera:camera-camera2:1.2.0-rc01" 부분에서 빌드에러가 날 수 있는데,

Sdk 버전을 33으로,  implementation 'androidx.core:core-ktx:1.9.0'  으로 업데이트하면 빌드된다.

 

위 버전으로 시도했을 때 계속 안되면 버전을 아래처럼 맞추면 될 것이다.

implementation 'androidx.core:core-ktx:1.7.0'

//CameraX
implementation 'androidx.camera:camera-view:1.1.0'
implementation "androidx.camera:camera-camera2:1.2.0-alpha03"
implementation 'androidx.camera:camera-lifecycle:1.1.0'

카메라 권한 등록

<uses-permission android:name="android.permission.CAMERA"/>

Manifest에 권한을 등록한다.


카메라 권한 체크

   /*
    * 생략
    */

    override fun onCreate(savedInstanceState: Bundle?) {
       /*
        * 생략
        */

        // 카메라 권한 확인
        if (allPermissionsGranted()) {
            startCamera() // 카메라 실행
        } else {
            ActivityCompat.requestPermissions(
                this, arrayOf(REQUIRED_PERMISSIONS), REQUEST_CODE_PERMISSIONS)
        }
    }
    
    // 권한 요청 결과를 판단(requestPermissions에 의해 호출)
    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>,
        grantResults:
        IntArray,
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                Toast.makeText(this, "접근 권한이 허용되지 않아 카메라를 실행할 수 없습니다. 설정에서 접근 권한을 허용해주세요.", Toast.LENGTH_SHORT).show()
            }
        }
    }

    // 카메라 권한
    private fun allPermissionsGranted() = ContextCompat.checkSelfPermission(
        baseContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED

앱 실행 시 카메라 권한을 체크하여 거절되었을 경우 토스트 팝업을 띄우고, 허용됐다면 미리보기를 띄우는 메서드를 실행하도록 하였다.


CamreaX • PreviewView 적용

1. CameraProvider 요청
2. CameraProvider 사용 가능 여부 확인
3. 카메라를 선택하고 use case를 같이 생명주기에 binding
   3-1. Preview 생성(use case)
   3-2. 카메라 세팅
   3-3. use case와 카메라를 생명 주기에 binding
4. Preview를 PreviewView에 연결
    private fun startCamera() {

        // 1. CameraProvider 요청
        // ProcessCameraProvider는 Camera의 생명주기를 LifeCycleOwner의 생명주기에 Binding 함
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener({
            // 2. CameraProvier 사용 가능 여부 확인
            // 생명주기에 binding 할 수 있는 ProcessCameraProvider 객체 가져옴
            val cameraProvider = cameraProviderFuture.get()

            // 3. 카메라를 선택하고 use case를 같이 생명주기에 binding

            // 3-1. Preview를 생성 → Preview를 통해서 카메라 미리보기 화면을 구현.
            // surfaceProvider는 데이터를 받을 준비가 되었다는 신호를 카메라에게 보내준다.
            // setSurfaceProvider는 PreviewView에 SurfaceProvider를 제공해준다.
            val preview = Preview.Builder().build()
            preview.setSurfaceProvider(mBinding.viewFinder.surfaceProvider)
            // 아래처럼 써도 됨
//           val preview = Preview.Builder().build().also {
//               it.setSurfaceProvider(mBinding.viewFinder.surfaceProvider)
//           }

            // 3-2. 카메라 세팅
            // CameraSelector는 카메라 세팅을 맡는다.(전면, 후면 카메라)
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                // binding 전에 binding 초기화
                cameraProvider.unbindAll()

                // 3-3. use case와 카메라를 생명 주기에 binding
                camera = cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview)

                cameraController = camera!!.cameraControl
                cameraController!!.setZoomRatio(1F) // 1x Zoom
            } catch (exc: Exception) {
                println("에러 $exc")
            }

            // 4. Preview를 PreviewView에 연결한다.
            // surfaceProvider는 데이터를 받을 준비가 되었다는 신호를 카메라에게 보내준다.
            // setSurfaceProvider는 PreviewView에 SurfaceProvider를 제공해준다.
            preview.setSurfaceProvider(mBinding.viewFinder.surfaceProvider)
        }, ContextCompat.getMainExecutor(this))
    }

 

 

내용 참고


전체 코드

'Android > Camera' 카테고리의 다른 글

[Android] 카메라 캡처(촬영)하기 - CameraX ˙ ImageCapture  (0) 2022.11.14

댓글