ios 카메라 화면 자동회전 (camera auto rotation)
코드
#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"
//화면 전체 가로, 세로길이 구하기
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
//screen orientation
bool g_isPortraitMode; //현재 세로냐 가로냐
float _screenWidth_Landscape; // 가로일때 가로길이
float _screenHeight_Landscape; //가로일때 세로길이
float _screenWidth_Portrait; //세로일때 가로길이
float _screenHeight_Portrait; //세로일때 세로길이
@interface ViewController () <AVCaptureVideoDataOutputSampleBufferDelegate>
{
CGRect s_frame;
}
@property (weak, nonatomic) IBOutlet UIButton *button;
@property (nonatomic,strong) AVCaptureSession *captureSession;
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;
@property (nonatomic,strong) AVCaptureVideoDataOutput *captureOutput;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"viewDidLoad 실행");
// 가로, 세로 스크린사이즈를 전역 변수에 할당
[self initScreenSizeParam];
//새로 화면으로 초기화
g_isPortraitMode = true;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self setScreenOrientation:UIInterfaceOrientationPortrait];
//설정 해주고
s_frame = CGRectMake(0, 0, _screenWidth_Portrait, _screenHeight_Portrait);
//화면이 세로 or 가로로 바뀔때마다 특정 함수를 호출한다.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChage:) name:UIDeviceOrientationDidChangeNotification object:nil];
//카메라 초기화
[self initCapture];
//
[self.view bringSubviewToFront:_button];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"viewWillAppear 실행");
NSLog(@"g_isPortraitMode : %@" , (g_isPortraitMode ? @"true - 세로" : @"false - 가로"));
if (g_isPortraitMode) {
[self rotateVideo:UIInterfaceOrientationPortrait];
[self updateViewUIWhenRotatedWithPortraitMode:YES];
}
}
//오리엔테이션이 바뀌면 위젯 상태를 조정할 수 있습니다.
- (void)updateViewUIWhenRotatedWithPortraitMode:(BOOL)isPortraitMode {
if (isPortraitMode) {
}else {
}
}
#pragma step 7.
-(void)initCapture {
NSLog(@"step 7. initCapture 실행");
//후방카메라 객체 만들기
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//입력데이터객체 만들기
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:nil];
//입력객체 null 체크
if(!captureInput){
NSLog(@"captureInput is null !");
return;
}
//비디오 출력객체 만들기
_captureOutput = [[AVCaptureVideoDataOutput alloc] init];
[_captureOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
NSString *key = (NSString *)kCVPixelBufferPixelFormatTypeKey;
NSNumber *value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[_captureOutput setVideoSettings:videoSettings];
//세션 객체 생성
self.captureSession = [[AVCaptureSession alloc] init];
NSString *preset;
if(!preset) preset = AVCaptureSessionPreset1920x1080;
//세션에 프리셋을 넣을 수 있다면
if ([_captureSession canSetSessionPreset:preset]) {
self.captureSession.sessionPreset = preset;
}else{
self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
}
//세션에 입력 객체를 넣을 수 있다면
if ([self.captureSession canAddInput:captureInput]) {
[self.captureSession addInput:captureInput];
}
//세션에 출력 객체를 넣을 수 있다면
if ([self.captureSession canAddOutput:_captureOutput]) {
[self.captureSession addOutput:_captureOutput];
}
//비디오 미리보기 레이어 객체가 없다면
if (!self.captureVideoPreviewLayer) {
self.captureVideoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
}
//프레임 위치 및 크기 셋팅
s_frame.origin.x = 0;
s_frame.origin.y = 0;
NSLog(@"initCapture - g_isPortraitMode : %@" , (g_isPortraitMode ? @"true - 세로" : @"false - 가로"));
if (g_isPortraitMode) {
NSLog(@"initCapture s_frame : 세로 셋팅 *" );
s_frame.size.width = _screenWidth_Portrait;
s_frame.size.height = _screenHeight_Portrait;
}else{
NSLog(@"initCapture s_frame : 가로 셋팅 *" );
s_frame.size.width = _screenWidth_Landscape;
s_frame.size.height = _screenHeight_Landscape;
}
self.captureVideoPreviewLayer.frame = s_frame;
NSLog(@"initCapture s_frame : %@" , NSStringFromCGRect(s_frame));
self.captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
if ([[self.captureVideoPreviewLayer connection] isVideoOrientationSupported]) {
NSLog(@"isVideoOrientationSupported - 가능!");
[self.captureVideoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
}
[self.view.layer addSublayer:self.captureVideoPreviewLayer];
[self.captureSession startRunning];
}
#pragma step 6.
-(void)adjustAVOutputDataOrientaion:(AVCaptureVideoOrientation)aOrientation{
NSLog(@"step 6 adjustAVOutputDataOrientaion 진입");
NSLog(@"aOrientation :%ld" , (long)aOrientation);
for (AVCaptureConnection *connection in _captureOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
if ([connection isVideoOrientationSupported]) {
[connection setVideoOrientation:aOrientation];
}
}
}
}
}
#pragma step 5.
//비디오 회전
-(int) rotateVideo:(UIInterfaceOrientation)interfaceOrientation {
NSLog(@"step 5. rotateVideo 진입");
NSLog(@"step 5 interfaceOrientation :%ld" , (long)interfaceOrientation);
if (_captureSession != NULL) {
NSLog(@"_captureSession is not null when video rotate");
//호출후에 는 출력을 추가 또는 제거 하거나 개별 캡처 입력 또는 출력 속성을 구성하거나 변경할 수 있습니다.
//사용자가 호출 할 때까지 실제로 변경되지 않으며 , 이 때 변경 사항이 적용됩니다.begin
[_captureSession beginConfiguration];
CALayer *previewViewLayer = [self.view layer];
NSArray *subviews= previewViewLayer.sublayers;
int i = 0;
NSLog(@"subviews count : %lu" , (unsigned long)[subviews count]);
while (true) {
NSLog(@" i : %d" , i );
//서브 레이어 수보다 i 가 크면
if (i > [subviews count]) {
break;
}
id layer = [subviews objectAtIndex:i];
if ([layer isKindOfClass:[AVCaptureVideoPreviewLayer class]] == TRUE) {
//변경된 프레임 할당하는 곳!!
[layer setFrame:s_frame];
switch (interfaceOrientation) {
case UIInterfaceOrientationPortrait:
NSLog(@"UIInterfaceOrientationPortrait = Portrait");
[[layer connection] setVideoOrientation:AVCaptureVideoOrientationPortrait];
[self adjustAVOutputDataOrientaion:AVCaptureVideoOrientationPortrait];
break;
case UIInterfaceOrientationPortraitUpsideDown:
NSLog(@"UIInterfaceOrientationPortrait = PortraitUpsideDown");
[[layer connection] setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
[self adjustAVOutputDataOrientaion:AVCaptureVideoOrientationPortraitUpsideDown];
break;
case UIInterfaceOrientationLandscapeLeft:
NSLog(@"UIInterfaceOrientationLandscapeLeft");
[[layer connection] setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
[self adjustAVOutputDataOrientaion:AVCaptureVideoOrientationLandscapeLeft];
break;
case UIInterfaceOrientationLandscapeRight:
NSLog(@"UIInterfaceOrientationLandscapeRight");
[[layer connection] setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
[self adjustAVOutputDataOrientaion:AVCaptureVideoOrientationLandscapeRight];
break;
default:
break;
}
break;
}
i++;
}
//캡쳐 세션의 구성변경 커밋
[_captureSession commitConfiguration];
}else if(![_captureSession isRunning]){
NSLog(@"_captureSession is not running when rotate video");
}
return 0;
}
#pragma step 4.
-(BOOL)rotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation{
NSLog(@"step 4. rotateToInterfaceOrientation 진입");
NSLog(@"interfaceOrientation :%ld" , (long)interfaceOrientation);
//가로 왼쪽이거나, 가로오른쪽일때 비디오 회전하기!
if((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight)|| (interfaceOrientation == UIInterfaceOrientationPortrait)) {
//rotate video
NSLog(@"비디오 회전해!!");
[self rotateVideo:interfaceOrientation];
}else{
return NO;
}
return YES;
}
#pragma step 3.
-(void) deviceOrientationDidChage:(NSNotification *) notification{
NSLog(@"step 3. deviceOrientationDidChage 진입");
//현재 디바이스 오리엔테이션 구하기
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
//세로 : 1, 거꾸로 : 2, 가로왼쪽 : 3, 가로오른쪽 : 4
NSLog(@"현재 디바이스 상태는 %ld 입니다", (long)orientation);
//디바이스 상태가 변경되면 처리할 내용
if (orientation == UIDeviceOrientationLandscapeLeft) {
NSLog(@"현재 디바이스 상태는 가로 왼쪽 입니다.");
//현재 오리엔테이션이 가로면 비디오 회전해주기
g_isPortraitMode = false;
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
s_frame = CGRectMake(0, 0, _screenWidth_Landscape, _screenHeight_Landscape);
[self rotateToInterfaceOrientation:(UIInterfaceOrientation)orientation];
}else if(orientation == UIDeviceOrientationLandscapeRight){
NSLog(@"현재 디바이스 상태는 가로 오른쪽 입니다.");
//현재 오리엔테이션이 가로면 비디오 회전해주기
g_isPortraitMode = false;
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
s_frame = CGRectMake(0, 0, _screenWidth_Landscape, _screenHeight_Landscape);
[self rotateToInterfaceOrientation:(UIInterfaceOrientation)orientation];
}else if (orientation == UIDeviceOrientationPortrait){
NSLog(@"현재 디바이스 상태는 세로 입니다.");
g_isPortraitMode = true;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
//[self setScreenOrientation:UIInterfaceOrientationPortrait];
//프레임을 재 설정 해주고
s_frame = CGRectMake(0, 0, _screenWidth_Portrait, _screenHeight_Portrait);
//비디오를 세로로 돌리기
[self rotateToInterfaceOrientation:(UIInterfaceOrientation)orientation];
}
// NSLog(@"deviceOrientationDidChage - g_isPortraitMode : %@" , (g_isPortraitMode ? @"true - 세로" : @"false - 가로"));
//
// //특정한 오리엔테이션 무시하기
// if (g_isPortraitMode || orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown){
// NSLog(@"특정한 오리엔테이션 무시하기");
// return;
// }
}
#pragma step 2.
- (void)initScreenSizeParam {
NSLog(@"step 2. initScreenSizeParam 실행");
CGFloat screenW = kScreenWidth;
CGFloat screenH = kScreenHeight;
//가로길이가 세로길이 보다 작으면 , 즉 디바이스가 portraite 모드 일때
if (screenW < screenH) {
NSLog(@"screenW < screenH" );
screenW = kScreenHeight; //screenW = 667
screenH = kScreenWidth; //screenH = 375
}
NSLog(@"screenW : %f" ,screenW );
NSLog(@"screenH : %f" ,screenH );
_screenWidth_Landscape = screenW; // 667
_screenHeight_Landscape = screenH; // 375
_screenHeight_Portrait = screenW; // 667
_screenWidth_Portrait =screenH; //375
NSLog(@"_screenWidth_Landscape : %f" , _screenWidth_Landscape );
NSLog(@"_screenHeight_Landscape : %f" , _screenHeight_Landscape );
NSLog(@"_screenHeight_Portrait : %f" , _screenHeight_Portrait );
NSLog(@"_screenWidth_Portrait : %f" , _screenWidth_Portrait );
}
#pragma step 1.
//앱 은 먼저 supportedInterfaceOrientations 메소드를 실행 한 다음 ViewDidLoad 메소드를 실행합니다.
//g_isPortraitMode 값을 설정합니다. - 화면이 바뀔때 항상 먼저 호출됨
//-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
// NSLog(@"step 1. supportedInterfaceOrientations 호출");
//
// //스크린 모드 변수
// UIInterfaceOrientationMask screenMode;
// // 세로인지 가로인지 체크
// if([[NSUserDefaults standardUserDefaults] boolForKey:@"isPortraitMode"]){
// g_isPortraitMode = true;
// screenMode = UIInterfaceOrientationMaskPortrait;
// NSLog(@" !! supportedInterfaceOrientations 실행 - Portrait");
// }else{
// g_isPortraitMode = false;
// screenMode = UIInterfaceOrientationMaskLandscape;
// NSLog(@" !! supportedInterfaceOrientations 실행 - Landscape");
// }
// //defalt 스크린 모드 리턴 (세로 or 가로)
// return screenMode;
//}
//버튼 클릭했을 때 -> 디바이스에 오리엔테이션 설정해주기 -> step 1 supportedInterfaceOrientations호출
- (IBAction)buttonAction:(UIButton *)sender {
NSLog(@"buttonAction 작동" );
sender.selected = !sender.selected;
if(sender.isSelected) { // Portrait
g_isPortraitMode = true;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self setScreenOrientation:UIInterfaceOrientationPortrait];
//프레임을 재 설정 해주고
s_frame = CGRectMake(0, 0, _screenWidth_Portrait, _screenHeight_Portrait);
//비디오를 세로로 돌리기
[self rotateVideo:UIInterfaceOrientationPortrait];
[self updateViewUIWhenRotatedWithPortraitMode:YES];
}else { // Landscape
g_isPortraitMode = false;
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isPortraitMode"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self setScreenOrientation:UIInterfaceOrientationLandscapeRight];
s_frame = CGRectMake(0, 0, _screenWidth_Landscape, _screenHeight_Landscape);
[self rotateVideo:UIInterfaceOrientationLandscapeRight];
[self updateViewUIWhenRotatedWithPortraitMode:NO];
}
}
//디바이스에 오리엔테이션 설정해주기 -> step 1 호출
- (void)setScreenOrientation:(UIInterfaceOrientation)orientation {
NSLog(@"setScreenOrientation :%ld" , (long)orientation);
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = orientation;//
[invocation setArgument:&val atIndex:2];
//step 1을 호출 ?
[invocation invoke];
NSLog(@"setScreenOrientation end!");
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
결과화면
'ios 뽀개기 > objective-c' 카테고리의 다른 글
core audioqueue player 에 대하여 (0) | 2019.03.28 |
---|---|
core audio queue service (ios recording) (0) | 2019.03.26 |
코어오디오 MediaPlayer 구현 (1) | 2019.03.04 |
엔터프라이즈 계정으로 배포 (0) | 2019.02.15 |
이미지 자르기 (0) | 2019.01.27 |
댓글