본문 바로가기
iOS

AVCapture Session

by 융식 2022. 10. 17.

AVCapture Session

 

애플 공식 문서 설명을 먼저 쭉 보고 시작하죠!

(오역이 있을 수 있습니다. 참고만 해주세요!)

 

AVFoundation에 속해 있으며, 비디오와 오디오의 캡쳐 서비스를 위해 사용 됩니다!

 

  • 사용자가 사용하기 편한 카메라 UI를 제공하고 싶을 경우
  • 사용자가 카메라 효과(노출, 대비, 포커스 등)를 제어 할 수 있는 기능을 제공하고 싶은 경우
  • 커스텀 카메라 시스템을 구성하고 싶을 경우 (ex. 커스텀 타이머 사용)
  • 캡처 장치에서 픽셀 또는 오디오 데이터 스트리밍에 실시간으로 접근하고 싶은 경우

캡처 구조의 주요 부분은 세션, 입력 및 출력 입니다. 

 

입력은 iOS의 내장 카메라와 마이크와 같은 캡처 장치의 미디어 소스입니다.

 

출력은 입력으로부터 미디어를 가져와 메모리에 기록된 영상 파일 또는 실시간 처리에 사용되는 픽셀 버퍼 같은 데이터를 생성합니다.

 

 

세션은 무슨 역할을 할까요? 

 

캡처 장치에 대한 앱의 액세스 뿐만 아니라 입력 장치에서 미디어 출력으로 데이터 흐름을 관리하게 됩니다.

 

Figure 1 Architecture of an example capture session

 

그럼 세션은 입력과 출력을 관리해야 하니까 입출력을 연결해주어야겠군요!

 

 

그럼 세션을 연결하는 코드를 살펴 봅시다.

captureSession = AVCaptureSession()

캡처 세션을 만들어주고

//캡쳐 세션 구성을 시작
captureSession.beginConfiguration()

//캡처 디바이스 종류 및 유형, 카메라 구성 설정
let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera,	
                                          for: .video, position: .unspecified)

카메라를 구성해줍니다.

 

캡처할 수 있는(입력) AVCaptureDevice 종류는 아래 링크를 참조!

https://developer.apple.com/documentation/avfoundation/avcapturedevice/devicetype

 

디바이스 종류를  선택할 수 있는 방법은 크게 두가지가 있습니다.

if let device = AVCaptureDevice.default(.builtInDualCamera,
                                        for: .video, position: .back) {
    return device
} else if let device = AVCaptureDevice.default(.builtInWideAngleCamera,
                                               for: .video, position: .back) {
    return device
} else {
    fatalError("Missing expected back camera device.")
}

사용하려는 디바이스의 우선순위가 있다면 if 문을 사용하여 분기처리를 하여 디바이스를 선택하는 방법이 있고,

 

 

let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes:
    [.builtInTrueDepthCamera, .builtInDualCamera, .builtInWideAngleCamera],
    mediaType: .video, position: .unspecified)

AVCaptureDevice의  default가 아닌 Discovery Session 객체를 만들어 사용하는 방법이 있습니다.

func bestDevice(in position: AVCaptureDevice.Position) -> AVCaptureDevice {
	// 위에서 만든 discoverSession의 값을 가져와 개발자가 원하는 방향에 따라 분기
    let devices = self.discoverySession.devices
    guard !devices.isEmpty else { fatalError("Missing capture devices.")}

    return devices.first(where: { device in device.position == position })!
}

 

사용할 디바이스 설정이 완료 되었다면

// 입력을 세션에 연결할 준비가 됐다면 연결
guard
    let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),
    captureSession.canAddInput(videoDeviceInput)	
    else { return }
captureSession.addInput(videoDeviceInput)

입력을 세션에 연결해줍니다.

 

이제 캡처한 미디어 유형에 대해 출력을 추가해주어야 합니다.

// 사진 캡처를 출력으로 설정 시  
let photoOutput = AVCapturePhotoOutput()
guard captureSession.canAddOutput(photoOutput) else { return }
// 사진 형식으로
captureSession.sessionPreset = .photo
captureSession.addOutput(photoOutput)
// 세션 구성 완료 시 호출
captureSession.commitConfiguration()

 

이렇게 하면 세션 연결 완료!

 

 

카메라 프리뷰 설정

 

카메라가 보는 것을 사용자도 볼 수 있게 하려면 캡처하고 있는 프리뷰를 만들어 주어야 합니다.

AVCaptureVideoPreviewLayer는 UIView에 에니메이션을 만들어주기 위해 CALayer를 이용한 layerClass를 만들어 프리뷰를 만들어 줍니다.

class PreviewView: UIView {
    override class var layerClass: AnyClass {
        return AVCaptureVideoPreviewLayer.self
    }
    
    /// Convenience wrapper to get layer as its statically known type.
    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }
}

그 후 캡처 세션을 layer 세션으로 설정해 줍니다.

self.previewView.videoPreviewLayer.session = self.captureSession

 

입력, 출력, 프리뷰까지 구성을 완료했다면 

captureSession.startRunning()

을 이용하여 데이터가 입력에서 출력으로 흐를 수 있게 설정합니다.

다른 캡처 출력이 있다면 첫 세션이 실행 한 후에 실행 됩니다.

 

당연히 start가 있다면 stop도 있겠죠?

captureSEssion.stopRunning()

 

이제 AVCaptureSession 의 속성들을 알아봅시다

 

AVCaptureSession의 구성을 시작하기 전과 구성을 완료했을 때 사용하는 

// 세션 구성 시작 전에 호출 해야하는 메소드
func beginConfiguration()

// 세션 구성 완료 후 호출 해야하는 메소드
func commitConfiguration()
// commit Configuration 메소드를 호출해야 구성했던 작업들을 업데이트 할 수 있음.

 

 

세션의 설정에 대해 관여하는 Preset

AVCaptureSession.Preset

// 해당 Preset을 사용할 수 있는지 확인할 수 있는 메소드로 현재 입력과 출력 세션에서 지원하는지에 대한 여부를 확인할 수 있슴
func canSetSessionPreset(_ preset: AVCaptureSession.Preset) -> Bool

여러 Preset 종류는 애플 홈페이지에서 확인!

https://developer.apple.com/documentation/avfoundation/avcapturesession/preset

 

 

세션을 구성할 때는 입력과 출력을 연결해야 합니다. 입력과 관련된 프로퍼티를 먼저 살펴 봅시다.

// 미디어 데이터를 캡처 세션에 제공하는 입력
var inputs: [AVCaptureInput] { get }

// 세션에 입력을 추가할 수 있는지의 여부를 확인하는 메소드
func canAddInput(_ input: AVCaptureInput) -> Bool

// 만약 위의 canAddInput 메소드에서 잘 넘어왔다면 안전하게 addInput메소드를 이용하여 세션에 입력 추가
func addInput(_ input: AVCaptureInput)

// 사용하던 입력을 제거하고 다른 입력을 구성하고 싶을 경우 사용. 세션 진행 중에 사용 가능
func removeInput(_ input: AVCaptureInput)

 

출력을 구성할 프로퍼티도 살펴볼까요?

// 세션이 데이터를 보내는 출력 대상
var outputs: [AVCaptureOutput] { get }

// 출력을 세션에 추가할 수 있는지 여부 확인
func canAddOutput(_ output: AVCaptureOutput) -> Bool

// 만약 위의 canAddOutput을 안전하게 넘어 온다면 아래 addOutput을 통해 세션 출력 추가
func addOutput(_ output: AVCaptureOutput)

// 세션의 출력을 지우고 싶을 때 세션 실행중에 사용 가능
func removeOutput(_ output: AVCaptureOutput)
 

세션의 입력과 출력의 연결은 add 메소드를 호출시켜 연결하면 connection이 됩니다. 

 

연결을 하면 세션의 입력과 출력의 데이터가 흐를 수 있게 해주어야 합니다.

// 캡처 시작
func startRunning()

// 캡처 중지
func stopRunning()
 

지금까지는 카메라를 사용할 때 항상 풀스크린의 앱에서만 카메라를 사용할 수 있게 했지만

iOS 16 이상부터는 멀티태스킹 중에서도 카메라르 사용할 수 있게 설정할 수 있는 프로퍼티를 준다고 합니다! 

var isMultitaskingCameraAccessEnabled: Bool { get set }

 

 

참고 자료 : https://developer.apple.com/documentation/avfoundation/capture_setup, https://developer.apple.com/documentation/avfoundation/capture_setup/setting_up_a_capture_session

 

'iOS' 카테고리의 다른 글

음악 재검색 후 기록 저장시 앱 다운 버그 수정 일지  (0) 2022.11.07
ARKit 과 SceneKit 기초!  (0) 2022.11.01
iOS ARKit LiDAR 에 대해  (0) 2022.09.27
Pencil Kit (iPadOS) - 기초편  (0) 2022.09.21
View Life Cycle  (0) 2022.09.06