참고: 이 페이지에서는 Camera2 패키지를 참조합니다. 앱에 Camera2의 특정 하위 수준 기능이 필요하지 않으면 CameraX를 사용하는 것이 좋습니다. CameraX와 Camera2는 모두 Android 5.0 (API 수준 21) 이상을 지원합니다.
최신 Android 기기에는 기기의 전면, 후면 또는 양쪽에 두 개 이상의 카메라가 있습니다. 각 렌즈에는 연속 촬영, 수동 제어 또는 모션 추적과 같은 고유한 기능이 있을 수 있습니다. 수표 입금 앱은 첫 번째 후면 카메라만 사용할 수 있지만 소셜 미디어 앱은 기본적으로 전면 카메라를 사용하지만 사용자가 사용 가능한 모든 렌즈 간에 전환할 수 있는 옵션을 제공할 수 있습니다. 선택사항을 기억할 수도 있습니다.
이 페이지에서는 카메라 렌즈와 기능을 나열하여 앱 내에서 특정 상황에 사용할 렌즈를 결정할 수 있도록 하는 방법을 설명합니다. 다음 코드 스니펫은 모든 카메라 목록을 가져와서 반복합니다.
Kotlin
try { val cameraIdList = cameraManager.cameraIdList // may be empty // iterate over available camera devices for (cameraId in cameraIdList) { val characteristics = cameraManager.getCameraCharacteristics(cameraId) val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API val isBackwardCompatible = cameraCapabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false ... } } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } ... }
자바
try { String[] cameraIdList = cameraManager.getCameraIdList(); // may be empty // iterate over available camera devices for (String cameraId : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); int cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); int[] cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); // check if the selected camera device supports basic features // ensures backward compatibility with the original Camera API boolean isBackwardCompatible = false; for (int capability : cameraCapabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { isBackwardCompatible = true; break; } } ... } } catch (CameraAccessException e) { Log.e(TAG, e.getMessage()); ... }
cameraLensFacing 변수는 기기 화면을 기준으로 카메라가 향하는 방향을 설명하며 다음 값 중 하나를 갖습니다.
CameraMetadata.LENS_FACING_FRONTCameraMetadata.LENS_FACING_BACKCameraMetadata.LENS_FACING_EXTERNAL
렌즈 방향 구성에 관한 자세한 내용은
CameraCharacteristics.LENS_FACING을 참고하세요.
이전 코드 샘플의 cameraCapabilities 변수에는 카메라가 출력으로 표준 프레임을 생성할 수 있는지 여부 (예: 깊이 센서 데이터만 생성하는 것과 반대)를 비롯한 기타 기능에 관한 정보가 포함되어 있습니다.
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
이 카메라의 나열된 기능 중 하나인지 확인할 수 있습니다. 이 기능은
isBackwardCompatible에 플래그로 저장됩니다.
적절한 기본값 선택
앱에서 기본적으로 특정 카메라를 열고 싶을 것입니다(사용 가능한 경우). 예를 들어 셀카 앱은 전면 카메라를 열고 증강 현실 앱은 후면 카메라로 시작할 수 있습니다. 다음 함수는 지정된 방향을 향하는 첫 번째 카메라를 반환합니다.
Kotlin
fun getFirstCameraIdFacing(cameraManager: CameraManager, facing: Int = CameraMetadata.LENS_FACING_BACK): String? { try { // Get list of all compatible cameras val cameraIds = cameraManager.cameraIdList.filter { val characteristics = cameraManager.getCameraCharacteristics(it) val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES) capabilities?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false } // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration cameraIds.forEach { val characteristics = cameraManager.getCameraCharacteristics(it) if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) { return it } } // If no camera matched desired orientation, return the first one from the list return cameraIds.firstOrNull() } catch (e: CameraAccessException) { e.message?.let { Log.e(TAG, it) } } }
자바
public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) { if (facing == null) facing = CameraMetadata.LENS_FACING_BACK; String cameraId = null; try { // Get a list of all compatible cameras String[] cameraIdList = cameraManager.getCameraIdList(); // Iterate over the list of cameras and return the first one matching desired // lens-facing configuration and backward compatibility for (String id : cameraIdList) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE && characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing)) { cameraId = id; break; } } } // If no camera matches the desired orientation, return the first one from the list cameraId = cameraIdList[0]; } catch (CameraAccessException e) { Log.e(TAG, "getFirstCameraIdFacing: " + e.getMessage()); } return cameraId; }
카메라 전환 사용 설정
많은 카메라 앱에서 사용자에게 카메라 간에 전환할 수 있는 옵션을 제공합니다.
많은 기기에 같은 방향을 향하는 여러 카메라가 있습니다. 일부 기기에는 외장 USB 카메라가 있습니다. 사용자에게 서로 다른 방향을 향하는 카메라 간에 전환할 수 있는 UI를 제공하려면 가능한 각 렌즈 방향 구성에 대해 사용 가능한 첫 번째 카메라를 선택하세요.
다음 카메라를 선택하는 보편적인 로직은 없지만 다음 코드는 대부분의 사용 사례에서 작동합니다.
Kotlin
fun filterCompatibleCameras(cameraIds: Array<String>, cameraManager: CameraManager): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains( CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false } } fun filterCameraIdsFacing(cameraIds: List<String>, cameraManager: CameraManager, facing: Int): List<String> { return cameraIds.filter { val characteristics = cameraManager.getCameraCharacteristics(it) characteristics.get(CameraCharacteristics.LENS_FACING) == facing } } fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? { // Get all front, back and external cameras in 3 separate lists val cameraIds = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager) val backCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK) val frontCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT) val externalCameras = filterCameraIdsFacing( cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL) // The recommended order of iteration is: all external, first back, first front val allCameras = (externalCameras + listOf( backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull() // Get the index of the currently selected camera in the list val cameraIndex = allCameras.indexOf(currCameraId) // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user return if (cameraIndex == -1) { // Return the first camera from the list allCameras.getOrNull(0) } else { // Return the next camera from the list, wrap around if necessary allCameras.getOrNull((cameraIndex + 1) % allCameras.size) } }
자바
public List<String> filterCompatibleCameras(CameraManager cameraManager, String[] cameraIds) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); for (int capability : capabilities) { if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { compatibleCameras.add(id); } } } } catch (CameraAccessException e) { Log.e(TAG, "filterCompatibleCameras: " + e.getMessage()); } return compatibleCameras; } public List<String> filterCameraIdsFacing(CameraManager cameraManager, List<String> cameraIds, int lensFacing) { final List<String> compatibleCameras = new ArrayList<>(); try { for (String id : cameraIds) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); if (characteristics.get(CameraCharacteristics.LENS_FACING) == lensFacing) { compatibleCameras.add(id); } } } catch (CameraAccessException e) { Log.e(TAG, "filterCameraIdsFacing: " + e.getMessage()); } return compatibleCameras; } public String getNextCameraId(CameraManager cameraManager, @Nullable String currentCameraId) { String nextCameraId = null; try { // Get all front, back, and external cameras in 3 separate lists List<String> compatibleCameraIds = filterCompatibleCameras(cameraManager, cameraManager.getCameraIdList()); List<String> backCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_BACK); List<String> frontCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_FRONT); List<String>externalCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_EXTERNAL); // The recommended order of iteration is: all external, first back, first front List<String> allCameras = new ArrayList<>(externalCameras); if (!backCameras.isEmpty()) allCameras.add(backCameras.get(0)); if (!frontCameras.isEmpty()) allCameras.add(frontCameras.get(0)); // Get the index of the currently selected camera in the list int cameraIndex = allCameras.indexOf(currentCameraId); // The selected camera may not be in the list, for example it could be an // external camera that has been removed by the user if (cameraIndex == -1) { // Return the first camera from the list nextCameraId = !allCameras.isEmpty() ? allCameras.get(0) : null; else { if (!allCameras.isEmpty()) { // Return the next camera from the list, wrap around if necessary nextCameraId = allCameras.get((cameraIndex + 1) % allCameras.size()); } } } catch (CameraAccessException e) { Log.e(TAG, "getNextCameraId: " + e.getMessage()); } return nextCameraId; }
이 코드는 다양한 구성이 있는 많은 기기에서 작동합니다. 특이 사례를 고려하는 방법에 관한 자세한 내용은 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA를 참고하세요.
호환되는 앱 만들기
지원 중단된 Camera API를 계속 사용하는 앱의 경우 카메라 수
는
Camera.getNumberOfCameras()
OEM 구현에 따라 다릅니다. 시스템에 논리적 다중 카메라가 있는 경우 앱 이전 버전과의 호환성을 유지하기 위해 이 메서드는 모든 논리적 카메라 및 기본 실제 카메라 그룹에 대해 하나의 카메라만 노출합니다.
Camera2 API를 사용하여 모든 카메라를 확인하세요.
카메라 방향에 관한 자세한 배경 정보는
Camera.CameraInfo.orientation을 참고하세요.
일반적으로
Camera.getCameraInfo()
API를 사용하여 모든 카메라
orientations를 쿼리하고
카메라 간에
전환하는 사용자에게 사용 가능한 각 방향에 대해 하나의 카메라만 노출합니다.
모든 기기 유형 수용
앱이 항상 카메라가 한두 개 있는 휴대기기에서 실행된다고 가정하지 마세요. 대신 앱에 가장 적합한 카메라를 선택하세요. 특정 카메라가 필요하지 않으면 원하는 방향을 향하는 첫 번째 카메라를 선택하세요. 특정 방향을 향하는 카메라를 사용할 수 없는 경우 사용자가 다른 카메라로 여정을 완료할 수 있는지 고려하세요. 카메라 하드웨어를 기준으로 특정 기기에서 앱의 사용 가능성을 제한하지 마세요. 외장 카메라가 연결되어 있으면 사용자가 기본값으로 선호할 것입니다.