-
-
Save cleexiang/e1fe70387b00ca9fb7059c6451a42263 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import AVFoundation | |
import Photos | |
import MobileCoreServices | |
class ViewController: UIViewController { | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
startVideoToGIFProcess() | |
} | |
func startVideoToGIFProcess() { | |
// Download the video and write it to temp storage | |
print("Downloading video…") | |
let data = try! Data(contentsOf: URL(string: "https://i.imgur.com/dXxP7a9.mp4")!) | |
let fileName = String(format: "%@_%@", ProcessInfo.processInfo.globallyUniqueString, "html5gif.mp4") | |
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName) | |
try! data.write(to: fileURL, options: [.atomic]) | |
createGIF(fromVideoAtURL: fileURL) | |
} | |
func createGIF(fromVideoAtURL url: URL) { | |
print("Downloaded!") | |
let frameRate: Int = 20 | |
let duration: TimeInterval = 9.68 | |
let totalFrames = Int(duration * TimeInterval(frameRate)) | |
let delayBetweenFrames: TimeInterval = 1.0 / TimeInterval(frameRate) | |
var timeValues: [NSValue] = [] | |
for frameNumber in 0 ..< totalFrames { | |
let seconds = TimeInterval(delayBetweenFrames) * TimeInterval(frameNumber) | |
let time = CMTime(seconds: seconds, preferredTimescale: Int32(NSEC_PER_SEC)) | |
timeValues.append(NSValue(time: time)) | |
} | |
let asset = AVURLAsset(url: url) | |
let generator = AVAssetImageGenerator(asset: asset) | |
generator.requestedTimeToleranceBefore = CMTime(seconds: 0.05, preferredTimescale: 600) | |
generator.requestedTimeToleranceAfter = CMTime(seconds: 0.05, preferredTimescale: 600) | |
let sizeModifier: CGFloat = 0.1 | |
generator.maximumSize = CGSize(width: 450.0 * sizeModifier, height: 563.0 * sizeModifier) | |
// Set up resulting image | |
let fileProperties: [String: Any] = [ | |
kCGImagePropertyGIFDictionary as String: [ | |
kCGImagePropertyGIFLoopCount as String: 0 | |
] | |
] | |
let frameProperties: [String: Any] = [ | |
kCGImagePropertyGIFDictionary as String: [ | |
kCGImagePropertyGIFDelayTime: delayBetweenFrames | |
] | |
] | |
let resultingFilename = String(format: "%@_%@", ProcessInfo.processInfo.globallyUniqueString, "html5gif.gif") | |
let resultingFileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(resultingFilename) | |
let destination = CGImageDestinationCreateWithURL(resultingFileURL as CFURL, kUTTypeGIF, totalFrames, nil)! | |
CGImageDestinationSetProperties(destination, fileProperties as CFDictionary) | |
print("Converting to GIF…") | |
var framesProcessed = 0 | |
let startTime = CFAbsoluteTimeGetCurrent() | |
generator.generateCGImagesAsynchronously(forTimes: timeValues) { (requestedTime, resultingImage, actualTime, result, error) in | |
guard let resultingImage = resultingImage else { return } | |
framesProcessed += 1 | |
CGImageDestinationAddImage(destination, resultingImage, frameProperties as CFDictionary) | |
if framesProcessed == totalFrames { | |
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime | |
print("Done converting to GIF! Frames processed: \(framesProcessed) • Total time: \(timeElapsed) s.") | |
// Save to Photos just to check… | |
let result = CGImageDestinationFinalize(destination) | |
print("Did it succeed?", result) | |
if result { | |
print("Saving to Photos…") | |
PHPhotoLibrary.shared().performChanges({ | |
PHAssetCreationRequest.creationRequestForAssetFromImage(atFileURL: resultingFileURL) | |
}) { (saved, err) in | |
print("Saved?", saved) | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment