Im trying to edit existing movie with added effects on top thus I need ability to scan all movie frames, get them as UIImage, apply effect and then either update that frame or write it into new movie. What I found is people suggesting to use AVAssetImageGenerator. Below is my final edited sample of how Im doing it:
-(void)processMovie:(NSString*)moviePath {
NSURL* url = [NSURL fileURLWithPath:moviePath];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
float movieTimeInSeconds = CMTimeGetSeconds([movie duration]);
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.requestedTimeToleranceBefore = generator.requestedTimeToleranceAfter = kCMTimeZero;
generator.appliesPreferredTrackTransform=TRUE;
[asset release];
// building array of time with steps as 1/10th of second
NSMutableArray* arr = [[[NSMutableArray alloc] init] retain];
for(int i=0; i<movieTimeInSeconds*10; i++) {
[arr addObject:[NSValue valueWithCMTime:CMTimeMake(i,10)]];
}
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
if (result == AVAssetImageGeneratorSucceeded) {
UIImage* img = [UIImage imageWithCGImage:im];
// use img to apply effect and write it in new movie
// after last frame do [generator release];
}
};
[generator generateCGImagesAsynchronouslyForTimes:arr completionHandler:handler];
}
2 problems with this approach:
- I need to guess what timesteps movie has or as in my example assume that its 10FPS for movie. Actual timesteps are not evenly spaced plus sometime we have skipped frames.
- It is slow to scan through the frames. If movie is recorded in high resolution I get around 0.5 seconds to retrieve UIImage for each frame.
It seems unnatural. Question: is there better way to scan all original frames of the movie?