iOS:AVPlayer – 获取video当前帧的快照

我花了一整天时间,经历了很多SO答案,Apple参考文献,文档等,但都没有成功。

我想要一个简单的事情: 我正在使用AVPlayer播放video,我想暂停它并将当前帧作为UIImage 。 而已。

我的video是位于互联网上的m3u8文件,它在AVPlayerLayer中正常播放没有任何问题。

我试过了什么:

  1. AVAssetImageGenerator 它不起作用,方法copyCGImageAtTime:actualTime: error:返回null image ref。 根据这里的答案, AVAssetImageGenerator不适用于流式传输video。
  2. 拍摄玩家视图的快照。 我在AVPlayerLayer上尝试了第一个renderInContext:但后来我意识到它没有呈现这种“特殊”层。 然后我发现在iOS 7中引入了一个新方法 – drawViewHierarchyInRect:afterScreenUpdates:它应该能够渲染特殊图层,但没有运气,仍然得到了带有空白黑色区域的UI快照,其中显示了video。
  3. AVPlayerItemVideoOutput 我为我的AVPlayerItem添加了一个video输出,但每当我调用hasNewPixelBufferForItemTime:它返回NO 。 我想问题是再次流式传输video, 我并不孤单 。
  4. AVAssetReader 我正在考虑尝试,但决定在这里找到相关问题后不要浪费时间。

所以,有没有什么方法可以获得我现在在屏幕上看到的某些内容的快照? 我不敢相信。

从m3u8开始, AVPlayerItemVideoOutput对我来说很好。 也许是因为我不咨询hasNewPixelBufferForItemTime而只是调用copyPixelBufferForItemTime ? 此代码生成CVPixelBuffer而不是UIImage ,但有些答案描述了如何执行此操作 。

这个答案大多来自这里

 #import "ViewController.h" #import  @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] initWithPixelBufferAttributes: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 URLWithString:@"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是对video进行快照的最佳方式,此方法异步返回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!)) } } } 

(这是Swift 2.3)