Civiele & structurele engineering
Een aangepaste video-miniatuurgenerator aanmaken in Ios met Avoundation
Table of Contents
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:
- AVAssetAfbeeldingGenerator Officiële documentatie
- AVAssetreferentie
- WWDC 2019: AVFoundation Performance Tips
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.