Video miniaturen zijn een hoeksteen van moderne media-rijke toepassingen, het aanbieden van gebruikers een snelle visuele preview zonder dat het nodig om de volledige video af te spelen. In iOS-ontwikkeling, AVFoundation biedt de meest performante en flexibele tools voor het extraheren van thumbnail beelden. Dit artikel loopt door het bouwen van een aangepaste video miniatuur generator die kan omgaan met real-world scenario's . inclusief lokale en externe bestanden, caching, foutafhandeling, en prestaties tuning met behulp van Swift en AVFoundation.

Begrijpen AVFoundation . Rol in Miniatuur Generatie

AVFoundation is Apple's primaire kader voor het werken met audiovisuele media. Voor thumbnail-generatie zijn de sleutelklassen AVAsset en AVAssetAssetGenerator.

  • AVAsset: vertegenwoordigt een getimed audiovisueel actief (een lokale of externe video) en bevat trackinformatie, duur en metagegevens.
  • AVAssetAfbeeldingGenerator: Biedt methoden om CGImageRefs te verkrijgen van het actief op specifieke tijdsintervallen. Het respecteert videooriëntatie, past kleurruimteaanpassingen toe, en ondersteunt asynchrone bulkgeneratie.

Met behulp van deze klassen direct geeft u volledige controle over beeldgrootte, tijdnauwkeurigheid en transformatie, in tegenstelling tot UIKit snelkoppelingen die vaak configuratie-opties verbergen.

Het project instellen

Start met het importeren van AVFoundation in uw Swift-bestand:

import AVFoundation

U heeft ook UIKit nodig om de gegenereerde beelden weer te geven. Maak een aan vanuit een URL. Gebruik voor lokale bestanden. Gebruik voor externe video's en zorg ervoor dat de asset kan worden geïnitialiseerd:

// 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)

Een enkele miniatuur aanmaken

Om één miniatuur op een bepaald moment te genereren, maak je een en roep je aan. Deze methode is synchroon en moet van de hoofddraad worden uitgevoerd om te voorkomen dat de UI wordt geblokkeerd.

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

Belangrijk: Instellen op zorgt ervoor dat het resulterende beeld de rotatiemetadata van video's respecteert (portret vs. landschap). Zonder dit zou een rechtopstaande video zijwaarts kunnen verschijnen.

Het juiste tijdstip kiezen

Miniaturen worden vaak genomen aan het begin van een video, maar overwegen met behulp van een tijd die de inhoud vertegenwoordigt, bijvoorbeeld 10% in de duur. Om een zinvol tijdspunt te krijgen, check de asset . Duur:

let duration = asset.duration
let midTime = CMTimeMultiplyByFloat64(duration, multiplier: 0.1)

Fouten en Randgevallen verwerken

Miniatuurgeneratie kan om verschillende redenen mislukken. Altijd elegant omgaan met fouten en terugval UI bieden.

  • Ongeldig actief: De video kan beschadigd zijn of de URL onbereikbaar.
  • Videospoor wordt gemist: Sommige activa bevatten alleen audio; controleer .
  • Tijd buiten de grenzen: Zorg ervoor dat de gevraagde tijd tussen en de duur van de activa ligt.
  • Netwerkfouten: Remote activa kunnen niet laden. Gebruik voordat u miniaturen aanmaakt.

Voorbeeld van voorlaadvermogenseigenschappen:

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

Miniatuuruitvoer aanpassen

AVAssetImageGenerator biedt verschillende eigenschappen om het uitvoerbeeld te verfijnen.

Maximumgrootte

Beperk het gegenereerde beeld tot een specifiek omgrenzend vak met ]. Dit vermindert het geheugen overhead en versnelt de generatie voor grote video's.

imageGenerator.maximumSize = CGSize(width: 640, height: 480)

Het gegenereerde beeld zal worden geschaald om binnen deze dimensies te passen, terwijl de aspectverhouding behouden blijft.

Tolerantie van de gevraagde tijd

Standaard geeft het exacte frame terug op het gewenste tijdstip (of zo dicht mogelijk). U kunt de nauwkeurigheid voor snelheid inwisselen door en ] in te stellen. Voor miniaturen is een tolerantie van 0,5 seconden vaak aanvaardbaar en sneller:

imageGenerator.requestedTimeToleranceBefore = CMTime(seconds: 0.5, preferredTimescale: 600)
imageGenerator.requestedTimeToleranceAfter = CMTime(seconds: 0.5, preferredTimescale: 600)

Diafragmamodus

