Table of Contents
تصاویر ویدئویی یک سنگ بنای برنامه های غنی از رسانه های مدرن است، ارائه کاربران یک پیش نمایش بصری سریع بدون نیاز به بازی کامل ویدیو در توسعه iOS، AVFoundation ارائه می دهد بهترین و انعطاف پذیر برای استخراج تصاویر کوچک است.این مقاله از طریق ساخت یک ژنراتور تصویری سفارشی که می تواند سناریوهای دنیای واقعی را اداره کند - از جمله فایل های محلی و دور، خطا، و اجرای - و اجرای آن -
درک نقش AVFoundation در نسل های Thumbnail
AVFoundation چارچوب اصلی اپل برای کار با رسانه های صوتی و بصری است [برای نسل کوچک]، کلاس های کلیدی AVAsset و و مولده .
- AVAsset : نمایندگی یک دارایی صوتی و بصری (یک ویدیو محلی یا دور) شامل اطلاعات، مدت و متاداده است.
- AVAssetImageGenerator: ارائه روش برای به دست آوردن CGImageRefs از دارایی در فواصل زمانی خاص احترام می گذارد، آن را به جهت گیری ویدیو، اعمال تنظیمات فضای رنگ، و پشتیبانی به عنوان نسل عمده.
استفاده از این کلاس ها به طور مستقیم به شما کنترل کامل بر اندازه تصویر، دقت زمان و تحول، بر خلاف میانبر UIKit که اغلب گزینه های پیکربندی را پنهان می کند.
راه اندازی پروژه
با وارد کردن AVFoundation به فایل Swift خود شروع کنید:
import AVFoundation
همچنین به UIKit نیاز دارید تا تصاویر تولید شده را نمایش دهد.(FLT:1) از 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)")
}
گزارشگر: تنظیم برای تضمین می کند تصویر حاصل به متاید چرخش ویدیو (پورتrait در مقابل چشم انداز) احترام می گذارد.
انتخاب زمان مناسب
ناخن ها اغلب در ابتدای یک ویدیو گرفته می شوند، اما با استفاده از زمانی که محتوای را نشان می دهد، به عنوان مثال، 10٪ در مدت زمان مناسب، مدت زمان دارایی را بررسی کنید:
let duration = asset.duration
let midTime = CMTimeMultiplyByFloat64(duration, multiplier: 0.1)
مدیریت خطا و پرونده های Edge
نسل Thumbnail می تواند به دلایل مختلف شکست بخورد.همیشه با خیال راحت خطا را مدیریت کند و UI را ارائه دهد.
- دارایی بی ارزش: ویدئو ممکن است فاسد یا غیر قابل دسترس باشد.
- مسیر ویدئویی: برخی از دارایی ها فقط شامل صدا هستند؛ بررسی کنید [FLT: 11]
- [در این باره] [از [و] [از] [به] [از [مشرکان]] [و [به]] [و [به]]] [به] [و]] [از [و]]] [به] [و]] [و [از]] [و] [به] [و] [از [به]] [و] [و] [به [و] [و [و [و]] [از [و] [و] [و [و [از [از [به]]] [و] [به [به] [و]]]] [به [و] [و [و]]]]] [و [و]] [و [و [و [و [و [به [به [و] [و] [از [از [و]]]]] [از [و]]]]] [از [از [از [از [از [از [از [از [از [از [از [به]] [از [به [و] [از [و]] [و]] [به] [از [از [از [از [از [و] [به [و
- خطای شبکه: دارایی های از راه دور ممکن است بارگیری نکنند [FLT 13] قبل از تولید تصاویر کوچک.
نمونه ای از خواص پیش بارگذاری دارایی:
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
}
}
سفارشی سازی Photonail
AVAssetImageGenerator ارائه می دهد چندین ویژگی برای تنظیم تصویر خروجی.
حداکثر اندازه
محدود کردن تصویر تولید شده به یک جعبه محدود خاص با استفاده از این باعث کاهش حافظه سربار و سرعت تولید برای فیلم های بزرگ.
imageGenerator.maximumSize = CGSize(width: 640, height: 480)
تصویر تولید شده در این ابعاد در حالی که حفظ نسبت ابعاد مقیاس پذیر خواهد بود.
درخواست زمان برای تحمل
به طور پیش فرض، فریم دقیق را در زمان درخواست شده (یا تا حد ممکن نزدیک) برمی گرداند (شما می توانید دقت را با تنظیم (FLT:18) و برای عکس های کوچک، تحمل 0.5 ثانیه اغلب قابل قبول و سریع تر:
imageGenerator.requestedTimeToleranceBefore = CMTime(seconds: 0.5, preferredTimescale: 600)
imageGenerator.requestedTimeToleranceAfter = CMTime(seconds: 0.5, preferredTimescale: 600)
حالت Aperture Mode
کنترل چگونه تصویر تولید شده را کنترل دیافراگم تمیز در مقابل دیافراگم تولید.استفاده از برای حذف گرد و غبار لبه و تولید یک تصویر تمیز:
imageGenerator.apertureMode = .cleanAperture
استفاده از تحولات
اگر نیاز به چرخش یا چرخش تصویر (به عنوان مثال برای جهت گیری خاص)، استفاده از سوئیچ های گرافیکی Core است.یک رویکرد این است که تصویر خام را ضبط کنید و سپس یک انتقال دهنده CGAffine را به صورت دستی اعمال کنید، می توانید تنظیم کنید تا (FLT 25 (همانطور که نشان داده شده) و اعتماد به جهت گیری طبیعی دارایی.
تولید چندین انگشت به طور موثر
برای شبکه های ویدئویی، اسکراب زمانی یا پیش نمایش های داستانی، شما اغلب به ده ها عکس نیاز دارید، از تماس گرفتن (FLT 26) در حلقه ای بر روی موضوع اصلی اجتناب کنید، به جای آن، از روش ناهمزمان (FLT 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 را به طور فزاینده ای به روز کنید تا به یاد داشته باشید که (FLT 29) اگر کاربر صفحه نمایش را به منابع آزاد واگذار کند.
کار با فیلم های از راه دور
هنگامی که URL ویدیو به یک سرور از راه دور اشاره می کند، باید منتظر بمانید تا دارایی به طور کامل بارگذاری شود یا حداقل اطلاعات پیگیری آن در دسترس باشد.(FLT:30) با هدرهای مناسب برای جلوگیری از بارگیری مکرر.
let urlAsset = AVURLAsset(url: remoteURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
urlAsset.loadValuesAsynchronously(forKeys: ["tracks"]) {
// Then create image generator and proceed
}
برای برنامه های تولید، به نظر می رسد که تصاویر Caching در دیسک به طوری که دسترسی مکرر به همان ویدیو دوباره تصویر را از بین نمی برد. استفاده از یا حافظه مبتنی بر فایل با استفاده از 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)
}
}
این را با ژنراتور تصویر ترکیب کنید تا از کار اضافی جلوگیری کنید.
ویژگی های Performance
تولید تصاویر کوچک یک عملیات CPU فشرده است، به ویژه برای فیلم های با وضوح بالا 4K، این بهترین شیوه ها را دنبال کنید:
- همیشه در یک صف پس زمینه (به عنوان مثال، تماس بگیرید.
- یک {{FLT:35}} برای کاهش ابعاد تصویر خروجی تنظیم کنید.یک اندازه 320x240 برای تصاویر کوچک کافی است.
- از [FLT36] استفاده کنید تا ژنراتور به جای حل دقیق ترین رمز، نزدیک ترین فریم را از بین ببرد.
- هر نسل ناهمگونی را که در آن مشاهده ناپدید می شود، لغو کنید.
- برای نمایش در یک دید جمع آوری، تولید عکس های کوچک در اندازه دقیق سلول و اجتناب از تجدید نظر در موضوع اصلی.
ادغام با 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)
}
}
}
}
پیشرفته سفارشی سازی
تصاویر با ترکیب ویدئو
اگر ویدیوی شما از یک استفاده می کند (به عنوان مثال، Watermark overlay، تنظیمات رنگ)، می توانید آن را به ژنراتور تصویر منتقل کنید:
imageGenerator.videoComposition = myVideoComposition
تصویرهای کوچک تولید شده، خروجی کامپوزیت شده را منعکس می کنند.
تولید تصاویر برای Live Photos
Live Photos ترکیبی از یک ویدیو و یک تصویر هنوز است که برای استخراج یک عکس کوچک از ویدیو زیر زمینی، از استفاده می کند و قبل از تغذیه آن به AVFoundation، یک URL ویدئویی را درخواست می کند.
قابلیت دسترسی و تجربه کاربری
Thumbnails اسکن بصری را افزایش می دهد، اما همیشه یک جایگزین متن برای کاربران VoiceOver ارائه می دهد.از در نظر تصویر استفاده کنید، توصیف محتوای ویدئویی در صورت امکان.
imageView.isAccessibilityElement = true
imageView.accessibilityLabel = "Thumbnail of video: \(videoTitle)"
منابع خارجی
برای درک عمیق تر، با موارد زیر مشورت کنید:
- [[ویرایش] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱]
- [[ویرایش] [۱]
- WDC 2019: AVFoundation Performance Tips
نتیجه گیری
ساخت یک ژنراتور عکس سفارشی با AVFoundation به شما آزادی کامل را در کیفیت تصویر، زمان و عملکرد می دهد.با استفاده از هر دو به طور همزمان و به عنوان هماهنگ، دستکاری خطا و نتایج Caching، شما می توانید یک تجربه کاربر یکپارچه در برنامه iOS خود را ارائه دهید، چه شما فایل های محلی را پردازش می کنید یا فیلم های از راه دور، تکنیک های پوشش داده شده در اینجا به شما کمک می کند تا به سرعت تصاویر و به شما کمک کند.