해결 및 요약
1. 동영상 캡처 시 캡쳐 할 동영상 시간의 오차 범위를 제한한다.
2. 시간 별 영상 프레임 캡처를 실패 할 경우를 고려한다.
문제 상황
💡 동영상을 FPS에 맞도록 이미지 배열들을 생성하지만, AVAssetImageGenerator에서 동영상 캡쳐를 요청하는 시간대와 AVAssetImageGenerator에서 반환하는 캡쳐한 영상의 시간대가 다르다.
위의 Track이 출력되면 4개의 프레임이 모두 같은 시간대의 이미지를 캡쳐하고 있음..!
...
for idx in (0..<Int(duration * 24)){
let time = CMTime(seconds: Double(idx) / 24, preferredTimescale: 600)
let (img,actualTime) = try await generator.image(at: time)
print("\(idx)-------------")
print("요청 Track: \(time.seconds)초")
print("실제 캡쳐 Track 시간 \(actualTime.seconds)초")
print("------------------\n")
}
문제 해결 접근
참고 자료
[WWDC22] 더욱 응답성 높은 미디어 앱 만들기(Create a more responsive media app)
안녕하세요 화요괴물 입니다!! 이번 글은 WWDC 22의 Create a more responsive media app 이라는 세션을 듣고 정리했습니다
medium.com
1. AVAssetImageGenerator의 오차 범위 설정하기
...
var images: [[UIImage]] = [[],[],[],[]]
...
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
generator.requestedTimeToleranceBefore = .init(seconds: Double(0.95 / 24), preferredTimescale: 600)
generator.requestedTimeToleranceAfter = .init(seconds: Double(0.95 / 24), preferredTimescale: 600)
for idx in (0..<Int(v.minDuration * 24)){ // FPS 기준 시간의 반복문
let time = CMTime(seconds: Double(idx) / 24, preferredTimescale: 600)
let (img,actual) = try? await generator.image(at: time)
if let img{
self.images[containerIdx].append(UIImage(cgImage:img))
}
}
...
- 동영상을 이미지 캡쳐 프레임을 24 FPS로 나누도록 제작
- 각 동영상 별 이미지 캡쳐 프레임을 담는 배열
[UIImage]
의 Count를 총 영상을 담을 시간을 기준으로 개수로 미리 생성함 - 캡쳐 허용 오차 시간을 24 FPS보다 작게 해, 영상 Track 접근을 24 FPS 별 추출할 수 있도록 제작
requestedTimeToleranceBefore
프로퍼티 값requestedTimeToleranceAfter
프로퍼티 값
- FPS 기준 시간의 반복문을 통해 동영상에서 이미지를 캡쳐하는 generator의 로직을 수행, FPS 기준 시간 인덱스에 접근해 이미지 값 할당
문제점
🚨 동영상의 일부를 빠르게 캡쳐를 시도하는 메서드이기 때문에 캡쳐에 실패할 경우가 있다.
let (img,actual) = try await generator.image(at: time)
2. 동영상 캡쳐를 실패 했을 경우 대비하기
옵셔널 타입과 이미지 프레임 배열의 Count를 미리 선언해 대응한다.
- 영상별 이미지 프레임 배열 생성 로직
...
// 1번 변경 사항
var images: [[UIImage?]] = [0,0,0,0].map{
Array(repeating: nil, count: Int(v.minDuration * 24) + 1)
}
...
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
generator.requestedTimeToleranceBefore = .init(seconds: Double(0.95 / 24), preferredTimescale: 600)
generator.requestedTimeToleranceAfter = .init(seconds: Double(0.95 / 24), preferredTimescale: 600)
for idx in (0..<Int(v.minDuration * 24)){ // FPS 기준 시간의 반복문
let time = CMTime(seconds: Double(idx) / 24, preferredTimescale: 600)
let (img,actual) = try? await generator.image(at: time)
// 2번 변경 사항
self.images[containerIdx][idx] = UIImage(cgImage: img)
}
...
✅ 미리 옵셔널 값으로 생성해 추출에 실패한 인덱스의 이미지는 `nil` 로 보존
- 이미지 프레임 배열 동시에 할당
...
for i in 0..<Int(self.minDuration! * 24) {
[imageView1,imageView2,imageView3,imageView4].enumerated().forEach { idx,view in
if let img = images[idx][i]{
view.image = img
}
}
...
// 위에서 프레임 별로 이미지가 바뀌는 UIImageView들을
// 하나의 장면으로 캡쳐해서 이미지로 저장하는 로직...
}
✅ 옵셔널 값이 존재해야만 기존 UIImageView에서 이미지를 바꾼다. 해당 프레임에 영상이 없을 경우, 해당 영역의 이미지가 사라지는 것이 아닌, 이전 이미지를 그대로 볼 수 있다.
해결 및 결론
결론
- 영상 추출 시, 추출할 Track의 시간 범위를 할당하지 않으면, 자체적인 시간 범위를 할당해 원하는 Track 추출을 하지 못할 수 있다.
- 영상을 추출하는 것은 실패 가능성이 있으므로 실패의 경우를 고려해서 로직을 구성해야한다.
추가 고려사항
- 여러 개별 동영상을 개별 이미지 배열들로 만드는 과정까지 성공
- 위에서 만든 이미지 배열들을 하나의 장면으로 만들고 이어 붙이는 과정에 최적화 필요
참고 자료
AVAssetImageGenerator | Apple Developer Documentation\
AVAssetImageGenerator | Apple Developer Documentation
An object that generates images from a video asset.
developer.apple.com
공동 개발자
Xerath의 코딩 공부
xerathcoder.tistory.com
'이모저모 > AVFoundation' 카테고리의 다른 글
9주차. 동영상 압축기술(1) (0) | 2024.07.07 |
---|---|
7주차. 영상처리(Image processing) (0) | 2024.07.07 |
6주차. 정지영상 파일 포맷 및 압축 (0) | 2024.06.23 |
4주차. 데이터 에러 검출 및 복구 (0) | 2024.06.15 |
3주차. 산술 부호화 (0) | 2024.06.15 |
댓글