I have VideoThumbnailManager and It serves to cache with SDWebImage the image of the video and display it to the user. But the Video thumbnail is showing 2 on the collectionview. but when I scroll, the collectionview changes and becomes correct. how do i solve this problem?
result :
//
// VideoThumbnailManager.swift
// Created by erhan demirci on 26.04.2023.
import Foundation
import AVFoundation
import SDWebImage
class VideoThumbnailManager {
static let shared = VideoThumbnailManager()
func generateThumbnailImage(for videoURL: URL, completion: @escaping (UIImage?) -> Void) {
let options: SDWebImageOptions = [.scaleDownLargeImages, .continueInBackground]
let cacheKey = SDWebImageManager.shared.cacheKey(for: videoURL)
if let cachedImage = SDImageCache.shared.imageFromCache(forKey: cacheKey) {
// Return cached image if available
completion(cachedImage)
} else {
// Generate new thumbnail image
let asset = AVAsset(url: videoURL)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
imageGenerator.maximumSize = CGSize(width: 100, height: 100)
let timestamp = CMTime(seconds: 1.0, preferredTimescale: 60)
imageGenerator.generateCGImagesAsynchronously(forTimes: [NSValue(time: timestamp)]) { (requestedTime, cgImage, actualTime, result, error) in
if let cgImage = cgImage {
let thumbnailImage = UIImage(cgImage: cgImage)
completion(thumbnailImage)
// Cache thumbnail image
if let data = thumbnailImage.jpegData(compressionQuality: 0.8) {
SDImageCache.shared.storeImageData(toDisk: data, forKey: cacheKey)
}
} else {
completion(nil)
}
}
}
}
}
my collection view cell
class TemplateCell: UICollectionViewCell {
@IBOutlet weak var thumbnailImageView: UIImageView!
func configure(with videoURL: URL) {
self.videoURL = videoURL
}
func loadVideo() {
guard let videoURL = self.videoURL else {
return
}
// use the VideoCacheManager to get the video asset and thumbnail image
VideoThumbnailManager.shared.generateThumbnailImage(for: videoURL) { thumbnail in
DispatchQueue.main.async {
self.thumbnailImageView.image = thumbnail
}
}
}
func unloadVideo() {
self.videoPlayerLayer?.removeFromSuperlayer()
//self.videoPlayerLayer = nil
}
}
I use on collection view like that:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
///....
cell.configure(with: myUrl)
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
videoCell.loadVideo()
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
videoCell.unloadVideo()
}
You can read this answer to understand why this is happening. https://stackoverflow.com/a/76261182/5973760
There are different ways to get this done, try to implement below code.
VideoThumbnailManager.shared.generateThumbnailImage(for: videoURL) { (thumbnail,thubmVideoURL) in
DispatchQueue.main.async {
if thubmVideoURL == videoURL{
self.thumbnailImageView.image = thumbnail
}
}
}
Here you need to change the completion of your generateThumbnailImage()
function along with image pass the video url also.
completion(thumbnailImage,videoURL)
You can check the other approach also: https://stackoverflow.com/a/31844232/5973760