Відео мініатюри є стразовим елементом сучасних медіа-багатих додатків, пропонуючи користувачам швидкий візуальний перегляд без необхідності грати в повне відео. У розробці iOS AVFoundation забезпечує найбільш виступаючих і гнучких інструментів для вилучення мініатюрних зображень. Ця стаття проходить через створення користувальницького відео пальника, який може обробляти реальні сценарії світу - включаючи локальні і віддалені файли, кешування, обробка помилок і налаштування продуктивності -using Swift і AVFoundation.

Розуміння ролі AVFoundation у Thumbnail Generation

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

Important: Налаштування до ] забезпечує отримане зображення по відношенню до метаданих відеопереміну (портрет проти пейзажу). Без цього відео може з'явитися бокові шляхи.

Вибір правого часу

На початку відео часто беруться ганнаїли, але враховують час, який представляє зміст, наприклад, 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
 }
}

Налаштування Thumbnail вихід

AVAssetImageGenerator пропонує декілька властивостей для тонкого відступу зображення.

Максимальний розмір

Обмеження створеного зображення на конкретну межу з використанням . Це зменшує надголову пам'яті і прискорює генерацію для великих відео.

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

Згенерований образ буде масштабований для влаштування в межах цих розмірів при збереженні співвідношення сторін.

Заявка часу толерантності

За замовчуванням повертає точний кадр за запитом часу (або якомога ближче). Ви можете дотримуватися точності торгів за швидкістю, встановивши і . Для ескізів, допуск 0,5 секунд часто прийнятний і швидше:

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

Режим протезування

контролює, як генерується зображення ручки чистої апертури проти. Використання для видалення крайового пилу і отримання пальчика для очищення:

imageGenerator.apertureMode = .cleanAperture

Застосування трансформацій

Якщо вам необхідно обертати або закріпити зображення (наприклад, для конкретної орієнтації), скористайтеся трансформами Core Graphics. Один підхід полягає в тому, щоб захопити сире зображення, а потім застосувати CGAffineTransform вручну. Крім того, ви можете встановити до ] (як показано) і довірити природну спрямованість активу.

Генерація декількох Thumbnails Ефективно

Для відеомереж, часової стяжки або попереднього перегляду сюжетної плати, вам часто потрібно десятки ескізів. Уникайте зателефонування в петлі на головній нитки. Замість цього використовуйте синхронний метод . Він обробляє кілька часових запитів ефективно, важільне внутрішні паралелізми.

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 незрівнянно. Пам'ятайте, що виклик , якщо користувач залишає екран на вільні ресурси.

Робота з дистанційним відео

Коли точка відео URL на віддалений сервер необхідно чекати, щоб актив був повністю завантажений або принаймні його інформація про трек, яку можна отримати. Використовуйте з відповідними заголовками кешування, щоб уникнути повторних завантажень.

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

Для виготовлення додатків вкажіть кальмари на диску, щоб повторити доступ до того ж відео не перенагріває зображення. Використовуйте або кеш-пам'яті, використовуючи URL-адресу відео як ключ.

Приклад стратегії кешування

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 часто достатній для списку пальці.
  • Використовуйте для того, щоб дозволити генератору пропустити найближчий кадр замість розв'язання точного декодування.
  • Скасуйте будь-яке синхронне покоління, коли зникне погляд.
  • Для відображення в виді колекції генеруйте ескізи на точний розмір комірки і не перезнімаючи на головній нитки.

Інтеграція з Swift Concurrency (Async/Await)

Якщо ваша заявка націлена на iOS 15+, ви можете загорнути блокуючий дзвінок в продовження для очищення асинхрону / коду провітрювання:

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

Згенерований пальчик відобразить композитний вихід.

Генерування Thumbnails для живих фотографій

Живі фотографії є поєднанням відео та зображенням на все ще. Для отримання ескізу з основного відео використовуйте і запитайте URL відео перед подачі його в AVFoundation.

Доступність та досвід користувача

Thumbnails посилює візуальне сканування, але завжди надає можливість текстову альтернативу користувачам VoiceOver. Використовуйте на перегляд зображень, що описує відеоконтент, якщо це можливо.

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

Зовнішні ресурси

Для глибокого розуміння, консультуйтеся з наступними:

Висновок

Побудова користувальницького відео-пальника з AVFoundation дає вам повну свободу над якістю зображення, терміном і продуктивністю. За допомогою важіль як синхронно і асинхронно, помилки обробки та результати кешування, ви можете доставити безшовний досвід користувача у додатку iOS. Незалежно від того, чи ви обробляєте локальні файли або віддалені відео, методи, які охоплюють тут, допоможуть вам виробляти хрустки, контекстно-програмні ескізи швидко і ефективно.