How to capture frames from a video using generateCGImagesAsynchronously()

Hello,


I am trying to capture frames from a video and I'm currently using generateCGImagesAsynchronously(). The problem is that each frame is captured at 0.0s, 1.0s, 2.0s, 3.0s ... But I really want to capture it at 0.0s, 0.2s, 0.4s ...


Here is my code

if let path = Bundle.main.path(forResource: "video", ofType:"MOV") {
    let fileUrl  = NSURL(fileURLWithPath: path)
    let asset = AVURLAsset(url: (fileUrl as URL), options: nil)
    let videoDuration = asset.duration
      
    let generator = AVAssetImageGenerator(asset: asset)

    var frameForTimes = [NSValue]()
    let sampleCounts = 20
    let totalTimeLength = Int(videoDuration.seconds * Double(videoDuration.timescale))
    let step = totalTimeLength / sampleCounts
  
    for i in 0 ..< sampleCounts {
        let cmTime = CMTimeMake(Int64(i * step), Int32(videoDuration.timescale))
        frameForTimes.append(NSValue(time: cmTime))
    }
  
    generator.generateCGImagesAsynchronously(forTimes: frameForTimes, completionHandler: {requestedTime, image, actualTime, result, error in
        DispatchQueue.main.async {
            if let image = image {
                print(requestedTime.value, requestedTime.seconds, actualTime.value)
                self.frames.append(UIImage(cgImage: image))
            }
        }
    })
}


The timescale is 600 and actualTime.value is always at 0, 601, 1202, 1802 ... It seems that it is only taking frames at an integer seconds (0, 1, 2, 3 ...)


Is there a way to capture frames at non-integer seconds using generateCGImagesAsynchronously()? For example: 0.2s, 0.4s?


Or should I look into other APIs?



Thank you,

Jass

  • Hi, I am new to swift and am faced with a similar problem to solve. Your code seems to work for me except for your last line when you type: self.frames.append(UIImage(cgImage: image)). When I use the line of code in my app, i get the error message: Type 'FrameExtract' has no member 'frames'. I assume that this only worked with a previous version of Swift. Do you know what I could do to make this work with the most recent version of Swift? Thank you in advance for your help.

Add a Comment

Replies

Need these two lines:

generator.requestedTimeToleranceAfter = kCMTimeZero
generator.requestedTimeToleranceBefore = kCMTimeZero
Thank you, really appreciated