我正在尝试禁用任何可辨别的方向旋转到AVCaptureVideoPreviewLayer,同时仍保持任何子视图的旋转。 AVCaptureVideoPreviewLayer确实具有方向属性,更改它确实允许图层正确显示任何方向。但是,旋转涉及AVCaptureVideoPreviewLayer的一些时髦旋转,而不是像在相机应用程序中那样保持平滑。
这就是我如何使方向正常工作,减去轮换中的障碍:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
_captureVideoPreviewLayer.frame = self.view.bounds;
_captureVideoPreviewLayer.orientation = [[UIDevice currentDevice] orientation];
}
如何让这个图层像Camera相同,同时保持其子视图的旋转?
另外,顺便说一下,我已经看到在AVCaptureVideoPreviewLayer上折旧了orientation属性,而且应该使用AVCaptureConnection的videoOrientation属性,但我不认为我有AVCaptureConnection可以在这里访问(我是只需在屏幕上显示相机)。我该如何设置它以访问videoOrientation?
答案 0 :(得分:12)
在包含预览图层的视图上使用仿射变换可创建平滑过渡:
- (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;
}
}
在旋转动画块中调用willAnimateRotationToInterfaceOrientation
函数,因此在此处更改属性将与其余旋转动画一起生成动画。此功能已在iOS 6中逐步淘汰,并替换为处理设备旋转的新方法,因此现在可以使用,但不是最佳解决方案。
答案 1 :(得分:10)
这是一个老问题,但由于它没有一个公认的答案,而且我在过去的几天里一直在处理这个问题,我想我会发布答案。
根据设备方向更改来旋转视频的技巧是 NOT ROTATE AVCaptureVideoPreviewLayer
或AVCaptureConnection
。
更改了AVCaptureConnection
上的方向(AVCaptureVideoPreviewLayer
的方向已被弃用)总是会导致动画更改。在视频旋转后,您会仍然需要转换预览图层。
执行此操作的正确方法是使用AVAssetWriter
编写视频和音频数据..然后在开始录制时对AVAssetWriterInput
应用转换。
以下是Apple关于此事的简介 -
Receiving rotated CVPixelBuffers from AVCaptureVideoDataOutput
要请求缓冲区轮换,客户端调用-setVideoOrientation:on AVCaptureVideoDataOutput的视频AVCaptureConnection。注意 物理旋转缓冲区确实带来性能成本,所以只有 如果有必要请求轮换。 例如,如果你想要的话 使用AVAssetWriter旋转写入QuickTime影片文件的视频, 最好在上面设置-transform属性 AVAssetWriterInput而不是物理地旋转缓冲区 AVCaptureVideoDataOutput 强>
变换的应用与上面发布的代码类似。
希望这可以帮助那些正在寻找答案的人。
答案 2 :(得分:2)
我能够通过以下代码完成此任务:
需要相机时设置:
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;
}
答案 3 :(得分:1)
我希望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];
}
答案 4 :(得分:1)
您应该使用适用于图层的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];
这样,图层就会像视图一样旋转。
答案 5 :(得分:0)
我就是这样做的:
- (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];
}
}
答案 6 :(得分:0)
在swift中我使用:
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
}
}
答案 7 :(得分:0)
检查Apple Example之后,我想出了如何在iOS 11及更高版本中禁用videoPreviewLayer
的旋转功能。 (不确定是否适用于旧版本)
只需在clipToBounds = false
的{{1}}上设置UIView
。
希望这会有所帮助。
答案 8 :(得分:-2)
由于AVCaptureVideoPreviewLayer
是CALayer,因此任何更改都将设置动画http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/AnimatingLayers.html。要仅停留动画[previewLayer removeAllAnimations]
。