Table of Contents
Τα βίντεο μικροσκοπικά σχέδια είναι ένας ακρογωνιαίος λίθος των σύγχρονων εφαρμογών πλούσια στα μέσα ενημέρωσης, προσφέροντας στους χρήστες μια γρήγορη οπτική προεπισκόπηση χωρίς να χρειάζεται να παίξουν το πλήρες βίντεο. Στην ανάπτυξη iOS, το AVFoundation παρέχει τα πιο αποδοτικά και ευέλικτα εργαλεία για την εξαγωγή εικόνων επισκόπησης. Αυτό το άρθρο περπατά μέσα από την οικοδόμηση μιας προσαρμοσμένης γεννήτριας μικροσκοπικών εικόνων βίντεο που μπορεί να χειριστεί σενάρια πραγματικού κόσμου ⁇ συμπεριλαμβανομένων τοπικών και απομακρυσμένων αρχείων, caching, διαχείριση σφαλμάτων, και τον συντονισμό επιδόσεων ⁇ χρησιμοποιώντας Swift και AVFoundation.
Κατανόηση του ρόλου του AVFoundation στη δημιουργία εικόνων επισκόπησης
Το AVFoundation είναι το βασικό πλαίσιο της Apple για τη συνεργασία με τα οπτικοακουστικά μέσα. Για την παραγωγή μικρογραφίας, οι βασικές τάξεις είναι AVASSET και AVASsetImageGenerator].
- AVAsset: Εκπροσωπεί ένα χρονομετρημένο οπτικοακουστικό περιουσιακό στοιχείο (ένα τοπικό ή απομακρυσμένο βίντεο). Περιέχει πληροφορίες κομματιών, διάρκεια και μεταδεδομένα.
- AVAssetImageGenerator: Παρέχει μεθόδους για την απόκτηση CGImageRefs από το περιουσιακό στοιχείο σε συγκεκριμένα χρονικά διαστήματα. Σέβεται τον προσανατολισμό βίντεο, εφαρμόζει τις ρυθμίσεις χρωματικού χώρου, και υποστηρίζει ασύγχρονη μαζική παραγωγή.
Χρησιμοποιώντας αυτές τις κατηγορίες άμεσα σας δίνει τον πλήρη έλεγχο πάνω στο μέγεθος της εικόνας, την ακρίβεια του χρόνου, και τη μετατροπή, σε αντίθεση με τις συντομεύσεις UIKit που συχνά κρύβουν τις επιλογές ρύθμισης.
⁇ του Έργου
Ξεκινήστε με την εισαγωγή AVFoundation στο αρχείο σας Swift:
import AVFoundation
Επίσης, χρειάζεστε το UIKit για να εμφανίσετε τις δημιουργημένες εικόνες. Δημιουργήστε ένα από ένα URL. Για τοπικά αρχεία, χρησιμοποιήστε . Για απομακρυσμένα βίντεο, χρησιμοποιήστε και βεβαιωθείτε ότι το περιουσιακό στοιχείο μπορεί να αρχικοποιηθεί:
// 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)
Δημιουργία μιας ενιαίας εικόνας επισκόπησης
Για να δημιουργήσετε μια μικρογραφία σε μια καθορισμένη στιγμή, δημιουργήστε ένα και καλέστε . Αυτή η μέθοδος είναι σύγχρονη και θα πρέπει να απενεργοποιηθεί το κύριο νήμα για να αποφευχθεί το μπλοκάρισμα του 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)")
}
Σημαντικό: ⁇ σε εξασφαλίζει ότι η εικόνα που προκύπτει σέβεται τα μεταδεδομένα περιστροφής του βίντεο (προσωπογραφία εναντίον τοπίου). Χωρίς αυτό, ένα όρθιο βίντεο μπορεί να εμφανιστεί πλάγια.
Επιλέγοντας τη σωστή ώρα
Οι εικόνες εικόνων λαμβάνονται συχνά στην αρχή ενός βίντεο, αλλά σκεφτείτε να χρησιμοποιήσετε μια φορά που αντιπροσωπεύει το περιεχόμενο ⁇ π.χ., 10% στη διάρκεια. Για να πάρετε ένα σημαντικό χρονικό σημείο, ερωτήστε τη διάρκεια του περιουσιακού στοιχείου:
let duration = asset.duration
let midTime = CMTimeMultiplyByFloat64(duration, multiplier: 0.1)
Χειρισμός σφαλμάτων και περιπτώσεων άκρων
Η γενιά εικόνων επισκόπησης μπορεί να αποτύχει για διάφορους λόγους. Πάντα να χειρίζεστε τα λάθη με χάρη και να παρέχετε εφεδρικό UI.
- Ακυρόριστο περιουσιακό στοιχείο: Το βίντεο μπορεί να αλλοιωθεί ή το URL να μην μπορεί να προσπελαστεί.
- Χάσιμο κομματιού βίντεο: Ορισμένα περιουσιακά στοιχεία περιέχουν μόνο ήχο· έλεγχος .
- Χρόνος εκτός ορίων: Βεβαιωθείτε ότι ο χρόνος που ζητήσατε είναι μεταξύ και της διάρκειας του περιουσιακού στοιχείου.
- Σφάλματα δικτύου: Τα απομακρυσμένα περιουσιακά στοιχεία ενδέχεται να αποτύχουν να φορτωθούν. Χρησιμοποιήστε πριν δημιουργήσετε μικροεπεξεργαστές.
Παράδειγμα προφόρτωσης περιουσιακών στοιχείων:
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
}
}
Προσαρμογή εξόδου εικόνων επισκόπησης
AVAssetImageGenerator προσφέρει αρκετές ιδιότητες για να τελειοποιήσετε την εικόνα εξόδου.
Μέγιστο μέγεθος
Περιορισμός της παραγόμενης εικόνας σε ένα συγκεκριμένο πλαίσιο σύνδεσης χρησιμοποιώντας . Αυτό μειώνει τη μνήμη πάνω από τα ύψη και επιταχύνει τη δημιουργία για μεγάλα βίντεο.
imageGenerator.maximumSize = CGSize(width: 640, height: 480)
Η παραγόμενη εικόνα θα κλιμακωθεί ώστε να χωρέσει σε αυτές τις διαστάσεις, ενώ παράλληλα θα διατηρείται η αναλογία διαστάσεων.
Ζητούμενη ανοχή Χρόνου
Εξ ορισμού, [[LFT:17]] επιστρέφει το ακριβές πλαίσιο κατά τον απαιτούμενο χρόνο (ή όσο το δυνατόν πιο κοντά). Μπορείτε να ανταλλάξετε ακρίβεια για ταχύτητα ρυθμίζοντας [[LFT:18]] και [[LFT:19]]. Για τις εικόνες επισκόπησης, η ανοχή 0,5 δευτερολέπτων είναι συχνά αποδεκτή και ταχύτερη:
imageGenerator.requestedTimeToleranceBefore = CMTime(seconds: 0.5, preferredTimescale: 600)
imageGenerator.requestedTimeToleranceAfter = CMTime(seconds: 0.5, preferredTimescale: 600)
Λειτουργία ανοίγματος
ελέγχει πώς η παραγόμενη εικόνα χειρίζεται καθαρό διάφραγμα έναντι του ανοίγματος παραγωγής. Χρησιμοποιήστε [[LPT:22]] για να αφαιρέσετε τη σκόνη άκρης και να παράγετε μια καθαρότερη μικρογραφία:
imageGenerator.apertureMode = .cleanAperture
Εφαρμογή Μετασχηματισμών
Αν χρειαστεί να περιστραφεί ή να αναστραφεί η εικόνα (π.χ. για συγκεκριμένο προσανατολισμό), χρησιμοποιήστε Core Graphics transforms. Μία προσέγγιση είναι να συλλάβει την ακατέργαστη εικόνα και στη συνέχεια να εφαρμόσει ένα CGAffineTransform χειροκίνητα. Εναλλακτικά, μπορείτε να ρυθμίσετε [[LFT:24]] σε [[LFT:25]] (όπως φαίνεται) και να εμπιστευτείτε τον φυσικό προσανατολισμό του περιουσιακού στοιχείου.
Δημιουργία πολλαπλών εικόνων επισκόπησης αποτελεσματικά
Για τα δίκτυα βίντεο, το timeline scrift, ή τις προεπισκοπήσεις του storyboard, συχνά χρειάζεστε δεκάδες μικροσκοπικά μικροσκοπικά μικροσκοπικά κυκλώματα. Αποφύγετε να καλέσετε [[[LFT:26]]] σε ένα βρόχο στο κύριο νήμα. Αντ 'αυτού, χρησιμοποιήστε την ασύγχρονη μέθοδο [[LFT:27]].
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")")
}
}
Αυτή η μέθοδος ζυγίζει καλά και σας επιτρέπει να ενημερώσετε το UI σταδιακά. Θυμηθείτε να καλέσετε [[LFT:29]] αν ο χρήστης αφήσει την οθόνη για να απελευθερώσει πόρους.
Εργασία με απομακρυσμένα βίντεο
Όταν το URL βίντεο δείχνει έναν απομακρυσμένο εξυπηρετητή, πρέπει να περιμένετε το περιουσιακό στοιχείο να φορτωθεί πλήρως ή τουλάχιστον να είναι διαθέσιμες οι πληροφορίες του κομματιού του. Χρησιμοποιήστε [[LFT:30]] με κατάλληλες κεφαλίδες caching για να αποφύγετε επαναλαμβανόμενες λήψεις.
let urlAsset = AVURLAsset(url: remoteURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
urlAsset.loadValuesAsynchronously(forKeys: ["tracks"]) {
// Then create image generator and proceed
}
Για εφαρμογές παραγωγής, εξετάστε το caching των εικόνων επισκόπησης στο δίσκο έτσι ώστε η επαναλαμβανόμενη πρόσβαση στο ίδιο βίντεο να μην επαναπροσδίδει την εικόνα. Χρησιμοποιήστε [] ή το αρχείο-βασισμένο cache χρησιμοποιώντας το URL βίντεο ως κλειδί.
Παράδειγμα στρατηγικής Caching
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)
}
}
Συνδυάστε αυτό με τη γεννήτρια εικόνας για να αποφύγετε περιττή εργασία.
Επιδόσεις
Η δημιουργία εικόνων επισκόπησης είναι μια εντατική λειτουργία της ΚΜΕ, ειδικά για βίντεο υψηλής ανάλυσης 4K. Ακολουθήστε αυτές τις βέλτιστες πρακτικές:
- Πάντα να εκτελείς συγχρονισμένες κλήσεις σε ουρά υποβάθρου (π.χ., ).
- Ορισμός ενός λογικού για τη μείωση των διαστάσεων της εικόνας εξόδου. Ένα μέγεθος 320x240 είναι συχνά αρκετό για τις εικόνες λίστας.
- Χρησιμοποιήστε για να επιτρέψετε στη γεννήτρια να παραλείψει το πλησιέστερο πλαίσιο αντί να λύσει την ακριβή αποκωδικοποίηση.
- Ακύρωση κάθε in ⁇ progress ασύγχρονης γενιάς όταν η θέα εξαφανίζεται.
- Για εμφάνιση σε μια εικόνα συλλογής, δημιουργήστε μικροεικόνες στο ακριβές μέγεθος του κελιού και αποφύγετε την αλλαγή μεγέθους στο κύριο νήμα.
Ενσωματώνοντας με Swift Concurrency (Async/Await)
Εάν η εφαρμογή σας στοχεύει iOS 15+, μπορείτε να τυλίξετε την κλήση αποκλεισμού σε μια συνέχεια για καθαρό κωδικό async/await:
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)
}
}
}
}
Προχωρημένες προσαρμογές
Εικόνες με σύνθεση βίντεο
Εάν το βίντεο σας χρησιμοποιεί (π.χ. επικάλυψη υδατογραφήματος, ρυθμίσεις χρωμάτων), μπορείτε να το μεταφέρετε στη γεννήτρια εικόνας:
imageGenerator.videoComposition = myVideoComposition
Η παραγόμενη μικρογραφία θα αντανακλά τη σύνθετη έξοδο.
Δημιουργία εικόνων επισκόπησης για ζωντανές φωτογραφίες
Για να εξαγάγετε μια μικρογραφία από το υποκείμενο βίντεο, χρησιμοποιήστε το [[LFT:40]] και ζητήστε ένα βίντεο URL πριν το τροφοδοτήσετε σε AVFoundation.
Προσβασιμότητα και Εμπειρία χρήστη
Οι εικόνες βελτιώνουν την οπτική σάρωση, αλλά πάντα παρέχουν μια εναλλακτική λύση κειμένου για τους χρήστες VoiceOver. Χρησιμοποιήστε το [[LFT:41]] στην προβολή της εικόνας, περιγράφοντας το περιεχόμενο βίντεο αν είναι δυνατόν.
imageView.isAccessibilityElement = true
imageView.accessibilityLabel = "Thumbnail of video: \(videoTitle)"
Εξωτερικοί πόροι
Για βαθύτερη κατανόηση, συμβουλευτείτε τα ακόλουθα:
Συμπέρασμα
Η δημιουργία μιας προσαρμοσμένης γεννήτριας μικρογραφίας βίντεο με AVFoundation σας δίνει πλήρη ελευθερία πάνω από την ποιότητα της εικόνας, το χρονοδιάγραμμα και την απόδοση. Με τη χρήση [[LFT:43]] και συγχρονισμένα και ασύγχρονα, το χειρισμό σφαλμάτων και την κοπή αποτελεσμάτων, μπορείτε να παράσχετε μια απρόσκοπτη εμπειρία χρήστη στην εφαρμογή iOS σας. Είτε επεξεργάζεται τοπικά αρχεία ή απομακρυσμένα βίντεο, οι τεχνικές που καλύπτονται εδώ θα σας βοηθήσουν να παράγετε τραγανές, συμφραζόμενα ⁇ αναγνώρισε τις μικροσκοπικές εικόνες γρήγορα και αποτελεσματικά.