web-dev-qa-db-fra.com

iPhone Lire UIimage (cadres) d'une vidéo avec AVFoundation

Désolé pour mon anglais) À la recherche d'informations sur les images lues d'une vidéo avec iPhone, j'ai trouvé ce projet, http://www.codza.com/extracting-frames-from-movies-on-iphone/comment-page-1 # comment-1116 , mais j'ai aussi lu quelque part que vous pouvez utiliser AVFoundation pour capturer des images d'une vidéo pour de meilleures performances.

Mais je ne trouve pas d'informations sur la façon dont je peux le faire ...

Une idée?

Merci d'avoir lu

21
matiasfh

Vous parlez d'utiliser les appels pour générer ce que Apple appelle des images miniatures à partir de vidéos à des heures précises.

Pour un MPMoviePlayerController (qu'iOS utilise pour stocker une vidéo à partir d'un fichier ou d'une autre source), deux commandes permettent d'effectuer cette opération. Le premier génère une seule vignette (image) à partir d'un film à un moment donné, et le second génère un ensemble de vignettes pour une période donnée.

Cet exemple obtient une image à 10 secondes dans un clip, myMovie.mp4 :

MPMoviePlayerController *movie = [[MPMoviePlayerController alloc]
        initWithContentURL:[NSURL URLWithString:@"myMovie.mp4"]];
UIImage *singleFrameImage = [movie thumbnailImageAtTime:10 
        timeOption:MPMovieTimeOptionExact];

Notez que cela fonctionne de manière synchrone - c’est-à-dire que l’utilisateur sera obligé d’attendre pendant que vous obtenez la capture d’écran.

L’autre option est d’obtenir une série d’images d’un film à partir de plusieurs époques:

MPMoviePlayerController *movie = [[MPMoviePlayerController alloc]
        initWithContentURL [NSURL URLWithString:@"myMovie.mp4"]];
NSNumber time1 = 10;
NSNumber time2 = 11;
NSNumber time3 = 12;
NSArray *times = [NSArray arrayWithObjects:time1,time2,time3,nil];
[movie requestThumbnailImagesAtTimes:times timeOption:MPMovieTimeOptionExact];

Cette deuxième manière déclenchera une notification de type MPMoviePlayerThumbnailImageRequestDidFinishNotification chaque fois qu'une nouvelle image est générée. Vous pouvez configurer un observateur pour surveiller cela et traiter l'image. Je vous laisse travailler par vous-même!

37
h4xxr

Vous pouvez également essayer AVAssetImageGenerator , plus précisément generateCGImagesAsynchronouslyForTimes: completionHandler .

Cette SO réponse a un bon exemple de code.

18
Steve

Swift 2 code pour prendre des images avec AVAssetImageGenerator:

func previewImageForLocalVideo(url:NSURL) -> UIImage?
{
    let asset = AVAsset(URL: url)
    let imageGenerator = AVAssetImageGenerator(asset: asset)
    imageGenerator.appliesPreferredTrackTransform = true

    var time = asset.duration
    //If possible - take not the first frame (it could be completely black or white on camara's videos)
    time.value = min(time.value, 2)

    do {
        let imageRef = try imageGenerator.copyCGImageAtTime(time, actualTime: nil)
        return UIImage(CGImage: imageRef)
    }
    catch let error as NSError
    {
        print("Image generation failed with error \(error)")
        return nil
    }
}
5
Avt

Dans Swift 4, cela fonctionnait pour moi avec quelques modifications, changeant principalement le paramètre "at" de imageGenerator.copyCGImage en un type CMTime:

func showFrame(from file:String) {
    let file = file.components(separatedBy: ".")
    guard let path = Bundle.main.path(forResource: file[0], ofType:file[1]) else {
        debugPrint( "\(file.joined(separator: ".")) not found")
        return
    }
    let url = URL(fileURLWithPath: path)
    let image = previewImageForLocalVideo(url: url)
    let imgView = UIImageView(image: image)
    view.addSubview(imgView)
}    

func previewImageForLocalVideo(url:URL) -> UIImage? {
    let asset = AVAsset(url: url)
    let imageGenerator = AVAssetImageGenerator(asset: asset)
    imageGenerator.appliesPreferredTrackTransform = true
    let tVal = NSValue(time: CMTimeMake(12, 1)) as! CMTime
    do {
        let imageRef = try imageGenerator.copyCGImage(at: tVal, actualTime: nil)
        return UIImage(cgImage: imageRef)
    }
    catch let error as NSError
    {
        print("Image generation failed with error \(error)")
        return nil
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    showFrame(from:"video.mp4")
}

La source

1
Mike Lee

Voici le code pour obtenir des images FPS à partir d'une vidéo

1) Importer

#import <Photos/Photos.h>

2) dans viewDidLoad

    videoUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:@"VfE_html5" ofType:@"mp4"]];
    [self createImage:5]; // 5 is frame per second (FPS) you can change FPS as per your requirement.

3) fonctions

-(void)createImage:(int)withFPS {
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
    AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    generator.requestedTimeToleranceAfter =  kCMTimeZero;
    generator.requestedTimeToleranceBefore =  kCMTimeZero;

    for (Float64 i = 0; i < CMTimeGetSeconds(asset.duration) *  withFPS ; i++){
        @autoreleasepool {
            CMTime time = CMTimeMake(i, withFPS);
            NSError *err;
            CMTime actualTime;
            CGImageRef image = [generator copyCGImageAtTime:time actualTime:&actualTime error:&err];
            UIImage *generatedImage = [[UIImage alloc] initWithCGImage:image];
            [self savePhotoToAlbum: generatedImage]; // Saves the image on document directory and not memory
            CGImageRelease(image);
        }
    }
}

-(void)savePhotoToAlbum:(UIImage*)imageToSave {

    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:imageToSave];
    } completionHandler:^(BOOL success, NSError *error) {
        if (success) {
            NSLog(@"sucess.");
        }
        else {
            NSLog(@"fail.");
        }
    }];
}
0
Hardik Thakkar