J'ai passé toute la journée et ai traversé beaucoup de réponses SO, references Apple, documentations, etc, mais pas de succès.
Je veux une chose simple: je joue une video en utilisant AVPlayer et je veux mettre en pause et get le cadre actuel comme UIImage
. C'est tout.
Ma video est un file m3u8 situé sur Internet, il est joué normalement dans AVPlayerLayer
sans aucun problème.
Qu'ai-je essayé?
AVAssetImageGenerator
. Il ne fonctionne pas, la méthode copyCGImageAtTime:actualTime: error:
renvoie null image réf. Selon la réponse , AVAssetImageGenerator
ne fonctionne pas pour le streaming de videos. renderInContext:
sur AVPlayerLayer
, mais ensuite j'ai réalisé qu'il ne rend pas ce genre de couches "spéciales". Ensuite, j'ai trouvé une nouvelle méthode introduite dans iOS 7 – drawViewHierarchyInRect:afterScreenUpdates:
qui devrait être capable de rendre aussi les couches spéciales, mais pas de chance, a toujours l'instantané de l'interface user avec une zone noire vide où la video est affichée. AVPlayerItemVideoOutput
. J'ai ajouté une sortie video pour mon AVPlayerItem
, cependant chaque fois que j'appelle hasNewPixelBufferForItemTime:
il renvoie NO
. Je suppose que le problème est encore en streaming video et je ne suis pas seul avec ce problème. AVAssetReader
. Je pensais essayer mais j'ai décidé de ne pas perdre de time après avoir trouvé une question similaire ici . Donc, n'y a-t-il pas moyen d'avoir un aperçu de quelque chose que je vois de toute façon à l'écran? Je ne peux pas le croire.
AVPlayerItemVideoOutput
fonctionne bien pour moi à partir d'un m3u8. Peut-être que c'est parce que je ne consulte pas hasNewPixelBufferForItemTime
et appelle simplement copyPixelBufferForItemTime
? Ce code produit un CVPixelBuffer
au lieu d'un UIImage
, mais il existe des réponses qui décrivent comment faire cela .
Cette réponse principalement cribbed à partir d' ici
#import "ViewController.h" #import <AVFoundation/AVFoundation.h> @interface ViewController () @property (nonatomic) AVPlayer *player; @property (nonatomic) AVPlayerItem *playerItem; @property (nonatomic) AVPlayerItemVideoOutput *playerOutput; @end @implementation ViewController - (void)setupPlayerWithLoadedAsset:(AVAsset *)asset { NSDictionary* settings = @{ (id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) }; self.playerOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAtsortingbutes:settings]; self.playerItem = [AVPlayerItem playerItemWithAsset:asset]; [self.playerItem addOutput:self.playerOutput]; self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; playerLayer.frame = self.view.frame; [self.view.layer addSublayer:playerLayer]; [self.player play]; } - (IBAction)grabFrame { CVPixelBufferRef buffer = [self.playerOutput copyPixelBufferForItemTime:[self.playerItem currentTime] itemTimeForDisplay:nil]; NSLog(@"The image: %@", buffer); } - (void)viewDidLoad { [super viewDidLoad]; NSURL *someUrl = [NSURL URLWithSsortingng:@"http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:someUrl options:nil]; [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler:^{ NSError* error = nil; AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error]; if (status == AVKeyValueStatusLoaded) { dispatch_async(dispatch_get_main_queue(), ^{ [self setupPlayerWithLoadedAsset:asset]; }); } else { NSLog(@"%@ Failed to load the tracks.", self); } }]; } @end
AVAssetImageGenerator
est le meilleur moyen d'instantané d'une video, cette méthode renvoie de manière asynchronous un UIImage
:
var player:AVPlayer? = // ... func screenshot(handler:((UIImage)->Void)) { guard let player = player , let asset = player.currentItem?.asset else { return } let imageGenerator = AVAssetImageGenerator(asset: asset) imageGenerator.appliesPreferredTrackTransform = true let times = [NSValue(CMTime:player.currentTime())] imageGenerator.generateCGImagesAsynchronouslyForTimes(times) { _, image, _, _, _ in if image != nil { handler(UIImage(CGImage: image!)) } } }
(C'est Swift 2.3)