regelt hoe het gegenereerde beeld een schone opening vs. productieopening behandelt. Gebruik om randstof te verwijderen en een schonere miniatuur te produceren:

imageGenerator.apertureMode = .cleanAperture

Transformaties toepassen

Als je de afbeelding moet draaien of omdraaien (bv. voor een specifieke oriëntatie), gebruik dan Core Graphics transformeert. Eén benadering is het vastleggen van de ruwe afbeelding en vervolgens handmatig een CGAffineTransform toepassen. Als alternatief kun je instellen op (zoals getoond) en de natuurlijke oriëntatie van de asset vertrouwen.

Meerdere miniaturen efficiënt genereren

Voor videorasters, tijdlijn schrobben, of storyboard previews, heb je vaak tientallen miniaturen nodig. Vermijd het bellen in een lus op de hoofddraad. In plaats daarvan, gebruik de asynchrone methode ]. Het verwerkt meerdere tijdsverzoeken efficiënt, waardoor interne parallellisme wordt benut.

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

Deze methode schalen goed en kunt u de UI incrementele update. Vergeet niet om te bellen .9.] als de gebruiker het scherm verlaat om bronnen vrij te maken.

Werken met externe video's

Wanneer de video-URL naar een externe server wijst, moet u wachten tot de asset volledig geladen is of tenminste de track-informatie beschikbaar is. Gebruik met de juiste caching-headers om herhaalde downloads te voorkomen.

let urlAsset = AVURLAsset(url: remoteURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
urlAsset.loadValuesAsynchronously(forKeys: ["tracks"]) {
 // Then create image generator and proceed
}

Voor productie-apps, overwegen caching miniaturen op de schijf, zodat herhaalde toegang tot dezelfde video niet opnieuw ophalen van de afbeelding. Gebruik of bestandsgebaseerde cache met behulp van de video-URL als een sleutel.

Voorbeeld van een strategie voor het inpakken van de lading

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

Combineer dit met de afbeeldingsgenerator om overbodig werk te voorkomen.

Prestatieoverwegingen

Het genereren van miniaturen is een CPU-intensieve operatie, vooral voor video's met een hoge resolutie van 4K. Volg deze beste praktijken:

  • Altijd synchrone oproepen uitvoeren op een achtergrondwachtrij (bv. ).
  • Stel een redelijke in om de afmetingen van de uitvoerafbeelding te verkleinen. Een grootte van 320x240 is vaak voldoende voor lijstminutjes.
  • Gebruik om de generator het dichtstbijzijnde frame over te laten in plaats van de exacte decodering op te lossen.
  • Annuleer elke in-voortgang asynchrone generatie wanneer het uitzicht verdwijnt.
  • Voor weergave in een collectieweergave, maak miniaturen op de exacte celgrootte en vermijd het wijzigen van de grootte op de hoofddraad.

Integratie met Swift Concurrency (Async/Await)

Als uw app iOS 15+ targets, kunt u de blokkerende oproep in een vervolg voor schone async / wacht code wrap:

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

Geavanceerde aanpassingen

Miniaturen met video-samenstelling

Als uw video een (bv. watermerk overlay, kleuraanpassingen) gebruikt, kunt u deze doorgeven aan de afbeeldingsgenerator:

imageGenerator.videoComposition = myVideoComposition

De gegenereerde miniatuur zal de samengestelde uitvoer weergeven.

Miniaturen voor live-foto's aanmaken

Live Foto's zijn een combinatie van een video en een stilstaande afbeelding. Om een miniatuur uit de onderliggende video te halen, gebruik de en vraag een video-URL aan voordat u deze in AVFoundation invoert.

Toegankelijkheid en gebruikerservaring

Miniaturen verbeteren visueel scannen, maar bieden altijd een tekst alternatief voor VoiceOver gebruikers. Gebruik de op de afbeelding, beschrijving van de video-inhoud indien mogelijk.

imageView.isAccessibilityElement = true
imageView.accessibilityLabel = "Thumbnail of video: \(videoTitle)"

Externe middelen

Voor een beter begrip, raadpleeg het volgende:

Conclusie

Het bouwen van een aangepaste video miniatuurgenerator met AVFoundation geeft u volledige vrijheid over beeldkwaliteit, timing en prestaties. Door gebruik te maken van , zowel synchrone als asynchrone, handling fouten en caching resultaten, kunt u een naadloze gebruikerservaring in uw iOS-app. Of u nu lokale bestanden of video's op afstand verwerkt, de technieken die hier worden behandeld zal u helpen bij het produceren van scherpe, context-bewuste miniaturen snel en efficiënt.