일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CPU
- debounce
- image
- Subject
- Thumbnail
- collision
- Filtering
- totalCostLimit
- operator
- publisher
- LinearProbing
- subscriber
- memory
- Video
- UINavigationController
- Subscription
- Hashtable
- switchToLatest
- DICTIONARY
- flatMapLatest
- countLimit
- NSCache
- SWIFT
- FlatMap
- combine
- IOS
- Throttle
- document
- Today
- Total
felix-iOS
[iOS] 영상의 URL을 통해 Thumbnail을 구해봅시다.(1) 본문
안녕하세요! 이번글은 영상의 Thumbnail을 구하는 방법에 대한 글을 작성하려고 합니다.
예전에 Notion에 정리해뒀던 내용인데 혼자 보기에는 좀 아까워서 ㅎㅎ..🥸
이번 주제에 대해서는
- 일반적인 영상의 Thumbnail 구하기
- HLS 포맷 영상의 Thumbnail 구하기
요렇게 두가지로 나눠서 연재를 해보려고 합니다!
직접 경험해본 내용을 토대로 작성하는 것이기 때문에 틀린부분이 있다면 지적 부탁드립니다 :)
일반적인 영상의 Thumbnail 구하기
일반적인 영상이란 것은 .mp4 포맷의 영상을 말합니다. mp4는 단일 파일로 구성되어 인코딩된 비디오, 오디오 등을 포함하는 컨테이너 형식입니다. 해당 포맷의 영상의 같은 경우에는 AVFoundation에서 제공하는 AVAssetImageGenerator를 통해서 쉽게 구할 수 있습니다.
AVAssetImageGenerator에 대한 공식문서를 확인해보면,
An object that generates thumbnail or preview images of video assets.
Video Asset의 미리보기 이미지나 Thumbnail을 생성하는 객체
라고 정의하고 있습니다.
let myUrl = URL(string: "some url")!
let myAsset = AVAsset(url: myUrl)
let imageGenerator = AVAssetImageGenerator(asset: asset)
위 코드로 imageGenerator를 생성합니다. (저는 강제 언래핑을 싫어합니다!😭)
"Asset의 미리보기 이미지나 Thumbnail을 생성하는 객체" 의 인스턴스는 생성을 했습니다. 이제 이미지를 구해봐야되겠죠?
generateCGImagesAsynchronously(forTimes:completionHandler:)
AVAssetImageGenerator를 통해 이미지를 구하는 두 가지 인스턴스 메서드 입니다. 하나 하나 알아봅시다!
copyCGImage(at:actualTime:)
asset에서 지정된 시간 또는 가까운(near) 시간의 이미지를 반환합니다.
generateCGImagesAsynchronously(forTimes:completionHandler:)
asset에서 지정된 시간 또는 가까운(near) 시간의 일련의 이미지를 생성합니다.
두 메서드의 가장 큰 차이는 두 가지 입니다.
- copyCGImage는 sync하게 하나의 이미지만 반환합니다.
- generateCGImagesAsynchronously는 async하게 일련의 이미지를 반환합니다.
먼저 copyCGImage를 사용해봅시다!
let time: CMTime = CMTime(value: 600, timescale: 600)
guard let cgImage = try? imageGenerator.copyCGImage(at: time, actualTime: nil) else { fatalError() }
let uiImage = UIImage(cgImage: cgImage)
CMTime의 경우 value를 분자 timescale을 분모로 생각하시면 됩니다. value / timescale = second 요런식으로 계산해서 초를 구합니다! 위 코드는 imageGenerator를 통해 sync하게 영상의 1초쯤 되는 프레임의 CGImage를 받아옵니다. UIImage로 사용하고 싶다면 변경을 해줘야합니다. 굉장히 간단합니다 :)
다음은 generateCGImagesAsynchronously를 사용해보겠습니다.
let firstTime = CMTime(value: 600, timescale: 600)
let secondTime = CMTime(value: 1200, timescale: 600)
let times: [NSValue] = [firstTime as NSValue, secondTime as NSValue]
imageGenerator.generateCGImagesAsynchronously(forTimes: times) { _, image, _, _, _ in
// handle CGImage
}
이렇게 async한 방법으로 image를 생성합니다. completionHandler 안에서 생성된 CGImage를 처리해주면 됩니다! 그런데 completionHandler에 뭔가 많네요. 한 번 알아봅시다 :)
typealias AVAssetImageGeneratorCompletionHandler = (CMTime, CGImage?, CMTime, AVAssetImageGenerator.Result, Error?) -> Void
요런식으로 구성이 되어 있습니다.
- requestedTime 이미지를 요청한 시간입니다. 우리가 generate를 요청할 때 forTimes에 시간을 넣어놨죠? 그것을 고대로 반환해줍니다.
- image 요청한 시간에 맞는 CGImage입니다.
- actualTime 이미지가 실제로 생성된 시간입니다.
- result 성공, 실패 또는 취소에 대한 결과를 반환합니다. (취소의 경우에는 cancelAllCGImageGeneration()을 확인해주세요.)
- error 만약 result가 실패인 경우에 대한 error를 반환해줍니다.
이제 사용방법에 대해서는 어느정도 알아봤는데요. 아까부터 좀 거슬리는 부분이 있을겁니다. 이미지를 생성하는 메서드들의 정의에서는 "asset에서 지정된 시간 또는 가까운(near) 시간의 이미지를 반환합니다." 이렇게 설명을합니다. 또 actualTime이 있는 것으로 보아 실제로 요청된 시간과 생성된 시간은 다르다는 것을 암시하는 것 같습니다. 이 부분에 대해서 알아보겠습니다.
AVAssetImageGenerator의 공식문서를 확인해보면,
생성된 이미지의 actualTime은 [요청된시간 - requestedTimeToleranceBefore, 요청된시간 + reqeustedTimeToleranceAfter]의 범위 안에 있습니다. 이 값은 효율성과 관련하여 요청된 시간과 다를 수 있습니다.
오옹.. 효율성의 문제 때문에 정확한 시간이 아니라 약간의 오차범위를 두고 있다는 것 같습니다. requestedTimeToleranceBefore/After에 대한 공식문서도 확인해보면 일단 기본값은 positiveInfinite입니다. 이 값을 zero로 할 경우 원하는 시간의 프레임에 정확히 접근할 수 있지만 이로 인해 추가적인 디코딩 지연이 발생할 수 있다고 하네요! 효율성과 정확성의 우선순위를 두고 값을 설정하면 좋을 것 같습니다 :)
이번 게시글에서는 일반적인 영상 포맷의 Thumbnail을 구하는 방법에 대해 알아봤습니다. 이 부분은 굉장히 간단하기 때문에 중요한 부분은 HLS 영상의 Thumbanil을 구하는 부분인 것 같아요. 그것은 다음 게시글에서 작성해보겠습니다!
긴 글 읽어주셔서 감사합니다 :) 잘못된 부분에 대한 지적은 언제나 환영입니다🤟
Referece
https://developer.apple.com/documentation/avfoundation/avassetimagegenerator
'iOS' 카테고리의 다른 글
[iOS] UINavigationController 공식문서 번역 (0) | 2021.08.20 |
---|---|
[iOS]NSCache에 대해 알아보자! (0) | 2021.08.13 |
[iOS] AutoLayout으로 애니메이션 구현하기 (2) | 2021.07.26 |
[iOS] WWDC 2018 Image and Graphics Best Practice (0) | 2021.07.21 |
[iOS] UIImage 공식문서를 파헤쳐봅시다! (0) | 2021.06.23 |