일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Decodable
- cancelstouchesinview
- 정보처리기사 실기 요약본
- 정보처리기사 실기
- JSON
- ios외부카메라연결
- AVFoundation
- swift
- ios카메라유선연결
- programmers
- 2018 KAKAO BLIND RECRUITMENT
- ios캡처감지
- 카메라유선연결
- Codable
- avcapturesession
- CustomCode
- 정보처리기사
- UITableView
- 위클리챌린지
- JSONParser
- ios캡처방지
- cocoapods
- Xcode
- ios외부디바이스연결
- Pod
- 외부카메라감지
- 프로그래머스
- IOS
- usb카메라연결
- parse
- Today
- Total
iOS 개발일기
[iOS] USB 카메라 연결(3) 본문
2025.01.09 - [iOS] - [iOS] USB 카메라 연결(1)
2025.02.19 - [iOS] - [iOS] USB 카메라 연결(2)
이번 글에서는 화면 캡처 방법과 그 과정에서 발생했던 문제와 해결 과정에 대해서 작성해보려고 한다.
이미지 캡처
외부 카메라와 미리보기 화면까지 표시하는 것 까지 모두 마친 다음에 캡처에 대해서 진행했는데 AVCaptureSession에 추가한 AVCapturePhotoOutput을 사용하여 캡처를 할 수 있다.
output.capturePhoto(with: AVCapturePhotoSetting(), delegate: self)
AVCapturePhotoCaptureDelegate 프로토콜을 채택하여 캡처한 이미지에 데이터를 가지고 이미지로 변경할 수 있다.
extension ExternalCameraController: AVCapturePhotoCaptureDelegate {
func photoOutput(
_ output: AVCapturePhotoOutput,
didFinishProcessingPhoto photo: AVCApturePhoto,
error: Error?
) {
if let error {
//에러
}
if let data = photo.fileDataRepresentation(), let image = UIImage(data: data) {
//이미지
}
}
}
해당 메서드는 캡처가 완료된 후에 캡처된 데이터를 넘겨주는 것이며, 이 메서드 외에도 캡처 타이밍 마다 메서드가 존재한다.
이렇게 캡처 후 데이터를 이미지를 저장했는데, 저장한 이미지를 CollectionViewCell에 띄워보니 이미지가 미리보기와 다르게 왼쪽으로 90도 회전되어 있는 것이었다. 미리보기 화면에서 왼쪽으로 90도 회전되어 있었던 현상과 같았다.
이 문제는 이전 게시글에서 말했듯이 외부 카메라 출력 객체의 방향이 Landscape로 설정되어 있기 때문이다. 캡처한 이미지의 회전을 시키기 위해서는 AVCapturePhotoOutput의 AVCaptureConnection 내 존재하는 `videoRotationAngle`의 파라미터를 수정해주면 된다.
if let connection = output.connection(with: .video) {
connection.videoRotationAngle = 90
}
이 외에는 조금 무식한 방법이긴 하지만 이미지를 그냥 회전 시켜버리는 방법인데 처음에는 AVCapturePhotoOutput의 대한 이해도가 낮아서 무식하게 이미지를 회전했었다....
캡처 후 미리보기 화면 깜빡임 현상
캡처된 이미지의 방향에 대해서도 해결했지만 캡처를 하고나면 꼭 미리보기 화면의 깜빡임이 있었다. 프로젝트로 진행되는 앱이 두 가지 버전으로 개발되고 있었는데 두 개의 뷰 컨트롤러의 구성이 조금 달랐다. (우측 상단이 UILabel로 되어있냐 UIButton으로 되어 있냐의 차이)
기본적으로 AVCaptureSession을 다른 뷰로 만들어서 사용하고 있지 않았고, 하나의 뷰 컨트롤러 안에 AVCaptureSession과 각종 뷰들을 같이 사용하는 방식이었다.
처음에는 두 개의 앱이 모두 캡처 후에 화면이 깜빡이길래 의심했던 부분은 AVCaptureSession의 재구성이었다.
왜 AVCaptureSession이 재구성되는 것일까?
원인은 AVCaptureDevice에 있었는데 카메라의 설정 중에 미러링(automaticallyAdjustsVideoMirroring)처럼 자동 조정을 해주는 값들이 존재한다. 자동 조정이 활성화되어 있으면 초기 디바이스의 설정 값들과 다른 값이 있다면 재구성을 하는 것이다. 이 재구성이 진행되면서 세션과 미리보기 화면이 영향을 받아 화면 깜빡임 현상이 생긴 것이 아닐까 생각했었는데 두 번째 앱의 경우에는 화면 해상도를 변경해주는 기능이 있기 때문에 화면의 해상도를 변경하게되면 초기 디바이스의 설정과 다르기 때문에 재구성이 된다. 하지만 첫 번째 앱의 경우에는 초기 디바이스의 설정에서 변경되는 부분이 일절 없었기 때문에 재구성이 일어나지 않았다. 그런데도 화면의 깜빡임이 발생하는 것이었다.
토스트 애니메이션 효과로 인한 뷰의 재구성?
그래서 다른 곳으로 눈이 갔는데 캡처 후 토스트를 띄워주는 것이었다. `Toast_Swift`라는 라이브러리를 사용하고 있었는데, 이 라이브러리가 사용할 때마다 View에 추가하여 애니메이션이 실행되면서 화면에 표시되는 방법이었다. 토스트가 추가되면서 뷰가 재구성되면서 화면의 깜빡이 발생하는 것이 아닌가 생각하게 되었다.(토스트의 애니메이션 효과로 인해서 뷰가 재구성될 수 있기 때문에)
그래서 뷰의 애니메이션 효과를 제거 해보기로 했다.
UIView.performWithoutAnimation {
//토스트 띄우기
}
애니메이션을 제거한 후에 캡처를 해보니 버튼으로만 구성된 캡처 화면은 화면 깜빡임 현상이 나타나지 않았다. 이제 뷰의 재구성으로 인해서 AVCaptureVideoPreviewLayer가 영향을 받아 화면이 깜빡이게 된다는 것을 알게 되었다. 그런데 UILabel이 추가되어 있는 화면에서는 여전히 화면의 깜빡임이 나타나고 있었다.
UILabel에도 애니메이션을 지우면 되지 않을까 생각해봤지만 UILabel의 text가 변경될 때는 애니메이션이 없기 때문에 `
performWithoutAnimation`의 사용은 효과가 없었다. UILabel은 캡처를 진행할 때마다 text가 변경되기 때문에 그에 따라 UILabel의 크기가 변경되면서 뷰가 재구성되는 것이 아닐까 생각하게 되었고 UILabel의 크기를 지정해주고 캡처를 해봤었지만 결과는 동일했다.
(AutoLayout으로 뷰를 구성했기 때문에 그런게 아닌가 생각된다.)
그래서 생각해낸 방법이 서로 뷰에 대한 영향을 최소한으로 하기 위해 외부 카메라와 관련된 뷰를 컨트롤러로 따로 빼낸 다음, 자식 뷰 컨트롤러로 추가하기로 했다.
lazy var cameraController = ExternalCameraViewController()
override func viewDidLoad() {
super.viewDidLoad()
addChild(cameraController)
view.addSubview(cameraController.view)
cameraController.view.snp.makeConstraints {
$0.top.bottom.equalToSuperview()
$0.left.equalTo(view.safeAreaLayoutGuide)
$0.right.equalToSuperview().multipliedBy(0.85)
}
view.addSubview(rightView)
rightView.snp.makeConstraints {
$0.top.bottom.equalToSuperview()
$0.left.equalTo(cameraController.view.snp.right)
$0.right.equalTo(view.safeAreaLayoutGuide).inset(8)
}
}
이렇게 UILabel과 Toast로 인해서 뷰가 재구성되더라도 addChild로 추가된 뷰 컨트롤러의 뷰는 독립적으로 관리되기 때문에 UILabel의 text가 변경되어도 부모 뷰 컨트롤러가 관리하는 전체 뷰 계층이 아닌 UILabel이 포함된 특정 뷰만 업데이트되기 때문에 AVCaptureVideoPreviewLayer가 같이 업데이트 되지 않는다. 그렇기 때문에 화면의 깜빡임이 사라지게 된 것이다.
'iOS' 카테고리의 다른 글
[iOS] USB 카메라 연결(2) (0) | 2025.02.19 |
---|---|
[iOS] USB 카메라 연결(1) (0) | 2025.01.09 |
[iOS] 화면 캡처 감지 및 방지 방법 (0) | 2024.12.31 |
[iOS] 오픈소스 라이선스 표시 및 라이브러리 (0) | 2024.12.04 |
[iOS] Realm 사용법 (0) | 2024.11.24 |