If I run the following in a project where ARC is enabled the completion handler never fires. But without ARC it works as expected. What am I missing here?
NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime,
CGImageRef im,
CMTime actualTime,
AVAssetImageGeneratorResult result,
NSError *error){
NSLog(@"completion handler");
};
generator.maximumSize = CGSizeMake(320, 180);
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
Based on Michael pointing out that generator doesn't get retained, if you simply 'use' the generator var inside the completion block, everything will work.
So I guess the answer is...
NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime,
CGImageRef im,
CMTime actualTime,
AVAssetImageGeneratorResult result,
NSError *error){
NSLog(@"make sure generator is used in this block and it'll work %@", generator);
};
generator.maximumSize = CGSizeMake(320, 180);
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
Looks like generateCGImagesAsynchronouslyForTimes does not retain the generator. Make generator a member variable of your instance and assign to it. As soon as I did that, it started working. The code will look something like this:
NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
[generator_ cancelAllCGImageGeneration];
generator_ = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator_.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime,
CGImageRef im,
CMTime actualTime,
AVAssetImageGeneratorResult result,
NSError *error){
NSLog(@"completion handler");
};
generator_.maximumSize = CGSizeMake(320, 180);
[generator_ generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
The image generator definitely does not get retained by the framework. Not sure how often Apple Programming Guide gets updated, but you can read that in AV Foundation Prog. Guide, in Generating a Sequence of Images quite clearly:
In addition, you must ensure that you retain the image generator
until it has finished creating the images.