LivePhotoUtilSwift
unknown
swift
11 days ago
4.5 kB
5
No Index
import Photos
import UIKit
import ImageIO
import MobileCoreServices
class LivePhotoUtilSwift: NSObject {
static func convertVideo(_ path: String, complete: @escaping (Bool, String?) -> Void) {
let metaURL = Bundle.main.url(forResource: "metadata", withExtension: "mov")
let livePhotoSize = CGSize(width: 1080, height: 1920)
let livePhotoDuration = CMTime(value: 550, timescale: 600)
let assetIdentifier = UUID().uuidString
let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let durationPath = documentPath + "/duration.mp4"
let acceleratePath = documentPath + "/accelerate.mp4"
let resizePath = documentPath + "/resize.mp4"
try? FileManager.default.removeItem(atPath: durationPath)
try? FileManager.default.removeItem(atPath: acceleratePath)
try? FileManager.default.removeItem(atPath: resizePath)
let finalPath = resizePath
let converter = Converter4Video(path: finalPath)
converter.durationVideo(at: path, outputPath: durationPath, targetDuration: 3) { success, error in
converter.accelerateVideo(at: durationPath, to: livePhotoDuration, outputPath: acceleratePath) { success, error in
converter.resizeVideo(at: acceleratePath, outputPath: resizePath, outputSize: livePhotoSize) { success, error in
let asset = AVURLAsset(url: URL(filePath: finalPath))
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
generator.requestedTimeToleranceAfter = .zero
generator.requestedTimeToleranceBefore = .zero
var times = [NSValue]()
let time = CMTime(value: CMTimeValue(0.5), timescale: asset.duration.timescale)
times.append(NSValue(time: time))
// serial queues are the default. No need to specify this.
let q = DispatchQueue(label: "image")
var index = 0
generator .generateCGImagesAsynchronously(forTimes: times) { requestedTime, image, actualTime, result, error in
guard let image else { return }
let picturePath = documentPath.appending(String(format: "/%@%d.heic", "live", index))
let videoPath = documentPath.appending(String(format: "/%@%d.mov", "live", index))
index += 1
try? FileManager.default.removeItem(atPath: picturePath)
try? FileManager.default.removeItem(atPath: videoPath)
let converter4Image = Converter4Image(image: UIImage(cgImage: image))
q.async {
print(picturePath)
print(videoPath)
converter4Image.write(dest: picturePath, assetIdentifier: assetIdentifier)
converter.write(dest: videoPath, assetIdentifier: assetIdentifier, metaURL: metaURL!) { success, error in
if !success {
print("merge failed: \(error)")
complete(false, error?.localizedDescription)
return
}
PHPhotoLibrary.shared().performChanges {
let request = PHAssetCreationRequest.forAsset()
let photoURL = URL(fileURLWithPath: picturePath)
let pairedVideoURL = URL(fileURLWithPath: videoPath)
request.addResource(with: .photo, fileURL: photoURL, options: PHAssetResourceCreationOptions())
request.addResource(with: .pairedVideo, fileURL: pairedVideoURL, options: PHAssetResourceCreationOptions())
} completionHandler: { success, error in
DispatchQueue.main.async {
complete(error == nil, error?.localizedDescription)
}
}
}
}
}
}
}
}
}
}
Editor is loading...