How to extract a UIImage from a video in iOS 9

Here are two ways to extract the first frame of vision and turn it into a UIImage. Both methods are from the generous Stack Overflow community.

Both methods make use to the AV Foundation framework. There’s no need to import it, UIKit will take care of it for us.

Video URLs can be obtained in many ways, one of which is from something like an image picker. You can grab the URL in its didFinishPickingMediaWithInfo delegate method:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    
    // dismiss the picker
    [self dismissViewControllerAnimated:YES completion:nil];

    // grab the video
    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
}

Now that we have a video URL, let’s see how we can extract a UIImage from it.

Method 1: Short and Sweet

Here’s a short and sweet method by nullp0inter. This will extract the first frame of the video:

- (UIImage *)firstFrame:(NSURL *)videoURL {

    // courtesy of null0pointer and Javi Campaña
    // http://stackoverflow.com/questions/10221242/first-frame-of-a-video-using-avfoundation
    
     AVURLAsset* asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
     AVAssetImageGenerator* generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
     generator.appliesPreferredTrackTransform = YES;
     UIImage* image = [UIImage imageWithCGImage:[generator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]];
    
    return image;
}

This creates an image generator from an asset, from which we can extract a CGImage near an iframe of the video. We’ll create our own time using CMTimeMake, setting it to the very beginning here.

Then we’ll turn the CGImage into a more usable UIImage. Setting the appliesPreferredTrackTransform property to YES guarantees that the image is returned the correct way up, rather than rotated (which otherwise happens sometimes).

 

Method 2: Complex and Elaborate

Another way to extract a UIImage comes courtesy of memmons. The principle is the same as above, with additional error checks in place, and the option to specify an NSTimeInterval at which the image should be returned:

- (UIImage *)imageFromVideo:(NSURL *)videoURL atTime:(NSTimeInterval)time {
    
    // courtesy of memmons
    // http://stackoverflow.com/questions/1518668/grabbing-the-first-frame-of-a-video-from-uiimagepickercontroller
    
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
    NSParameterAssert(asset);
    AVAssetImageGenerator *assetIG =
    [[AVAssetImageGenerator alloc] initWithAsset:asset];
    assetIG.appliesPreferredTrackTransform = YES;
    assetIG.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
    
    CGImageRef thumbnailImageRef = NULL;
    CFTimeInterval thumbnailImageTime = time;
    NSError *igError = nil;
    thumbnailImageRef =
    [assetIG copyCGImageAtTime:CMTimeMake(thumbnailImageTime, 60)
                    actualTime:NULL
                         error:&igError];
    
    if (!thumbnailImageRef)
        NSLog(@"thumbnailImageGenerationError %@", igError );
    
    UIImage *image = thumbnailImageRef
    ? [[UIImage alloc] initWithCGImage:thumbnailImageRef]
    : nil;
    
    return image;
}

Further Reading





Leave a Reply