Charmi
Charmi

Reputation: 453

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.

Upvotes: 16

Views: 35576

Answers (5)

Sai kumar Reddy
Sai kumar Reddy

Reputation: 1829

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.

Author: https://www.swiftdevcenter.com

Upvotes: 13

Shivam Garg
Shivam Garg

Reputation: 117

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

Upvotes: 3

Shivam Garg
Shivam Garg

Reputation: 117

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

Upvotes: 1

Reimond Hill
Reimond Hill

Reputation: 4760

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.

Upvotes: 3

javimuu
javimuu

Reputation: 1859

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.

Upvotes: 33

Related Questions