55

How to create thumbnail in swift from a local video file ?

For example if the video file path is located here :

file:///Users/Dev/Library/Developer/CoreSimulator/Devices/F33222DF-D8F0-448B-A127-C5B03C64D0DC/data/Containers/Data/Application/4BC62DBF-0108-453C-9324-5BC0E356FE24/tmp/trim.059D11E6-F0EF-43DB-9E97-CA4F1F95D6B6.MOV

Thank you.

BaseZen
  • 8,650
  • 3
  • 35
  • 47
Ralph
  • 2,065
  • 3
  • 15
  • 23

9 Answers9

74

BaseZen's answer translated Swift 3 / Swift 4

You need to set the location of the video you want to make a thumbnail of as the url asset path, like:

Don't forget to import AVFoundation

func generateThumbnail(path: URL) -> UIImage? {
    do {
        let asset = AVURLAsset(url: path, options: nil)
        let imgGenerator = AVAssetImageGenerator(asset: asset)
        imgGenerator.appliesPreferredTrackTransform = true
        let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
        let thumbnail = UIImage(cgImage: cgImage)
        return thumbnail
    } catch let error {
        print("*** Error generating thumbnail: \(error.localizedDescription)")
        return nil
    }
}

For everyone having issues with this I have created the following drop in example hosted on Github

Simon Bengtsson
  • 7,573
  • 3
  • 58
  • 87
David Seek
  • 16,783
  • 19
  • 105
  • 136
73

Translated with some edits from:

First frame of a video using AVFoundation

    var err: NSError? = nil
    let asset = AVURLAsset(URL: NSURL(fileURLWithPath: "/that/long/path"), options: nil)
    let imgGenerator = AVAssetImageGenerator(asset: asset)
    let cgImage = imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil, error: &err)
    // !! check the error before proceeding
    let uiImage = UIImage(CGImage: cgImage)
    let imageView = UIImageView(image: uiImage)
    // lay out this image view, or if it already exists, set its image property to uiImage
BaseZen
  • 8,650
  • 3
  • 35
  • 47
25

This is a cleaned up version of David's answer and tested against iOS 11 / Swift 4.x.

Please note the different calls for handling the initial time based on which version of Swift you are using.

func generateThumbnail(url: URL) -> UIImage? {
    do {
        let asset = AVURLAsset(url: url)
        let imageGenerator = AVAssetImageGenerator(asset: asset)
        imageGenerator.appliesPreferredTrackTransform = true
        // Select the right one based on which version you are using
        // Swift 4.2
        let cgImage = try imageGenerator.copyCGImage(at: .zero,
                                                     actualTime: nil)
        // Swift 4.0
        let cgImage = try imageGenerator.copyCGImage(at: kCMTimeZero,
                                                     actualTime: nil)


        return UIImage(cgImage: cgImage)
    } catch {
        print(error.localizedDescription)

        return nil
    }
}
  1. Creates an AVURLAsset from the provided URL
  2. Creates an AVAssetImageGenerator using the newly created AVURLAsset, is responsible for making the thumbnail
  3. appliesPreferredTrackTransform informs the generator to apply the matrix to the thumbnail generation. The default value is false.
  4. Attempts to create a CGImage at the first frame of the video track
  5. Creates a UIImage using the newly created CGImage & returns it
  6. If the image generation step fails, an error is caught and presented to the console along with a nil UIImage
CodeBender
  • 35,668
  • 12
  • 125
  • 132
13

BaseZen's answer translated to Swift 2:

import UIKit
import AVFoundation

do {
    let asset = AVURLAsset(URL: NSURL(fileURLWithPath: "/that/long/path"), options: nil)
    let imgGenerator = AVAssetImageGenerator(asset: asset)
    imgGenerator.appliesPreferredTrackTransform = true
    let cgImage = try imgGenerator.copyCGImageAtTime(CMTimeMake(0, 1), actualTime: nil)
    let uiImage = UIImage(CGImage: cgImage)
    let imageView = UIImageView(image: uiImage)
    // lay out this image view, or if it already exists, set its image property to uiImage
} catch let error as NSError {
    print("Error generating thumbnail: \(error)")
}
Carl Smith
  • 1,236
  • 15
  • 18
13

It's better to write less and simple code for understanding. This is what I convert the solutions in Swift (3.1 ... 5.2)

import AVFoundation

func imagePreview(from moviePath: URL, in seconds: Double) -> UIImage? {
    let timestamp = CMTime(seconds: seconds, preferredTimescale: 60)
    let asset = AVURLAsset(url: moviePath)
    let generator = AVAssetImageGenerator(asset: asset)
    generator.appliesPreferredTrackTransform = true

    guard let imageRef = try? generator.copyCGImage(at: timestamp, actualTime: nil) else {
        return nil
    }
    return UIImage(cgImage: imageRef)
}

Hope it will help someone.

Bilal Arslan
  • 307
  • 3
  • 10
5

Swift 5.3

As an alternative to other answers, with slight modification I decided to make an URL extension.

import AVFoundation

extension URL {
    func generateThumbnail() -> UIImage? {
        do {
            let asset = AVURLAsset(url: self)
            let imageGenerator = AVAssetImageGenerator(asset: asset)
            imageGenerator.appliesPreferredTrackTransform = true
            
            // Swift 5.3
            let cgImage = try imageGenerator.copyCGImage(at: .zero,
                                                         actualTime: nil)

            return UIImage(cgImage: cgImage)
        } catch {
            print(error.localizedDescription)

            return nil
        }
    }
}

Usage:

let image = someURL.generateThumbnail()
cora
  • 1,916
  • 1
  • 10
  • 18
1

Here is how you generate a thumbnail (first frame) of a video in swift 5:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
    
        let video = AVURLAsset(url: URL(fileURLWithPath: Bundle.main.path(forResource: "sampleVideo", ofType: "mov")!))
        let thumbnailGenerator = AVAssetImageGenerator(asset: video)
    
        do
        {
            let cgImage = try thumbnailGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
            let UiImage = UIImage(cgImage: cgImage)
            imageView.image = UiImage
        }
        catch
        { print(error) }
    
    }

}

In this example the video name is sampleVideo.mov (change the file url to the name of your video file), make sure you import the video into your local Xcode project and add it to your app's target.

I have make a youtube explaining this here

Aryaa Sk
  • 81
  • 1
  • 5
0
func saveImageDocumentDirectoryWithDate(tempImage:UIImage, block : @escaping (_ url: URL?) -> Void ){

    let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

    let random : String =  randomString(length: 5)

    let fileURL = documentsDirectoryURL.appendingPathComponent(String(format:"CPImage%@.png",random))
    do { try tempImage.pngData()?.write(to: fileURL) }
    catch { block(nil) }
    block(fileURL)}
mle
  • 2,466
  • 1
  • 19
  • 25
0

You can use Kingfisher to generate the thumbnail.

Note:- It will handle all the cache work for you.

Usage:-

Step 1

import Kingfisher

Step 2

guard let url = URL(string: videoUrlString) else { return }
self.imageView.kf.setImage(with: AVAssetImageDataProvider(assetURL: url, seconds: 1))

Here is the link of Kingfisher SDK

Note:- It will work fine with latest version of kingfisher/ higher or equals to version 7.2.3