]> git.r.bdr.sh - rbdr/captura/blob - Captura/Domain/CapturaCaptureSession.swift
Add multimonitor support
[rbdr/captura] / Captura / Domain / CapturaCaptureSession.swift
1 import AppKit
2 import AVFoundation
3
4 class CapturaCaptureSession: AVCaptureSession, AVCaptureFileOutputRecordingDelegate, AVCaptureVideoDataOutputSampleBufferDelegate {
5
6 let videoOutput = AVCaptureVideoDataOutput()
7 let movieFileOutput = AVCaptureMovieFileOutput()
8 var receivedFrames = false
9
10 init(_ screen: NSScreen, box: NSRect) {
11 super.init()
12
13 let displayId = screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as! CGDirectDisplayID
14 let screenInput = AVCaptureScreenInput(displayID: displayId)
15 var croppingBox = NSOffsetRect(box, -screen.frame.origin.x, -screen.frame.origin.y)
16 if croppingBox.width.truncatingRemainder(dividingBy: 2) != 0 {
17 croppingBox.size.width -= 1
18 }
19 screenInput?.cropRect = croppingBox.insetBy(dx: 1, dy: 1)
20
21 if self.canAddInput(screenInput!) {
22 self.addInput(screenInput!)
23 }
24
25 videoOutput.setSampleBufferDelegate(self, queue: Dispatch.DispatchQueue(label: "sample buffer delegate", attributes: []))
26
27 if self.canAddOutput(videoOutput) {
28 self.addOutput(videoOutput)
29 }
30
31 if self.canAddOutput(movieFileOutput) {
32 self.addOutput(movieFileOutput)
33 }
34 }
35
36 func startRecording() {
37 receivedFrames = false
38 self.startRunning()
39
40 DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
41 if !self.receivedFrames {
42 NotificationCenter.default.post(name: .failedToStart, object: nil, userInfo: nil)
43 }
44 }
45 }
46
47 func startRecording(to url: URL) {
48 self.startRecording()
49 movieFileOutput.startRecording(to: url, recordingDelegate: self)
50 }
51
52 // MARK: - AVCaptureVideoDataOutputSampleBufferDelegate Implementation
53
54 func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
55 receivedFrames = true
56
57 guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
58 NotificationCenter.default.post(name: .receivedFrame, object: nil, userInfo: ["frame": imageBuffer])
59 }
60
61 // MARK: - AVCaptureFileOutputRecordingDelegate Implementation
62
63 func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {}
64 }