我使用AVFoundation
显示相机。
我想,以防止相机自身旋转,所以观众会看到相机仅在纵向和图像将只在纵向模式下服用。
我定义Supported Interface Orientation
,以支持仅纵向和本身仅在纵向模式被显示的视图,但不是相机-正在与该设备定向旋转
我怎样才能迫使AVFoundation
只有在像UIViewController的画像显示的相机,捕捉图像?
我的代码来设置相机:
AVCaptureVideoPreviewLayer* lay = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.sess];
UIView *view = [self videoPreviewView];
CALayer *viewLayer = [view layer];
[viewLayer setMasksToBounds:YES];
CGRect bounds = [view bounds];
[lay setFrame:bounds];
if ([lay respondsToSelector:@selector(connection)])
{
if ([lay.connection isVideoOrientationSupported])
{
[lay.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
}
[lay setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[viewLayer insertSublayer:lay below:[[viewLayer sublayers] objectAtIndex:0]];
self.previewLayer = lay;
这是基于我对你的问题(从你有其他的答案不同)的了解了部分答案。
您已锁定为纵向的应用程序。 因此,状态栏始终在手机的顶部肖像无论手机的方向。 这成功地锁定您的接口,包括您的AVCapture接口。 但你也想锁定从相机的原始图像饲料,使图像地平线总是与状态栏平行。
这将非常需要连续进行-所以,如果你有摄像头在45度角的图像会适得其反旋转45度。 否则,大多数时候,图像将无法正确对齐(另一种方法是,它始终是脱节的,直到你90degree方向开关的更新,这将转体图像90度)。
要做到这一点,你需要使用核心运动和加速度计。 你想拿到手机的Y轴为真垂直的角度,并相应地旋转图像。 看到这里的几何细节:
iPhone方向-如何找出哪个方向是向上?
使用核心运动,触发从viewDidLoad中这种方法
- (void)startAccelerometerUpdates {
self.coreMotionManager = [[CMMotionManager alloc] init];
if ([self.coreMotionManager isAccelerometerAvailable] == YES) {
CGFloat updateInterval = 0.1;
// Assign the update interval to the motion manager
[self.coreMotionManager setAccelerometerUpdateInterval:updateInterval];
[self.coreMotionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error) {
CGFloat angle = -atan2( accelerometerData.acceleration.x,
accelerometerData.acceleration.y)
+ M_PI ;
CATransform3D rotate = CATransform3DMakeRotation(angle, 0, 0, 1);
self.previewLayer.transform = rotate;
}];
}
}
一个 b C
举行(一)肖像电话; (b)中旋转30度〜; (三)景观
。
您可能会发现这是一个有点神经质,而且还有几分设备的移动和视图之间的滞后。 你可以用updateInterval玩,并与其他核心运动挂羊头卖狗肉,以抑制运动更深得到。 ( 我还没有处理的手机确切地说是倒挂的情况下,如果你按住相机面朝下或面朝上,其结果是不确定的 固定更新的代码/使用atan2
)。
现在的方向是正确合理的,但你的形象不适合你的看法。 没有很多可以做这为原料摄像头输入的格式由物理尺寸,它的传感器阵列固定。 解决办法是让你在各个角度足够的多余的图像数据,使您可以裁剪图像,以适应你想要的肖像格式来缩放图像。
无论是在界面生成器:
- 设定previewLayer的视图正方形围绕它的上海华,具有宽度和高度等于该对角线上的可视图像的区域(SQRT(宽度2 +高度2)
或代码:
- (void)resizeCameraView
{
CGSize size = self. videoPreviewView.bounds.size;
CGFloat diagonal = sqrt(pow(size.width,2)+pow(size.height,2));
diagonal = 2*ceil(diagonal/2); //rounding
self.videoPreviewView.bounds = (CGRect){0,0,diagonal,diagonal};
}
如果你这样做的代码, resizeCameraView
应该如果你从你叫它工作viewDidLoad
。 确保self.videoPreviewView
是您的IBOutlet中引用正确的观点。
现在,当你拍照,你会捕捉整个从相机阵列“原始”的图像数据,这将是横向格式的。 它将被保存与屏幕旋转的方向标志。 但你可能想要的是将照片保存为屏幕上看到的。 这意味着,你将不得不旋转,裁剪照片保存前以符合您的屏幕上查看和删除它的方向元数据。 这对你的工作了(即“部分答案”的其他部分):我怀疑你可能会觉得这整个的做法并没有得到你想要的东西(我想你很想被摄像机传感器硬件对设备的旋转-rotates保持稳定的地平线)。
更新
改变startAccelerometerUpdates
从中获取角度atan2
代替acos
,顺畅,考虑到各个方向的不摆弄
更新2
从您的意见,似乎你的旋转预览层卡住? 我不能复制你的错误,那一定是在你的代码或设置其他一些地方。
所以,你可以用干净的代码检查,我增加了我的解决方案为苹果的AVCam项目 ,这样你就可以检查它对抗。 这里是做什么的:
在AVCamViewController.m
-
#import <CoreMotion/CoreMotion.h>
- 加我
startAccelerometerUpdates
方法 - 加我
resizeCameraView
方法(坚持这两种方法附近的类文件的顶部,或者你可能会感到困惑,也有不止一个@implementation
在那只文件) - 添加一行:
[self resizeCameraView];
到viewDidLoad
(它可以是该方法的第一行) - 添加属性
@property (strong, nonatomic) CMMotionManager* coreMotionManager
在@interface(它并不需要是一个财产,但我的方法假定它的存在,所以如果你不加它,你将不得不修改我的方法来代替)。
在startAccelerometerUpdates
改变这一行:
self.previewLayer.transform = rotate;
至:
self.captureVideoPreviewLayer.transform = rotate;
同样,在对象列表AVCamViewController.xib
,移动工具栏(否则,当你放大你覆盖控件)以上的videoPreview查看
一定要禁用转 - 适用于iOS <6.0,这已经是事实,但为6.0+,你需要在目标总结支撑取向只选择肖像。
我认为这是我对AVCam所做的更改的完整列表,旋转/定向所有工作得很好。 我建议你尝试这样做。 如果你能得到这个工作的顺利开展,你知道有你的代码中的一些其他故障的地方。 如果你仍然觉得你的旋转坚持,我会好奇地想知道更多关于你的硬件和软件环境,如哪些设备正在测试你的。
我在编译4.6的XCode / OSX10.8.2和测试上:
- iPhone4S / iOS5.1
- iPhone3G / iOS6.1
- iPad mini / iOS6.1
所有的结果都是平稳和准确。
我猜你需要用这个方法来限制摄像机旋转。
AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]];
if ([videoConnection isVideoOrientationSupported])
{
[videoConnection setVideoOrientation:[UIDevice currentDevice].orientation];
}
假设您的预览层定义为属性,可以使用
[self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]];
你的情况,你可以取代[的UIDevice currentDevice]取向]由UIInterfaceOrientationPortrait
编辑
尝试添加预览层当你真正需要它。 例
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;
}
假设你previewlayer被添加到一个视图控制器视图。 在执行此操作viewDidLoad
:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
并定义选择为:
- (void)orientationChanged:(NSNotification*)notification {
UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if ([self.previewlayer respondsToSelector:@selector(orientation)]) {
//for iOS5
if (interfaceOrientation != UIInterfaceOrientationPortrait) {
self.previewlayer.orientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
}
} else {
//for iOS6
if (interfaceOrientation != UIInterfaceOrientationPortrait) {
self.previewlayer.connection.videoOrientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
}
}
}
注意:把tempPreviewLayer
在属性self.previewlayer
。
这将预览层强制纵向位置当设备方向变化。
编辑
您还可以在乌拉圭回合“的的viewController的shouldAutoRotate`方法添加此
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([self.previewlayer respondsToSelector:@selector(orientation)]) {
if (interfaceOrientation != UIInterfaceOrientationPortrait) {
self.previewlayer.orientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
}
} else {
if (interfaceOrientation != UIInterfaceOrientationPortrait) {
self.previewlayer.connection.videoOrientation = (AVCaptureVideoOrientation)UIInterfaceOrientationPortrait;
}
}
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
为iOS6的乘坐过这两个检查。
-(NSUInteger)supportedInterfaceOrientations {
//UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
//return (
//interfaceOrientation == UIInterfaceOrientationLandscapeLeft |
//interfaceOrientation == UIInterfaceOrientationLandscapeRight);
return UIInterfaceOrientationMaskLandscape;//(UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight);
}
- (BOOL)shouldAutorotate {
return YES;
}
前return
在这两种方法中apend,我给通知的代码..和,看看它,当你roate设备调用。