I’m wanting random access to individual movie frames so I’m using the AVAssetImageGenerator class but for this part of the project using generateCGImagesAsynchronously is not appropriate. Now clearly performance is not the crucial component here but at the same time you don’t want to do something that is stupidly slow.

I’d like to not have to hold onto a AVAssetImageGenerator object to use each time I need an image but just create one at the time a image is requested. So I thought I’d find out the penalty of creating a AVAssetImageGenerator object each time.

To compare the performance I added some performance tests and ran those tests on my i7 MBP with an SSD and on my iPad Mini 2. I’ve confirmed that the images are generated. See code at end.

On my iPad Mini 2 the measure block in performance test 1 took between 0.25 and 0.45 seconds to run. Most results clustering around 0.45 seconds. It was the second run that returned the 0.25 second result. Performance test 2 on the iPad Mini 2 was much more consistent with times ranging between 0.5 and 0.52 seconds. But reversing the order in which the tests run reverses these results. I’m not sure what to think about this, but in relation to what I’m testing for I feel comfortable that the cost of creating an AVAssetImageGenerator object before generating an image is minimal in comparison to generating the CGImage.

Strangely my MBP pro is slower, but doesn’t have the variation observed on the iPad. The measure block in both performance tests take 1.1 seconds.

Whatever performance difference there is in keeping a AVAssetImageGenerator object around or not is inconsequential.

    func testAVAssetImageGeneratorPerformance1() {
        let options = [
            AVURLAssetPreferPreciseDurationAndTimingKey: true,
            AVURLAssetReferenceRestrictionsKey:
                AVAssetReferenceRestrictions.RestrictionForbidNone.rawValue
        ]
        
        let asset = AVURLAsset(URL: movieURL, options: options)!
        self.measureBlock() {
            let generator = AVAssetImageGenerator(asset: asset)
            var actualTime:CMTime = CMTimeMake(0, 600)
            for i in 0..<10 {
                let image = generator.copyCGImageAtTime(
                    CMTimeMake(i * 600 + 30, 600),
                    actualTime: &actualTime, error: nil)
            }
        }
    }
    
    func functionToTestPerformance(#movieAsset:AVURLAsset, index:Int) -> Void {
        let generator = AVAssetImageGenerator(asset: movieAsset)
        var actualTime:CMTime = CMTimeMake(0, 600)
        let image = generator.copyCGImageAtTime(
            CMTimeMake(index * 600 + 30, 600),
            actualTime: &actualTime, error: nil)
    }
    
    func testAVAssetImageGeneratorPerformance2() {
        let options = [
            AVURLAssetPreferPreciseDurationAndTimingKey: true,
            AVURLAssetReferenceRestrictionsKey:
                AVAssetReferenceRestrictions.RestrictionForbidNone.rawValue
        ]
        
        let asset = AVURLAsset(URL: movieURL, options: options)!
        self.measureBlock() {
            for i in 0..<10 {
                self.functionToTestPerformance(movieAsset: asset, index: i)
            }
        }
    }