Skip to content

Commit

Permalink
Merge pull request #2217 from anyproto/ios-3181-show-attachments-in-m…
Browse files Browse the repository at this point in the history
…essage-list

iOS-3181 Video preview storage | migrate to actor (to chat)
  • Loading branch information
mgolovko authored Oct 15, 2024
2 parents 0067307 + 57710e6 commit 854e495
Showing 1 changed file with 29 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ protocol VideoPreviewStorageProtocol {
func preview(url: URL, size: CGSize) async throws -> UIImage
}

final class VideoPreviewStorage: VideoPreviewStorageProtocol {
actor VideoPreviewStorage: VideoPreviewStorageProtocol {

private struct StorageKey: Hashable {
let url: URL
let size: CGSize
}

private var taskCache = [StorageKey: Task<UIImage, any Error>]()
private let storage: Storage<StorageKey, UIImage>?

private let operationsQueue = DispatchQueue(label: "VideoPreviewQueue")

init() {
let diskConfig = DiskConfig(name: "VideoPreviewCache", maxSize: 30 * 1024 * 1024) // 30 Mb
let memoryConfig = MemoryConfig(expiry: .never, countLimit: 100, totalCostLimit: 300)
Expand All @@ -31,58 +30,42 @@ final class VideoPreviewStorage: VideoPreviewStorageProtocol {
}

func preview(url: URL, size: CGSize) async throws -> UIImage {
return try await withCheckedThrowingContinuation { continuation in
loadPreviewInQueue(url: url, size: size) { result in
switch result {
case .success(let success):
continuation.resume(returning: success)
case .failure(let failure):
continuation.resume(throwing: failure)
}
}
}
}

private func loadPreviewInQueue(url: URL, size: CGSize, completion: @escaping (Result<UIImage, any Error>) -> Void) {

let key = StorageKey(url: url, size: size)

operationsQueue.async { [weak self] in

guard let self else {
completion(.failure(CommonError.undefined))
return
}

if let image = try? storage?.object(forKey: key) {
completion(.success(image))
return
}

guard let image = UIImage(videoPreview: url, size: size) else {
completion(.failure(CommonError.undefined))
return
}

if let task = taskCache[key] {
return try await task.value
}

if let image = try? storage?.object(forKey: key) {
return image
}

let task = Task {
return try UIImage(videoPreview: url, size: size)
}

taskCache[key] = task

do {
let image = try await task.value
try? storage?.setObject(image, forKey: key)
completion(.success(image))
return image
} catch {
taskCache[key] = nil
throw error
}
}
}

fileprivate extension UIImage {

convenience init?(videoPreview path: URL?, size: CGSize) {
guard let path else { return nil }
do {
let asset = AVURLAsset(url: path, options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
imgGenerator.maximumSize = size
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
self.init(cgImage: cgImage)
} catch {
return nil
}
convenience init(videoPreview path: URL, size: CGSize) throws {
let asset = AVURLAsset(url: path, options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
imgGenerator.maximumSize = size
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
self.init(cgImage: cgImage)
}
}

0 comments on commit 854e495

Please sign in to comment.