AVCaptureVideoPreviewLayer平滑的方向旋转

我试图禁用任何可辨别的方向旋转到AVCaptureVideoPreviewLayer,同时仍然保持任何子视图的旋转。 AVCaptureVideoPreviewLayer确实有一个方向属性,改变它确实允许图层正确显示任何方向。 然而,旋转涉及AVCaptureVideoPreviewLayer的一些时髦的旋转,而不是像在相机应用程序中一样保持平滑。

这就是我如何正确工作的方向,减去旋转中的障碍:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { _captureVideoPreviewLayer.frame = self.view.bounds; _captureVideoPreviewLayer.orientation = [[UIDevice currentDevice] orientation]; } 

如何让这个图层像Camera应用一样运行,同时保持子视图的旋转?

此外,顺便说一下,我已经看到AVCaptureVideoPreviewLayer方向属性折旧,AVCaptureConnection的videoOrientation属性应该用来代替,但我不认为我有一个AVCaptureConnection访问在这里(我只是显示相机在屏幕上)。 我应该如何设置这个访问videoOrientation?

在包含预览图层的视图上使用仿射变换可创build平滑的过渡:

 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { if (cameraPreview) { if (toInterfaceOrientation==UIInterfaceOrientationPortrait) { cameraPreview.transform = CGAffineTransformMakeRotation(0); } else if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) { cameraPreview.transform = CGAffineTransformMakeRotation(M_PI/2); } else if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) { cameraPreview.transform = CGAffineTransformMakeRotation(-M_PI/2); } cameraPreview.frame = self.view.bounds; } } 

将在旋转animation块内调用willAnimateRotationToInterfaceOrientation函数,以便在此处更改属性将与其余的旋转animation一起进行animation处理。 这个function已经在iOS 6中被淘汰了,并被replace为处理设备旋转的新方法,所以这个function现在可行,但并不是最好的解决scheme。

这是一个古老的问题,但由于它没有被接受的答案,而且我在过去几天一直在处理这个问题,所以我想我会公布答案。

基于设备方向改变旋转video的技巧是根本不旋转 AVCaptureVideoPreviewLayerAVCaptureConnection

改变AVCaptureVideoPreviewLayer的方向( AVCaptureVideoPreviewLayer的方向已被弃用) 总是导致一个丑陋的animation变化..而且在video旋转后,你仍然需要转换预览图层。

正确的方法是使用AVAssetWriter写入video和audio数据,然后在开始录制时在AVAssetWriterInput上应用转换。

这里是苹果关于这个的一个简短的介绍 –

从AVCaptureVideoDataOutput接收旋转的CVPixelBuffers

要请求缓冲区旋转,客户端调用AVCaptureVideoDataOutput的videoAVCaptureConnection上的-setVideoOrientation:。 请注意,物理旋转的缓冲区确实带有性能成本,所以只有在必要时才请求旋转。 例如,如果要使用AVAssetWriter将旋转的video写入QuickTime影片文件,则最好在AVAssetWriterInput上设置-transform属性,而不是物理旋转AVCaptureVideoDataOutput中的缓冲区。

转换的应用类似于上面的代码。

  1. 您注册设备方向更改。
  2. 根据新的设备方向跟踪变换应用。
  3. 按下logging时,设置AVAssetWriterInput并对其应用变换。

希望这有助于谁在寻找答案。

我可以用下面的代码来完成这个工作:

在需要相机时设置:

 preview = [[self videoPreviewWithFrame:CGRectMake(0, 0, 320, 480)] retain]; [self.view addSubview:preview]; 

videoPreviewWithFrame函数。

 - (UIView *) videoPreviewWithFrame:(CGRect) frame { AVCaptureVideoPreviewLayer *tempPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:[self captureSession]]; [tempPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; tempPreviewLayer.frame = frame; UIView* tempView = [[UIView alloc] init]; [tempView.layer addSublayer:tempPreviewLayer]; tempView.frame = frame; [tempPreviewLayer autorelease]; [tempView autorelease]; return tempView; } 

我希望AVCaptureVideoPreviewLayer能够很好地跟随所有旋转。 这就是我做的( overlayView只是一个正确的界限)。 只有当你把你的电话超级到他们在代码中的位置时,它才会动起来。

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; if ([[[self previewLayer] connection] isVideoOrientationSupported]) { [[[self previewLayer] connection] setVideoOrientation:toInterfaceOrientation]; } } - (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { CGRect layerRect = [[self overlayView] bounds]; [[self previewLayer] setBounds:layerRect]; [[self previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect), CGRectGetMidY(layerRect))]; [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration: duration]; } 

你应该使用CATransform3DMakeRotation这是为了图层,就像它已经提到的评论:

例如:

 float degreesToRotate = 90.0; //Degrees you want to rotate self.previewLayer.transform = CATransform3DMakeRotation(degreesToRotate / 180.0 * M_PI, 0.0, 0.0, 1.0); 

在我的情况下,被“self.previewLayer”层旋转。 请记住,你应该把它夹到容器视图的边界之后:

 self.previewLayer.frame = self.view.bounds; 

。 。 。

编辑:如果你要旋转的设备被旋转的结果( willAnimateRotationToInterfaceOrientation )你应该做这样的转换:

 [CATransaction begin]; [CATransaction setAnimationDuration:duration]; [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; //**Perform Transformation here** [CATransaction commit]; 

这样,图层就会像视图一样旋转。

这是我如何做到的:

 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { if (tookFirstPicture) return; if (toInterfaceOrientation == UIInterfaceOrientationPortrait) { [previewLayer setOrientation:AVCaptureVideoOrientationPortrait]; } else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) { [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeLeft]; } else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) { [previewLayer setOrientation:AVCaptureVideoOrientationLandscapeRight]; } else { [previewLayer setOrientation:AVCaptureVideoOrientationPortraitUpsideDown]; } } 

在迅速我使用:

 override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { if !UIDevice.currentDevice().model.contains("Simulator") { if (toInterfaceOrientation == .Portrait) { prevLayer?.transform = CATransform3DMakeRotation(0, 0, 0, 1) } else if (toInterfaceOrientation == .LandscapeLeft) { prevLayer?.transform = CATransform3DMakeRotation(CGFloat(M_PI)/2, 0, 0, 1) } else if (toInterfaceOrientation == .LandscapeRight) { prevLayer?.transform = CATransform3DMakeRotation(-CGFloat(M_PI)/2, 0, 0, 1) } prevLayer?.frame = self.scanView.frame } } 

由于AVCaptureVideoPreviewLayer是一个CALayer,所以任何更改都将animation化, http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/AnimatingLayers.html 。 要停止animation只是[previewLayer removeAllAnimations]