Civil Ximp; amp; Structural Engineering
Kreatyng a Własny Video Thumbnail Generator ie IoosCity in New York USA wigh Avfoundation
Table of Contents
Video thumbnails are a cornerstone of modern medial-rich applications, offering users a quick visual preview with out needing to play the full video. In iOS development, AVFoundation provides the most performant and d flexible tools for extracting thumbnail images. Thi article walks the full videvelogh building a custim videmo thumbnail generator that can n handle realreald - includincluding local and ade files, caching, error handling, ance enche tuning - using - using Swift and Funidind.
Understanding AVFoundation 's Role in Thumbnail Generation
AVFoundation is accordies primary work for working wigh audiovisual media. For thumbnail generation, the key classes are indi.1; indi1; FLT: 0 condition 3; indis3; AVAsset indis1; indis1; FLT: 1 condis3; and indis1; indis1; FLT: 2 condis3; AVAssetImageGenerator endis1; FLT: 3 condis3; indis3.;
- Xi1; Xi1; FLT: 0 Xi3; Xi3; AVAsset Xi1; Xi1; FLT: 1 Xi3; Xi3;: Represents a timed audiovisaal asset (a local or remote video). It contains track information, duration, and metadata.
- Respekt: 1, 1, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
Using these classes directly gives you full control over image size, time closacy, and transformation, unlike UIKit shortcuts that often hide configuration options.
Setting Up thee Project
Start by by by importing AVFoundation into your Swift file:
import AVFoundation
You also need UIKit to display the generated images. Create an present 1; Ig1; FLT: 1 presendi3; Ig3; from a URL. For local files, use present 1; Ig.1; FLT: 2 presendi3; Iglo3; FLT: For remote videos, use presendi1; Iglo1; Iglo1; FLT: 3 presendise 3; and ensure thee asset can bee initialization:
// Local
let localURL = Bundle.main.url(forResource: "sample", withExtension: "mp4")!
let asset = AVAsset(url: localURL)
// Remote
let remoteURL = URL(string: "https://example.com/video.mp4")!
let remoteAsset = AVAsset(url: remoteURL)
Generating a Single Thumbnail
To generate one thumbnail at a specified time, create an indis1; endis1; FLT: 5 indis3; endis3; and call indis1; entis1; FLT: 6 indis3; entis3;. Thi methode is syncours and should be run off thee main thread two avoid blocking the UI.
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
let time = CMTime(seconds: 2.0, preferredTimescale: 600) // 2 seconds into the video
do {
let cgImage = try imageGenerator.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
// Update UI on main thread
DispatchQueue.main.async {
imageView.image = thumbnail
}
} catch {
print("Thumbnail generation failed: \(error.localizedDescription)")
}
Xi1; Xi1; FLT: 0 XI3; XI3; XI3; FLT: 1 XI1; XI3; FLTNG: 1 XI3; XI1; FLT: 8 XI3; XI3; XI1; FLT: 9 XI3; XI3; exires the resucting image respects the Video 's rotation metadata (portrait vs. landscape). Without this, an upright video might appear side ways.
Choosing the Right Time
Pseudonim are often taken at thee beginning of a video, but consider using a time that presents the content - np., 10% into the duration. To get a contexful time point, query the asset 's duration:
let duration = asset.duration
let midTime = CMTimeMultiplyByFloat64(duration, multiplier: 0.1)
Handling Errors andEdge Cases
Thumbnail generation can fail for sereal reasons. Always handle errs gracefuly andd provide fallback UI.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Invalid asset: Xi1; Xi1; FLT: 1 Xi3; Xi3; The video may be corruted or the URL unreachable.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Missing video track: Xi1; Xi1; FLT: 1 Xi3; Xi3; Some assets contain only audio; check Xi1; Xi1; FLT: 11 Xi3; Xi3;.
- Xi1; Xi1; FLT: 0 Xi3; Xi3; Time out of bounds: Xi1; Xi1; FLT: 1 Xi3; Xi3; Ensure the requested time is between Xi1; Xi1; FLT: 12 Xi3; Xi3; ande the asset 's duration.
- Remote assets may fail too load. Usie bee fail too load. Usie bee 1; FLT: 13 ema.europa.eu; Before generating thumbnails.
Example of preloading asset properties:
let assetKeys = ["tracks", "duration", "playable"]
asset.loadValuesAsynchronously(forKeys: assetKeys) {
var error: NSError?
let status = asset.statusOfValue(forKey: "tracks", error: &error)
if status == .loaded {
// Safe to generate thumbnails
} else {
// Handle error
}
}
Customizing Thumbnail Output
AVAssetImageGenerator offers several properties to fine- tune thee output image.
Maximum Size
Ograniczenie tego generated imagine to a specific bounding box using present 1; Xi1; FLT: 15 presents 3; Xi3;. This reduces memory overhead andd speeds up generation for large videos.
imageGenerator.maximumSize = CGSize(width: 640, height: 480)
Generated wyobraża sobie, że będzie to tylko fit z tymi wymiarami, podczas gdy zachowaj ving jako ratio.
Requested Time Tolerance
By default, Xi1; FLT: 17 exact 3; Xi3; returns the exact frame at the requested time (or as close as possible). You can trade closiacy for speed by setting Xi1; Xi1; FLT: 18 X3; Xi3; anddi1; Xi1; FLT: 19 Xi3; Xi3; Xi3; For thumbnails, a tolerance of 0.5 seconsis is often acceptable and faster:
imageGenerator.requestedTimeToleranceBefore = CMTime(seconds: 0.5, preferredTimescale: 600)
imageGenerator.requestedTimeToleranceAfter = CMTime(seconds: 0.5, preferredTimescale: 600)
Mode Apertury
Xi1; Xi1; FLT: 21 Xi3; Xi3; controls how the generated image handles s clean apertura vs. production apertura. Usie Xi1; Xi1; FLT: 22 Xion3; Xion3; tu remove edge dust and produce a cleaner thumbnail:
imageGenerator.apertureMode = .cleanAperture
Amplying Transformations
If you need to rotate or flip the image (np., for a specific orientationion), use Cora Graphics transformations. One approach is to capture the raw image andd then appey a CGaffineTransform manually. Alternatively, you can set presens 1; Iglo1; FLT: 24 contribution 3; Igloous 1; TO AF: 25 contribute 1; FLT: 25 contribute thee asset 's natural orientation.
Generating Multiple Thumbnails Efficiently
For video grids, timeline scrubbing, or storyboard previews, you often need dozens of thumbnails. Avoid calling indi.1; Ig1; FLT: 26 contribution 3; Ign a loop one thee main the maid. Instad, use thee asynchronours method indirec1; Ig1; FLT: 27 contribution 3; It processes multiple requests efficiently, leveraging internal paralelism.
var times: [NSValue] = []
for i in 0..<10 {
let time = CMTime(seconds: Double(i) * 2.0, preferredTimescale: 600)
times.append(NSValue(time: time))
}
imageGenerator.generateCGImagesAsynchronously(forTimes: times) { requestedTime, cgImage, actualTime, result, error in
if result == .succeeded, let cgImage = cgImage {
let thumbnail = UIImage(cgImage: cgImage)
DispatchQueue.main.async {
// Append to array or update collection view cell
}
} else {
print("Failed at \(requestedTime): \(error?.localizedDescription ?? "unknown")")
}
}
This methodscale well ande lets you update thee UI incrementally. Remember to call indis1; indi1; FLT: 29 condis3; indis3; if thee user leaves thee screen to free resources.
Working wigh Remote Videos
When the video URL points to a demote server, you must wait for thee asset to o be fuly loaded or at least ass it s track information to bo avaible. Use independence 1; independence 1; FLT: 30 context 3; index3; with appropriate caching headers to avoid repeated downts.
let urlAsset = AVURLAsset(url: remoteURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
urlAsset.loadValuesAsynchronously(forKeys: ["tracks"]) {
// Then create image generator and proceed
}
For production apps, consider caching thumbnails on disk so that repeated accessis to te same video does note re-fetch the image. Usie inde1; FLT: 32 index3; contex3; or file-based cache using the video URL as a key.
Caching Strategy Example
class ThumbnailCache {
static let shared = ThumbnailCache()
private let cache = NSCache<NSString, UIImage>()
func thumbnail(for url: URL) -> UIImage? {
return cache.object(forKey: url.absoluteString as NSString)
}
func setThumbnail(_ image: UIImage, for url: URL) {
cache.setObject(image, forKey: url.absoluteString as NSString)
}
}
Kombinacja tych with te obraz generator to avoid reducant work.
Rozważanie wydajności
Generating thumbnails is a CPU-intensive operation, especially for high-resolution 4K videos. Follow these beste practices:
- Always perfom syncrours calls on a background queue (np., Xi1; Xi1; FLT: 34 Xi3; Xi3;).
- Ustawić racjonale dla 1; 1; FLT: 35 dla 3; Empl3; to reduce thee output image dimensions. A size of 320x240 is often dependent for list thumbnails.
- Use present 1; Belgium: 36 presents 3; Belgium; to allow thee generator to skip thee nearest frame instead of solving thee exact decode.
- Cancel any in-progress asynchronos generation when they view disappears.
- For display in a collection view, generate thumbnails at thee exact cell size and avoid resizing on thee main thread.
Integrating wigh Swift Concurrency (Async / Awaint)
Jeśli chcesz, aby cel iOS 15 +, you can wrap thee blocking call in a continuation for clean async / wait code:
func generateThumbnail(forVideoAt url: URL, at time: CMTime) async throws -> UIImage {
let asset = AVAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
imageGenerator.maximumSize = CGSize(width: 640, height: 480)
return try await withCheckedThrowingContinuation { continuation in
let times = [NSValue(time: time)]
imageGenerator.generateCGImagesAsynchronously(forTimes: times) { _, cgImage, _, result, error in
if let cgImage = cgImage, result == .succeeded {
let image = UIImage(cgImage: cgImage)
continuation.resume(returning: image)
} else {
continuation.resume(throwing: error ?? ThumbnailError.generationFailed)
}
}
}
}
Zaawansowane dostosowania
Thumbnails wigh Video Composition
If your video uses an behind 1; If your video uses an behind 1; If your video uses an behind 1; Iden1; FLT: 38 behind 3; Identi3; (np., watermark overlay, color adjustments), you can pass it to the images generator:
imageGenerator.videoComposition = myVideoComposition
To generated thumbnail will reflect thee composited output.
Generating Thumbnails for Live Photos
Live Photos are a combination of a video anda still image. Tu extract a thumbnail frem the underlying video, use the indis1; indi1; FLT: 40 contribution 3; indis3; and request a video URL before feesing it into AVFoundation.
Accessibility andd User Experience
Thumbnails enhance visaal al scanning, but always provide a text confidentiva for VoiceOver users. Use the invidence 1; environ1; FLT: 41 confidence 3; enviden3; on the image view, describing the video content if possible.
imageView.isAccessibilityElement = true
imageView.accessibilityLabel = "Thumbnail of video: \(videoTitle)"
Ekstranal Resources
For deeper undering, consult the following:
- (zob. pkt 2.2.1.1.1 niniejszego załącznika)
- (zob. pkt 2.2.1.1.1 niniejszego załącznika)
- WHFDC 2019: AVFoundation Performance Tips Budapest 1; VHFT: 1 VHFD 3; VHF: 1 VHF 3; VHF 3; VHF;
Konkluzja
Building a custim video thumbnail generator with AVFoundation gives you complete freedem over images quality, timing, and performance. By leveraging generator with 1; FLT: 43 employ3; AVFOundation gives you complete youte freedom over id asynchronously, handling errors, and caching result, you can deliver a creampless user experience in your iOS app. Whether you are processing local files or remone videvelopecles, thumbles.