Skip to content

Instantly share code, notes, and snippets.

@cleexiang
Forked from christianselig/video-to-gif.swift
Created February 21, 2023 03:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cleexiang/e1fe70387b00ca9fb7059c6451a42263 to your computer and use it in GitHub Desktop.
Save cleexiang/e1fe70387b00ca9fb7059c6451a42263 to your computer and use it in GitHub Desktop.
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