티스토리 뷰

이 글은 레코딩 기능을 하는 화면을 구현하면서 정리한 내용입니다.

 

1. captureSession 생성

세션은 입력에서 출력 장치로의 데이터 흐름을 제어하는데 사용됩니다.

간단히 아래와 같이 초기화 할 수 있습니다.

let captureSession = AVCaptureSession()
captureSession.sessionPreset = .high

sessionPreset은 비디오 및 오디오의 녹화 품질을 설정하는 속성입니다.

저품질로 할 경우 배터리 소비량이 낮아집니다.

 

2. captureDevice 생성

세션을 생성되면 이제 사용하려는 장치(카메라 or 마이크)를 정의합니다.

영상을 녹화할 것이기 때문에 AVMediaType은 video로 설정하고, DeviceType은 원하는 타입을 선택하여 설정해줍니다.

let videoDevice = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back)

 

하지만 device 별로 카메라 타입의 사용여부가 다르기 때문에 사용 가능한 타입을 찾아서 리턴해주는 메서드를 만들었습니다.

func bestDevice(in position: AVCaptureDevice.Position) -> AVCaptureDevice {
  var deviceTypes: [AVCaptureDevice.DeviceType]!
  
  if #available(iOS 11.1, *) {
    deviceTypes = [.builtInTrueDepthCamera, .builtInDualCamera, .builtInWideAngleCamera]
  } else {
    deviceTypes = [.builtInDualCamera, .builtInWideAngleCamera]
  }
  
  let discoverySession = AVCaptureDevice.DiscoverySession(
    deviceTypes: deviceTypes,
    mediaType: .video,
    position: .unspecified
  )
  
  let devices = discoverySession.devices
  guard !devices.isEmpty else { fatalError("Missing capture devices.")}
  
  return devices.first(where: { device in device.position == position })!
}

let videoDevice = bestDevice(in: .back)

 

- DeviceType에 대한 Apple Document

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

https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/choosing_a_capture_device

 

3. captureDeviceInput 생성

위에서 만든 videoDevice를 이용하여 session에 입력 장치(captureDeviceInput)를 추가해 줍니다.

private func setupSession() {
  do {
    captureSession.beginConfiguration() // 1

    // 2
    let videoInput = try AVCaptureDeviceInput(device: videoDevice!)
    if captureSession.canAddInput(deviceInput) {
      captureSession.addInput(deviceInput)
    }

    // 3
    let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)!
    let audioInput = try AVCaptureDeviceInput(device: audioDevice)
    if captureSession.canAddInput(audioInput) {
      captureSession.addInput(audioInput)
    }

    // 4
    videoOutput = AVCaptureMovieFileOutput()
    if captureSession.canAddOutput(videoOutput) {
      captureSession.addOutput(videoOutput)
    }

    captureSession.commitConfiguration() // 5
  }
  catch let error as NSError {
    NSLog("\(error), \(error.localizedDescription)")
  }
}

 

  1. 세션 구성의 시작을 나타냅니다.

  2. 비디오 장치에 대한 입력을 만들어 세션에 추가합니다.

  3. 오디오 장치에 대한 입력을 만들어 세션에 추가합니다.

  4. 비디오 및 오디오를 파일로 출력하기 위한 인스턴스를 만들어 세션에 추가합니다.

  5. 세션 구성의 완료를 나타냅니다.

 

4. View Rendering

이제 비디오의 입력이 UI에서 보여지도록 해야 합니다.

lazy var previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession).then {
  $0.bounds = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
  $0.position = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)
  $0.videoGravity = .resizeAspectFill
}

override func viewDidLoad() {
  super.viewDidLoad()
	
  self.view.layer.addSublayer(previewLayer)
  captureSession.startRunning()
}

 

생성된 previewLayer를 뷰에 추가하고 세션을 실행시켜주면, 레코딩을 위한 화면이 출력되는 것을 볼 수 있을 것입니다.

코딩을 끝내고 실행해보면 화면이 안나올텐데, info.plist에 권한 설정을 해주는 것도 잊지 말고 해줘야 합니다!

 

5. Recording

이제 출력되는 화면을 녹화해야 하는데, 그러기 위해서는 출력되는 비디오/오디오를 파일에 기록하는 AVCaptureMovieFileOutput 를 구현합니다. 

코드를 보면 금방 이해할 것입니다.

// Propertie
var videoOutput: AVCaptureMovieFileOutput!

private func setupSession() {
  ...

  videoOutput = AVCaptureMovieFileOutput()
  if captureSession.canAddOutput(videoOutput) {
    captureSession.addOutput(videoOutput)
  }
  
  ...
}

// Recording Methods
private func startRecording() {
  outputURL = tempURL()	// 파일이 저장될 경로
  videoOutput.startRecording(to: outputURL!, recordingDelegate: self)
}
  
private func stopRecording() {
  if videoOutput.isRecording {
    videoOutput.stopRecording()
  }
}

 

 

 

마지막으로 녹화 종료 후 작업입니다.

AVCaptureFileOutputRecordingDelegate를 준수하면 녹화의 시작/종료 시점에 따른 라이프사이클 메서드를 제공받아 사용할 수 있습니다.

녹화 종료를 하면 아래 함수중 fileOutPut(didFinishRecordingTo:)가 실행될 것이고 이 부분에서 받은 URL을 기반으로 저장하는 작업을 하면 됩니다.

extension RecordingViewController: AVCaptureFileOutputRecordingDelegate {
  
  // 레코딩이 시작되면 호출
  func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
    // do someting..
  }
  
  // 레코딩이 끝나면 호출
  func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    if (error != nil) {
      print("Error recording movie: \(error!.localizedDescription)")
    } else {
      let videoRecorded = outputURL! as URL
      UISaveVideoAtPathToSavedPhotosAlbum(videoRecorded.path, nil, nil, nil)
    }
  }
  
}

 

 

orientation 처리, 레코딩 타이머 등의 부가적인 처리는 전체 코드에서 확인할 수 있습니다.

 

'Swift' 카테고리의 다른 글

[Swift] HTTP Live Streaming을 위한 재생 목록 (m3u8)  (0) 2020.06.09
[Swift] Documentation Comments  (0) 2020.05.29
[swift] escaping closure  (0) 2019.04.14
[swift] Optional  (0) 2019.03.29
[swift] Enum  (0) 2019.03.29
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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 31
글 보관함