swiftuikitavfoundationphassetavkit

Split PHAsset to frames swift


I need to split video(PHAsset) to frames. Please could anyone write an extension for PHAsset for example to call function like this:

extension PHAsset {
   func getFrame(timecode: Float) -> UIImage? {
      *something*
      return frame
   }
}

You can change parameters in below function. Help!


Solution

  • Try this:

    import Photos
    
    extension PHAsset {
        
        func getVideoFrames(completion: @escaping ([UIImage]?) -> Void) {
            guard self.mediaType == .video else { completion(nil); return }
            
            let manager = PHCachingImageManager()
            
            manager.requestAVAsset(forVideo: self, options: nil) { asset, audioMix, info in
                guard let asset = asset else { completion(nil); return }
                let imgGenerator: AVAssetImageGenerator = AVAssetImageGenerator(asset: asset)
                imgGenerator.appliesPreferredTrackTransform = true
                imgGenerator.requestedTimeToleranceBefore = CMTimeMake(value: 1, timescale: 15)
                imgGenerator.requestedTimeToleranceAfter = CMTimeMake(value: 1, timescale: 15)
                let duration: Float64 = CMTimeGetSeconds(asset.duration)
                var frames = [UIImage]()
                for index: Int in 0..<Int(duration) {
                    let time: CMTime  = CMTimeMakeWithSeconds(Float64(index), preferredTimescale: 600)
                    let cgImage: CGImage
                    do {
                        try cgImage = imgGenerator.copyCGImage(at: time, actualTime: nil)
                        frames.append(UIImage(cgImage: cgImage))
                    } catch {
                        print("Error generating image: \(error)")
                    }
                }
                completion(frames)
            }
        }
    }
    
    

    Usage:

    let asset = // Some PHAsset
    var frames = [UIImage]()
    asset.getVideoFrame { images in 
        if let images = images {
            frames = images
            // Do something
        }
    }