Extract frame from video in fast

I am trying to extract frames like UIImages from a video in Swift. I found several Objective-C solutions, but I'm having trouble finding anything in Swift. Assuming the following is correct, can someone help me convert the following to Swift or give me my own opinion on how to do this?

- (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;
}
+4
source share
1 answer

It really worked.

func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? {
    let asset = AVURLAsset(url: url)

    let assetIG = AVAssetImageGenerator(asset: asset)
    assetIG.appliesPreferredTrackTransform = true
    assetIG.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels

    let cmTime = CMTime(seconds: time, preferredTimescale: 60)
    let thumbnailImageRef: CGImage
    do {
        thumbnailImageRef = try assetIG.copyCGImage(at: cmTime, actualTime: nil)
    } catch let error {
        print("Error: \(error)")
        return nil
    }

    return UIImage(cgImage: thumbnailImageRef)
}

But remember that this function is synchronous, and it’s better not to call it in the main queue.

You can do the following:

DispatchQueue.global(qos: .background).async {
    let image = self.imageFromVideo(url: url, at: 0)

    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

Or use generateCGImagesAsynchronouslyinstead copyCGImage.

+5
source

Source: https://habr.com/ru/post/1671084/


All Articles