1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
silica-viewer/SilicaViewer/AppDelegate.swift

148 lines
6.5 KiB
Swift

import Cocoa
import ZIPFoundation
import AVFoundation
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations {
var exporter: AVAssetExportSession?
@IBAction func showInfoAction(_ sender: Any) {
NSApplication.shared.keyWindow?.contentViewController?.performSegue(withIdentifier: "showInfo", sender: self)
}
@IBAction func showTimelapseAction(_ sender: Any) {
NSApplication.shared.keyWindow?.contentViewController?.performSegue(withIdentifier: "showTimelapse", sender: self)
}
func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
// Show timelapse and show info buttons
if(item.tag == 67 || item.tag == 68) {
return NSApplication.shared.keyWindow != nil
}
return true
}
@IBAction func exportAction(_ sender: Any) {
let document = NSApplication.shared.keyWindow?.windowController?.document as? Document;
let savePanel = NSSavePanel()
savePanel.title = "Save"
savePanel.allowedFileTypes = ["public.png", "public.jpeg"]
savePanel.accessoryView = ExportAccessoryView.fromNib()
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
let canvas = document?.makeComposite()
let canvasTiff = canvas?.tiffRepresentation
let bitmapImage = NSBitmapImageRep(data: canvasTiff!)
let canvasPng = bitmapImage!.representation(using: .png, properties: [:])
try? canvasPng?.write(to: savePanel.url!)
}
}
}
@IBAction func exportThumbnailAction(_ sender: Any) {
let document = NSApplication.shared.keyWindow?.windowController?.document as? Document;
let savePanel = NSSavePanel()
savePanel.title = "Save Thumbnail"
savePanel.allowedFileTypes = ["public.png"]
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
let canvas = document?.makeThumbnail()
let canvasTiff = canvas?.tiffRepresentation
let bitmapImage = NSBitmapImageRep(data: canvasTiff!)
let canvasPng = bitmapImage!.representation(using: .png, properties: [:])
try? canvasPng?.write(to: savePanel.url!)
}
}
}
@IBAction func exportTimelapseAction(_ sender: Any) {
guard let originalWindow = NSApplication.shared.keyWindow else {
return
}
let document = originalWindow.windowController?.document as? Document;
let savePanel = NSSavePanel()
savePanel.title = "Save Timelapse"
savePanel.allowedFileTypes = ["public.mpeg-4"]
savePanel.begin { (result) in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
guard let archive = Archive(data: (document?.data)!, accessMode: Archive.AccessMode.read) else {
return
}
let directory = NSTemporaryDirectory()
let mixComposition = AVMutableComposition()
var instructions: [AVMutableVideoCompositionLayerInstruction] = []
var duration = CMTime.zero
for entry in archive.makeIterator() {
if entry.path.contains(VideoPath) {
let fileName = NSUUID().uuidString + ".mp4"
// This returns a URL? even though it is an NSURL class method
let fullURL = NSURL.fileURL(withPathComponents: [directory, fileName])!
let _ = try? archive.extract(entry, to: fullURL)
let asset = AVAsset(url: fullURL)
guard let track = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else {
return
}
try? track.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration),
of: asset.tracks(withMediaType: .video)[0],
at: duration)
duration = CMTimeAdd(duration, asset.duration)
let opacityInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
opacityInstruction.setOpacity(0.0, at: duration + asset.duration)
instructions.append(opacityInstruction)
}
}
let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: duration)
mainInstruction.layerInstructions = instructions
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [mainInstruction]
mainComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
mainComposition.renderSize = CGSize(width: document!.info.videoFrame.0, height: document!.info.videoFrame.1)
self.exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
self.exporter?.outputURL = savePanel.url!
self.exporter?.outputFileType = AVFileType.mp4
self.exporter?.videoComposition = mainComposition
let alert = NSAlert()
alert.messageText = "Exporting timelapse..."
alert.addButton(withTitle: "Cancel")
alert.beginSheetModal(for: originalWindow) { (resonse) in
self.exporter?.cancelExport()
alert.window.close()
}
self.exporter?.exportAsynchronously {
if self.exporter?.status != .cancelled {
DispatchQueue.main.sync {
alert.window.close()
}
}
}
}
}
}
}