비디오 엄지나일은 현대 미디어 풍부한 응용 분야의 코너스톤으로, 사용자가 전체 비디오를 재생할 필요없는 빠른 시각 미리보기를 제공합니다. iOS 개발에서 AVFoundation은 엄지나일 이미지를 추출하기위한 가장 수행 및 유연한 도구를 제공합니다. 이 문서는 로컬 및 원격 파일, 캐싱, 오류 처리 및 성능 조정을 포함하여 실제 시나리오를 처리 할 수있는 사용자 정의 비디오 엄지나일 발전기를 구축하여 걸어 걷습니다. Swift 및 AVFoundation.

Thumbnail Generation의 AVFoundation 역할 이해

AVFoundation은 시청각 미디어와 함께 일하는 Apple의 기본 프레임 워크입니다. 썸네일 세대의 경우, 주요 클래스는 ]AVAsset]AVAssetImageGenerator입니다.

  • AVAsset: 시간된 오디오 자산(국적 또는 원격 비디오)를 나타냅니다. 이 트랙 정보, 기간 및 메타데이터가 포함되어 있습니다.
  • AVAssetImageGenerator: 특정 시간 간격에 자산에서 CGImageRefs를 얻는 방법을 제공합니다. 그것은 비디오 방향을 존중하고, 색 공간 조정을 적용하고, 비동기 대량 생성을 지원합니다.

이 클래스를 사용하여 이미지 크기, 시간 정확도, 변환을 통해 전체 제어를 제공합니다. UIKit Shortcuts와는 달리 구성 옵션을 숨깁니다.

프로젝트 설정

Swift 파일로 AVFoundation을 가져 오기로 시작:

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)

단일 Thumbnail 생성

지정된 시간에 하나의 엄밀을 생성하려면 ]을 만들고 ]를 호출합니다. 이 방법은 동기이며 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: ] ]]]는 영상의 교체 메타데이터 (초상 vs. 풍경)를 존중합니다. 이 없이, 밝은 영상은 보도될 수 있습니다.

오른쪽 시간 선택

Thumbnails는 종종 비디오의 시작 부분에 촬영되지만, 콘텐츠를 나타내는 시간을 고려합니다. 예를 들어, 10 %는 지속 시간입니다. 의미있는 시간을 얻으려면 자산의 지속 시간을 쿼리하십시오.

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

처리 오류 및 Edge 케이스

Thumbnail 세대는 여러 가지 이유로 실패 할 수 있습니다. 항상 과실을 처리하고 fallback UI를 제공합니다.

  • 무효 자산:비디오는 손상되거나 URL이 제한될 수 있습니다.
  • Misssing video track:] 일부 자산은 오디오만 포함; ].
  • ]시간의 경계: 요청된 시간을 보장하는 것은 과 자산의 지속 시간입니다.
  • Network error: Remote Assets는 로드에 실패할 수 있습니다. 썸네일 생성하기 전에 를 사용하십시오.

preloading 자산의 예:

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)

생성된 이미지는 이 차원 안에 적합하기 위하여 종횡비를 보존하는 동안 확장될 것입니다.

위탁된 시간 포용력

기본적으로 ]는 요청된 시간에 정확한 프레임을 반환합니다 (또는 가능한 한 가까이). 과 ]]을 설정하여 속도를 위해 정확도를 거래 할 수 있습니다. thumbnails의 경우 0.5 초의 허용 오차는 종종 허용되고 빠릅니다.

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

가늠구멍 형태

] 생성 된 이미지가 깨끗한 조리대를 처리하는 방법을 제어합니다. 생산 노출. 가장자리 먼지를 제거하고 깨끗한 엄밀을 생산하기 위해 를 사용합니다.

imageGenerator.apertureMode = .cleanAperture

Transformations 적용

이미지를 회전하거나 플립 할 필요가 있다면 (예 : 특정 방향), 코어 그래픽 변환을 사용합니다. 한 가지 접근법은 원시 이미지를 캡처하고 수동으로 CGAffineTransform을 적용합니다. 또는 [[FLT : 24]]]를 [[FLT : 25]]]로 설정하고 자산의 자연 방향을 신뢰합니다.

여러 가지 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를 incrementally 업데이트 할 수 있습니다. 사용자가 스크린을 무료 리소스로 나타낸 경우 ]를 호출하는 것을 기억하십시오.

원격 동영상 작업

원격 서버에 비디오 URL 포인트가 있을 때, 완전히 로드되거나 적어도 트랙 정보를 사용할 수 있도록 자산을 기다릴 필요가 있습니다. 반복 다운로드를 방지하기 위해 적절한 캐싱 헤더를 사용하여 ]를 사용하십시오.

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

생산 앱의 경우 디스크에 캐싱 엄밀을 고려하여 동일한 비디오에 대한 액세스를 반복하는 것은 이미지를 재 ‐fetch하지 않습니다. 또는 비디오 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)
 }
}

이 이미지를 결합하여 중복 작업을 피하기 위해 생성기.

성능 고려

thumbnails 생성은 CPU ‐ 집중적인 가동, 특히 고해상도 4K 비디오를 위해입니다. 이 모범 사례를 따르십시오:

  • 항상 배경 큐에 비동기 통화를 수행 (예를 들어, ).
  • 출력 이미지 크기를 줄이기 위해 합리적인 를 설정합니다. 320x240의 크기는 종종 목록 썸네일에 충분합니다.
  • ]를 사용하여 발전기를 사용하여 정확한 디코드를 해결하는 대신 가장 가까운 프레임을 건너 뛸 수 있습니다.
  • 보기가 사라질 때 비동기 발생을 방지하십시오.
  • 수집보기에 표시를 위해 정확한 셀 크기에 엄밀하게 생성하고 주요 스레드에 재조정을 방지합니다.

Swift Concurrency (Async/Await)와 통합

앱이 iOS 15+를 대상으로 하는 경우, 깨끗한 async/await 코드를 위한 continuation에 있는 차단 통화를 감싸는 수 있습니다:

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

고급 사용자 정의

Thumbnails 와 비디오 구성

비디오가 (예 : 워터 마크 오버레이, 색상 조정)을 사용한다면 이미지 생성기로 전달할 수 있습니다.

imageGenerator.videoComposition = myVideoComposition

생성 된 썸네일은 복합 출력을 반영합니다.

라이브 사진에 대한 Thumbnails 생성

라이브 사진은 비디오와 여전히 이미지의 조합입니다. 언더리 비디오에서 엄밀을 추출하려면 ]을 사용하며 AVFoundation로 먹이기 전에 비디오 URL을 요청하십시오.

접근성 및 사용자 경험

Thumbnails는 시각적 인 스캐닝을 향상하지만 항상 VoiceOver 사용자를위한 텍스트 대안을 제공합니다. 이미지보기에 ]를 사용하여 비디오 콘텐츠를 설명 할 수 있습니다.

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

외부 자료

더 깊은 이해를 위해, 뒤에 오는 상담:

관련 기사

AVFoundation을 가진 사용자 정의 비디오 엄밀 발전기를 구축하면 이미지 품질, 타이밍 및 성능에 대한 완벽한 자유를 제공합니다. 를 레버리지로 활용하면 동시 및 비동기적으로 처리 오류 및 캐싱 결과가 가능하며 iOS 앱에서 원활한 사용자 경험을 제공할 수 있습니다. 로컬 파일이나 원격 비디오를 처리하는 경우, 이 기술을 통해 crisp, context-aware thumbnails를 신속하고 효율적으로 생산할 수 있습니다.