iOS:AVPlayer – 获取video当前帧的快照
我花了一整天时间,经历了很多SO答案,Apple参考文献,文档等,但都没有成功。
我想要一个简单的事情: 我正在使用AVPlayer播放video,我想暂停它并将当前帧作为UIImage
。 而已。
我的video是位于互联网上的m3u8文件,它在AVPlayerLayer
中正常播放没有任何问题。
我试过了什么:
-
AVAssetImageGenerator
。 它不起作用,方法copyCGImageAtTime:actualTime: error:
返回null image ref。 根据这里的答案,AVAssetImageGenerator
不适用于流式传输video。 - 拍摄玩家视图的快照。 我在
AVPlayerLayer
上尝试了第一个renderInContext:
但后来我意识到它没有呈现这种“特殊”层。 然后我发现在iOS 7中引入了一个新方法 –drawViewHierarchyInRect:afterScreenUpdates:
它应该能够渲染特殊图层,但没有运气,仍然得到了带有空白黑色区域的UI快照,其中显示了video。 -
AVPlayerItemVideoOutput
。 我为我的AVPlayerItem
添加了一个video输出,但每当我调用hasNewPixelBufferForItemTime:
它返回NO
。 我想问题是再次流式传输video, 我并不孤单 。 -
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)
- 即使userInteractionEnabled设置为NO,UITextField也会显示光标
- 应用程序商店的webview应用程序,它会被接受吗?
- 在NSArray内的NSDictionary中排列NSDates?
- 应用商店或App Center参数构建,测试e交付em Apps iOS
- 如何告诉ABPeoplePickerNavigationController仅列出具有电子邮件地址的联系人?
- 像通知中心那样的可拉动视图反弹
- AFNetworking 2.0 – 使用responseObject作为NSDictionary
- Swift:使用未解析的标识符’json’
- 如何在没有任何第三方库的情况下使用Alamofire在Swift 3.0中parsingJSON