Reputation: 453
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
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
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
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
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
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