Creating thumbnail from local video in swift

IosSwiftIphoneVideo Capture

Ios Problem Overview


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.

Ios Solutions


Solution 1 - Ios

Translated with some edits from:

https://stackoverflow.com/questions/10221242/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

Solution 2 - Ios

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

Solution 3 - Ios

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

Solution 4 - Ios

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)")
}

Solution 5 - Ios

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.

Solution 6 - Ios

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()

Solution 7 - Ios

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

Solution 8 - Ios

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)}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRalphView Question on Stackoverflow
Solution 1 - IosBaseZenView Answer on Stackoverflow
Solution 2 - IosDavid SeekView Answer on Stackoverflow
Solution 3 - IosCodeBenderView Answer on Stackoverflow
Solution 4 - IosCarl SmithView Answer on Stackoverflow
Solution 5 - IosBilal ArslanView Answer on Stackoverflow
Solution 6 - IoscoraView Answer on Stackoverflow
Solution 7 - IosAryaa SkView Answer on Stackoverflow
Solution 8 - Iosuser11378394View Answer on Stackoverflow