mirror of
git://jb55.com/damus
synced 2024-09-30 00:40:45 +00:00
camera: add PhotoCaptureProcessor and VideoCaptureProcessor
This commit is contained in:
parent
476f52562a
commit
88b3c6fe8d
@ -416,6 +416,8 @@
|
||||
9C83F89329A937B900136C08 /* TextViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83F89229A937B900136C08 /* TextViewWrapper.swift */; };
|
||||
9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */; };
|
||||
BA37598A2ABCCDE40018D73B /* ImageResizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759892ABCCDE30018D73B /* ImageResizer.swift */; };
|
||||
BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */; };
|
||||
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */; };
|
||||
BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */; };
|
||||
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */; };
|
||||
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
|
||||
@ -1096,6 +1098,8 @@
|
||||
9C83F89229A937B900136C08 /* TextViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewWrapper.swift; sourceTree = "<group>"; };
|
||||
9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachMediaUtility.swift; sourceTree = "<group>"; };
|
||||
BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; };
|
||||
BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCaptureProcessor.swift; sourceTree = "<group>"; };
|
||||
BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCaptureProcessor.swift; sourceTree = "<group>"; };
|
||||
BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEmojiView.swift; sourceTree = "<group>"; };
|
||||
BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiListItemView.swift; sourceTree = "<group>"; };
|
||||
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
|
||||
@ -2258,6 +2262,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BA3759892ABCCDE30018D73B /* ImageResizer.swift */,
|
||||
BA37598B2ABCCE500018D73B /* PhotoCaptureProcessor.swift */,
|
||||
BA37598C2ABCCE500018D73B /* VideoCaptureProcessor.swift */,
|
||||
);
|
||||
path = Camera;
|
||||
sourceTree = "<group>";
|
||||
@ -2713,6 +2719,7 @@
|
||||
4C2859602A12A2BE004746F7 /* SupporterBadge.swift in Sources */,
|
||||
4C1A9A2A29DDF54400516EAC /* DamusVideoPlayer.swift in Sources */,
|
||||
4CA352A22A76AEC5003BB08B /* LikedNotify.swift in Sources */,
|
||||
BA37598D2ABCCE500018D73B /* PhotoCaptureProcessor.swift in Sources */,
|
||||
4C9146FD2A2A87C200DDEA40 /* wasm.c in Sources */,
|
||||
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
||||
4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */,
|
||||
@ -2877,6 +2884,7 @@
|
||||
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
|
||||
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
|
||||
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
|
||||
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */,
|
||||
4C9B0DF32A65C46800CBDA21 /* ProfileEditButton.swift in Sources */,
|
||||
4C32B95F2A9AD44700DC3548 /* Enum.swift in Sources */,
|
||||
4C2859622A12A7F0004746F7 /* GoldSupportGradient.swift in Sources */,
|
||||
|
91
damus/Models/Camera/PhotoCaptureProcessor.swift
Normal file
91
damus/Models/Camera/PhotoCaptureProcessor.swift
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// PhotoCaptureProcessor.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Suhail Saqan on 8/5/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Photos
|
||||
|
||||
class PhotoCaptureProcessor: NSObject {
|
||||
private(set) var requestedPhotoSettings: AVCapturePhotoSettings
|
||||
private(set) var photoOutput: AVCapturePhotoOutput?
|
||||
|
||||
lazy var context = CIContext()
|
||||
var photoData: Data?
|
||||
private var maxPhotoProcessingTime: CMTime?
|
||||
|
||||
private let willCapturePhotoAnimation: () -> Void
|
||||
private let completionHandler: (PhotoCaptureProcessor) -> Void
|
||||
private let photoProcessingHandler: (Bool) -> Void
|
||||
|
||||
init(with requestedPhotoSettings: AVCapturePhotoSettings,
|
||||
photoOutput: AVCapturePhotoOutput?,
|
||||
willCapturePhotoAnimation: @escaping () -> Void,
|
||||
completionHandler: @escaping (PhotoCaptureProcessor) -> Void,
|
||||
photoProcessingHandler: @escaping (Bool) -> Void) {
|
||||
self.requestedPhotoSettings = requestedPhotoSettings
|
||||
self.willCapturePhotoAnimation = willCapturePhotoAnimation
|
||||
self.completionHandler = completionHandler
|
||||
self.photoProcessingHandler = photoProcessingHandler
|
||||
self.photoOutput = photoOutput
|
||||
}
|
||||
|
||||
func capturePhoto(settings: AVCapturePhotoSettings) {
|
||||
if let photoOutput = self.photoOutput {
|
||||
photoOutput.capturePhoto(with: settings, delegate: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PhotoCaptureProcessor: AVCapturePhotoCaptureDelegate {
|
||||
func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
|
||||
maxPhotoProcessingTime = resolvedSettings.photoProcessingTimeRange.start + resolvedSettings.photoProcessingTimeRange.duration
|
||||
}
|
||||
|
||||
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
|
||||
DispatchQueue.main.async {
|
||||
self.willCapturePhotoAnimation()
|
||||
}
|
||||
|
||||
guard let maxPhotoProcessingTime = maxPhotoProcessingTime else {
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.photoProcessingHandler(true)
|
||||
}
|
||||
|
||||
let oneSecond = CMTime(seconds: 2, preferredTimescale: 1)
|
||||
if maxPhotoProcessingTime > oneSecond {
|
||||
DispatchQueue.main.async {
|
||||
self.photoProcessingHandler(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
|
||||
DispatchQueue.main.async {
|
||||
self.photoProcessingHandler(false)
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
print("Error capturing photo: \(error)")
|
||||
} else {
|
||||
photoData = photo.fileDataRepresentation()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {
|
||||
if let error = error {
|
||||
print("Error capturing photo: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.completionHandler(self)
|
||||
}
|
||||
}
|
||||
}
|
77
damus/Models/Camera/VideoCaptureProcessor.swift
Normal file
77
damus/Models/Camera/VideoCaptureProcessor.swift
Normal file
@ -0,0 +1,77 @@
|
||||
//
|
||||
// VideoCaptureProcessor.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Suhail Saqan on 8/5/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import Photos
|
||||
|
||||
class VideoCaptureProcessor: NSObject {
|
||||
private(set) var movieOutput: AVCaptureMovieFileOutput?
|
||||
|
||||
private let beginHandler: () -> Void
|
||||
private let completionHandler: (VideoCaptureProcessor, URL) -> Void
|
||||
private let videoProcessingHandler: (Bool) -> Void
|
||||
private var session: AVCaptureSession?
|
||||
|
||||
init(movieOutput: AVCaptureMovieFileOutput?,
|
||||
beginHandler: @escaping () -> Void,
|
||||
completionHandler: @escaping (VideoCaptureProcessor, URL) -> Void,
|
||||
videoProcessingHandler: @escaping (Bool) -> Void) {
|
||||
self.beginHandler = beginHandler
|
||||
self.completionHandler = completionHandler
|
||||
self.videoProcessingHandler = videoProcessingHandler
|
||||
self.movieOutput = movieOutput
|
||||
}
|
||||
|
||||
func startCapture(session: AVCaptureSession) {
|
||||
if let movieOutput = self.movieOutput, session.isRunning {
|
||||
let outputFileURL = uniqueOutputFileURL()
|
||||
movieOutput.startRecording(to: outputFileURL, recordingDelegate: self)
|
||||
}
|
||||
}
|
||||
|
||||
func stopCapture() {
|
||||
if let movieOutput = self.movieOutput {
|
||||
if movieOutput.isRecording {
|
||||
movieOutput.stopRecording()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func uniqueOutputFileURL() -> URL {
|
||||
let tempDirectory = FileManager.default.temporaryDirectory
|
||||
let fileName = UUID().uuidString + ".mov"
|
||||
return tempDirectory.appendingPathComponent(fileName)
|
||||
}
|
||||
}
|
||||
|
||||
extension VideoCaptureProcessor: AVCaptureFileOutputRecordingDelegate {
|
||||
|
||||
func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
|
||||
DispatchQueue.main.async {
|
||||
self.beginHandler()
|
||||
}
|
||||
}
|
||||
|
||||
func fileOutput(_ output: AVCaptureFileOutput, willFinishRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
|
||||
DispatchQueue.main.async {
|
||||
self.videoProcessingHandler(true)
|
||||
}
|
||||
}
|
||||
|
||||
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
|
||||
if let error = error {
|
||||
print("Error capturing video: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.completionHandler(self, outputFileURL)
|
||||
self.videoProcessingHandler(false)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user