OnePIC (Android App)/카메라

[Camera2] 전면 후면 카메라 전환

경걍 2023. 8. 9. 21:49
반응형
전체 흐름

 

다음 방식으로 카메라가 전환된다

 

1. 현재 사용 중인 카메라 Close

2. 사용할 카메라 설정 및 Open

 

        binding.changeCameraBtn.setOnCheckedChangeListener { _, isChecked ->
            
            // 원하는 카메라 설정
            wantCameraDirection = if(isChecked) {
                CameraCharacteristics.LENS_FACING_FRONT // 전면
            } else {
                CameraCharacteristics.LENS_FACING_BACK // 후면
            } 

            // 기존 카메라 close
            closeCamera()

            // texture 사용 가능한지 확인
            if (binding.texture.isAvailable) {
                // 새로운 카메라 open
                openCamera(binding.texture.width, binding.texture.height)
            } else {
                binding.texture.surfaceTextureListener = surfaceTextureListener
            }
        }

현재 사용 중인 카메라 Close

 

	fun closeCamera() {
        try {
            cameraOpenCloseLock.acquire()
            captureSession?.close()
            captureSession = null
            cameraDevice?.close()
            cameraDevice = null
            imageReader?.close()
            imageReader = null
        } catch (e: InterruptedException) {
            throw RuntimeException("Interrupted while trying to lock camera closing.", e)
        } finally {
            cameraOpenCloseLock.release()
        }
    }

 

사용할 카메라 설정 및 Open

 

            // texture 사용 가능한지 확인
            if (binding.texture.isAvailable) {
                // 카메라 열기
                openCamera(binding.texture.width, binding.texture.height)
            } else {
                binding.texture.surfaceTextureListener = surfaceTextureListener
            }

 

openCamera( ... ) 함수에 대해서 자세한 정보는 다음 포스팅에서 확인 바란다.

 

[Camera2] Camera2로 Preview 띄우기

Camera2 프리뷰띄우기 및 캡처 샘플 코드 - GitHub GitHub - googlearchive/android-Camera2Basic: Migrated: Migrated:. Contribute to googlearchive/android-Camera2Basic development by creating an account on GitHub. github.com Camera2 흐름도 - pre

kyumq.tistory.com

 

openCamera ( ... ) 함수에서 setUpCameraOutputs( ... ) 함수가 조금 변경된다.

 

    /**
     * 카메라 설정 및 카메라 관련 멤버 변수 초기화
     */
    private fun setUpCameraOutputs(width: Int, height: Int) {
        // 카메라 매니저 얻기 (사용가능한 카메라 장치들 얻어오기)
        val manager = activity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        try {
            // 카메라 중에 조건에 맞는 거 하나를 찾고 return (첫번째부터 확인 후, 조건이 맞지 않을 continue)
            for (cameraId in manager.cameraIdList) {
                // 카메라 정보 알아내기
                val characteristics = manager.getCameraCharacteristics(cameraId)

                // 렌즈 정보 알아낸 후, 원하는 카메라가 아닐 시 continue
                val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
                if (cameraDirection != null && cameraDirection == wantCameraDirection
                ) {
                    continue
                }

                // 스트림 구성 맵이 null인 경우 continue =>
                val map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
                ) ?: continue

                // 이미지 해상도 및 포맷 설정 -> 가장 높은(좋은) 해상도 선택
                val largest = Collections.max(
                    Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)), CompareSizesByArea()
                )
                // 선택된 해상도로 ImageReader 설정 -> JPEG으로, width, height는 가장 크게
                imageReader = ImageReader.newInstance(
                    largest.width, largest.height,
                    ImageFormat.JPEG, /*maxImages*/ 10
                ).apply {
                    setOnImageAvailableListener(onImageAvailableListener, backgroundHandler)
                }

                // 디바이스에 따른 센서 방향 고려해서 preview 크기 결정
                val displayRotation = activity?.windowManager?.defaultDisplay?.rotation

                sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!
                val swappedDimensions = areDimensionsSwapped(displayRotation!!)

                val displaySize = Point()
                activity?.windowManager?.defaultDisplay?.getSize(displaySize)
                val rotatedPreviewWidth = if (swappedDimensions) height else width
                val rotatedPreviewHeight = if (swappedDimensions) width else height
                var maxPreviewWidth = if (swappedDimensions) displaySize.y else displaySize.x
                var maxPreviewHeight = if (swappedDimensions) displaySize.x else displaySize.y

                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) maxPreviewWidth = MAX_PREVIEW_WIDTH
                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) maxPreviewHeight = MAX_PREVIEW_HEIGHT

                previewSize = chooseOptimalSize(
                    map.getOutputSizes(SurfaceTexture::class.java),
                    rotatedPreviewWidth, rotatedPreviewHeight,
                    maxPreviewWidth, maxPreviewHeight,
                    largest
                )

                // We fit the aspect ratio of TextureView to the size of preview we picked.
                if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    binding.texture.setAspectRatio(previewSize.width, previewSize.height)
                } else {
                    binding.texture.setAspectRatio(previewSize.height, previewSize.width)
                }

                // Check if the flash is supported.
                flashSupported =
                    characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) == true

                this.cameraId = cameraId

                // 렌즈 LENS_INFO_MINIMUM_FOCUS_DISTANCE 값 알아오기 (최대값 = 변수 등록) : 최대 초점 거리
                minimumFocusDistance = characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)!!

                return
            }
        } catch (e: CameraAccessException) {
            Log.e(TAG, e.toString())
        } catch (e: NullPointerException) { }
    }

 

위 코드에서 다음 부분이 가장 중요하다.

내가 원하는 카메라 방향이 아닐 경우에는 continue로 다음 카메라를 확인한다.

if (cameraDirection == null || cameraDirection != wantCameraDirection) {
	continue
}

 

반응형