Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 리펙터링
- ios
- map
- swiftUI
- UITextView
- 스위프트
- 클린 코드
- collectionview
- MVVM
- swift documentation
- Protocol
- RxCocoa
- Clean Code
- Refactoring
- ribs
- combine
- SWIFT
- Observable
- uiscrollview
- clean architecture
- 애니메이션
- 리팩토링
- uitableview
- Human interface guide
- rxswift
- UICollectionView
- Xcode
- HIG
- tableView
- 리펙토링
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] AVFoundation, Camera 다루는 방법 본문
핵심 타입
- AVCaptureSession
- AVCaptureDevice
- AVCaptureDeviceInput, AVCapturePhotoOutput
- AVCaptureVideoPreviewLayer
AVCaptureSession
- 개념: 세션이란 입력에서 출력 장치로의 데이터 흐름을 제어하는데 사용
- 해상도 설정: captureSession.sessionPreset
captureSession = AVCaptureSession()
captureSession.sessionPreset = .photo // set resoultion
AVCaptureDevice
- 개념: 말 그래로 "capture"하는 물리적인 device를 참조하는 데이터형
guard let backCamera = AVCaptureDevice.default(for: AVMediaType.video) else {
return
}
captureDevice = backCamera
AVCaptureDeviceInput, AVCapturePhotoOutput
- AVCaptureDeviceInput: device의 입력
- AVCapturePhotoOutput: device의 출력
- DeviceInput으로 input을 참조, PhotoOutput으로 output을 참조하여 captureSession에 등록
do {
let input = try AVCaptureDeviceInput(device: backCamera)
stillIamgeOutput = AVCapturePhotoOutput()
if captureSession = captureSession.canAddInput(input), captureSession.canAddOutput(stillImageOutput) {
captureSession.addInput(input)
captureSession.addOutput(stillImageOutput)
// 여기에서 preview 세팅하는 함수 호출
}
} catch {
print(error.localizedDescription)
}
AVCaptureVideoPreviewLayer
- 개념: input, output이 설정된 AVCaptureSession의 객체를 받아서 미리보기 화면의 정보를 갖는 Layer 데이터형
- Layer이므로 따로 UIView를 만들어서 이곳에 부착하는 형태로 사용
private func setupLivePreview() {
// previewLayer 세팅
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer.videoGravity = .resizeAspectFill
videoPreviewLayer.connection?.videoOrientation = .portrait
// UIView객체인 preView 위 객체 입힘
preView.layer.insertSublayer(videoPreviewLayer, at: 0) // 맨 앞(0번쨰로)으로 가져와서 보이게끔 설정
DispatchQueue.main.async { in
self.videoPreviewLayer.frame = self.preView.bounds
}
// preview까지 준비되었으니 captureSession을 시작하도록 설정
}
- captureSession에 시작을 알림
private func startCaptureSession() {
DispatchQueue.global(qos: .userInitiated).async {
self.captureSession.startRunning()
}
}
기능 구현
- focus
- 카메라 전환 (앞, 뒤)
- flash 버튼
Focus
- preView에서 tap한 위치를 찾아내어 그 좌표를 focus시키는 방식
- tap 이벤트 바인딩
preView.rx.tapGesture()
.asDriverOnErrorNever()
.drive(onNext: { [weak self] (gesture) in
self?.tapFocus(gesture)
}).disposed(by: bag)
- focus : captureDevice를 가지고 focus 처리
private func tapFocus(_ sender: UITapGestureRecognizer) {
if (sender.state == .ended) {
let thisFocusPoint = sender.location(in: preView)
focusAnimationAt(thisFocusPoint)
let focus_x = thisFocusPoint.x / preView.frame.size.width
let focus_y = thisFocusPoint.y / preView.frame.size.height
if (captureDevice!.isFocusModeSupported(.autoFocus) && captureDevice!.isFocusPointOfInterestSupported) {
do {
try captureDevice?.lockForConfiguration()
captureDevice?.focusMode = .autoFocus
captureDevice?.focusPointOfInterest = CGPoint(x: focus_x, y: focus_y)
if (captureDevice!.isExposureModeSupported(.autoExpose) && captureDevice!.isExposurePointOfInterestSupported) {
captureDevice?.exposureMode = .autoExpose;
captureDevice?.exposurePointOfInterest = CGPoint(x: focus_x, y: focus_y);
}
captureDevice?.unlockForConfiguration()
} catch {
print(error)
}
}
}
}
- focus 받은 부분 애니메이션 처리
fileprivate func focusAnimationAt(_ point: CGPoint) {
let focusView = UIImageView(image: UIImage(named: "aim"))
focusView.center = point
preView.addSubview(focusView)
focusView.transform = CGAffineTransform(scaleX: 2, y: 2)
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
focusView.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
}) { (success) in
UIView.animate(withDuration: 0.15, delay: 1, options: .curveEaseInOut, animations: {
focusView.alpha = 0.0
}) { (success) in
focusView.removeFromSuperview()
}
}
}
카메라 전환
- 새로운 device를 생성한 후 captureSession에 등록
private func switchCamera(captureSession: AVCaptureSession?) {
captureSession?.beginConfiguration()
let currentInput = captureSession?.inputs.first as? AVCaptureDeviceInput
captureSession?.removeInput(currentInput!)
let newCameraDevice = currentInput?.device.position == .back ? camera(with: .front) : camera(with: .back)
let newVideoInput = try? AVCaptureDeviceInput(device: newCameraDevice!)
captureSession?.addInput(newVideoInput!)
captureSession?.commitConfiguration()
}
private func camera(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
let devices = AVCaptureDevice.devices(for: AVMediaType.video)
return devices.filter { $0.position == position }.first
}
- flashMode의 flag값을 가지고 있다가, 사진을 찍을 때, AVCapturePhotoSetting의 객체를 가지고 stillImageOutput에 설정
func didTapBtnTakePicture(stillImageOutput: AVCapturePhotoOutput) {
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
settings.flashMode = flashMode.value == .off ? .off : .on
stillImageOutput.capturePhoto(with: settings, delegate: self)
}
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] containerVC와 ChildVC 다루는 방법, 투명 뷰 (PassThroughView) (0) | 2021.02.03 |
---|---|
[iOS - swift] 문자열 파일 저장하기 (userDomainMask, documentDirectory) (0) | 2021.02.02 |
[iOS - swift] URL, URI 파싱, path, query string (URLComponents, URITemplate 프레임워크) (2) | 2021.01.25 |
[iOS - swift] Lottie 프레임워크 (애니메이션) (0) | 2021.01.24 |
[iOS - swift] Hero 프레임워크 (화면전환 애니메이션) (0) | 2021.01.24 |
Comments