我有一个AVPlayerLayer(CALayer的子类),我需要进入一个可以传递给QCRenderer的图像类型(QCRenderer接受NSImages和CIImages。)我可以将CALayer转换为CGImageRef,并将其转换为NSImage,但内容始终清晰。
我把它缩小到以下两个原因之一:
我没有收到任何错误,并且找到了一些关于转换CALayers的文档。另外,我将AVPlayerLayer添加到NSView,它仍然是空的,所以我认为2是问题所在。
我正在使用Apple的AVPlayerDemo的AVPlayerDemoPlaybackViewController的修改版本。我把它变成了NSObject,因为我从中删除了所有的接口代码。
我在创建AVPlayer时在(void)prepareToPlayAsset:withKeys:方法中创建AVPlayerLayer :(我只是将图层添加到NSView以测试它是否正常工作。)
if (![self player])
{
/* Get a new AVPlayer initialized to play the specified player item. */
[self setPlayer:[AVPlayer playerWithPlayerItem:self.mPlayerItem]];
/* Observe the AVPlayer "currentItem" property to find out when any
AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did
occur.*/
[self.player addObserver:self
forKeyPath:kCurrentItemKey
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:AVPlayerDemoPlaybackViewControllerCurrentItemObservationContext];
mPlaybackView = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.theView setWantsLayer:YES];
[mPlaybackView setFrame:self.theView.layer.bounds];
[self.theView.layer addSublayer:mPlaybackView];
}
然后我创建一个NSRunLoop来每秒抓取一次AVPlayerLayer的帧30次:
framegrabTimer = [NSTimer timerWithTimeInterval:(1/30) target:self selector:@selector(grabFrameFromMovie) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:framegrabTimer forMode:NSDefaultRunLoopMode];
这是我用来抓取框架并将其传递给处理QCRenderer的类的代码:
-(void)grabFrameFromMovie {
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef theContext = CGBitmapContextCreate(NULL, mPlaybackView.frame.size.width, mPlaybackView.frame.size.height, 8, 4*mPlaybackView.frame.size.width, colorSpace, kCGImageAlphaPremultipliedLast);
[mPlaybackView renderInContext:theContext];
CGImageRef CGImage = CGBitmapContextCreateImage(theContext);
NSImage *image = [[NSImage alloc] initWithCGImage:CGImage size:NSMakeSize(mPlaybackView.frame.size.width, mPlaybackView.frame.size.height)];
[[NSNotificationCenter defaultCenter] postNotificationName:@"AVPlayerLoadedNewFrame" object:[image copy]];
CGContextRelease(theContext);
CGColorSpaceRelease(colorSpace);
CGImageRelease(CGImage); }
我无法弄清楚为什么我只是清楚了。非常感谢任何帮助,因为OS X没有足够的AVFoundation文档。
答案 0 :(得分:0)
它适用于我:
AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:[[[self player] currentItem] asset]];
CGImageRef capture = [gen copyCGImageAtTime:self.player.currentTime actualTime:NULL error:NULL];
NSImage *img = [[NSImage alloc] initWithCGImage:capture size:self.playerView.frame.size];
答案 1 :(得分:0)
您可以将AVPlayerItemVideoOutput添加到AVPlayerItem,然后调用copyPixelBufferForItemTime来查询在指定时间内包含该帧的CVPixelBufferRef对象,下面是示例代码:
df['type'] = np.where(df['model'].isin(dictMobile.keys()), 'mobile','tablet')
print (df)
assigned to model type
0 user1 ipad air 2 tablet
1 user2 galaxy a5 mobile
2 user3 ipad air tablet
你可以查看苹果公司的官方样本:
答案 2 :(得分:0)
SWIFT 5.2版本:
我认为 rozochkin 的答案是正确的,我发现它真的很有用。我自己进行了测试,它可以正常工作。
我只想发布更新的Swift 5.2版本,以防万一有人需要它。
func getCurrentFrame() -> CGImage? {
guard let player = self.player, let avPlayerAsset = player.currentItem?.asset else {return nil}
let assetImageGenerator = AVAssetImageGenerator(asset: avPlayerAsset)
assetImageGenerator.requestedTimeToleranceAfter = .zero
assetImageGenerator.requestedTimeToleranceBefore = .zero
assetImageGenerator.appliesPreferredTrackTransform = true
let imageRef = try! assetImageGenerator.copyCGImage(at: player.currentTime(), actualTime: nil)
return imageRef
}
重要说明:
requestedTimeToleranceAfter 和 requestedTimeToleranceBefore 应该设置为.zero,因为根据源代码,“生成图像的实际时间可能与[...]要求的效率时间”。
appliesPreferredTrackTransform 必须设置为 TRUE (默认为FALSE),否则会出现帧旋转不良。将此属性设置为TRUE,您将获得在播放器中真正看到的内容。