インカメラから映像を取得するのも録画するのも簡単だが,鏡写しで保存するのに意外と手こずったので備忘録.
CustomView
import Cocoa
import AVFoundation
class CameraView: NSView {
let output = AVCaptureMovieFileOutput() // ファイル出力用
let session = AVCaptureSession()
var camera: AVCaptureDevice? = nil
var previewLayer: AVCaptureVideoPreviewLayer? = nil // プレビュー用
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
wantsLayer = true
let devices = AVCaptureDevice.devices(for: AVMediaType.video)
if devices.count > 0 {
camera = devices.first!
} else {
Swift.print("No Available Devices")
return
}
do {
let input = try AVCaptureDeviceInput(device: camera!)
// プレビューの設定
if session.canAddInput(input) {
session.addInput(input)
session.sessionPreset = AVCaptureSession.Preset.medium
previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer!.frame = bounds
previewLayer!.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer!.setAffineTransform(CGAffineTransform(scaleX: -1, y: 1))
layer?.addSublayer(previewLayer!)
}
// ファイル出力の設定
if session.canAddOutput(output) {
session.addOutput(output)
// ここからが鏡写しのキモ
session.beginConfiguration()
if let connection = output.connection(with: AVMediaType.video) {
if connection.isVideoMirroringSupported {
connection.automaticallyAdjustsVideoMirroring = false
connection.isVideoMirrored = true
}
}
session.commitConfiguration()
}
} catch {
Swift.print("No Available Devices")
}
}
// 画面のリサイズ対応
public func resizeWindow() {
previewLayer!.frame = bounds
}
}
ViewController
import Cocoa
import AVFoundation
class CameraVC: NSViewController, NSWindowDelegate, AVCaptureFileOutputRecordingDelegate {
@IBOutlet weak var cameraView: CameraView!
override func viewDidLoad() {
super.viewDidLoad()
cameraView.session.startRunning()
}
override func viewWillAppear() {
self.view.window?.delegate = self
}
override func viewWillDisappear() {
cameraView.output.stopRecording()
cameraView.session.stopRunning()
}
// 画面のリサイズに対応
func windowDidResize(_ notification: Notification) {
cameraView.resizeWindow()
}
public func startRecording() {
let fileName = "sample.mov"
// とりあえず書類フォルダに保存する
guard let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return
}
let url = docDir.appendingPathComponent(fileName)
cameraView.output.startRecording(to: url, recordingDelegate: self)
}
public func stopRecording() {
cameraView.output.stopRecording()
}
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
Swift.print("Finish Recording.")
}
}