'Get thumbail / preview image from a server video URL in Swift 3.0

I want a thumbnail image from a video underlying on the server. The video file is not on local. It's on my server. The video file has extension .m3u8.



Solution 1:[1]

You can do it.

First step: You need to import AVFoundation:

    import AVFoundation

Then add the code below to your controller:

func getThumbnailImage(forUrl url: URL) -> UIImage? {
    let asset: AVAsset = AVAsset(url: url)
    let imageGenerator = AVAssetImageGenerator(asset: asset)

    do {
        let thumbnailImage = try imageGenerator.copyCGImage(at: CMTimeMake(value: 1, timescale: 60), actualTime: nil)
        return UIImage(cgImage: thumbnailImage)
    } catch let error {
        print(error)
    }

    return nil
}

Usage:

    let imageView = UIImageView()
    let url = URL(string: "your_video_url")

    if let thumbnailImage = getThumbnailImage(forUrl: url) {
        imageView.image = thumbnailImage
    }

Change url to your video link.

Solution 2:[2]

Step 1

import AVFoundation

Step 2

Add the following function in your ViewController:

func getThumbnailImageFromVideoUrl(url: URL, completion: @escaping ((_ image: UIImage?)->Void)) {
    DispatchQueue.global().async { //1
        let asset = AVAsset(url: url) //2
        let avAssetImageGenerator = AVAssetImageGenerator(asset: asset) //3
        avAssetImageGenerator.appliesPreferredTrackTransform = true //4
        let thumnailTime = CMTimeMake(value: 2, timescale: 1) //5
        do {
            let cgThumbImage = try avAssetImageGenerator.copyCGImage(at: thumnailTime, actualTime: nil) //6
            let thumbNailImage = UIImage(cgImage: cgThumbImage) //7
            DispatchQueue.main.async { //8
                completion(thumbNailImage) //9
            }
        } catch {
            print(error.localizedDescription) //10
            DispatchQueue.main.async {
                completion(nil) //11
            }
        }
    }
}

Step 3

self.getThumbnailImageFromVideoUrl(url: videoUrl) { (thumbNailImage) in
    self.yourImageView.image = thumbNailImage
}

If you need a complete explanation, refer to Get a thumbnail from a video URL in the background in Swift.

Solution 3:[3]

In Swift 5.1 (older versions too), you can do it like this:

private func createVideoThumbnail(from url: URL) -> UIImage? {

    let asset = AVAsset(url: url)
    let assetImgGenerate = AVAssetImageGenerator(asset: asset)
    assetImgGenerate.appliesPreferredTrackTransform = true
    assetImgGenerate.maximumSize = CGSize(width: frame.width, height: frame.height)

    let time = CMTimeMakeWithSeconds(0.0, preferredTimescale: 600)
    do {
        let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
        let thumbnail = UIImage(cgImage: img)
        return thumbnail
    }
    catch {
      print(error.localizedDescription)
      return nil
    }

}

Note that AVKit needs to be imported.

Solution 4:[4]

In this solution, I have created a cache as well for the image so that we don't need to fetch the same images again from the internet.

 func createVideoThumbnail( url: String?,  completion: @escaping ((_ image: UIImage?)->Void)) {
    
    guard let url = URL(string: url ?? "") else { return }
    DispatchQueue.global().async {
        
        let url = url as URL
        let request = URLRequest(url: url)
        let cache = URLCache.shared
        
        if
            let cachedResponse = cache.cachedResponse(for: request),
            let image = UIImage(data: cachedResponse.data)
        {
            DispatchQueue.main.async {
                completion(image)
            }
        }
        
        let asset = AVAsset(url: url)
        let imageGenerator = AVAssetImageGenerator(asset: asset)
        imageGenerator.appliesPreferredTrackTransform = true
        
        var time = asset.duration
        time.value = min(time.value, 2)
        
        var image: UIImage?
        
        do {
            let cgImage = try imageGenerator.copyCGImage(at: time, actualTime: nil)
            image = UIImage(cgImage: cgImage)
        } catch { DispatchQueue.main.async {
            completion(nil)
        } }
        
        if
            let image = image,
            let data = image.pngData(),
            let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)
        {
            let cachedResponse = CachedURLResponse(response: response, data: data)
            
            cache.storeCachedResponse(cachedResponse, for: request)
        }
        
        DispatchQueue.main.async {
            completion(image)
        }
        
    }
    
}

Usage:

      createVideoThumbnail(url: data.url ?? "") { [weak self] (img) in
            guard let strongSelf = self else { return }
            if let image = img {
                strongSelf.mediaImg.image = image
            }
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Mortensen
Solution 2 Peter Mortensen
Solution 3 Peter Mortensen
Solution 4