안녕하세요 코더스하이!
이번에 개발중인 앱에서 핵심 기능인 비디오에서 프레임을 추출하는 부분에 문제가 있어 질문드립니다.
참고할만한 레퍼런스나 링크 무엇이든 답변해주시면 감사하겠습니다!
구현하고자 하는 기능
- 설정된 fps 값을 바탕으로 카메라롤에서 선택한 비디오의 모든 프레임을 이미지 배열로 저장
- 썸네일이 아닌 해상도 감소가 없는 이미지로 추출
문제점
- 1분이 넘는 동영상을 아래 코드로 추출해도 총 16개의 프레임 밖에 나오지 않음
- 비디오에 따라 같은 frame 이 여러번 추출되는 경우도 있었음
시도한 코드 1
private func video2ImageGenerator(video_url url : URL, mediaType type : String){
//https://stackoverflow.com/questions/42665271/swift-get-all-frames-from-video
let videoURL : URL = url
var generator : AVAssetImageGenerator!
let asset : AVAsset = AVAsset(url: videoURL)
let duration: Float64 = CMTimeGetSeconds(asset.duration)
generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
let tracks = asset.tracks(withMediaType: .video)
let fps = ceil((tracks.first?.nominalFrameRate)!)
let totalFrameNum = Int(Double(fps) * duration)
print("duration: \(duration)")
print("total frame: \(totalFrameNum)")
print("fps: \(fps)")
let timeScale = 100
let convertedFps = 1
let convertedTimeGap = Int32(timeScale/convertedFps)
var index = 0
while(Int32(index) * convertedTimeGap < Int32(duration * Double(timeScale))){
let time:CMTime = CMTimeMakeWithSeconds(Float64(index), preferredTimescale: convertedTimeGap)
print("time: \(time)")
let image:CGImage
do {
try image = generator.copyCGImage(at: time, actualTime: nil)
}catch {
print("pass")
return
}
imageArray.append(UIImage(cgImage: image))
index = index + 1
}
print("image frame count : \(self.imageArray.count)")
}
시도한 코드2
import UIKit
import AVFoundation
import AVKit
import Photos
import Combine
class Video2Image{
let assetIG: AVAssetImageGenerator
let fps: Int
let running_time: Double
let total_frame_num: Int
init(
video_url: URL
){
// let video_url = Bundle.main.url(forResource: resource_name, withExtension: suffix_name)!
let video_url = video_url
let asset = AVAsset(url: video_url)
self.assetIG = AVAssetImageGenerator(asset: asset)
assetIG.appliesPreferredTrackTransform = true
assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
let tracks = asset.tracks(withMediaType: .video)
self.fps = Int(ceil((tracks.first?.nominalFrameRate)!))
self.running_time = Double(asset.duration.value) / 600.0
self.total_frame_num = Int(Double(fps) * running_time)
}
func getSingleFrame(frame: Int) -> UIImage? {
let timestamp = Double(frame) / Double(fps)
let cm_time = CMTime(seconds: timestamp, preferredTimescale: 60)
let image_ref: CGImage
do {
image_ref = try self.assetIG.copyCGImage(at: cm_time, actualTime: nil)
} catch let error{
print("Error: \(error)")
return nil
}
return UIImage(cgImage: image_ref)
}
}