인디노트

Swift 에서 화면(Screen) 캡춰와 녹화관련 본문

소스 팁/Objective C, Swift, iOS, macOS

Swift 에서 화면(Screen) 캡춰와 녹화관련

인디개발자 2021. 4. 17. 11:49

github.com/nirix/swift-screencapture

 

nirix/swift-screencapture

A Swift framework to easily capture the screen on OS X. - nirix/swift-screencapture

github.com

 

AppDelegate.swift

//
//  AppDelegate.swift
//  Example
//
//  Created by Jack P. on 11/12/2015.
//  Copyright © 2015 Jack P. All rights reserved.
//

import Cocoa
import AVKit
import AVFoundation
import ScreenCapture

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!
    @IBOutlet weak var imgView: NSImageView!
    @IBOutlet weak var playerView: AVPlayerView!
    @IBOutlet weak var startRecordingBtn: NSButton!
    @IBOutlet weak var stopRecordingBtn: NSButton!
    
    let tmpDir: String = NSTemporaryDirectory()
    var player: AVPlayer?
    
    var screenRecorder: ScreenCapture.ScreenRecorder?

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        stopRecordingBtn.isEnabled = false
    }

    func applicationWillTerminate(aNotification: NSNotification) {
        do {
            if (FileManager.default.fileExists(atPath: "\(self.tmpDir)captureRegion.png")) {
                try FileManager.default.removeItem(atPath: "\(self.tmpDir)captureRegion.png")
            }
            
            if (FileManager.default.fileExists(atPath: "\(self.tmpDir)captureScreen.png")) {
                try FileManager.default.removeItem(atPath: "\(self.tmpDir)captureScreen.png")
            }
            
            if (FileManager.default.fileExists(atPath: "\(self.tmpDir)screenRecording.mp4")) {
                try FileManager.default.removeItem(atPath: "\(self.tmpDir)screenRecording.mp4")
            }
        } catch {}
    }
    
    @IBAction func captureRegion(sender: NSButton) {
        let imgPath: String = ScreenCapture.captureRegion("\(self.tmpDir)captureRegion.png").path
        
        if (FileManager.default.fileExists(atPath: imgPath)) {
            let img: NSImage = NSImage(contentsOfFile: imgPath)!
            imgView.image = img
        }
    }
    
    @IBAction func captureScreen(sender: NSButton) {
        window.performMiniaturize(sender)
        let imgPath: String = ScreenCapture.captureScreen("\(self.tmpDir)captureScreen.png").path
        let img: NSImage = NSImage(contentsOfFile: imgPath)!
        imgView.image = img
    }
    
    @IBAction func startRecording(sender: NSButton) {
        do {
            if (FileManager.default.fileExists(atPath: "\(self.tmpDir)screenRecording.mp4")) {
                try FileManager.default.removeItem(atPath: "\(self.tmpDir)screenRecording.mp4")
            }
        } catch {}
        
        startRecordingBtn.isEnabled = false
        stopRecordingBtn.isEnabled = true
        screenRecorder = ScreenCapture.recordScreen("\(self.tmpDir)screenRecording.mp4")
        screenRecorder!.start()
    }
    
    @IBAction func stopRecording(sender: NSButton) {
        screenRecorder!.stop()
        
        startRecordingBtn.isEnabled = true
        stopRecordingBtn.isEnabled = false
        
        debugPrint(screenRecorder!.destination)
    }
    
    
    // It's better to seperate the playback function cause the stopRunning / writing video process may take some time
    @IBAction func playback(_ sender: NSButton) {
        
        self.player = AVPlayer(url: screenRecorder!.destination)
        self.playerView.player = self.player
        self.playerView.player?.play()
    }
}

ScreenCapture.swift

//
//  ScreenCapture.swift
//  ScreenCapture
//
//  Created by Jack P. on 11/12/2015.
//  Copyright © 2015 Jack P. All rights reserved.
//

import Foundation

// -------------------------------------------------------------------
// Allow passing of strings, just convert them to an NSURL.

public func captureRegion(_ destination: String) -> URL {
    return captureRegion(URL(fileURLWithPath: destination))
}

public func captureScreen(_ destination: String) -> URL {
    return captureScreen(URL(fileURLWithPath: destination))
}

public func recordScreen(_ destination: String) -> ScreenRecorder {
    return recordScreen(URL(fileURLWithPath: destination))
}

// -------------------------------------------------------------------

public func captureRegion(_ destination: URL) -> URL {
    let destinationPath = destination.path as String
    
    let task = Process()
    task.launchPath = "/usr/sbin/screencapture"
    task.arguments = ["-i", "-r", destinationPath]
    task.launch()
    task.waitUntilExit()
    
    return destination
}

public func captureScreen(_ destination: URL) -> URL {
    let img = CGDisplayCreateImage(CGMainDisplayID())
    let dest = CGImageDestinationCreateWithURL(destination as CFURL, kUTTypePNG, 1, nil)
    CGImageDestinationAddImage(dest!, img!, nil)
    CGImageDestinationFinalize(dest!)
    
    return destination
}

public func recordScreen(_ destination: URL) -> ScreenRecorder {
    return ScreenRecorder(destination: destination)
}

 

ScreenRecorder.swift

//
//  ScreenRecorder.swift
//  ScreenCapture
//
//  Created by Jack P. on 11/12/2015.
//  Copyright © 2015 Jack P. All rights reserved.
//

import Foundation
import AVFoundation

open class ScreenRecorder: NSObject, AVCaptureFileOutputRecordingDelegate {
	public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
		
	}
	
    let destinationUrl: URL
    let session: AVCaptureSession
    let movieFileOutput: AVCaptureMovieFileOutput
    
    open var destination: URL {
        get {
            return self.destinationUrl
        }
    }

    public init(destination: URL) {
        destinationUrl = destination
        
        session = AVCaptureSession()
		session.sessionPreset = AVCaptureSession.Preset.high
        
        let displayId: CGDirectDisplayID = CGDirectDisplayID(CGMainDisplayID())

        let input: AVCaptureScreenInput = AVCaptureScreenInput(displayID: displayId)

        
        if session.canAddInput(input) {
            session.addInput(input)
        }
        
        movieFileOutput = AVCaptureMovieFileOutput()

        if session.canAddOutput(movieFileOutput) {
            session.addOutput(movieFileOutput)
        }
        
    }
 
    open func start() {
        session.startRunning()
		movieFileOutput.startRecording(to: self.destinationUrl, recordingDelegate: self)
    }
    
    open func stop() {
        movieFileOutput.stopRecording()
    }
    
    open func capture(
        _ captureOutput: AVCaptureFileOutput!,
        didFinishRecordingToOutputFileAt outputFileURL: URL!,
        fromConnections connections: [Any]!,
        error: Error!
    ) {
        //
        session.stopRunning()
    }
}
반응형
Comments